Replace youtube redirect links

Replace youtube redirect links with direct links and extend links text to its full length

  1. // ==UserScript==
  2. // @name Replace youtube redirect links
  3. // @description Replace youtube redirect links with direct links and extend links text to its full length
  4. // @author MK
  5. // @namespace max44
  6. // @homepage https://greasyfork.org/en/users/309172-max44
  7. // @match *://*.youtube.com/*
  8. // @match *://*.youtu.be/*
  9. // @icon https://cdn.icon-icons.com/icons2/1488/PNG/512/5295-youtube-i_102568.png
  10. // @version 1.4
  11. // @license MIT
  12. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
  13. // @run-at document-idle
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. //Workaround: This document requires 'TrustedHTML' assignment
  20. if (window.trustedTypes && trustedTypes.createPolicy) {
  21. if (!trustedTypes.defaultPolicy) {
  22. const passThroughFn = (x) => x;
  23. trustedTypes.createPolicy('default', {
  24. createHTML: passThroughFn,
  25. createScriptURL: passThroughFn,
  26. createScript: passThroughFn,
  27. });
  28. }
  29. }
  30.  
  31. const rootCallback = function (mutationsList, observer) {
  32.  
  33. //Remove all events listeners from redirected links
  34. var link = document.querySelectorAll("a[href*='/redirect?']");
  35. if (link != null && link.length > 0) {
  36. for (var i = 0; i < link.length; i++) {
  37. link[i].replaceWith(link[i].cloneNode(true));
  38. }
  39. }
  40. //Replace redirect links by direct links
  41. document.querySelectorAll("a[href*='/redirect?']").forEach(replaceRedirect);
  42.  
  43. document.querySelectorAll("a:not([expanded-by-script])").forEach(showFullLink);
  44. document.querySelectorAll("div#below span.yt-core-attributed-string > span > span.yt-core-attributed-string--highlight-text-decorator:not([expanded-by-script]) > a[href*='/watch?']").forEach(showFullVideoName);
  45. document.querySelectorAll("div#below span.yt-core-attributed-string > span > span.yt-core-attributed-string--highlight-text-decorator:not([expanded-by-script]) > a[href*='/shorts/']").forEach(showFullVideoName);
  46. document.querySelectorAll("div#below span.yt-core-attributed-string > span > span.yt-core-attributed-string--highlight-text-decorator:not([expanded-by-script]) > a[href*='/playlist?']").forEach(showFullVideoName);
  47. }
  48.  
  49. const rootNode = document.querySelector("body");
  50. if (rootNode != null) {
  51. const rootObserver = new MutationObserver(rootCallback);
  52. rootObserver.observe(rootNode, {childList: true, subtree: true});
  53. }
  54.  
  55. function replaceRedirect(link) { //Remove redirection
  56. link.href = decodeURIComponent(link.href.replace (/^.*\?(.*&)q=([^&]+)(&.*)?$/, '$2'));
  57. const wrpLink = link.wrappedJSObject || link;
  58. if (wrpLink.data && wrpLink.data.urlEndpoint) {
  59. wrpLink.data.urlEndpoint.url = link.href;
  60. }
  61. showFullLink(link);
  62. }
  63.  
  64. function showFullLink(link) { //Expand link to full length
  65. if (link.innerText.substring(0, 20) == link.href.substring(0, 20) && link.innerText.substring(link.innerText.length-3, link.innerText.length) === "...") {
  66. link.innerText = link.href;
  67. link.setAttribute("expanded-by-script", "true");
  68. } else link.setAttribute("expanded-by-script", "false");
  69. }
  70.  
  71. function showFullVideoName(link) { //Expand short video name to full one, taken from previous text
  72. link.parentElement.setAttribute("expanded-by-script", "false");
  73.  
  74. const rangeBefore = document.createRange(); //Create a range
  75. if (link.parentElement.parentElement.previousElementSibling == null) {
  76. rangeBefore.setStart(link.parentElement.parentElement.parentElement, 0); //from the start of the parent
  77. } else {
  78. rangeBefore.setStartAfter(link.parentElement.parentElement.previousElementSibling); //from the end of previous element
  79. }
  80. rangeBefore.setEndBefore(link.parentElement.parentElement); // till the target element
  81. var strFullName = rangeBefore.toString();
  82. strFullName = strFullName.replace(/.*[\n](?!$)/g, ""); //Remove all text except the last line
  83. strFullName = strFullName.replace(/\&/g, "&amp;"); //Replace & with its html-code
  84.  
  85. if (strFullName.length > 0) {
  86. var strHTML = link.parentElement.parentElement.parentElement.outerHTML;
  87. strHTML = strHTML.replace(strFullName, ""); //Remove full video name from text
  88. strHTML = strHTML.replace(/yt-core-image--content-mode-scale-to-fill"><\/span>/gi, "yt-core-image--content-mode-scale-to-fill yt-core-image--loaded\" src=\"https://www.gstatic.com/youtube/img/watch/yt_favicon.png\"></span>"); //Add YT icon if missed
  89. link.parentElement.parentElement.parentElement.outerHTML = strHTML;
  90.  
  91. strFullName = strFullName.replace(/[\n]/g, ""); //Remove \n
  92. strFullName = strFullName.replace(/\s+$/g, ""); //Remove trailing spaces
  93. strFullName = strFullName.replace(/:+$/g, ""); //Remove trailing semicolon
  94. strFullName = strFullName.replace(/-+$/g, ""); //Remove trailing dash
  95. strFullName = strFullName.replace(/:+$/g, ""); //Remove trailing semicolon
  96. strFullName = strFullName.replace(/\(+$/g, ""); //Remove trailing (
  97. strFullName = strFullName.replace(/\s+$/g, ""); //Remove trailing spaces
  98. strFullName = strFullName.replace(/^\s*/g, ""); //Remove leading spaces
  99. strFullName = strFullName.replace(/^\)/g, ""); //Remove leading )
  100. strFullName = strFullName.replace(/^\./g, ""); //Remove leading .
  101. strFullName = strFullName.replace(/^,/g, ""); //Remove leading ,
  102. strFullName = strFullName.replace(/^\s*/g, ""); //Remove leading spaces
  103.  
  104. var newLink = document.querySelector("div#below span.yt-core-attributed-string > span > span.yt-core-attributed-string--highlight-text-decorator[expanded-by-script='false'] > a"); //New query, because previous setting of outerHTML rebuilded this node in DOM
  105. if (newLink != null) {
  106. newLink.parentElement.setAttribute("expanded-by-script", "true");
  107. var bgStyle = newLink.parentElement.getAttribute("style");
  108. newLink.parentElement.style = ""; //Remove background
  109. newLink.parentElement.firstElementChild.style = "margin: 1px 0px; " + bgStyle; //Add background
  110.  
  111. var strHTML2 = newLink.parentElement.outerHTML;
  112. strHTML2 = strHTML2.replace(/<\/span>&nbsp;•&nbsp;.*&nbsp;&nbsp;<\/a><\/span>/gi, "<div class='yt-core-attributed-string__link yt-core-attributed-string__link--display-type yt-core-attributed-string__link--call-to-action-color'>&nbsp;•&nbsp;</div></span>" + strFullName + "&nbsp;&nbsp;</a></span>"); //Add full video name to link
  113. newLink.parentElement.outerHTML = strHTML2;
  114. }
  115. }
  116. }
  117. })();