您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
1/13/2024, 7:11:55 PM
当前为
// ==UserScript== // @name YouTube Live: Auto RealTime // @namespace UserScripts // @match https://www.youtube.com/* // @grant none // @version 0.5.0 // @author CY Fung // @description 1/13/2024, 7:11:55 PM // @run-at document-start // @license MIT // // ==/UserScript== (() => { let pbRate = +((13.52 + Math.random() * 0.45).toFixed(2)); // might change in method 2 let byPassPlaybackRate = false; let tmpPlaybackRate = null; let byPassPlaybackRates = null; // [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2] if (typeof AbortSignal === 'undefined') return; let __requestAnimationFrame__ = typeof webkitRequestAnimationFrame === 'function' ? window.webkitRequestAnimationFrame.bind(window) : window.requestAnimationFrame.bind(window); let instance = null; /** @type {globalThis.PromiseConstructor} */ const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve. 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_; } } }; })(); 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 } } } let fc = 0; const pd = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'playbackRate'); const isPassiveArgSupport = (typeof IntersectionObserver === 'function'); const bubblePassive = isPassiveArgSupport ? { capture: false, passive: true } : false; const capturePassive = isPassiveArgSupport ? { capture: true, passive: true } : true; const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0); let pageFetchedDataLocal = null; document.addEventListener('yt-page-data-fetched', (evt) => { pageFetchedDataLocal = evt.detail; }, bubblePassive); function getFormatDates() { if (!pageFetchedDataLocal) return null; const formatDates = {} try { formatDates.publishDate = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.publishDate } catch (e) { } // 2022-12-30 try { formatDates.uploadDate = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.uploadDate } catch (e) { } // 2022-12-30 try { formatDates.publishDate2 = pageFetchedDataLocal.pageData.response.contents.twoColumnWatchNextResults.results.results.contents[0].videoPrimaryInfoRenderer.dateText.simpleText } catch (e) { } // 2022/12/31 if (typeof formatDates.publishDate2 === 'string' && formatDates.publishDate2 !== formatDates.publishDate) { formatDates.publishDate = formatDates.publishDate2 formatDates.uploadDate = null } try { formatDates.broadcastBeginAt = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.liveBroadcastDetails.startTimestamp } catch (e) { } try { formatDates.broadcastEndAt = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.liveBroadcastDetails.endTimestamp } catch (e) { } try { formatDates.isLiveNow = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.liveBroadcastDetails.isLiveNow } catch (e) { } return formatDates; } const promiseVideoNextFn = async (video, v) => { if (typeof video.requestVideoFrameCallback === 'function' && v !== false) { return true === await Promise.race([ new Promise(resolve => video.requestVideoFrameCallback(() => { resolve(true); })), new Promise(resolve => setTimeout(resolve, 1000)) ]); } else { return true === await Promise.race([ new Promise(resolve => video.addEventListener('timeupdate', () => { resolve(true); }, { once: true, passive: true, capture: false })), new Promise(resolve => setTimeout(resolve, 1000)) ]); } } let promisePR1; let videoTarget = null; let pr01 = new PromiseExternal(); let pr02 = new PromiseExternal(); document.addEventListener('durationchange', function (evt) { const target = (evt || 0).target; if (!(target instanceof HTMLVideoElement)) return; if (target.classList.contains('video-stream') && target.classList.contains('html5-main-video')) { videoTarget = target; if (target.duration !== 3600 && target.duration > 120) { pr01.resolve(); pr01 = new PromiseExternal(); } } }, true); let _speedMasterObj = null; async function run(pageFetchedDataLocal) { if (fc > 1e9) fc = 9; let tc = ++fc; const timeout = new Promise(r => setTimeout(r, 1000)); const video = videoTarget; // const video = watchPage.querySelector('video.video-stream.html5-main-video'); if (!video) return; if (video.paused !== false || video.isConnected !== true) return; if (!pageFetchedDataLocal) return; const dates = getFormatDates(); if (!dates) return; const fn = () => { if (video.paused || !video.isConnected || video.networkState !== 2 || video.readyState !== 4) return false; return video.currentTime > 0.1 && video.duration > 0.1 && instance; } if (!fn()) { await observablePromise(fn, timeout).obtain(); } if (tc !== fc) return; await new Promise(resolve => video.addEventListener('timeupdate', () => { resolve(); }, { once: true, passive: true, capture: false })); if (tc !== fc) return; if (dates.broadcastBeginAt && !dates.broadcastEndAt && dates.isLiveNow === true) { } else { return; } window.sss = instance; let keytb = ''; for(const key of Object.getOwnPropertyNames(instance.app)){ if (typeof (instance.app[key]||0) !== 'object') continue; if(!instance.app[key].videoData) continue; if(typeof instance.app[key].getPlayerState !=='function') continue; keytb = key; break; } const ff = async (v)=>{ // await promiseVideoNextFn(video); let Ga = instance.getPlaybackRate(); let La = instance.app[keytb].getPlayerState().isPaused(); // byPassPlaybackRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, v]; if(v>1) byPassPlaybackRates = [1, v]; if(v<1) byPassPlaybackRates = [v, 1]; const waiterPromise = new Promise(resolve => video.addEventListener('waiting', () => { resolve(); }, { once: true, passive: true, capture: false })); instance.setPlaybackRate(v); instance.hideControls(); instance.playVideo(); await waiterPromise.then(); instance.showControls(); byPassPlaybackRates = null; instance.setPlaybackRate(Ga); instance.showControls(); if(instance.getPlayerState() === 3){ // instance.pauseVideo(); // instance.app.cancelPlayback() instance.playVideo(); } La ? instance.pauseVideo() : instance.playVideo(); } for (let i = 0; i < 1000; i++) { if (video.paused || !video.isConnected) return; if (video.networkState === 2 && video.readyState === 4) { break; } await new Promise(resolve => setTimeout(resolve, 100)); } // await ff(16); // await ff(8); await ff(2.9); // for (let i = 0; i < 8; i++) { // if (video.paused || !video.isConnected) return; // if (video.networkState === 2 && video.readyState === 4) { // break; // } // await new Promise(resolve => setTimeout(resolve, 100)); // } // await new Promise(resolve => setTimeout(resolve, 800)); // await ff(2.1); // await ff(2); return; if (_speedMasterObj !== null) { // method 1 // use speedMaster const speedMasterObj = _speedMasterObj; const delayer = speedMasterObj.delay; if (!delayer) return; let keyD = ''; let keyj = ''; const pn = new Set(Object.getOwnPropertyNames(speedMasterObj)); const po = {}; const keyArr = []; const pp = new Proxy(po, { get(target, prop, handler) { if (pn.has(prop) || (prop in po)) { keyArr.push(prop); return undefined; } throw 'Error'; }, set(target, prop, value, handler) { if (pn.has(prop) || (prop in po)) { keyArr.push(prop); return true; } throw 'Error'; } }); for (const prop of Object.getOwnPropertyNames(delayer)) { if (typeof delayer[prop] !== 'function') continue; if (delayer[prop].length !== 0) continue; let isErr = true; try { delayer[prop].call(pp); isErr = false; } catch (e) { } if (isErr) { keyArr.length = 0; continue; } if (keyArr.length === 1) { keyD = keyArr[0]; keyj = prop; keyArr.length = 0; break; // console.log('ss',keyArr) } keyArr.length = 0; } // window.sm = speedMasterObj; // console.log('speedMasterObj',speedMasterObj) // console.log('smD', keyD, keyj, delayer[keyj]) for(let i = 0; i < 1000; i++){ if (video.paused || !video.isConnected ) return; if(video.networkState === 2 && video.readyState === 4){ break; } await new Promise(resolve => setTimeout(resolve, 100)); } const ff = async () => { await new Promise(resolve => video.addEventListener('timeupdate', () => { resolve(); }, { once: true, passive: true, capture: false })); await new Promise(resolve => setTimeout(resolve, 100)); console.log('video.playbackRate [0]', video.playbackRate); byPassPlaybackRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, pbRate]; const waiterPromise = new Promise(resolve => video.addEventListener('waiting', () => { resolve(); }, { once: true, passive: true, capture: false })); try { delayer[keyj].call(new Proxy(speedMasterObj, { get(target, prop, handler) { // console.log(2123, prop, target[prop]) if (prop === keyD) { // console.log('D',keyD) target[prop] = true; return true; } if (typeof target[prop] === 'number' && target[prop] > 1) { // console.log('Na',prop) target[prop] = pbRate; return pbRate; } return Reflect.get(target, prop); }, set(target, prop, value, handler) { return Reflect.set(target, prop, value); }, })); } catch (e) { console.log('error', e) } /* if(speedMasterObj.C === false && speedMasterObj.D === false){ speedMasterObj.C = false; speedMasterObj.D = true; speedMasterObj.Na = 200; speedMasterObj.Da(); console.log(12883, speedMasterObj) } console.log(speedMasterObj.C, speedMasterObj.D) */ console.log('video.playbackRate [1]', video.playbackRate); await waiterPromise.then(); byPassPlaybackRates = null; console.log('video.playbackRate [1.wait]', video.playbackRate); if(instance.getPlayerState() !== 1){ instance.pauseVideo(); instance.playVideo(); } while(instance.getPlayerState() !== 1){ await new Promise(resolve => setTimeout(resolve, 100)); } console.log('video.playbackRate [1.state]', video.playbackRate); console.log('video.playbackRate [2]', video.playbackRate); }; const gg = async (w)=>{ for (let pi = 0; pi < 4; pi++) { await instance.clearQueue(); pbRate = w await ff(); if(video.readyState === 2 || instance.getPlayerState() !== 1){ await new Promise(resolve => setTimeout(resolve, 400000)); await instance.clearQueue(); await instance.playVideo(); } console.log(video.seeking, video.waiting) // if(video.seeking){ // await instance.pauseVideo(); // await instance.pauseVideo(); // await instance.clearQueue(); // await instance.playVideo(); // } await promiseVideoNextFn(video); await new Promise(resolve => setTimeout(resolve, 400)); } } await gg(+((13.52 + Math.random() * 0.45).toFixed(2))); await gg(+((7.52 + Math.random() * 0.45).toFixed(2))); await gg(+((3.52 + Math.random() * 0.45).toFixed(2))); await gg(+((1.52 + Math.random() * 0.45).toFixed(2))); } else { // method 2 // old way for(let i = 0; i < 1000; i++){ if (video.paused || !video.isConnected ) return; if(video.networkState === 2 && video.readyState === 4){ break; } await new Promise(resolve => setTimeout(resolve, 100)); } await new Promise(resolve => video.addEventListener('timeupdate', () => { resolve(); }, { once: true, passive: true, capture: false })); await new Promise(resolve => setTimeout(resolve, 100)); let crate = pd.get.call(video) if (!(crate > 0.99 && crate < 1.01)) return; for (let i = 0; i < 1; i++) { promisePR1 = null; if (video.paused || !video.isConnected || video.networkState !== 2 || video.readyState !== 4) return; if (false === await promiseVideoNextFn(video)) return; if (tc !== fc) return; byPassPlaybackRate = true; try { const pr = promisePR1 = new PromiseExternal(); let rate = 1; rate = 13.52 + Math.random() * 0.45; rate = +rate.toFixed(2); console.log(`run #${i}: rate = `, rate) pbRate = rate; byPassPlaybackRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, pbRate]; instance.setPlaybackRate(rate, true); const pv55 = new PromiseExternal(); const ee = () => { // console.log('rate', video.playbackRate) if (video.playbackRate === pbRate) return; video.removeEventListener('timeupdate', ee, { passive: true, capture: false }); pv55.resolve(); }; video.addEventListener('timeupdate', ee, { passive: true, capture: false }); await pv55.then(); byPassPlaybackRates = null; await promiseVideoNextFn(video); // byPassPlaybackRates = null; await pr.then(); console.log(`run #${i}: rate restored`); // await promiseVideoNextFn(video); // await promiseVideoNextFn(video, false); } finally { byPassPlaybackRate = false; byPassPlaybackRates = null; } } } } const speedmasterUserEduWM = new WeakMap(); Object.defineProperty(Object.prototype, 'speedmasterUserEdu', { get() { return speedmasterUserEduWM.get(this) }, set(nv) { if (this && typeof this.hasOwnProperty === 'function' && this.hasOwnProperty('api')) { _speedMasterObj = this; } speedmasterUserEduWM.set(this, nv); }, enumerable: false, configurable: true }) document.addEventListener('yt-navigate-finish', () => { pr02.resolve(); pr02 = new PromiseExternal(); }, false); (async () => { let lastSrc = null; while (1) { await Promise.all([pr01, pr02]); if (!videoTarget || !videoTarget.isConnected) return; let src = videoTarget.src; if (lastSrc !== src) { lastSrc = src; run(pageFetchedDataLocal); } await new Promise(resolve => __requestAnimationFrame__(resolve)); } })(); const _yt_player_observable = observablePromise(() => { return (((window || 0)._yt_player || 0) || 0); }); (async () => { const _yt_player = await _yt_player_observable.obtain(); if (!_yt_player || typeof _yt_player !== 'object') return; 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 getGU = (_yt_player) => { const w = 'GU'; let arr = []; for (const [k, v] of Object.entries(_yt_player)) { const p = typeof v === 'function' ? v.prototype : 0; if (p && typeof p.setPlaybackRate === 'function' && p.setPlaybackRate.length === 2 && typeof p.getPlaybackRate === 'function' && p.getPlaybackRate.length === 0 // && typeof p.isAtLiveHead === 'function' && typeof p.getVideoUrl === 'function' && p.getVideoUrl.length === 4 && typeof p.getCurrentTime === 'function' && p.getCurrentTime.length == 2 && typeof p.getDuration === 'function' && p.getDuration.length == 2 && !(typeof p.isPaused === 'function' && p.isPaused.length === 0 && typeof p.getCurrentTime === 'function' && p.getCurrentTime.length === 0 && typeof p.getDuration === 'function' && p.getDuration.length === 0 // && typeof p.isAtLiveHead === 'function' && p.isAtLiveHead.length === 0 && typeof p.getVideoPlaybackQuality === 'function' && p.getVideoPlaybackQuality.length === 0 && typeof p.stopVideo === 'function' && p.stopVideo.length === 0) // && Object.keys(_yt_player[k].prototype).includes('addEventListener') // && !p.dispose && !p.isDisposed ) { arr = addProtoToArr(_yt_player, k, arr) || arr; } } // console.log(1222, arr.map(k=> Object.keys(_yt_player[k].prototype).sort())) if (arr.length === 0) { console.warn(`Key does not exist. [${w}]`); } else { console.log(`[${w}]`, arr); return arr[0]; } } const key = getGU(_yt_player); // console.log(1233, key) const g = _yt_player; const k = key; const gk = g[k]; const gkp = g[k].prototype; gkp.getPlaybackRate322 = gkp.getPlaybackRate; gkp.getPlaybackRate = function () { // console.log(5556, this.getPlaybackRate322) instance = this; return this.getPlaybackRate322(); } gkp.setPlaybackRate322 = gkp.setPlaybackRate; gkp.setPlaybackRate = function (a, b) { instance = this; if (byPassPlaybackRate) { // console.log(5888, 12333,a, b) // return; } // console.log(5388, arguments) return this.setPlaybackRate322(a, b); } if (typeof gkp.getAvailablePlaybackRates === 'function' && typeof gkp.getAvailablePlaybackRates322 !== 'function') { gkp.getAvailablePlaybackRates322 = gkp.getAvailablePlaybackRates; gkp.getAvailablePlaybackRates = function () { instance = this; if (byPassPlaybackRates) { // console.log(5888, 12333,a, b) return byPassPlaybackRates; } // console.log(5388, arguments) return this.getAvailablePlaybackRates322(); } //[0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2] } })(); Storage.prototype.setItem322 = Storage.prototype.setItem; Storage.prototype.setItem = function (a, b) { if (a === 'yt-player-playback-rate') { tmpPlaybackRate = b; // if(!byPassPlaybackRate) debugger if (promisePR1 && b && typeof b === 'string' && b.indexOf('{"data":"1"') >= 0) { promisePR1.resolve(); promisePR1 = null; } // console.log(5883, a, b,byPassPlaybackRate, 'XX_'+tmpPlaybackRate+'_', location.pathname) if (window.location.pathname === '/live_chat') return; } if (byPassPlaybackRate && a === 'yt-player-playback-rate') return; this.setItem322(a, b); } Storage.prototype.getItem322 = Storage.prototype.getItem; Storage.prototype.getItem = function (a) { if (a === 'yt-player-playback-rate') { if (window.location.pathname === '/live_chat') return null; if (typeof tmpPlaybackRate === 'string') return tmpPlaybackRate; } if (a === 'yt-player-playback-rate' && typeof tmpPlaybackRate === 'string') return tmpPlaybackRate; return this.getItem322(a); } Object.defineProperty(Storage.prototype, 'yt-player-playback-rate', { get() { return this.getItem('yt-player-playback-rate'); }, set(nv) { this.setItem('yt-player-playback-rate', nv); return true; }, enumerable: true, configurable: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址