// ==UserScript== // @name YouTube to Invidious // @author OdinBrood, Jesús E. // @namespace InvidiousRedirect // @description Scan page for Youtube urls and replace with Invidious. // @homepageURL https://git.sr.ht/~heckyel/book/blob/master/scripts-greasemonkey // @include * // @exclude /^http(s|)://(www[.]|)invidio[.]us/.*$/ // @exclude /^http(s|)://(www[.]|proxy[.]|)invidious[.]snopyta[.]org/.*$/ // @exclude /^http(s|)://(www[.]|)vid[.]wxzm[.]sx/.*$/ // @exclude /^http(s|)://(www[.]|)invidious[.]kabi[.]tk/.*$/ // @exclude /^http(s|)://(www[.]|)invidiou[.]sh/.*$/ // @exclude /^http(s|)://(www[.]|)yewtu[.]be/.*$/ // @exclude /^http(s|)://(www[.]|)invidious[.]ggc-project[.]de/.*$/ // @exclude /^http(s|)://(www[.]|)invidious[.]enkirton[.]net/.*$/ // @exclude /^http(s|)://(www[.]|)tube[.]poal[.]co/.*$/ // @exclude /^http(s|)://(www[.]|)invidious[.]13ad[.]de/.*$/ // @grant none // @version 8.4.9 // @license GPL version 3 or any later version::: https://www.gnu.org/licenses/gpl-3.0.html // ==/UserScript== /* jshint esversion: 6 */ // set you favorite Invidious instance! (https://github.com/omarroth/invidious/wiki/Invidious-Instances) let instance = 'invidious.13ad.de'; // Console Style - Debug const consoleCSS = 'background: #000; color: #00FF00; padding: 0px 7px; border: 1px solid #00FF00; line-height: 16px;'; const name = GM_info.script.name; const version = GM_info.script.version; const log = (...args) => console.log('%cUSERSCRIPT | %s %s | %s', consoleCSS, name, version, ...args); // change script options, default values recommended let a=1; //set to 0 to force autoplay off, set to 1 to keep embed's value [default 1] let b=1; //set to 0 to not replace all youtube links to Invidious [default 1] let ytdomains=new RegExp(/http(s|):\/\/(m[.]|i[.]|www[.]|img[.]|)(youtu(|be|be-nocookie)|.*ytimg)[.](com|be)\/.*/); let params=new RegExp(/^(autoplay|channel|v|playlist|list)$/); let current=window.location.href.match(ytdomains)===null; let thumbs,links,skip; function link(){ for(let i=0;i<links.length;i++){ let url=new URL(links[i].href.match(ytdomains)[0]); url.hostname=instance; links[i].href=url; } } function ytel(el){ for(let i=0;i<el.attributes.length;i++){ let val=el.attributes[i].value; if(val.substring(0,2)=='//')val='https:'+val; try{val=decodeURIComponent(val);}catch(e){} if(val.match(ytdomains)){ el.attributes[i].value=val; return true; } } } function ythref(el){ return(decodeURIComponent(el.href).match(ytdomains)); } function thumb(){ for(let i=0;i<thumbs.length;i++){ let url=new URL(thumbs[i].src.match(ytdomains)[0]); url.hostname=instance; thumbs[i].src=url; } } function redir(){ let url=new URL(window.location.href); url.hostname=instance; location.href=url; } function addbtn(){ for(let i=0;i<title.length;i++){ let btn=document.createElement('a'); btn.innerHTML='<h2>Watch on '+instance+'</h2>'; btn.href='javascript:void(0)'; btn.onclick=function(){ redir(); } btn.className='skipinv'; title[i].parentNode.appendChild(btn); } } if(current){ thumbs=Array.prototype.slice.call(document.getElementsByTagName('img')).filter(ytel); if(b==1)links=Array.prototype.slice.call(document.getElementsByTagName('a')).filter(ythref); if(thumbs.length>0){ thumb(); } if(links.length>0){ link(); } log('successfully initialized'); }else{ let title=Array.prototype.slice.call(document.getElementsByTagName('h1')); addbtn(); } let observer=new MutationObserver(function(mutations){ mutations.forEach(function(mutation){ if(current){ thumbs=Array.prototype.slice.call(mutation.target.getElementsByTagName('img')).filter(ytel); if(thumbs.length>0){ thumb(); } if(b==1){ links=Array.prototype.slice.call(mutation.target.getElementsByTagName('a')).filter(ythref); if(links.length>0){ link(); } } }else{ skip=Array.prototype.slice.call(mutation.target.getElementsByClassName('skipinv')); if(skip<1){ title=Array.prototype.slice.call(mutation.target.getElementsByTagName('h1')); addbtn(); } } }); }); observer.observe(document.body,{childList:true,subtree:true});