您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Reduce Browser's Energy Impact for playing YouTube Video
当前为
// ==UserScript== // @name YouTube CPU Tamer by AnimationFrame // @name:en YouTube CPU Tamer by AnimationFrame // @name:jp YouTube CPU Tamer by AnimationFrame // @name:zh-tw YouTube CPU Tamer by AnimationFrame // @name:zh-cn YouTube CPU Tamer by AnimationFrame // @namespace http://tampermonkey.net/ // @version 2021.08.29.4 // @license MIT License // @description Reduce Browser's Energy Impact for playing YouTube Video // @description:en Reduce Browser's Energy Impact for playing YouTube Video // @description:jp YouTubeビデオのエネルギーインパクトを減らす // @description:zh-tw 減少YouTube影片所致的能源消耗 // @description:zh-cn 减少YouTube影片所致的能源消耗 // @author CY Fung // @include https://www.youtube.com/* // @include https://www.youtube.com/embed/* // @include https://www.youtube-nocookie.com/embed/* // @include https://www.youtube.com/live_chat* // @include https://www.youtube.com/live_chat_replay* // @icon https://www.google.com/s2/favicons?domain=youtube.com // @run-at document-start // @grant none // ==/UserScript== (function $$() { 'use strict'; const window = new Function('return window;')(); // real window object const hkey_script = 'nzsxclvflluv'; if (window[hkey_script]) return; // avoid duplicated scripting window[hkey_script] = true; //if (!document.documentElement) return window.requestAnimationFrame($$); // no document access // copies of native functions const $$requestAnimationFrame = window.requestAnimationFrame.bind(window); // core looping const $$setTimeout = window.setTimeout.bind(window); // for race const $$setInterval = window.setInterval.bind(window); // for background execution let mi = 0; const sb = {}; const sFunc = (prop) => { return (func, ms, ...args) => { mi++; // start at 1 sb[mi] = { handler: args.length > 0 ? func.bind(null, ...args) : func, // original func if no extra argument [prop]: ms, // timeout / interval; value can be undefined nextAt: Date.now() + (ms > 0 ? ms : 0) // overload for setTimeout(func); }; return mi; }; }; const rm = (jd) => { let o = sb[jd]; if (typeof o != 'object') return; for (let k in o) o[k] = null; o = null; sb[jd] = null; delete sb[jd]; }; window.setTimeout = sFunc('timeout'); window.setInterval = sFunc('interval'); window.clearInterval = window.clearTimeout = rm; const $busy = Symbol('$busy'); const pf = (handler => { if ($busy in handler) return; handler[$busy] = true; // max. 1 time of calling per each tf return new Promise(resolve => { // == microTask [Promise] == // microTask is called after all handlers set with $busy, though it is not guaranteed. handler(); // try catch is not required - no further execution on the handler delete handler[$busy]; resolve(); // == microTask [Promise] == }); }); let jf, tf; let bgExecutionAt = 0; // set at 0 to trigger tf in background startup when requestAnimationFrame is not responsive tf = () => { let now = Date.now(); // ======= MarcoTask [requestAnimationFrame / setInterval] ======= let promises = []; for (let mi in sb) { const o = sb[mi]; let { handler, // timeout, interval, nextAt } = o; if (now < nextAt) continue; promises.push(pf(handler)); if (interval > 0) { // prevent undefined, zero, negative values o.nextAt += +interval; // convertion from string to number if necessary; decimal is acceptable } else { rm(mi); } } // ======= MarcoTask [requestAnimationFrame / setInterval] ======= if (!document.hidden) { // calling requestAnimationFrame in visible tab(s) only if (promises.length > 0) { let ret1 = Promise.all(promises); let ret2 = new Promise(resolve => $$setTimeout(resolve, 16)); let race = Promise.race([ret1, ret2]); // ensure jf must be called after 16ms to maintain visual changes in high fps. // >16ms examples: repaint/reflow, change of style/content race.then(jf); } else { jf(); // execution interval is no less than AnimationFrame } } bgExecutionAt = now + 160; // if requestAnimationFrame is not responsive (e.g. background running) }; (jf = $$requestAnimationFrame.bind(window, tf))(); $$setInterval(() => { // no response of requestAnimationFrame; e.g. running in background if (Date.now() > bgExecutionAt) tf(); }, 250); // i.e. 4 times per second for background execution - to keep YouTube application functional // Your code here... })();