// ==UserScript== // @name YouTube to Invidious video link replacer // @description Replace video links in the youtube site to their Invidious equivalents // // @version 1.1 // @license MIT // @author Syndamia // // @source https://gitlab.com/Syndamia/userscripts/-/blob/main/youtube-invidious-link-replacer.js // @supportURL https://gitlab.com/Syndamia/userscripts/-/issues // @homepage https://gitlab.com/Syndamia/userscripts/ // @icon https://upload.wikimedia.org/wikipedia/commons/a/a0/Invidious-logo.svg // // @namespace Syndamia // @match *://www.youtube.com/* // @run-at document-start // ==/UserScript== const invidiousInstance = 'yewtu.be'; // Wait for ytd-app element to appear const ytdObserver = new MutationObserver(function(mutations) { /* Detect when ytd-app element is present */ // Thanks https://stackoverflow.com/a/45267350/12036073 if (document.getElementsByTagName('ytd-app').length > 0) { disableCertainClickEventListeners(); // Refer to function for information /* When you open a link in YouTube, the site doesn't fully reload, but the ytd-app element * (which contains the whole UI) is updated (and the website URL also updates). * Also, YouTube's infinite scroll updates the ytd-app element, so the best way to detect * when we need to fix links is when ytd-app changes. */ const observer = new MutationObserver(replaceAnchors); observer.observe(document.getElementsByTagName('ytd-app')[0], { childList: true, attributes: true, subtree: true, }); ytdObserver.disconnect(); } }); ytdObserver.observe(document, {attributes: false, childList: true, characterData: false, subtree:true}); function replaceAnchors() { for (var anchor of document.getElementsByTagName('ytd-app')[0].getElementsByTagName('a')) { if (anchor.href.indexOf('www.youtube.com/watch') > 0) { anchor.href = anchor.href.replace('www.youtube.com/watch', invidiousInstance + '/watch'); } } } /* As already meantioned, opening a link in YouTube doesn't work like clicking on a normal anchor, * it updates the ytd-app element and website URL. When clicking on a video, a special eventListener(s) * handles loading the YouTube video page and if we don't disable it(them), even with anchors that href to * a page outside YouTube, we'll still load the YouTube video as normal. */ function disableCertainClickEventListeners() { /* It's not enough to only override the HTMLAnchorElement addEventListener function, * from testing it seems that there are other elements that also have the appropriate event listeners * which trigger opening of the YouTube player */ // Thanks https://stackoverflow.com/a/57437878/12036073 HTMLElement.prototype.oldaddEventListener = HTMLElement.prototype.addEventListener; HTMLElement.prototype.addEventListener = function(event, handler, placeholder) { if (event === 'click') { /* The functions that actually handles clicking on videos to open player is this: * (c){if(a[b])a[b](c,c.detail);else console.warn("listener method `"+b+"` not defined")} * As far as I have tested, '_handleNative$$module$third_party$javascript$polymer$v2$polymer$lib$utils$gestures' and functions like: * (a){a.target===this.liveBadge.element&&(this.api.seekTo(Infinity),this.api.playVideo())} * don't play a direct role in the click video -> open player process. */ if (handler.toString().indexOf('c', 7) === 9 && this.tagName !== 'YT-ICON-BUTTON') { // The second condition allows some buttons to work return; } } this.oldaddEventListener(event, handler, placeholder); } }