您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Fixes the channel links for the "Up next" and recommended videos below it on youtube.
当前为
// ==UserScript== // @name Youtube - Fix channel links in sidebar recommendations // @namespace 1N07 // @version 0.7.2 // @description Fixes the channel links for the "Up next" and recommended videos below it on youtube. // @author 1N07 // @license unlicense // @icon https://www.google.com/s2/favicons?domain=youtube.com // @match https://www.youtube.com/* // @require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js // @require https://update.gf.qytechs.cn/scripts/12036/70722/Mutation%20Summary.js // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // @compatible firefox Compatible with: Tampermonkey, Violentmonkey // @compatible firefox Not compatible with: Greasemonkey, FireMonkey // @compatible chrome Latest version untested, but likely works with at least Tampermonkey // @compatible opera Latest version untested, but likely works with at least Tampermonkey // @compatible edge Latest version untested, but likely works with at least Tampermonkey // @compatible safari Latest version untested, but likely works with at least Tampermonkey // ==/UserScript== (function() { 'use strict'; var videoSectionOption; var videoSection = GM_getValue("videoSection", true); SetVidSecOption(); GM_addStyle(` ytd-compact-video-renderer .channel-link-blocker:hover ~ a #text.ytd-channel-name { text-decoration: underline; } .channel-link-blocker-parent { position: relative; } .channel-link-blocker { display: inline-block; position: absolute; width: 100%; height: 25px; background-color: rgba(255, 25, 25, 0); top: 32px; left: 0; z-index: 2019; } `); var perVideoObservers = []; var perVideoObserverIndexTally = 0; var containerObserver = new MutationSummary({ callback: (containerSummary) => { //console.log("%cContainer Observer triggered - Added: " + containerSummary[0].added.length + ", Removed: " + containerSummary[0].removed.length + ", Reparented: " + containerSummary[0].reparented.length, "color: green"); //On video added containerSummary[0].added.forEach(vid => { //add blocker element const blockerParent = $(vid).find(".metadata.ytd-compact-video-renderer"); blockerParent.addClass("channel-link-blocker-parent"); blockerParent.prepend(`<a class="channel-link-blocker" href="#"></a>`); const channelLink = $(blockerParent).find(".channel-link-blocker"); UpdateBlockerPositioning(channelLink); UpdateUrl(vid, channelLink); //add observer id to element so we can clean up the right observer when the element is later removed $(vid).attr("data-active-observer-id", perVideoObserverIndexTally); //Add per-video observer for when the video href changes, so we can update the channel link accordingly. Doing this because apparently these days YT just swaps the data in the elements without swapping the elements themselves. //Also put the observer in an array with an access key for later access perVideoObservers.push({ key: perVideoObserverIndexTally, observer: new MutationSummary({ callback: (vidSummary) => { //console.log("%cPer Video Observer triggered: href changed", "color: green"); UpdateBlockerPositioning(channelLink); UpdateUrl(vid, channelLink); }, rootNode: $(blockerParent).find("a[href^='/watch']")[0], queries: [{attribute: "href"}] }) }); perVideoObserverIndexTally++; }); //on removed containerSummary[0].removed.forEach(vid => { //get the observer id/key we stored in the element previously const id = $(vid).data("activeObserverId"); //console.log("%cAttempting to remove observer: " + id, "color: red"); if(id !== undefined) { //console.log("id valid"); //get the observer from the observer array with the key const index = perVideoObservers.findIndex(o => o.key === id); if(index > -1) { //console.log("observer found"); //disconnect the observer and remove it from the array perVideoObservers[index].observer.disconnect(); perVideoObservers.splice(index, 1); //console.log("%cRemoved observer: " + id, "color: red"); } } }); //console.log("%cObservers alive: ", "color: yellow"); //console.log(perVideoObservers.map(x => x.key)); }, queries: [{element: "ytd-compact-video-renderer.ytd-item-section-renderer, ytd-compact-video-renderer.ytd-watch-next-secondary-results-renderer"}] }); function UpdateBlockerPositioning(blocker) { //blocker position adjustment $(blocker).prop("style", "top: " + $(blocker).parent().find("a[href^='/watch'] > h3").height() + "px;"); //above adjustment appears to rarely and randomly fail. Attempted fix by delaying adjustment as perhaps the height hasn't been computed yet? setTimeout(() => { $(blocker).prop("style", "top: " + $(blocker).parent().find("a[href^='/watch'] > h3").height() + "px;") }, 1000); } function UpdateUrl(fromElem, toElem) { //get data source object from element. Newest source used by YT is .polymerController, but older sources that may still be in use if certain flags are in place include .inst or just the element itself const getVideoDataSource = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0); let channelHandle = getVideoDataSource(fromElem)?.data?.longBylineText?.runs?.find(el => el.navigationEndpoint?.browseEndpoint?.canonicalBaseUrl?.match(/^\/(@|channel)/))?.navigationEndpoint.browseEndpoint.canonicalBaseUrl; if(channelHandle?.length) { $(toElem).prop("href", channelHandle + (videoSection ? "/videos" : "")); } else { console.log("Failed to get channel url"); $(toElem).on("click", (e) => { e.preventDefault(); e.stopPropagation(); alert("'Youtube - Fix channel links in sidebar recommendations' failed to get the channel link for this video for some reason. If this happens consistently, please report it at greasyfork."); }); } } function SetVidSecOption() { GM_unregisterMenuCommand(videoSectionOption); videoSectionOption = GM_registerMenuCommand("Fix channel links- videos section (" + (videoSection ? "yes" : "no") + ") -click to change-", function(){ videoSection = !videoSection; GM_setValue("videoSection", videoSection); SetVidSecOption(); }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址