您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
通过智能节流计时器,显著降低YouTube的CPU使用率,同时保护关键播放器功能以防冻结。
// ==UserScript== // @name YouTube CPU Tamer – Hybrid Edition // @name:ja YouTube CPU負荷軽減スクリプト – ハイブリッド方式 // @name:en YouTube CPU Tamer – Hybrid Edition // @name:zh-CN YouTube CPU减负脚本 – 混合策略 // @name:zh-TW YouTube CPU負載減輕工具 – 混合策略 // @name:ko YouTube CPU 부하 감소 스크립트 – 하이브리드 방식 // @name:fr Réducteur de charge CPU YouTube – Édition Hybride // @name:es Reductor de carga de CPU para YouTube – Edición Híbrida // @name:de YouTube CPU-Last-Reduzierer – Hybrid-Edition // @name:pt-BR Redutor de uso da CPU no YouTube – Edição Híbrida // @name:ru Снижение нагрузки на CPU в YouTube – Гибридная версия // @version 4.80 // @description Dramatically reduces CPU usage on YouTube by intelligently throttling timers, while protecting critical player functions to prevent freezing. // @description:ja YouTubeのCPU負荷を劇的に削減します。動画プレイヤーの重要機能を保護し、無限ロードなどのフリーズ現象を防止する安定性重視の設計です。 // @description:en Dramatically reduces CPU usage on YouTube by intelligently throttling timers, while protecting critical player functions to prevent freezing. // @description:zh-CN 通过智能节流计时器,显著降低YouTube的CPU使用率,同时保护关键播放器功能以防冻结。 // @description:zh-TW 透過智慧節流計時器,顯著降低YouTube的CPU使用率,同時保護關鍵播放器功能以防凍結。 // @description:ko 타이머를 지능적으로 조절하여 YouTube의 CPU 사용량을 크게 줄이고, 중요한 플레이어 기능을 보호하여 멈춤 현상을 방지합니다. // @description:fr Réduit considérablement l'utilisation du CPU sur YouTube en régulant intelligemment les minuteurs, tout en protégeant les fonctions critiques du lecteur pour éviter les blocages. // @description:es Reduce drásticamente el uso de la CPU en YouTube al regular inteligentemente los temporizadores, protegiendo las funciones críticas del reproductor para evitar congelaciones. // @description:de Reduziert die CPU-Auslastung auf YouTube drastisch durch intelligentes Drosseln von Timern, während kritische Player-Funktionen geschützt werden, um ein Einfrieren zu verhindern. // @description:pt-BR Reduz drasticamente o uso da CPU no YouTube ao limitar inteligentemente os temporizadores, protegendo as funções críticas do player para evitar congelamentos. // @description:ru Значительно снижает нагрузку на процессор на YouTube за счет интеллектуального регулирования таймеров, защищая при этом критически важные функции плеера для предотвращения зависаний. // @namespace https://github.com/koyasi777/youtube-cpu-tamer-hybrid // @author koyasi777 // @match https://www.youtube.com/* // @match https://www.youtube.com/embed/* // @match https://www.youtube-nocookie.com/embed/* // @match https://music.youtube.com/* // @run-at document-start // @grant none // @inject-into page // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @homepageURL https://github.com/koyasi777/youtube-cpu-tamer-hybrid // @supportURL https://github.com/koyasi777/youtube-cpu-tamer-hybrid/issues // ==/UserScript== (() => { "use strict"; // --- 設定値 --- const MIN_DELAY_THRESHOLD = 250; const PLAYER_READY_SELECTOR = "#movie_player .ytp-chrome-bottom"; // プレイヤー準備完了を判断するためのDOMセレクタ const REPATCH_TIMEOUT = 10000; // プレイヤーを検出できなかった場合に再パッチするまでの最大待機時間(ms) // --- スクリプトの初期化と多重実行防止 --- const FLAG = "__yt_cpu_tamer_hybrid_running__"; if (window[FLAG]) return; window[FLAG] = true; // --- 非同期ヘルパー関数 --- const nextAnimationFrame = () => new Promise(resolve => requestAnimationFrame(resolve)); const waitForDocReady = async () => { while (!document.documentElement || !document.head) { await nextAnimationFrame(); } }; const PromiseExt = (() => { let _res, _rej; const shim = (r, j) => { _res = r; _rej = j; }; return class extends Promise { constructor(cb = shim) { super(cb); if (cb === shim) { this.resolve = _res; this.reject = _rej; } } }; })(); const setup = async () => { await waitForDocReady(); // --- 1. ネイティブタイマーAPIの安全な取得 --- const FRAME_ID = "yt-cpu-tamer-timer-frame"; let frame = document.getElementById(FRAME_ID); if (frame && (!frame.contentWindow || !frame.contentWindow.setTimeout)) { frame.remove(); frame = null; } if (!frame) { frame = document.createElement("iframe"); frame.id = FRAME_ID; frame.style.display = "none"; frame.sandbox = "allow-same-origin allow-scripts"; frame.srcdoc = "<!doctype html><title>yt-cpu-tamer-timer-provider</title>"; document.documentElement.appendChild(frame); } while (!frame.contentWindow || !frame.contentWindow.setTimeout) { await nextAnimationFrame(); } const nativeTimers = { setTimeout: frame.contentWindow.setTimeout.bind(frame.contentWindow), setInterval: frame.contentWindow.setInterval.bind(frame.contentWindow), clearTimeout: frame.contentWindow.clearTimeout.bind(frame.contentWindow), clearInterval: frame.contentWindow.clearInterval.bind(frame.contentWindow), }; // --- 2. バックグラウンド用トリガーの準備 --- const DUMMY_ID = "yt-cpu-tamer-trigger-node"; let dummy = document.getElementById(DUMMY_ID); if (!dummy) { dummy = document.createElement("div"); dummy.id = DUMMY_ID; dummy.style.display = "none"; document.documentElement.appendChild(dummy); } // --- 3. ハイブリッド戦略の構築 --- let timersAreThrottled = document.visibilityState === "visible"; const makeHybridTrigger = () => { if (document.visibilityState === "visible") { return (callback) => { const p = new PromiseExt(); requestAnimationFrame(p.resolve); return p.then(callback); }; } else { return (callback) => { const p = new PromiseExt(); const MO = new MutationObserver(() => { MO.disconnect(); p.resolve(); }); MO.observe(dummy, { attributes: true }); dummy.setAttribute("data-yt-cpu-tamer-trigger", Math.random().toString(36)); return p.then(callback); }; } }; let currentTrigger = makeHybridTrigger(); const VC_LISTENER_FLAG = "__yt_cpu_tamer_visibility_listener__"; if (!window[VC_LISTENER_FLAG]) { document.addEventListener("visibilitychange", () => { timersAreThrottled = document.visibilityState === "visible"; currentTrigger = makeHybridTrigger(); console.log(`[YouTube CPU Tamer] Visibility changed. Throttling is now ${timersAreThrottled ? 'ON' : 'OFF'}`); }); window[VC_LISTENER_FLAG] = true; } // --- 4. タイマー関数のパッチ(モンキーパッチ) --- const activeTimeouts = new Set(); const makeTimeoutPatcher = (nativeTimeout, pool) => { return function patchedSetTimeout(callback, delay = 0, ...args) { if (typeof callback !== "function" || !timersAreThrottled || delay < MIN_DELAY_THRESHOLD) { return nativeTimeout(callback, delay, ...args); } const id = nativeTimeout(() => { currentTrigger(() => callback.apply(window, args)); }, delay); pool.add(id); return id; }; }; const makeClear = (nativeClear, pool) => (id) => { if (pool.has(id)) pool.delete(id); nativeClear(id); }; const mirrorToString = (patched, native) => { try { patched.toString = native.toString.bind(native); } catch (e) { /* ignore */ } }; const installPatches = () => { window.setTimeout = makeTimeoutPatcher(nativeTimers.setTimeout, activeTimeouts); window.clearTimeout = makeClear(nativeTimers.clearTimeout, activeTimeouts); window.setInterval = nativeTimers.setInterval; window.clearInterval = nativeTimers.clearInterval; mirrorToString(window.setTimeout, nativeTimers.setTimeout); mirrorToString(window.setInterval, nativeTimers.setInterval); mirrorToString(window.clearTimeout, nativeTimers.clearTimeout); mirrorToString(window.clearInterval, nativeTimers.clearInterval); console.log("[YouTube CPU Tamer] Patches installed."); }; const uninstallPatches = () => { window.setTimeout = nativeTimers.setTimeout; window.clearTimeout = nativeTimers.clearTimeout; window.setInterval = nativeTimers.setInterval; window.clearInterval = nativeTimers.clearInterval; console.log("[YouTube CPU Tamer] Patches uninstalled. Timers are native."); }; // --- 5. 初期パッチ適用 --- installPatches(); // --- 6. YouTubeのSPA遷移への対応(v4.80: DOM監視によるインテリジェント方式) --- let navigationHandler = null; window.addEventListener("yt-navigate-finish", () => { if (navigationHandler) { navigationHandler.abort(); // 既に進行中のハンドラがあれば中止 } // 新しいナビゲーションに対応するハンドラを生成 navigationHandler = (function() { let aborted = false; let observer = null; let timeoutId = null; const cleanup = () => { if (observer) observer.disconnect(); if (timeoutId) nativeTimers.clearTimeout(timeoutId); observer = null; timeoutId = null; navigationHandler = null; }; const handleRepatch = (reason) => { if (aborted) return; console.log(`[YouTube CPU Tamer] ${reason}. Re-installing patches...`); installPatches(); timersAreThrottled = document.visibilityState === "visible"; console.log(`[YouTube CPU Tamer] Re-patching complete. Throttling is now ${timersAreThrottled ? 'ON' : 'OFF'}`); cleanup(); }; // --- メインロジック --- console.log("[YouTube CPU Tamer] 'yt-navigate-finish' detected. Uninstalling patches..."); uninstallPatches(); // プレイヤー要素を監視 observer = new MutationObserver(() => { if (document.querySelector(PLAYER_READY_SELECTOR)) { handleRepatch("Player element detected"); } }); if(document.body){ observer.observe(document.body, { childList: true, subtree: true }); } // タイムアウトを設定(安全装置) timeoutId = nativeTimers.setTimeout(() => { handleRepatch("Repatch timeout reached"); }, REPATCH_TIMEOUT); // 既にプレイヤーが存在する場合に即時実行 if (document.querySelector(PLAYER_READY_SELECTOR)) { nativeTimers.setTimeout(() => handleRepatch("Player element already exists"), 0); } return { abort: () => { if (aborted) return; console.log("[YouTube CPU Tamer] Aborting previous navigation handler."); aborted = true; cleanup(); } }; })(); }); }; setup().catch(err => console.error("[YouTube CPU Tamer] A critical error occurred during setup:", err)); })();