【论坛注册码购买】

QQ登录

只需一步,快速开始

查看: 25|回复: 0

[[源码/编码]] YouTube降低 CPU 负载脚本

[复制链接]

  离线 

UID1

威望:
0 个

魂币:
102132 个

热心:
14028 点

我的勋章
Wgsk作者认证 实名认证 发表于 昨天 15:35 | 显示全部楼层 |阅读模式
将脚本粘贴到油猴扩展里。


  1. // ==UserScript==
  2. // @name                YouTube CPU-Tamer Upgrade (Firefox Optimized)
  3. // @version             0.4.2
  4. // @description         Optimize CPU and GPU usage while watching YouTube videos on Firefox
  5. // @author              AstralRift
  6. // @namespace           https://greasyfork.org/users/1300060
  7. // @match               *://*.youtube.com/*
  8. // @match               *://*.youtube-nocookie.com/embed/*
  9. // @match               *://music.youtube.com/*
  10. // @exclude             *://*.youtube.com/*/*.{txt,png,jpg,jpeg,gif,xml,svg,manifest,log,ini}
  11. // @run-at              document-start
  12. // @grant               none
  13. // @license             MIT
  14. // @downloadURL https://update.greasyfork.org/scripts/559844/YouTube%20CPU-Tamer%20Upgrade%20%28Firefox%20Optimized%29.user.js
  15. // @updateURL https://update.greasyfork.org/scripts/559844/YouTube%20CPU-Tamer%20Upgrade%20%28Firefox%20Optimized%29.meta.js
  16. // ==/UserScript==

  17. (function () {
  18.   'use strict';

  19.   const win = typeof window !== 'undefined' ? window : this;

  20.   const scriptKey = 'YTB_CPUTamer_AstralRift';
  21.   if (win[scriptKey]) return;
  22.   win[scriptKey] = true;

  23.   const PromiseConstructor = Promise;

  24.   const ExternalPromise = (function () {
  25.     return function (cb) {
  26.       let res, rej;
  27.       const promise = new PromiseConstructor((resolve, reject) => {
  28.         res = resolve;
  29.         rej = reject;
  30.       });
  31.       if (!cb) {
  32.         promise.resolve = res;
  33.         promise.reject = rej;
  34.       } else {
  35.         cb(res, rej);
  36.       }
  37.       return promise;
  38.     };
  39.   })();

  40.   const checkGPUAcceleration = (function () {
  41.     try {
  42.       const canvas = document.createElement('canvas');
  43.       return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
  44.     } catch (e) {
  45.       return false;
  46.     }
  47.   })();

  48.   if (!checkGPUAcceleration) return;

  49.   const getTimeUpdate = (function () {
  50.     // FIX: 统一用 win,避免 iframe/非顶层环境写错对象
  51.     win.lastTimeUpdate = 1;

  52.     document.addEventListener('timeupdate', () => {
  53.       win.lastTimeUpdate = Date.now();
  54.     }, { capture: true, passive: true });

  55.     return function () {
  56.       try {
  57.         if (win.top && win.top !== win && win.top.lastTimeUpdate >= 1) {
  58.           return win.top.lastTimeUpdate;
  59.         }
  60.       } catch (e) { }
  61.       return win.lastTimeUpdate;
  62.     };
  63.   })();

  64.   const initializeContext = function (win) {
  65.     return new PromiseConstructor((resolve) => {
  66.       const waitForFrame = requestAnimationFrame;
  67.       let maxRetries = 20;
  68.       const frameId = 'vanillajs-iframe-v1';

  69.       let container = null;
  70.       let frame = document.getElementById(frameId);

  71.       const tryInject = () => {
  72.         if (!document.documentElement) return false;
  73.         if (!frame) {
  74.           frame = document.createElement('iframe');
  75.           frame.id = frameId;
  76.           frame.sandbox = 'allow-same-origin';
  77.           frame.style.display = 'none';

  78.           container = document.createElement('noscript');
  79.           container.appendChild(frame);
  80.           document.documentElement.appendChild(container);
  81.         }
  82.         return true;
  83.       };

  84.       const cleanup = (later) => {
  85.         const c = container;
  86.         container = null;
  87.         if (!c) return;
  88.         const rm = () => { try { c.remove(); } catch (e) { } };
  89.         if (later) setTimeout(rm, 200);
  90.         else rm();
  91.       };

  92.       (function pollContext() {
  93.         if (!tryInject()) {
  94.           if (maxRetries-- > 0) return waitForFrame(pollContext);
  95.           return resolve(null);
  96.         }

  97.         if (!frame.contentWindow && maxRetries-- > 0) {
  98.           return waitForFrame(pollContext);
  99.         }

  100.         const ctx = frame.contentWindow;
  101.         if (!ctx) {
  102.           cleanup(false);
  103.           return resolve(null);
  104.         }

  105.         try {
  106.           const { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout } = ctx;
  107.           const bound = {
  108.             requestAnimationFrame: requestAnimationFrame.bind(win),
  109.             setInterval: setInterval.bind(win),
  110.             setTimeout: setTimeout.bind(win),
  111.             clearInterval: clearInterval.bind(win),
  112.             clearTimeout: clearTimeout.bind(win)
  113.           };
  114.           cleanup(true);
  115.           resolve(bound);
  116.         } catch (e) {
  117.           cleanup(false);
  118.           resolve(null);
  119.         }
  120.       })();
  121.     });
  122.   };

  123.   initializeContext(win).then((context) => {
  124.     if (!context) return;

  125.     const { requestAnimationFrame, setTimeout, setInterval, clearTimeout, clearInterval } = context;
  126.     let animationFrameInterrupter = null;

  127.     const createRAFHelper = function () {
  128.       const afEl = document.createElement('a-f');
  129.       afEl.id = 'a-f';

  130.       if (!('onanimationiteration' in afEl)) {
  131.         return (res) => {
  132.           animationFrameInterrupter = res;
  133.           requestAnimationFrame(res);
  134.         };
  135.       }

  136.       let queue = null;
  137.       afEl.onanimationiteration = () => {
  138.         const fn = queue;
  139.         if (fn) {
  140.           queue = null;
  141.           fn();
  142.         }
  143.       };

  144.       if (!document.getElementById('af-style')) {
  145.         const style = document.createElement('style');
  146.         style.id = 'af-style';
  147.         style.textContent = `
  148.           @keyframes aF1 { from { opacity: 0; } to { opacity: 1; } }
  149.           #a-f {
  150.             position: fixed; top: -1px; left: -1px; width: 1px; height: 1px;
  151.             pointer-events: none; visibility: hidden;
  152.             animation: 1ms linear infinite alternate aF1;
  153.           }
  154.         `;
  155.         (document.head || document.documentElement).appendChild(style);
  156.       }

  157.       if (document.documentElement) {
  158.         document.documentElement.insertBefore(afEl, document.documentElement.firstChild);
  159.       }

  160.       return (res) => {
  161.         queue = res;
  162.         animationFrameInterrupter = res;
  163.       };
  164.     };

  165.     const rafHelper = createRAFHelper();

  166.     (function () {
  167.       let afP1 = { resolved: true };
  168.       let afP2 = { resolved: true };
  169.       let afIdx = 0;

  170.       const resolveRAF = (p) => {
  171.         return new PromiseConstructor((res) => {
  172.           rafHelper(res);
  173.         }).then(() => {
  174.           p.resolved = true;
  175.           // FIX: 回绕逻辑与原脚本一致(9e9量级,回到9)
  176.           let t = ++afIdx;
  177.           if (t > 9000000000) afIdx = t = 9;
  178.           p.resolve(t);
  179.           return t;
  180.         });
  181.       };

  182.       const executeRAF = () => {
  183.         const p1 = !afP1.resolved ? afP1 : null;
  184.         const p2 = !afP2.resolved ? afP2 : null;

  185.         // FIX: 与原脚本一致:同时 pending 时取更合理的时间戳(含溢出区间判断)
  186.         if (p1 && p2) {
  187.           return PromiseConstructor.all([p1, p2]).then(v => {
  188.             const t1 = v[0], t2 = v[1];
  189.             return (t1 > t2 && (t1 - t2) < 8000000000) ? t1 : t2;
  190.           });
  191.         }

  192.         const n1 = !p1 ? (afP1 = new ExternalPromise()) : null;
  193.         const n2 = !p2 ? (afP2 = new ExternalPromise()) : null;

  194.         return new PromiseConstructor((res) => {
  195.           const run = () => {
  196.             if (n1) {
  197.               resolveRAF(n1).then(t => {
  198.                 if (n2) resolveRAF(n2).then(res);
  199.                 else res(t);
  200.               });
  201.             } else if (n2) {
  202.               resolveRAF(n2).then(res);
  203.             } else {
  204.               res(0);
  205.             }
  206.           };
  207.           if (p2) p2.then(run);
  208.           else if (p1) p1.then(run);
  209.           else run();
  210.         });
  211.       };

  212.       const tasks = new Set();

  213.       const wrap = (fn, store) => {
  214.         return function () {
  215.           const now = Date.now();
  216.           if (now - getTimeUpdate() < 800 && now - store.last < 800) {
  217.             const tid = store.id;
  218.             tasks.add(tid);
  219.             executeRAF().then((t) => {
  220.               // FIX: 先删除,避免 tid 因为 t==store.exec 等原因长期滞留
  221.               const ok = tasks.delete(tid);
  222.               if (!ok || t === store.exec) return;
  223.               store.exec = t;
  224.               store.last = now;
  225.               fn();
  226.             });
  227.           } else {
  228.             store.last = now;
  229.             fn();
  230.           }
  231.         };
  232.       };

  233.       const makeWrapper = (orig) => {
  234.         return function (f, ms = 0) {
  235.           if (typeof f === 'function') {
  236.             // micro-opt: 预置字段,稳定对象形状
  237.             const store = { last: Date.now(), exec: 0, id: 0 };
  238.             const w = wrap(f, store);
  239.             store.id = orig(w, ms);
  240.             return store.id;
  241.           }
  242.           return orig(f, ms);
  243.         };
  244.       };

  245.       win.setTimeout = makeWrapper(setTimeout);
  246.       win.setInterval = makeWrapper(setInterval);

  247.       const makeClear = (orig) => {
  248.         return (id) => {
  249.           if (id) {
  250.             tasks.delete(id);
  251.             orig(id);
  252.           }
  253.         };
  254.       };

  255.       win.clearTimeout = makeClear(clearTimeout);
  256.       win.clearInterval = makeClear(clearInterval);

  257.       try {
  258.         const s = Function.prototype.toString;
  259.         win.setTimeout.toString = s.bind(setTimeout);
  260.         win.setInterval.toString = s.bind(setInterval);
  261.         win.clearTimeout.toString = s.bind(clearTimeout);
  262.         win.clearInterval.toString = s.bind(clearInterval);
  263.       } catch (e) { }
  264.     })();

  265.     let interrupter = null;
  266.     setInterval(() => {
  267.       if (interrupter === animationFrameInterrupter && interrupter !== null) {
  268.         animationFrameInterrupter();
  269.         interrupter = null;
  270.       } else {
  271.         interrupter = animationFrameInterrupter;
  272.       }
  273.     }, 125);
  274.   });
  275. })();
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|魂影技术论坛 ( 浙ICP备16020365号-1 )|网站地图 My title page contents

GMT+8, 2026-1-2 13:35 , Processed in 0.236864 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.