Invidious (inv.nadeko.net) embed

Replace YouTube embeds with inv.nadeko.net embeds.

  1. // ==UserScript==
  2. // @name Invidious (inv.nadeko.net) embed
  3. // @description Replace YouTube embeds with inv.nadeko.net embeds.
  4. // @author Backend & SkauOfArcadia
  5. // @homepage https://codeberg.org/mthsk/userscripts/src/branch/master/invidious-embed
  6. // @include *
  7. // @exclude *://*.youtube.com/*
  8. // @exclude *://*.google.com/*
  9. // @exclude *://turntable.fm/*
  10. // @exclude *://web.archive.org/web/*
  11. // @exclude *://*/embed/*
  12. // @exclude *://*/watch?v=*
  13. // @inject-into content
  14. // @version 2025.03
  15. // @grant none
  16. // @allFrames true
  17. // @namespace https://greasyfork.org/users/751327
  18. // ==/UserScript==
  19. (function() {
  20. "use strict";
  21. const instance = "inv.nadeko.net";
  22. const a = -1; //defines autoplay value on the initial page load
  23. const b = -1; //defines autoplay for embedded videos that appear on page interaction
  24. // -1 = will only autoplay if the embed has the "autoplay=1" parameter
  25. // 0 = disables autoplay
  26. // 1 = enables autoplay
  27. const dash = false; //defines if the quality=dash parameter will be used
  28.  
  29. var observer = new MutationObserver(mutate);
  30. observer.observe(document, {
  31. childList: true,
  32. attributes: true,
  33. subtree: true
  34. });
  35.  
  36. function mutate() {
  37. go(b);
  38. }
  39.  
  40. function go(auto) {
  41. let frames = document.body.querySelectorAll('iframe[src], embed[src]');
  42. frames = Object.values(frames).filter(youtubeiFrame);
  43.  
  44. for (let i = 0; i < frames.length; i++) {
  45. let frame = frames[i];
  46. let invid = frame.src;
  47. let params = new URLSearchParams();
  48. if (invid.indexOf('?') !== -1) {
  49. params = new URLSearchParams(invid.substring(invid.indexOf('?') + 1).split('#')[0]);
  50. invid = invid.split('?')[0];
  51. } else if (invid.indexOf('&') !== -1) {
  52. params = new URLSearchParams(invid.substring(invid.indexOf('&') + 1).split('#')[0]);
  53. invid = invid.split('&')[0];
  54. }
  55. params.delete('controls');
  56.  
  57. if (params.get('v'))
  58. {
  59. invid = 'https://' + instance + '/embed/' + params.get('v');
  60. params.delete('v');
  61. }
  62. else if (invid.toLowerCase().indexOf('/embed/') !== -1)
  63. {
  64. invid = 'https://' + instance + '/embed/' + invid.substring(invid.toLowerCase().indexOf('/embed/') + 7).split('/')[0].split(';')[0];
  65. }
  66. else if (invid.toLowerCase().indexOf('/v/') !== -1)
  67. {
  68. invid = 'https://' + instance + '/embed/' + invid.substring(invid.toLowerCase().indexOf('/v/') + 3).split('/')[0].split(';')[0];
  69. }
  70. else
  71. invid = 'https://' + instance + '/' + invid.split('/')[3].split(';')[0];
  72.  
  73. if (auto !== -1) {
  74. params.set('autoplay', auto);
  75. } else if (!params.get('autoplay')) {
  76. params.set('autoplay', 0);
  77. }
  78.  
  79. if ((parseInt(frame.width, 10) <= 4 || parseInt(frame.style.width, 10) <= 4)
  80. && (parseInt(frame.height, 10) <= 4 || parseInt(frame.style.height, 10) <= 4)
  81. && params.get('autoplay') === '1') {
  82. params.set('listen', 1);
  83. }
  84.  
  85. if(dash){ params.set('quality', 'dash'); }
  86.  
  87. invid += '?' + params;
  88. frame.setAttribute('src', invid);
  89.  
  90. if (frame.hasAttribute('srcdoc')) { frame.removeAttribute('srcdoc'); }
  91.  
  92. if (frame.tagName.toLowerCase() === 'embed'){
  93. let newframe = document.createElement('iframe');
  94. newframe.innerHTML = frame.innerHTML;
  95. frame.getAttributeNames().forEach(attrName => { newframe.setAttribute(attrName, frame.getAttribute(attrName)); });
  96. frame.parentNode.replaceChild(newframe, frame);
  97. }
  98. }
  99.  
  100. //Replace thumbnail embeds
  101. let thumbs = document.body.querySelectorAll('img[src*="img.youtube.com"], img[src*="i.ytimg.com"]');
  102.  
  103. for (let x = 0; x < thumbs.length; x++)
  104. {
  105. let thumb = thumbs[x];
  106. let thumbsrc = new URL(thumb.src);
  107.  
  108. if (thumbsrc.hostname === "img.youtube.com" || thumbsrc.hostname === "i.ytimg.com")
  109. {
  110. thumb.getAttributeNames().forEach(attrName => {
  111. if (attrName !== 'src' && thumb.getAttribute(attrName).indexOf(thumbsrc.hostname) !== -1)
  112. thumb.setAttribute(attrName, thumb.getAttribute(attrName).replace(thumbsrc.hostname, instance));
  113. });
  114.  
  115. thumb.setAttribute('src', thumbsrc.protocol + '//' + instance + thumbsrc.pathname + thumbsrc.search + thumbsrc.hash);
  116. }
  117. }
  118. }
  119.  
  120. function youtubeiFrame(el) {
  121. try {
  122. let url = new URL(el.src);
  123. return (url.hostname === "youtube.com" || url.hostname.endsWith(".youtube.com")
  124. || url.hostname === "youtube-nocookie.com" || url.hostname.endsWith(".youtube-nocookie.com")
  125. || url.hostname === "youtu.be" || url.hostname.endsWith(".youtu.be"));
  126. } catch (_) {
  127. return false;
  128. }
  129. }
  130.  
  131. go(a);
  132. })();