Greasy Fork is available in English.
shorts is a shit, fuck you youtube
// ==UserScript== // @name Youtube Anti Shorts // @name:zh Youtube Anti Shorts 反短片 // @namespace Anong0u0 // @version 0.7.5 // @description shorts is a shit, fuck you youtube // @description:zh 短片就是坨屎,去你的youtube // @author Anong0u0 // @match *://*.youtube.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @run-at document-start // @license MIT // ==/UserScript== console.log("[Anti Shorts] load start"); let Hide_Shorts_Renderer = GM_getValue("Hide_Shorts_Renderer", true); let Hide_Shorts_Video = GM_getValue("Hide_Shorts_Video", true); let Redirect_Shorts_URL = GM_getValue("Redirect_Shorts_URL", true); Node.prototype.getParentElement = function(times = 0){let e=this;for(let i=0;i<times;i++)e=e.parentElement;return e;} NodeList.prototype.filter = Array.prototype.filter NodeList.prototype.slice = Array.prototype.slice const delay = (ms = 0) => {return new Promise((r)=>{setTimeout(r, ms)})} const waitElementLoad = (elementSelector, isSelectAll, tryTimes = 1, interval = 0) => { return new Promise(async (resolve, reject)=> { let t = 1, result; while(true) { if(isSelectAll) {if((result = document.querySelectorAll(elementSelector)).length > 0) break;} else {if(result = document.querySelector(elementSelector)) break;} if(tryTimes>0 && ++t>tryTimes) {return reject(new Error("Wait Timeout"))} await delay(interval); } resolve(result); }) } if (window.trustedTypes) { const policy = trustedTypes.createPolicy("ytAntiShorts", {createHTML: (string) => string,}); Node.prototype.setHTML = function (html) {this.innerHTML = policy.createHTML(html)} } else Node.prototype.setHTML = function (html) {this.innerHTML = html} const fillRow = () => { if(window.location.pathname!="/feed/subscriptions") return; console.log("[Anti Shorts] fill row count") let row = document.querySelector("ytd-browse[page-subtype='subscriptions'] ytd-rich-grid-renderer > div#contents.ytd-rich-grid-renderer > ytd-rich-grid-row") const rowCount = getComputedStyle(row).getPropertyValue("--ytd-rich-grid-items-per-row") while(row.nextElementSibling?.tagName=="YTD-RICH-GRID-ROW") { const showedItem = row.querySelectorAll("ytd-rich-item-renderer").filter((e)=>getComputedStyle(e).display!="none") let need = rowCount-showedItem.length let nextRow = row while(need>0 && nextRow.nextElementSibling!=null) { nextRow = nextRow.nextElementSibling const rowContent = row.querySelector("div#contents.ytd-rich-grid-row") for (const e of nextRow.querySelectorAll("ytd-rich-item-renderer")) { if (need == 0) break; if (getComputedStyle(e).display != "none") { rowContent.appendChild(e); need--; } } } row = row.nextElementSibling } } const unfillRow = () => { if(window.location.pathname!="/feed/subscriptions") return; console.log("[Anti Shorts] unfill row count") let row = document.querySelector("ytd-browse[page-subtype='subscriptions'] ytd-rich-grid-renderer > div#contents.ytd-rich-grid-renderer > ytd-rich-grid-row") const rowCount = getComputedStyle(row).getPropertyValue("--ytd-rich-grid-items-per-row") while(row.nextElementSibling?.tagName=="YTD-RICH-GRID-ROW") { const rowContent = row.nextElementSibling.querySelector("div#contents.ytd-rich-grid-row") row.querySelectorAll("ytd-rich-item-renderer").slice(rowCount).forEach((e)=> { rowContent.appendChild(e) }) row = row.nextElementSibling } } const debounce = ()=> { clearTimeout(lockID) lockID = setTimeout(() => {fillRow()}, 50); } if((()=>{try{document.querySelector(":has(body)");return false;}catch{return true;}})()) { alert(`[Anti Shorts] Warning: Your browser Does Not Support CSS4 selector (:has). Please update or change your browser. For Firefox users, please to go to "about:config" and enable "layout.css.has-selector.enabled" setting.`) } let menuID = [], oldHref = null, lockID = null; const css = { hideRenderer: document.createElement("style"), hideVideo: document.createElement("style"), } css.hideRenderer.setHTML(` ytm-pivot-bar-item-renderer:has(.pivot-shorts), ytm-rich-section-renderer:has(a[href^='/shorts']), ytm-reel-shelf-renderer:has(a[href^='/shorts']), ytd-reel-shelf-renderer.style-scope:is(.ytd-item-section-renderer,.ytd-structured-description-content-renderer), ytd-mini-guide-entry-renderer[aria-label='Shorts'], ytd-rich-shelf-renderer[is-shorts], a.yt-simple-endpoint.style-scope.ytd-guide-entry-renderer[title='Shorts'] {display:none !important}`); css.hideVideo.setHTML(` .is-shorts, ytm-reel-item-renderer:has(a[href^='/shorts']), ytm-video-with-context-renderer:has(a[href^='/shorts']), ytm-compact-video-renderer:has(a[href^='/shorts']), [is-short], [is-shorts-grid] ytd-continuation-item-renderer, ytd-video-renderer:has(a[href^='/shorts']), ytd-reel-item-renderer:has(a[href^='/shorts']), ytd-rich-item-renderer:has(a[href^='/shorts']), ytd-grid-video-renderer:has(a[href^='/shorts']), ytd-compact-video-renderer:has(a[href^='/shorts']), ytd-search ytd-shelf-renderer:has(a[href^='/shorts']), ytd-browse ytd-item-section-renderer:has(yt-img-shadow#avatar):has(div#title-text):has(ytd-video-renderer):has(a[href^='/shorts']) {display:none !important}`); // ":has" selector is simple and "efficient", Use it instead of javascript DOM manipulation const onPageUpdate = () => { //console.log("[Anti Shorts] page updated"); if (oldHref != window.location.href) { oldHref = window.location.href; toggle.redirect(); } } const toggle = { renderer: ()=> { if(Hide_Shorts_Renderer) document.documentElement.append(css.hideRenderer); else css.hideRenderer.remove(); }, video: async ()=> { if(Hide_Shorts_Video) { document.addEventListener("yt-rendererstamper-finished", debounce) document.documentElement.append(css.hideVideo); fillRow(); } else { document.removeEventListener("yt-rendererstamper-finished", debounce) css.hideVideo.remove(); unfillRow() } }, redirect: ()=> { if(Redirect_Shorts_URL) { if(window.location.pathname.indexOf("/shorts/")!=-1) {console.log("[Anti Shorts] redirected");window.location.replace(window.location.href.replace("/shorts/","/watch?v="));} } } } const setMenu = ()=> { menuID.forEach((e)=>{GM_unregisterMenuCommand(e)}) menuID = []; menuID.push(GM_registerMenuCommand(`${Hide_Shorts_Renderer?"Dis":"En"}able "Hide Shorts Renderer"`, ()=> { Hide_Shorts_Renderer = !Hide_Shorts_Renderer; GM_setValue("Hide_Shorts_Renderer", Hide_Shorts_Renderer); toggle.renderer(); setMenu(); })) menuID.push(GM_registerMenuCommand(`${Hide_Shorts_Video?"Dis":"En"}able "Hide Shorts Video"`, ()=> { Hide_Shorts_Video = !Hide_Shorts_Video; GM_setValue("Hide_Shorts_Video", Hide_Shorts_Video); toggle.video(); setMenu(); })) menuID.push(GM_registerMenuCommand(`${Redirect_Shorts_URL?"Dis":"En"}able "Redirect Shorts URL"`, ()=> { Redirect_Shorts_URL = !Redirect_Shorts_URL; GM_setValue("Redirect_Shorts_URL", Redirect_Shorts_URL); toggle.redirect(); setMenu(); })) } console.log("[Anti Shorts] try to call function"); toggle.redirect(); toggle.renderer(); toggle.video(); setMenu(); document.addEventListener("yt-page-data-fetched", onPageUpdate) document.addEventListener("yt-navigate-finish", onPageUpdate); waitElementLoad("yt-page-navigation-progress",false,40,250) .then((e)=>{new MutationObserver(onPageUpdate).observe(e, {attributes: true});}) window.addEventListener("state-change", onPageUpdate); console.log("[Anti Shorts] loaded");