YouTube Live: Auto RealTime

1/13/2024, 7:11:55 PM

目前为 2024-01-13 提交的版本。查看 最新版本

// ==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);

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址