您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
try to take over the world!
当前为
// ==UserScript== // @name Youtube Speed By Channel // @namespace Alpe // @version 0.1 // @description try to take over the world! // @author Alpe // @include https://www.youtube.com/* // @grant GM.setValue // @grant GM.getValue // @require https://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== const COLOR_SELECTED = "red", COLOR_NORMAL = "#dcdcdc", DEFAULT_SPEED = 1; const BUTTON_TEMPLATES = [ ["50%", 0.5], ["75%", 0.75], ["Normal", 1], ["1.25x", 1.25], ["1.5x", 1.5], ["1.75x", 1.75], ["2x", 2], ["2.25x", 2.25], ["2.5x", 2.5] ]; var vis = (function(){ var stateKey, eventKey, keys = { hidden: "visibilitychange", webkitHidden: "webkitvisibilitychange", mozHidden: "mozvisibilitychange", msHidden: "msvisibilitychange" }; for (stateKey in keys) { if (stateKey in document) { eventKey = keys[stateKey]; break; } } return function(c) { if (c) document.addEventListener(eventKey, c); return !document[stateKey]; } })(); function getspeed(params = {}){ let speed, reason; if (params.hasOwnProperty('force1x') && params.force1x){ speed = 1; reason = "forcing 1x (live?)"; } else if (params.hasOwnProperty('channelspeed') && typeof params.channelspeed === "number"){ speed = params.channelspeed; reason = "channelspeed"; //} else if (params.hasOwnProperty('channelname') && params.channelname in speedperchannel){ // speed = speedperchannel[params.channelname]; // reason = "channel"; //} } else if (params.hasOwnProperty('defspeed') && Number.isInteger(params.defspeed)){ speed = params.defspeed; reason = "overwritten default (music?)"; } else { speed = DEFAULT_SPEED; reason = "default"; } if (params.channelspeed === undefined) delete params.channelspeed; if (params.defspeed === null) delete params.defspeed; if (params.force1x === false) delete params.force1x; params['chosenspeed'] = speed; params['chosenreason'] = reason; console.log(params); return speed; } function buttonclick(el){ let id = el.target.parentNode.id.match(/\d+$/)[0]; el = $(el.target); el.parent().children(":not([title])").css("color", COLOR_NORMAL); el.css("color", COLOR_SELECTED); $('video[vsb-video=' + id + ']')[0].playbackRate = parseFloat(el.attr('speed')); } function setchanneldefault(el){ let id = el.target.parentNode.id.match(/\d+$/)[0]; let channel = $('#channel-name[vsb-channel=' + id + ']').find('#container').text().trim(); let currentspeed = $('video[vsb-video=' + id + ']')[0].playbackRate; el = $(el.target).parent(); el.children().css("text-decoration", "").filter('span[speed="' + currentspeed + '"]').css("text-decoration", "underline"); GM.setValue(channel, currentspeed); console.log('changing default for (' + channel + ') to (' + currentspeed + ')'); } function createcontainer(curspeed, id){ let div = document.createElement("div"); let prev_node = null; //div.className = "vsb-container"; div.id = "vsb-container" + id; div.style.marginBottom = "0px"; div.style.paddingBottom = "0px"; div.style.float = "left"; div.innerHTML += '<span style="margin-right: 10px; font-weight: bold; font-size: 80%; color: white; cursor: pointer;" title="Set current speed as default for this channel">setdefault</span>'; BUTTON_TEMPLATES.forEach(function(button){ div.innerHTML += '<span style="margin-right: 10px; font-weight: bold; font-size: 80%; color: ' + (curspeed === button[1] ? 'red' : 'rgb(220, 220, 220)') + '; cursor: pointer;" speed="' + button[1] + '">' + button[0] + '</span>'; }); $('span:not([title])', div).on( "click", buttonclick); $('span[title]', div).on( "click", setchanneldefault); return div; } window.vsbid = 0; function getid(){ let id = window.vsbid; window.vsbid++; return id; } function ob_youtube_movieplayer (mutationsList, observer){ for(let mutation of mutationsList) { //if (mutation.type === 'attributes' && mutation.attributeName === 'video-id'){ if (mutation.attributeName === 'video-id'){ let el = $('[id^=vsb-container]', mutation.target); let id = el[0].id.match(/\d+$/)[0]; let channeldiv = $('#channel-name[vsb-channel=' + id + ']'); $('span[speed="1"]', el).click(); $('span', el).css("text-decoration", ""); setTimeout(async function(){ let channelspeed = await GM.getValue(channeldiv.find('#container').text().trim()); $('span[speed="' + channelspeed + '"]', el).css("text-decoration", "underline") let speed = getspeed({ //channelname: channeldiv.find('#container').text().trim(), channelspeed: channelspeed, defspeed: (channeldiv.find('.badge-style-type-verified-artist').length === 1 ? 1 : null), force1x: (el.closest('#movie_player').find('.ytp-live').length === 1) }); if($('span[speed="' + speed + '"]', el).click().length === 0) $('video[vsb-video=' + id + ']')[0].playbackRate = speed; },1000); } } } function ob_youtube_c4player (mutationsList, observer){ for(let mutation of mutationsList) { if (mutation.attributeName === 'src' && mutation.target.src !== ''){ let id = mutation.target.getAttribute("vsb-video"); let channeldiv = $('#channel-name[vsb-channel=' + id + ']'); $('video[vsb-video=' + id + ']')[0].playbackRate = 1; setTimeout(async function(){ $('video[vsb-video=' + id + ']')[0].playbackRate = getspeed({ //channelname: channeldiv.find('#container').text().trim(), channelspeed: await GM.getValue(channeldiv.find('#container').text().trim()), defspeed: (channeldiv.find('.badge-style-type-verified-artist').length === 1 ? 1 : null) });; },1000); } } } function youtube(){ $('#movie_player:visible:not([monitored]), #c4-player:visible:not([monitored])').each(async function( index ) { let el = $(this); let speed, channelspeed; if (this.id === "movie_player"){ let channeldiv = el.closest('ytd-watch-flexy').find('#upload-info #channel-name'); if (!channeldiv.length) return; let channelname = channeldiv.find('#container').text().trim(); if (channelname === '') return; let appendto = el.find("div.ytp-right-controls"); if (!appendto.length) return; let videodiv = el.find('video') if (!videodiv.length) return; el.attr('monitored', ''); let id = getid(); channeldiv.attr('vsb-channel', id); videodiv.attr('vsb-video', id); $('#ytp-id-20 .ytp-menuitem-label:contains(Playback speed)', el).parent().css('display', 'none'); console.log("Adding video-id observer"); (new MutationObserver(ob_youtube_movieplayer)).observe(el.closest('ytd-watch-flexy')[0], { attributes: true }); channelspeed = await GM.getValue(channelname); speed = getspeed({ //channelname: channelname, channelspeed: channelspeed, defspeed: (channeldiv.find('.badge-style-type-verified-artist').length === 1 ? 1 : null), force1x: (el.find('.ytp-live').length === 1) }); let div = createcontainer(speed, id); $('span[speed="' + channelspeed + '"]', div).css("text-decoration", "underline"); appendto.append(div); videodiv[0].playbackRate = speed; } else if (this.id === "c4-player"){ let channeldiv = el.closest('ytd-browse').find('#header #channel-name'); if (!channeldiv.length) return; let channelname = channeldiv.find('#container').text().trim(); if (channelname === '') return; let videodiv = el.find('video') if (!videodiv.length) return; el.attr('monitored', ''); let id = getid(); channeldiv.attr('vsb-channel', id); videodiv.attr('vsb-video', id); console.log("Adding c4 observer"); (new MutationObserver(ob_youtube_c4player)).observe(el.find('video')[0], { attributes: true, subtree: true }); videodiv[0].playbackRate = getspeed({ //channelname: channelname, channelspeed: await GM.getValue(channelname), defspeed: (channeldiv.find('.badge-style-type-verified-artist').length === 1 ? 1 : null) }); } }); } function mark_loop(){ if (location.host.endsWith('youtube.com')){ youtube(); if (window.vsbid < 2){ setTimeout(mark_loop, ((window.vsbid === 0 ? 500 : 2500) * (vis() ? 1 : 2))); } else { console.log('stopping loop'); } } else { setTimeout(mark_loop, 1500 * (vis() ? 1 : 4)); } } window.addEventListener('load', mark_loop);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址