您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
none
// ==UserScript== // @name yt blocker // @version 24 // @description none // @run-at document-start // @author rssaromeo // @license GPLv3 // @match *://youtube.com/* // @match *://*.youtube.com/* // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAHJQTFRFAAAAEIijAo2yAI60BYyuF4WaFIifAY6zBI2wB4usGIaZEYigIoiZCIyrE4igG4iYD4mjEomhFoedCoqpDIqnDomlBYyvE4efEYmiDYqlA42xBoytD4mkCYqqGYSUFYidC4qoC4upAo6yCoupDYqmCYur4zowOQAAACZ0Uk5TAO////9vr////1+/D/+/L+/Pf/////+f3///////H4////////+5G91rAAACgUlEQVR4nM2Y22KjIBCGidg1264liZqDadK03X3/V2wNKHMC7MpF/xthHD5mgERAqZhWhfYqH6K+Qf2qNNf625hCoFj9/gblMUi5q5jLkXLCKudgyiRm0FMK82cWJp1fLbV5VmvJbCIc0GCYaFqqlDJgADdBjncqAXYobm1xh72aFMflbysteFfdy2Yi1XGOm5HGBzQ1dq7TzEoxjeNTjQZb7VA3e1c7+ImgasAgQ9+xusNVNZIo5xmOMgihIS2PbCQIiHEUdTvhxCcS/kPomfFI2zHy2PkWmA6aNatIJpKFJyekyy02xh5Y3DI9T4aOT6VhIUrsNTFp1pf79Z4SIIVDegl6IJO6cHiL/GimIZDhgTu/BlYWCQzHMl0zBWT/T3KAhtxOuUB9FtBrpsz0RV4xsjHmW+UCaffcSy/5viMGer0/6HdFNMZBq/vjJL38H9Dqx4Fuy0Em12DbZy+9pGtiDijbglwAehyj11n0tRD3WUBm+lwulE/8h4BuA+iWAQQnteg2Xm63WQLTpnMnpjdge0Mgu/GRPsV4xdjQ94Lfi624fabhDkfUqIKNrM64Q837v8yL0prasepCgrtvw1sJpoqanGEX7b5mQboNW8eawXaWXTMfMGxub472hzWzHSn6Sg2G9+6TAyRruE71s+zAzjWaknoyJCQzwxrghH2k5FDT4eqWunuNxyN9QCGcxVod5oADbYnIUkDTGZEf1xDJnSFteQ3KdsT8zYDMQXcHxsevcLH1TrsABzkNPyA/L7b0jg704viMMlpQI96WsHknCt/3YH0kOEo9zcGkwrFK39ck72rmoehmKqo2RKlilzSy/nJKEV45CT38myJp456fezktHjN5aeMAAAAASUVORK5CYII= // @grant unsafeWindow // @require https://update.greasyfork.org/scripts/491829/1356221/tampermonkey%20storage%20proxy.js // @grant GM_getValue // @grant GM_setValue // @grant unsafeWindow // @namespace https://greasyfork.org/users/1184528 // ==/UserScript== // % of video watched to hide, 0 to not hide any const hideWatchedVidProg = 1 const rclickBlocksUrl = true const rclickBlocksTitle = true ;(async () => { const a = loadlib("allfuncs") const sp = new storageproxy("globaloptions") var ls = sp.get() // var lastvol // stores the last volume to restore to when muting from sub button border var vidlock = true const LOC = {} updateLoc() // var LOADED = false function setVidSpeed() { unsafeWindow.novidspeedcontroller = true for (var vid of a.qsa("video")) { vid.playbackRate = vidlock ? 0 : Number(!globalname ? 0 : localStorage.playrate ?? 0) } } ls.blockedCreators ??= [] ls.blockedTitles ??= [] ls.blockedTitlesReg ??= [] ls.blockedCreatorsReg ??= [] ls.blockedUrls ??= [] if (LOC.watch) { var fastint = setInterval(setVidSpeed, 0) setVidSpeed() update() await a.waitforelem( "#channel-name>#container>#text-container>yt-formatted-string>a" ) clearInterval(fastint) } setInterval(update, 1000) // LOADED = true var globalname function newBlockBtn(title, creator) { var elem = a.newelem("button", { innerHTML: ls.blockedCreators.includes(this.title) ? "unblock" : "block", creator, title, id: "blockbtn", onclick(e) { e.stopImmediatePropagation() e.stopPropagation() e.preventDefault() log(this.creator) if (ls.blockedCreators.includes(this.creator)) { ls.blockedCreators.splice( ls.blockedCreators.indexOf(this.creator), 1 ) } else { ls.blockedCreators.push(this.creator) } update() log(ls.blockedCreators, this.creator) }, oncontextmenu(e) { e.stopImmediatePropagation() e.stopPropagation() e.preventDefault() if (rclickBlocksUrl) { log(this.url) if (ls.blockedUrls.includes(this.url)) { ls.blockedUrls.splice(ls.blockedUrls.indexOf(this.url), 1) } else { ls.blockedUrls.push(this.url) } update() log(ls.blockedUrls, this.url) } if (rclickBlocksTitle) { log(this.title) if (ls.blockedTitles.includes(this.title)) { ls.blockedTitles.splice( ls.blockedTitles.indexOf(this.title), 1 ) } else { ls.blockedTitles.push(this.title) } update() log(ls.blockedTitles, this.title) } }, }) ;((elem, creator) => { var val = creator Object.defineProperty(elem, "creator", { get() { return val }, set(newval) { val = newval.replace(/ • \d+\w? views$/, "") }, enumerable: true, configurable: true, }) })(elem, creator) return elem } update() function update() { try { updateLoc() unsafeWindow.ls = ls = sp.get() if (LOC.search) { addVid( "div#dismissible.style-scope.ytd-video-renderer:has(a#video-title)", "a#video-title", "#video-title", "#text > a", "#channel-info" ) } else if (LOC.root) { globalname = null addVid( "ytd-rich-item-renderer:has(#video-title-link):has(a.yt-simple-endpoint.style-scope.yt-formatted-string):has(a.yt-simple-endpoint.style-scope.yt-formatted-string)", "#video-title-link", "#video-title:not(.cbCustomTitle)", "a.yt-simple-endpoint.style-scope.yt-formatted-string", "#details>#meta>ytd-video-meta-block:has(#additional-metadata-line):has(#metadata)" ) } else if (LOC.feed) { addVid( "#dismissible:has(#video-title-link)", "#video-title-link", "#video-title-link>yt-formatted-string:not(.cbCustomTitle)", "#container>#text-container>yt-formatted-string#text>a", "#byline-container" ) } else if (LOC.userhome || LOC.uservids) { const CREATOR = getCreatorNameFromUrl(location.href) const btn = a.qs( "#page-header > yt-page-header-renderer > yt-page-header-view-model > div > div.page-header-view-model-wiz__page-header-headline > div > yt-dynamic-text-view-model > h1 > #blockbtn" ) if ( a.qs( "#page-header > yt-page-header-renderer > yt-page-header-view-model > div > div.page-header-view-model-wiz__page-header-headline > div > yt-dynamic-text-view-model > h1" ) && !btn ) { a.qs( "#page-header > yt-page-header-renderer > yt-page-header-view-model > div > div.page-header-view-model-wiz__page-header-headline > div > yt-dynamic-text-view-model > h1" ).appendChild(newBlockBtn(null, CREATOR)) } else if (btn) { btn.innerHTML = isBlocked(btn.creator, btn.title, btn.url) ? "unblock - " + JSON.stringify( isBlocked(btn.creator, btn.title, btn.url) ) : "block" } if (LOC.userhome) { addVid( "#dismissible:has(#video-title-link)", "#video-title-link", "#video-title-link", { raw: CREATOR, }, "#byline-container" ) addVid( "#dismissible:has(#video-title-link)", "#video-title-link", "#video-title-link", "#container>#text-container>yt-formatted-string#text", "#byline-container" ) } if (LOC.uservids) { addVid( "ytd-rich-item-renderer:has(#dismissible #video-title-link)", "#video-title-link", "#video-title-link > #video-title:not(.cbCustomTitle)", { raw: CREATOR, }, "#meta > h3" ) } } else if (LOC.watch) { if (!a.qs("#playrate") && a.qs(".ytp-right-controls")) { a.qs(".ytp-right-controls").appendChild( a.newelem( "div", { display: "inline flex", flexDirection: "row", id: "playrate", class: "ytp-button ytp-settings-button ytp-hd-quality-badge", minWidth: "200xp", Width: "200xp", }, [ a.newelem("button", { innerHTML: "1", onclick() { localStorage.playrate = 1 update() }, }), a.newelem("button", { innerHTML: "2", onclick() { localStorage.playrate = 2 update() }, }), ] ) ) } globalname = a.qs( "#upload-info>ytd-channel-name#channel-name>#container>#text-container>yt-formatted-string#text > a" )?.textContent if ( a.qs("ytd-video-owner-renderer") && a.qs("#title > h1 > span.cbCustomTitle") ) { addVid( "ytd-watch-metadata", { raw: location.href.split("?v=").at(-1).split("&")[0], }, "#title > h1 > yt-formatted-string", "#container>#text-container>yt-formatted-string#text>a", "ytd-video-owner-renderer" ) a.qs("ytd-watch-metadata").style.display = "" const btn = a.qs("ytd-video-owner-renderer>#blockbtn") vidlock = isBlocked(btn.creator, btn.title, btn.url) btn.innerHTML = isBlocked(btn.creator, btn.title, btn.url) ? "unblock - " + JSON.stringify( isBlocked(btn.creator, btn.title, btn.url) ) : "block" } // these don't have creator id anywhere only creator name so all will be hidden // addVid( // "ytd-compact-video-renderer:has(#dismissible #video-title-link)", // "#video-title-link", // "#container>#text-container>yt-formatted-string#text", // "#metadata" // ) // these also don't have creator data // addVid( // "#movie_player > div.html5-endscreen.ytp-player-content.videowall-endscreen.ytp-show-tiles > div > a:has(span.ytp-videowall-still-info)", // "span.ytp-videowall-still-info > span > span>div>.cbCustomTitle", // "span.ytp-videowall-still-info > span > span>.ytp-videowall-still-info-author", // "span.ytp-videowall-still-info > span > span>div" // ) // new youtube display classes? a.qsa( "yt-lockup-view-model:has(yt-lockup-metadata-view-model)" ).forEach((e) => (e.style.visibility = "hidden")) a.qsa(".ytp-videowall-still").forEach( (e) => (e.style.visibility = "hidden") ) // addVid( // "yt-lockup-view-model:has(yt-lockup-metadata-view-model)", // "div.yt-lockup-metadata-view-model-wiz__text-container > h3 > a", // "yt-content-metadata-view-model > div:nth-child(1) > span", // ".yt-lockup-view-model-wiz__metadata:has(yt-lockup-metadata-view-model)" // ) setVidSpeed() } } catch (e) { trace("update", e) } } function addVid( mainDivID, url, titleID, creatorID, blockButtonParentID ) { try { // log(mainDivID, a.qsa(mainDivID)) // remove invalid block buttons on root // if (isroot()) // a.qsa("#blockbtn") // .filter(function (btn) { // return btn.closest(blockButtonParentID) // }) // .forEach((e) => e.remove()) for (var viddiv of a.qsa(mainDivID)) { if (viddiv.textContent.includes("Free with ads")){ viddiv.style.display='none' continue } var btn = a.qs(blockButtonParentID + ">#blockbtn", viddiv) if (!btn) btn = a .qs(blockButtonParentID, viddiv) .appendChild(newBlockBtn("", "")) btn.url = url.raw ?? a.qs(url, viddiv).href.split("?v=").at(-1).split("&")[0] btn.title = titleID.raw?.toLowerCase?.() ?? a.qs(titleID, viddiv).textContent.toLowerCase() btn.creator = creatorID.raw ?? getCreatorNameFromUrl(a.qs(creatorID, viddiv).href) btn.innerHTML = ls.blockedCreators.includes(btn.creator) ? "unblock" : "block" var prog = a.qs( ".ytd-thumbnail-overlay-resume-playback-renderer.style-scope", viddiv ) || a.qs( ".ytThumbnailOverlayProgressBarHostWatchedProgressBarSegment", viddiv ) viddiv.style.display = isBlocked(btn.creator, btn.title, btn.url) || (hideWatchedVidProg && prog && prog.style.width.replace("%", "") > hideWatchedVidProg) ? "none" : "" } } catch (e) { trace("addVid", e, titleID, creatorID, viddiv) } } unsafeWindow.isBlocked = isBlocked unsafeWindow.addVid = addVid function isBlocked(creator, title, url) { try { if (creator == undefined) return { type: "invalid creator", val: { creator, title, url }, } if (ls.blockedUrls.includes(url)) return { type: "blockedUrls", val: url } if (ls.blockedTitles.includes(title)) return { type: "blockedTitles", val: title } if (ls.blockedCreators.includes(creator)) return { type: "blockedCreators", val: creator } for (let reg of ls.blockedCreatorsReg) { if (new RegExp(reg, "i").test(creator)) return { type: "blockedCreatorsReg", val: reg } } for (let reg of ls.blockedTitlesReg) { if (new RegExp(reg, "i").test(title)) return { type: "blockedTitlesReg", val: reg } } return false } catch (e) { trace("isBlocked", e) } } function updateLoc() { Object.assign(LOC, { root: /^https?:\/\/(?:www\.)?youtube\.com\/?(?:\?|#|$)/.test( location.href ), watch: /^https?:\/\/(?:www\.)?youtube\.com\/watch\/?(?:\?|#|$)/.test( location.href ), search: /^https?:\/\/(?:www\.)?youtube\.com\/results\?search_query=.*(?:#|$)/.test( location.href ), feed: /^https?:\/\/(?:www\.)?youtube\.com\/feed\/subscriptions/.test( location.href ), userhome: /^https?:\/\/(?:www\.)?youtube\.com\/@[^\/]+\/?$/.test( location.href ), uservids: /^https?:\/\/(?:www\.)?youtube\.com\/@[^\/]+\/videos\/?$/.test( location.href ), }) } function getCreatorNameFromUrl(url) { return url.match(/(?:\/@|\/(?:channel|user|c)\/)([^\/]*)/i)?.[1] } })()