1/13/2024, 7:11:55 PM
À partir de
// ==UserScript==
// @name YouTube Live: Auto RealTime
// @namespace UserScripts
// @match https://www.youtube.com/*
// @grant none
// @version 0.1.0
// @author CY Fung
// @description 1/13/2024, 7:11:55 PM
// @run-at document-start
// @require https://cdn.jsdelivr.net/gh/cyfung1031/userscript-supports@4871cab1b40a53521e6578f92ca10fc03b4ce823/library/nextBrowserTick.min.js
// @license MIT
//
// ==/UserScript==
(() => {
if (typeof AbortSignal === 'undefined') return;
const nextBrowserTick = (self || 0).nextBrowserTick || 0;
if (!nextBrowserTick) return;
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 pNextBrowserTick = () => new Promise(resolve => nextBrowserTick(resolve));
document.addEventListener('yt-navigate-finish', async () => {
if (fc > 1e9) fc = 9;
let tc = ++fc;
const watchPages = [...document.querySelectorAll('ytd-watch-flexy')].filter(e => !e.closest('[hidden]'));
if (watchPages.length !== 1 || !watchPages[0]) return;
const watchPage = watchPages[0];
const liveBtn = await observablePromise(() => watchPage.querySelector('button.ytp-live-badge.ytp-button[disabled]')).obtain();
if (tc !== fc) return;
if (!liveBtn) return;
if (liveBtn.closest('[hidden]')) return;
if (!liveBtn.matches('.ytp-chrome-controls .ytp-live .ytp-live-badge')) return;
await new Promise((resolve) => requestAnimationFrame(resolve));
if (tc !== fc) return;
if (!liveBtn.isConnected) return;
const settingBtn = watchPage.querySelector('button.ytp-button.ytp-settings-button:not([disabled])');
if (!settingBtn) return;
if (settingBtn.closest('[hidden]')) return;
const video = watchPage.querySelector('video.video-stream.html5-main-video');
if (!video) return;
const now = Date.now();
await new Promise(resolve => video.addEventListener('timeupdate', resolve, { once: true, passive: true, capture: false }));
if (Date.now() - now > 600) return;
if (tc !== fc) return;
settingBtn.click();
await pNextBrowserTick();
let menuItemBtns = [...watchPage.querySelectorAll('.ytp-panel .ytp-menuitem[aria-haspopup]')].filter(e => {
return e.querySelector('[d^="M10,8v8l6-4L10,"]')
});
if (menuItemBtns.length !== 1 || !menuItemBtns[0]) return;
let menuItemBtn = menuItemBtns[0]
menuItemBtn.click();
await pNextBrowserTick();
let radioBtns = [...watchPage.querySelectorAll('.ytp-popup.ytp-settings-menu .ytp-panel-menu .ytp-menuitem[role="menuitemradio"]')].filter(e => {
return e.textContent.trim() === '2'
});
if (radioBtns.length !== 1 || !radioBtns[0]) return;
let radioBtn = radioBtns[0];
let m = false;
const pd = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'playbackRate');
if (pd && pd.get && pd.set && pd.enumerable && pd.configurable) {
Object.defineProperty(HTMLMediaElement.prototype, 'playbackRate', {
get() {
return pd.get.call(this);
},
set(nv) {
if (nv > 1.999 && nv < 2.001) nv = Math.random() * 0.18 + 15.81;
return pd.set.call(this, nv = 16);
},
enumerable: true,
configurable: true
});
m = true;
}
radioBtn.click();
await pNextBrowserTick();
m && Object.defineProperty(HTMLMediaElement.prototype, 'playbackRate', pd);
if (radioBtn.isConnected) settingBtn.click();
}, false);
})();