Avoid Yandex Turbo

Redirect directly to target page avoiding Yandex Turbo

  1. // ==UserScript==
  2. // @name Avoid Yandex Turbo
  3. // @name:ru Обход Яндекс Турбо
  4. // @description Redirect directly to target page avoiding Yandex Turbo
  5. // @description:ru Переадресация на целевую страницу в обход Яндекс Турбо
  6. // @namespace https://github.com/Autapomorph/userscripts
  7. // @author Autapomorph
  8. // @version 3.5.0
  9. // @run-at document_start
  10. // @match *://yandex.tld/*
  11. // @match *://*.turbopages.org/*
  12. // @supportURL https://github.com/Autapomorph/userscripts/discussions
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. (function avoidYandexTurbo() {
  17. const checkIntervalMs = 1000;
  18.  
  19. const domainRegex = {
  20. turbopages: /\.turbopages\.org/,
  21. yandex: /yandex\..+/,
  22. };
  23.  
  24. function redirectWithTurboScript() {
  25. const turboScriptSelector = 'script[data-name="post-message"][data-message]';
  26. const turboScript = document.querySelector(turboScriptSelector);
  27. if (!turboScript) {
  28. return;
  29. }
  30.  
  31. const dataMessage = turboScript.getAttribute('data-message');
  32. if (typeof dataMessage !== 'string') {
  33. return;
  34. }
  35.  
  36. let redirectTo;
  37. try {
  38. const dataMessageJson = JSON.parse(dataMessage);
  39. if (dataMessageJson && dataMessageJson.originalUrl) {
  40. redirectTo = dataMessageJson.originalUrl;
  41. }
  42. } catch {
  43. return;
  44. }
  45.  
  46. if (redirectTo) {
  47. top.location.replace(redirectTo);
  48. }
  49. }
  50.  
  51. function redirectWithTurboOverlay() {
  52. const titleHostActive = document.querySelector('.turbo-overlay__title-host_active');
  53. if (!titleHostActive) return;
  54.  
  55. const titleHostActiveText = titleHostActive.textContent;
  56. const hostLinks = document.querySelectorAll('a[data-sc-host]');
  57. for (let i = 0; i < hostLinks.length; i += 1) {
  58. const hostLink = hostLinks[i];
  59. let dataCounter;
  60. try {
  61. dataCounter = JSON.parse(hostLink.getAttribute('data-counter'));
  62. } catch {
  63. return;
  64. }
  65.  
  66. if (dataCounter.find(e => e.indexOf(titleHostActiveText) > -1)) {
  67. let redirectTo;
  68. if (dataCounter[0] === 'b') {
  69. redirectTo = dataCounter[1];
  70. } else if (dataCounter[0] === 'w') {
  71. redirectTo = dataCounter[3];
  72. } else return;
  73.  
  74. top.location.replace(redirectTo);
  75. }
  76. }
  77. }
  78.  
  79. function redirectWithURLPathname(urlPathname) {
  80. const turboIndex = urlPathname.indexOf('/turbo/');
  81. const delimeterIndex = urlPathname.search(/\/(s|h)\//);
  82. const delimeterLength = 2;
  83.  
  84. if (delimeterIndex < 0) return;
  85.  
  86. const host =
  87. turboIndex === -1
  88. ? urlPathname.substring(1, delimeterIndex)
  89. : urlPathname.substring(turboIndex + '/turbo/'.length, delimeterIndex);
  90. const pathName = urlPathname.substring(delimeterIndex + delimeterLength);
  91. top.location.replace(`//${host}${pathName}`);
  92. }
  93.  
  94. function redirectWithURLSearchParam(urlSearchParams) {
  95. const textQuery = urlSearchParams.get('text');
  96. if (textQuery) {
  97. top.location.replace(textQuery);
  98. }
  99. }
  100.  
  101. function isTurboPage(urlHostname, urlPathname, urlSearchParams) {
  102. // Turbopages domain
  103. if (domainRegex.turbopages.test(urlHostname)) {
  104. return true;
  105. }
  106.  
  107. // Yandex domains
  108. if (domainRegex.yandex.test(urlHostname) && urlPathname.includes('/turbo')) {
  109. if (/\.*\/(s|h)\/.*/.test(urlPathname)) {
  110. return true;
  111. }
  112.  
  113. if (urlSearchParams.has('text')) {
  114. // Do not redirect Yandex Health Turbo inline
  115. if (domainRegex.yandex.test(urlSearchParams.get('text'))) {
  116. return false;
  117. }
  118.  
  119. return true;
  120. }
  121. }
  122.  
  123. return false;
  124. }
  125.  
  126. function main() {
  127. const urlHostname = top.location.hostname;
  128. const urlPathname = top.location.pathname;
  129. const urlSearchParams = new URLSearchParams(top.location.search);
  130.  
  131. if (!isTurboPage(urlHostname, urlPathname, urlSearchParams)) {
  132. return;
  133. }
  134.  
  135. redirectWithTurboScript();
  136. redirectWithTurboOverlay();
  137. redirectWithURLPathname(urlPathname);
  138. redirectWithURLSearchParam(urlSearchParams);
  139. }
  140.  
  141. if (typeof module === 'object' && module.exports) {
  142. module.exports = {
  143. avoidYandexTurbo,
  144. main,
  145. isTurboPage,
  146. redirectWithTurboScript,
  147. redirectWithTurboOverlay,
  148. redirectWithURLPathname,
  149. redirectWithURLSearchParam,
  150. };
  151.  
  152. return;
  153. }
  154.  
  155. let currentURLPathname = top.location.pathname;
  156. setInterval(() => {
  157. if (currentURLPathname !== top.location.pathname) {
  158. currentURLPathname = top.location.pathname;
  159. main();
  160. }
  161. }, checkIntervalMs);
  162.  
  163. main();
  164. })();