您需要先安装一个扩展,例如 篡改猴、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.1.0 // @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 = 8; /* * , $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.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; 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 onRegistryReady = (callback) => { if (typeof customElements === 'undefined') { if (!('__CE_registry' in document)) { // https://github.com/webcomponents/polyfills/ Object.defineProperty(document, '__CE_registry', { get() { // return undefined }, set(nv) { if (typeof nv == 'object') { delete this.__CE_registry; this.__CE_registry = nv; this.dispatchEvent(new CustomEvent(EVENT_KEY_ON_REGISTRY_READY)); } return true; }, enumerable: false, configurable: true }) } let eventHandler = (evt) => { document.removeEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false); const f = callback; callback = null; eventHandler = null; f(); }; document.addEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false); } else { callback(); } }; 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' ? (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; } }; const promiseForCustomYtElementsReady = new Promise(onRegistryReady); cleanContext(window).then(__CONTEXT__ => { if (!__CONTEXT__) return null; const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, animate, requestIdleCallback, getComputedStyle } = __CONTEXT__; let rafPromiseForTickers = null; const getRafPromiseForTickers = () => rafPromiseForTickers || (rafPromiseForTickers = new Promise(resolve => { requestAnimationFrame(hRes => { rafPromiseForTickers = null; resolve(hRes); }); })); const getForegroundPromise = () => { if (document.visibilityState === 'visible') { return Promise.resolve(); } else { return getRafPromiseForTickers(); } }; const promiseForTamerTimeout = new Promise(resolve => { promiseForCustomYtElementsReady.then(() => { customElements.whenDefined('ytd-app').then(() => { setTimeout(resolve, 1200); }); }); setTimeout(resolve, 3000); }); class RAFHub { constructor() { /** @type {number} */ this.startAt = 8170; /** @type {number} */ this.counter = 0; /** @type {number} */ this.rid = 0; /** @type {Map<number, FrameRequestCallback>} */ this.funcs = new Map(); const funcs = this.funcs; /** @type {FrameRequestCallback} */ this.bCallback = this.mCallback.bind(this); this.pClear = () => funcs.clear(); } /** @param {DOMHighResTimeStamp} highResTime */ mCallback(highResTime) { this.rid = 0; Promise.resolve().then(this.pClear); this.funcs.forEach(func => Promise.resolve(highResTime).then(func).catch(console.warn)); } /** @param {FrameRequestCallback} f */ request(f) { if (this.counter > 1e9) this.counter = 9; let cid = this.startAt + (++this.counter); this.funcs.set(cid, f); if (this.rid === 0) this.rid = requestAnimationFrame(this.bCallback); return cid; } /** @param {number} cid */ cancel(cid) { cid = +cid; if (cid > 0) { if (cid <= this.startAt) { return cancelAnimationFrame(cid); } if (this.rid > 0) { this.funcs.delete(cid); if (this.funcs.size === 0) { cancelAnimationFrame(this.rid); this.rid = 0; } } } } } 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 dataSetPromise = new PromiseExternal(); const instSetPromise = new PromiseExternal(); const rafHub = new RAFHub(); const _yt_player = await new Promise(resolve => { let cid = setInterval(() => { let t = (((window || 0)._yt_player || 0) || 0); if (t) { clearInterval(cid); resolve(t); } }, 1); promiseForTamerTimeout.then(() => { resolve(null) }); }); if (!_yt_player || typeof _yt_player !== 'object') return; function onSetsT(inst) { if (!inst) return; let r = trySetSecs(); if (r) dataSetPromise.resolve(); instSetPromise.resolve(); } const pm = new Proxy({}, { set(target, prop, value, receiver) { let old = target[prop]; if (old !== value) { target[prop] = old = value; if (prop === 'instsT') onSetsT(value); } } }); const doSetOnData = (playerOverlayAutoplayRenderer, entries) => { let b = playerOverlayAutoplayRenderer.countDownSecsForFullscreen === playerOverlayAutoplayRenderer.countDownSecs if (b && entries) entries = entries.filter(e => Math.abs(e[1] - playerOverlayAutoplayRenderer.countDownSecsForFullscreen * 1E3) < 1e-8) playerOverlayAutoplayRenderer.countDownSecsForFullscreen = second_to_play_next; if (b) playerOverlayAutoplayRenderer.countDownSecs = second_to_play_next; return b; } let qrz = false; Promise.all([dataSetPromise, instSetPromise]).then(() => { const inst = pm.instsT; const playerOverlayAutoplayRenderer = pm.playerOverlayAutoplayRenderer; if (!inst || !playerOverlayAutoplayRenderer) return; let entries = Object.entries(inst).filter(e => typeof e[1] === 'number'); let b = doSetOnData(playerOverlayAutoplayRenderer, entries); setTimeout(() => { let filtered = Object.entries(inst).filter(e => Math.abs(e[1] - second_to_play_next * 1E3) < 1e-8) console.log(`sT(${b ? 'T' : 'F'}):`, filtered, filtered.length) }, 80); qrz = true; }) const trySetSecs = () => { let playerOverlayAutoplayRenderer = null; let pageDataMgr = document.querySelector('ytd-page-manager#page-manager'); let pageData = pageDataMgr ? (pageDataMgr.inst || pageDataMgr).data : null; if (pageData) { try { playerOverlayAutoplayRenderer = pageData.response.playerOverlays.playerOverlayRenderer.autoplay.playerOverlayAutoplayRenderer; } catch (e) { } } if (playerOverlayAutoplayRenderer && typeof playerOverlayAutoplayRenderer.countDownSecsForFullscreen === 'number' && playerOverlayAutoplayRenderer.countDownSecsForFullscreen < 15) { pm.playerOverlayAutoplayRenderer = playerOverlayAutoplayRenderer; return true; } } document.addEventListener('yt-navigate-finish', function () { // onSetsT(pm.instsT) let r = trySetSecs(); if (r) qrz ? doSetOnData(pm.playerOverlayAutoplayRenderer, null) : dataSetPromise.resolve(); }, 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[pk]){ // gkp[pk+'75'] = gkp[pk]; // gkp[pk]=function(){ // console.log(pk) // return this[pk+'75'].apply(this, arguments); // } // } // } if (!gkp.isLoaded75 && typeof gkp.isLoaded === 'function') { gkp.isLoaded75 = gkp.isLoaded; gkp.isLoaded = function () { pm.instsT = this; return this.isLoaded75.apply(this, arguments); } } } console.log(keysT); const sT = [_yt_player] })(); }); })();