YouTube CPU Tamer by AnimationFrame

Reduce Browser's Energy Impact for playing YouTube Video

当前为 2021-08-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube CPU Tamer by AnimationFrame
  3. // @name:en YouTube CPU Tamer by AnimationFrame
  4. // @name:jp YouTube CPU Tamer by AnimationFrame
  5. // @name:zh-tw YouTube CPU Tamer by AnimationFrame
  6. // @name:zh-cn YouTube CPU Tamer by AnimationFrame
  7. // @namespace http://tampermonkey.net/
  8. // @version 2021.08.29
  9. // @license MIT License
  10. // @description Reduce Browser's Energy Impact for playing YouTube Video
  11. // @description:en Reduce Browser's Energy Impact for playing YouTube Video
  12. // @description:jp YouTubeビデオのエネルギーインパクトを減らす
  13. // @description:zh-tw 減少YouTube影片所致的能源消耗
  14. // @description:zh-cn 减少YouTube影片所致的能源消耗
  15. // @author CY Fung
  16. // @include https://www.youtube.com/*
  17. // @include https://www.youtube.com/embed/*
  18. // @include https://www.youtube-nocookie.com/embed/*
  19. // @include https://www.youtube.com/live_chat*
  20. // @include https://www.youtube.com/live_chat_replay*
  21. // @icon https://www.google.com/s2/favicons?domain=youtube.com
  22. // @run-at document-start
  23. // @grant none
  24. // ==/UserScript==
  25. (function $$() {
  26. 'use strict';
  27.  
  28. const window = new Function('return window;')();
  29.  
  30. let hkey_script = 'nzsxclvflluv';
  31. if (window[hkey_script]) return;
  32. window[hkey_script] = true;
  33.  
  34. //if (!document.documentElement) return window.requestAnimationFrame($$);
  35.  
  36. let $$requestAnimationFrame = window.requestAnimationFrame.bind(window);
  37. let $$setTimeout = window.setTimeout.bind(window);
  38.  
  39. let mi = 0;
  40. let sb = {};
  41. const sFunc = (prop) => {
  42. return (func, ms, ...args) => {
  43. mi++;
  44. sb[mi] = {
  45. handler: args.length > 0 ? func.bind(null, ...args) : func,
  46. isNative: (func + "").indexOf('[native code]') > 0,
  47. [prop]: ms,
  48. nextAt: Date.now() + (ms > 0 ? ms : 0)
  49. };
  50. return mi;
  51. }
  52. }
  53. const rm = (jd) => {
  54. let o = sb[jd];
  55. if (typeof o != 'object') return;
  56. for (let k in o) o[k] = null;
  57. o = null;
  58. sb[jd] = null;
  59. delete sb[jd];
  60. }
  61. window.setTimeout = sFunc('timeout');
  62. window.setInterval = sFunc('interval');
  63. window.clearInterval = window.clearTimeout = rm;
  64.  
  65. const $busy = Symbol('$busy');
  66.  
  67. // high energy for non-native API
  68. let pf = (handler =>
  69. new Promise(resolve => {
  70. if (!($busy in handler)) {
  71. handler[$busy] = true;
  72. handler();
  73. delete handler[$busy];
  74. }
  75. resolve();
  76. })
  77. );
  78.  
  79. // low energy for native API
  80. let qf = (handler =>
  81. new Promise(resolve => {
  82. handler();
  83. resolve();
  84. })
  85. );
  86.  
  87. let dt = 0;
  88. let jf;
  89. (jf = $$requestAnimationFrame.bind(window, () => {
  90. let now = Date.now();
  91. if (now < dt) return jf();
  92. // ======= MarcoTask [requestAnimationFrame] =======
  93. let promises = [];
  94. for (let mi in sb) {
  95. const o = sb[mi];
  96. let {
  97. handler,
  98. timeout,
  99. interval,
  100. nextAt,
  101. isNative
  102. } = o;
  103. if (now < nextAt) continue;
  104. isNative ? promises.push(qf(handler)) : promises.push(pf(handler));
  105. if (interval > 0) {
  106. o.nextAt += interval;
  107. } else {
  108. rm(mi);
  109. }
  110. }
  111. // ======= MarcoTask [requestAnimationFrame] =======
  112. if (promises.length > 0) {
  113. if (document.hidden) dt = Date.now() + 160; // lower task execution rate for background playing
  114. let ret1 = Promise.all(promises);
  115. let ret2 = new Promise(resolve => $$setTimeout(resolve, 16));
  116. let race = Promise.race([ret1, ret2]);
  117. race.then(jf);
  118. } else {
  119. jf();
  120. }
  121. }))();
  122.  
  123. // Your code here...
  124. })();