您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
To make AutoPlay Next Duration longer
// ==UserScript== // @name YouTube: Make AutoPlay Next More Than 3 seconds // @namespace UserScripts // @match https://www.youtube.com/* // @version 0.2.9 // @author CY Fung // @license MIT // @description To make AutoPlay Next Duration longer // @grant none // @run-at document-start // @unwrap // @inject-into page // ==/UserScript== (() => { const second_to_play_next_def = 8; const valuer = { get second_to_play_next() { return +localStorage.second_to_play_next || second_to_play_next_def; } } const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0); const Promise = (async () => { })().constructor; /* * , $mb = function(a, b) { b = void 0 === b ? -1 : b; a = a.j.Ha("ytp-autonav-endscreen-upnext-header"); g.of(a); if (0 <= b) { b = String(b); var c = "$SECONDS \u79d2\u5f8c\u306b\u6b21\u306e\u52d5\u753b\u3092\u518d\u751f".match(RegExp("\\$SECONDS", "gi"))[0] , d = "$SECONDS \u79d2\u5f8c\u306b\u6b21\u306e\u52d5\u753b\u3092\u518d\u751f".indexOf(c); if (0 <= d) { a.appendChild(g.mf("$SECONDS \u79d2\u5f8c\u306b\u6b21\u306e\u52d5\u753b\u3092\u518d\u751f".slice(0, d))); var e = g.lf("span"); g.$t(e, "ytp-autonav-endscreen-upnext-header-countdown-number"); g.Bf(e, b); a.appendChild(e); a.appendChild(g.mf("$SECONDS \u79d2\u5f8c\u306b\u6b21\u306e\u52d5\u753b\u3092\u518d\u751f".slice(d + c.length))); return } } g.Bf(a, "\u6b21\u306e\u52d5\u753b") } */ /* * if (!a.Qk()) { a.J.Bf() ? $mb(a, Math.round(anb(a) / 1E3)) : $mb(a); b = !!a.suggestion && !!a.suggestion.Bs; var c = a.J.Bf() || !b; g.fu(a.container.element, "ytp-autonav-endscreen-upnext-alternative-header-only", !c && b); g.fu(a.container.element, "ytp-autonav-endscreen-upnext-no-alternative-header", c && !b); g.FG(a.B, a.J.Bf()); g.fu(a.element, "ytp-enable-w2w-color-transitions", bnb(a)) } */ /* * * , anb = function(a) { if (a.J.isFullscreen()) { var b; a = null == (b = a.J.getVideoData()) ? void 0 : b.CB; return -1 === a || void 0 === a ? 8E3 : a } return 0 <= a.J.Ss() ? a.J.Ss() : g.WJ(a.J.W().experiments, "autoplay_time") || 1E4 } */ // a.J instanceof g.AU /* * * g.AU {Dp: false, xk: undefined, app: g.b1, state: WQa, playerType: undefined, …} Dp: false UK: pYa {Dp: false, xk: Array(6), Ub: {…}, Td: {…}, element: div#ytp-id-18.ytp-popup.ytp-settings-menu, …} app: g.b1 {Dp: false, xk: Array(21), logger: g.pY, di: false, bA: false, …} element: null j: false playerType: undefined state: WQa {Dp: false, xk: undefined, D: Set(89), G: {…}, S: {…}, …} xk: undefined */ // a.J.Ss = ƒ (){return this.app.Ss()} // a.J.app.Ss = ƒ (){return this.getVideoData().aU} // a.J.app.getVideoData() = ƒ (){return this.Qb.getVideoData()} = object instanceof g.sT // a.J.app.Qb.getVideoData = ƒ (){return this.videoData} // g.sT.prototype /* * getAudioTrack getAvailableAudioTracks getHeartbeatResponse getPlayerResponse getPlaylistSequenceForTime getStoryboardFormat hasProgressBarBoundaries hasSupportedAudio51Tracks isAd isDaiEnabled isLoaded isOtf useInnertubeDrmService */ const getsT = (_yt_player) => { const w = 'sT'; let arr = []; for (const [k, v] of Object.entries(_yt_player)) { const p = typeof v === 'function' ? v.prototype : 0; if (p) { let q = 0; if (typeof p.isLoaded === 'function' && p.isLoaded.length === 0) q += 200; if (q < 200) continue; // p.isLoaded is required if (typeof p.hasSupportedAudio51Tracks === 'function' && p.hasSupportedAudio51Tracks.length === 0) q += 2; if (typeof p.getStoryboardFormat === 'function' && p.getStoryboardFormat.length === 0) q += 4; if (typeof p.getPlaylistSequenceForTime === 'function' && p.getPlaylistSequenceForTime.length === 1) q += 4; if (typeof p.isOtf === 'function' && p.isOtf.length === 0) q += 2; if (typeof p.getAvailableAudioTracks === 'function' && p.getAvailableAudioTracks.length === 0) q += 4; if (typeof p.getAudioTrack === 'function' && p.getAudioTrack.length === 0) q += 4; if (typeof p.getPlayerResponse === 'function' && p.getPlayerResponse.length === 0) q += 2; if (typeof p.getHeartbeatResponse === 'function' && p.getHeartbeatResponse.length === 0) q += 2; if (typeof p.isAd === 'function' && p.isAd.length === 0) q += 2; if (typeof p.isDaiEnabled === 'function' && p.isDaiEnabled.length === 1) q += 2; if (typeof p.useInnertubeDrmService === 'function' && p.useInnertubeDrmService.length === 0) q++; if (typeof p.hasProgressBarBoundaries === 'function' && p.hasProgressBarBoundaries.length === 0) q += 2; if (q > 0) arr.push([k, q]); } } if (arr.length === 0) { console.warn(`Key does not exist. [${w}]`); } else { if (arr.length > 1) arr.sort((a, b) => b[1] - a[1]); console.log(`[${w}]`, arr); return arr[0][0]; } } // const addProtoToArr = (parent, key, arr) => { // let isChildProto = false; // for (const sr of arr) { // if (parent[key].prototype instanceof parent[sr]) { // isChildProto = true; // break; // } // } // if (isChildProto) return; // arr = arr.filter(sr => { // if (parent[sr].prototype instanceof parent[key]) { // return false; // } // return true; // }); // arr.push(key); // return arr; // } // const getAU = (_yt_player) => { // const w = 'VG'; // let arr = []; // for (const [k, v] of Object.entries(_yt_player)) { // const p = typeof v === 'function' ? v.prototype : 0; // if (p // && typeof p.show === 'function' && p.show.length === 1 // && typeof p.hide === 'function' && p.hide.length === 0 // && typeof p.stop === 'function' && p.stop.length === 0) { // arr = addProtoToArr(_yt_player, k, arr) || arr; // } // } // if (arr.length === 0) { // console.warn(`Key does not exist. [${w}]`); // } else { // console.log(`[${w}]`, arr); // return arr[0]; // } // } const cleanContext = async (win) => { const waitFn = requestAnimationFrame; // shall have been binded to window try { let mx = 16; // MAX TRIAL const frameId = 'vanillajs-iframe-v1'; /** @type {HTMLIFrameElement | null} */ let frame = document.getElementById(frameId); let removeIframeFn = null; if (!frame) { frame = document.createElement('iframe'); frame.id = frameId; const blobURL = typeof webkitCancelAnimationFrame === 'function' && typeof kagi === 'undefined' ? (frame.src = URL.createObjectURL(new Blob([], { type: 'text/html' }))) : null; // avoid Brave Crash frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting) n.appendChild(frame); while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine const root = document.documentElement; root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL if (blobURL) Promise.resolve().then(() => URL.revokeObjectURL(blobURL)); removeIframeFn = (setTimeout) => { const removeIframeOnDocumentReady = (e) => { e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false); win = null; const m = n; n = null; setTimeout(() => m.remove(), 200); } if (document.readyState !== 'loading') { removeIframeOnDocumentReady(); } else { win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false); } } } while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn); const fc = frame.contentWindow; if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, requestIdleCallback, getComputedStyle } = fc; const res = { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, requestIdleCallback, getComputedStyle }; for (let k in res) res[k] = res[k].bind(win); // necessary if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn); res.animate = fc.HTMLElement.prototype.animate; return res; } catch (e) { console.warn(e); return null; } }; cleanContext(window).then(__CONTEXT__ => { if (!__CONTEXT__) return null; const { setTimeout } = __CONTEXT__; const isUrlInEmbed = location.href.includes('.youtube.com/embed/'); const isAbortSignalSupported = typeof AbortSignal !== "undefined"; const promiseForTamerTimeout = new Promise(resolve => { !isUrlInEmbed && isAbortSignalSupported && document.addEventListener('yt-action', function () { setTimeout(resolve, 480); }, { capture: true, passive: true, once: true }); !isUrlInEmbed && isAbortSignalSupported && typeof customElements === "object" && customElements.whenDefined('ytd-app').then(() => { setTimeout(resolve, 1200); }); setTimeout(resolve, 3000); }); const PromiseExternal = ((resolve_, reject_) => { const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject }; return class PromiseExternal extends Promise { constructor(cb = h) { super(cb); if (cb === h) { /** @type {(value: any) => void} */ this.resolve = resolve_; /** @type {(reason?: any) => void} */ this.reject = reject_; } } }; })(); (async () => { const autoplayRendererP = new PromiseExternal(); const instReadyP = new PromiseExternal(); let bSetupDone = false; const observablePromise = (proc, timeoutPromise) => { let promise = null; return { obtain() { if (!promise) { promise = new Promise(resolve => { let mo = null; const f = () => { let t = proc(); if (t) { mo.disconnect(); mo.takeRecords(); mo = null; resolve(t); } } mo = new MutationObserver(f); mo.observe(document, { subtree: true, childList: true }) f(); timeoutPromise && timeoutPromise.then(() => { resolve(null) }); }); } return promise } } } if (isAbortSignalSupported && !isUrlInEmbed) { await customElements.whenDefined('ytd-player'); } const _yt_player = await observablePromise(() => { return (((window || 0)._yt_player || 0) || 0); }, promiseForTamerTimeout).obtain(); if (!_yt_player || typeof _yt_player !== 'object') return; // store and control variables const pm = new Proxy({}, { set(target, prop, value, receiver) { let old = target[prop]; if (old !== value) { target[prop] = old = value; if (prop === 'instsT') value && objProceed(true); } } }); window.set_second_to_play_next = function (sec) { if (!arguments.length) return +localStorage.second_to_play_next; localStorage.second_to_play_next = `${sec}`; assignDurationToOAR(pm.playerOAR); console.log('The value will be applied to the next video'); } const objProceed = (toResolveInstSetPromise) => { const resAssigned = obtainOAR(); if (resAssigned) bSetupDone ? assignDurationToOAR(pm.playerOAR) : autoplayRendererP.resolve(); if (toResolveInstSetPromise) instReadyP.resolve(); } const assignDurationToOAR = (playerOAR) => { if (!playerOAR) return; const t4 = playerOAR.countDownSecsForFullscreen; const t5 = playerOAR.countDownSecs; let b = t4 === t5 const second_to_play_next = valuer.second_to_play_next; playerOAR.countDownSecsForFullscreen = second_to_play_next; if (b) playerOAR.countDownSecs = second_to_play_next; return b; } Promise.all([autoplayRendererP, instReadyP]).then(() => { const inst = pm.instsT; const playerOAR = pm.playerOAR; if (!inst || !playerOAR) return; let entriesA = Object.entries(inst).filter(e => typeof e[1] === 'number'); let m = new Map(); for (const entry of entriesA) { m.set(entry[0], entry[1]); } const second_to_play_next = valuer.second_to_play_next; let b = assignDurationToOAR(playerOAR); bSetupDone = true; setTimeout(() => { const entriesB = Object.entries(inst).filter(e => typeof e[1] === 'number' && m.get(e[0]) !== e[1]); m = null; const filtered = entriesB.filter(e => Math.abs(e[1] - second_to_play_next * 1E3) < 1e-8); if (filtered.length >= 1) { pm.targetKeys = filtered.map(e => e[0]); } else { pm.targetKeys = null; } console.log(`sT(${b ? 'T' : 'F'}):`, filtered, filtered.length) }, 80); }); const obtainOAR = () => { let playerOAR = null; let pageDataMgr = document.querySelector('ytd-page-manager#page-manager'); let pageData = pageDataMgr ? insp(pageDataMgr).data : null; if (pageData) { try { playerOAR = pageData.response.playerOverlays.playerOverlayRenderer.autoplay.playerOverlayAutoplayRenderer; } catch (e) { } } if (playerOAR && typeof playerOAR.countDownSecsForFullscreen === 'number' && playerOAR.countDownSecsForFullscreen < 15) { pm.playerOAR = playerOAR; return true; } }; document.addEventListener('yt-navigate-finish', function () { objProceed(false); }, false); const g = _yt_player; const keysT = getsT(_yt_player); if (keysT) { let k = keysT; let gk = g[k]; let gkp = g[k].prototype; /* * if (typeof p.hasSupportedAudio51Tracks === 'function' && p.hasSupportedAudio51Tracks.length === 0) q += 2; if (typeof p.getStoryboardFormat === 'function' && p.getStoryboardFormat.length === 0) q += 4; if (typeof p.getPlaylistSequenceForTime === 'function' && p.getPlaylistSequenceForTime.length === 1) q += 4; if (typeof p.isLoaded === 'function' && p.isLoaded.length === 0) q += 2; if (typeof p.isOtf === 'function' && p.isOtf.length === 0) q += 2; if (typeof p.getAvailableAudioTracks === 'function' && p.getAvailableAudioTracks.length === 0) q += 4; if (typeof p.getAudioTrack === 'function' && p.getAudioTrack.length === 0) q += 4; if (typeof p.getPlayerResponse === 'function' && p.getPlayerResponse.length === 0) q += 2; if (typeof p.getHeartbeatResponse === 'function' && p.getHeartbeatResponse.length === 0) q += 2; if (typeof p.isAd === 'function' && p.isAd.length === 0) q += 2; if (typeof p.isDaiEnabled === 'function' && p.isDaiEnabled.length === 1) q += 2; if (typeof p.useInnertubeDrmService === 'function' && p.useInnertubeDrmService.length === 0) q++; if (typeof p.hasProgressBarBoundaries === 'function' && p.hasProgressBarBoundaries.length === 0) q += 2; */ // for(const pk of ['hasSupportedAudio51Tracks','getStoryboardFormat','getPlaylistSequenceForTime','isLoaded', // 'isOtf',//'getAvailableAudioTracks','getAudioTrack', // 'getPlayerResponse','getHeartbeatResponse', // // 'isAd', // 'isDaiEnabled','useInnertubeDrmService', // //'hasProgressBarBoundaries' // ]){ // } if (!gkp.isLoaded75 && typeof gkp.isLoaded === 'function') { gkp.isLoaded75 = gkp.isLoaded; gkp.isLoaded = function () { pm.instsT = this; return arguments.length === 0 ? this.isLoaded75() : this.isLoaded75(...arguments); } } } })(); }); })();