- // ==UserScript==
- // @name YouTube CPU Tamer by DOMMutation
- // @name:ja YouTube CPU Tamer by DOMMutation
- // @name:zh-TW YouTube CPU Tamer by DOMMutation
- // @namespace http://tampermonkey.net/
- // @version 2025.02.24.0
- // @license MIT License
- // @author CY Fung
- // @match https://www.youtube.com/*
- // @match https://www.youtube.com/embed/*
- // @match https://www.youtube-nocookie.com/embed/*
- // @match https://www.youtube.com/live_chat*
- // @match https://www.youtube.com/live_chat_replay*
- // @match https://music.youtube.com/*
- // @exclude /^https?://\S+\.(txt|png|jpg|jpeg|gif|xml|svg|manifest|log|ini)[^\/]*$/
- // @icon https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/youtube-cpu-tamper-by-animationframe.webp
- // @supportURL https://github.com/cyfung1031/userscript-supports
- // @run-at document-start
- // @grant none
- // @unwrap
- // @allFrames true
- // @inject-into page
-
- // @description Reduce Browser's Energy Impact for playing YouTube Video
- // @description:en Reduce Browser's Energy Impact for playing YouTube Video
- // @description:ja YouTubeビデオのエネルギーインパクトを減らす
- // @description:zh-TW 減少YouTube影片所致的能源消耗
- // @description:zh-CN 减少YouTube影片所致的能源消耗
-
- // @description:ko YouTube 비디오 재생 시 브라우저의 에너지 영향을 줄입니다.
- // @description:ru Снижает энергетическое воздействие браузера при воспроизведении видео на YouTube.
- // @description:af Verminder die energie-impak van die blaaier vir YouTube-video speel
- // @description:az YouTube videolarını oynamaq üçün Brauzer enerji təsirini azaldır
- // @description:id Kurangi Dampak Energi Browser untuk memutar Video YouTube
- // @description:ms Kurangkan Impak Tenaga Pelayar untuk memainkan Video YouTube
- // @description:bs Smanji energetski uticaj preglednika za reprodukciju YouTube videa
- // @description:ca Redueix l'impacte energètic del navegador per reproduir vídeos de YouTube
- // @description:cs Snížit energetický dopad prohlížeče při přehrávání videí na YouTube
- // @description:da Reducer browserens energipåvirkning for at afspille YouTube-video
- // @description:de Reduzieren Sie die Energieauswirkungen des Browsers für die Wiedergabe von YouTube-Videos
- // @description:et Vähendage YouTube'i video esitamiseks brauseri energiamõju
- // @description:es Reduzca el impacto energético del navegador al reproducir videos de YouTube
- // @description:eu Gutxitu nabigatzeko energiaren eragina YouTube bideoak erreproduzitzeko
- // @description:fr Réduire l'impact énergétique du navigateur lors de la lecture de vidéos YouTube
- // @description:gl Reduzca o impacto enerxético do navegador para reproducir vídeos de YouTube
- // @description:hr Smanjite energetski utjecaj preglednika za reprodukciju YouTube videa
- // @description:zu Qaqalitsha Umbono We-Energy we-Browser ukuze udlale i-Video ye-YouTube
- // @description:is Minkaðu orkuáhrif vafra til að spila YouTube myndband
- // @description:it Riduci l'impatto energetico del browser per la riproduzione di video di YouTube
- // @description:sw Punguza Athari ya Nishati ya Kivinjari kwa kucheza Video za YouTube
- // @description:lv Samaziniet pārlūkprogrammas enerģijas ietekmi YouTube video atskaņošanai
- // @description:lt Sumažinkite naršyklės energijos poveikį žaidžiant „YouTube“ vaizdo įrašus
- // @description:hu Csökkentse a böngésző energiaterhelését a YouTube videó lejátszásához
- // @description:nl Verminder de energie-impact van de browser bij het afspelen van YouTube-video's
- // @description:uz YouTube videoni tinglash uchun brauzer energiyasi ta'sirini kamaytirish
- // @description:pl Zmniejsz zużycie energii przeglądarki podczas odtwarzania filmów na YouTube
- // @description:pt Reduza o Impacto Energético do Navegador ao reproduzir Vídeos do YouTube
- // @description:pt-BR Reduza o Impacto Energético do Navegador ao reproduzir Vídeos do YouTube
- // @description:ro Reduceți impactul energetic al browser-ului pentru redarea videoclipurilor YouTube
- // @description:sq Zvogëlo ndikimin e energjisë të shfletuesit për luajtjen e video YouTube
- // @description:sk Znížte energetický dopad prehliadača pri prehrávaní videí na YouTube
- // @description:sl Zmanjšajte energijski vpliv brskalnika pri predvajanju videoposnetkov YouTube
- // @description:sr Smanjite energetski uticaj pregledača za reprodukciju YouTube videa
- // @description:fi Vähennä selaimen energiankulutusta YouTube-videoiden toistossa
- // @description:sv Minska webbläsarens energipåverkan för att spela YouTube-video
- // @description:vi Giảm tác động năng lượng của trình duyệt khi phát Video YouTube
- // @description:tr YouTube Videolarını Oynatırken Tarayıcının Enerji Etkisini Azaltın
- // @description:be Змяншыце энергетычны ўплыў браўзара на прайграванне YouTube-відэа
- // @description:bg Намалете енергийния влияние на браузъра при възпроизвеждане на видео в YouTube
- // @description:ky YouTube видеонун ойнотуусунан башкаруу үчүн браузердеги энергиялык турмуштарды көмүштөштүрүү
- // @description:kk YouTube-дың браузерде көрсету мүмкіндігін көмеге қысқартыңыз
- // @description:mk Намалете ја енергетската присутност на пребарувачот за репродукција на YouTube видео
- // @description:mn YouTube видеогийг тоглуулж буй хөтөчийн энерги хүчинг буурах
- // @description:uk Зменште енергетичний вплив браузера на відтворення відео на YouTube
- // @description:el Μειώστε την ενεργειακή επίδραση του προγράμματος περιήγησης για την αναπαραγωγή βίντεο στο YouTube
- // @description:hy Փոքրանալիքայինը դանդարեցրեք բրաուզերի էներգիայի ազդեցությունը YouTube վիդեոների ներածման դեպքում
- // @description:ur یوٹیوب ویڈیو کھیلنے کے لئے براؤزر کی توانائی پر اثر کم کریں
- // @description:ar تقليل تأثير استهلاك الطاقة لمتصفح تشغيل مقاطع فيديو يوتيوب
- // @description:fa کاهش تأثیر انرژی مرورگر برای پخش ویدئوی یوتیوب
- // @description:ne युट्युब भिडियो खेल्नका लागि ब्राउजरको ऊर्जा प्रभाव कम गर्नुहोस्
- // @description:mr YouTube व्हिडिओ चालवण्यासाठी ब्राउझरचे ऊर्जाचे प्रभाव कमी करा
- // @description:hi यूट्यूब वीडियो चलाने के लिए ब्राउज़र की ऊर्जा प्रभाव को कम करें
- // @description:as YouTube ভিডিঅ' প্ৰশ্ন কৰা ব্ৰাউজাৰৰ শক্তিৰ প্ৰভাৱ কমিয়া দিব
- // @description:bn YouTube ভিডিও চালাতে ব্রাউজারের শক্তি প্রভাব কমান
- // @description:pa YouTube ਵਿਡੀਓ ਚਲਾਉਣ ਲਈ ਬਰਾਉਜ਼ਰ ਦੀ ਊਰਜਾ ਪ੍ਰਭਾਵ ਘਟਾਓ
- // @description:gu YouTube વિડિઓ ચલાવવા માટે બ્રાઉઝરનું ઊર્જા પ્રભાવ ઘટાડો
- // @description:or YouTube ଭିଡିଓ ଚାଲାନ୍ତୁ ପାଇଁ ବ୍ରାଉଜରର ଶକ୍ତି ପ୍ରଭାବ କମାନ୍ତୁ
- // @description:ta யூடியூப் வீடியோவை இயக்குவதற்கான உலாவியின் மிக்க விளைவுகளை குறைக்கவும்
- // @description:te YouTube వీడియోను ప్రసారం చేయడానికి బ్రౌజర్ యొక్క శక్తి ప్రభావాన్ని తగ్గించుకోండి
- // @description:kn YouTube ವೀಡಿಯೊಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಬ್ರೌಸರ್ ಯನ್ನು ಉಪಯೋಗಿಸುವಾಗ ಶಕ್ತಿ ಪ್ರಭಾವವನ್ನು ಕಡಿಮೆಗೊಳಿಸಿ
- // @description:ml YouTube വീഡിയോ പ്രവർത്തിപ്പിക്കുവാൻ ബ്രൗസർയുടെ പ്രഭാവം കുറയ്ക്കുക
- // @description:si YouTube වීඩියෝ චාරිකා කිරීම සඳහා බ්රවුසරයේ ඊම්ජි බලන්න
- // @description:th ลดผลกระทบทางพลังงานของเบราว์เซอร์ในการเล่นวิดีโอ YouTube
- // @description:lo ບຣາຣິໂຄດລາວເອີ້ນໃນການເພີ່ມເວັບວຽກຂອງ YouTube ສຳ ລັບການຂະໜາດໃນການເພີ່ມເວັບວຽກ
- // @description:my YouTube ဗီဒီယိုများကို ဖွင့်ရန် Browser အတွက် Energy Impact ကိုအနိုင်ရန်
- // @description:ka YouTube ვიდეოების დაკვრებისას ბრაუზერის ენერგიის შეცვლა
- // @description:am YouTube ቪዲዮዎችን ለመቀነስ የባህሪውን አርእስት ግንኙነት ማድረግ
- // @description:km បង្កើតការធ្វើបរិមាណលំអិតរបស់ការកំណត់ការដាក់នៅលើសម្ពាធរបស់ប្រព័ន្ធបញ្ចូលបន្ទាត់ YouTube
- // ==/UserScript==
-
- /*
-
- MIT License
-
- Copyright 2024-2025 CY Fung
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-
- */
-
- /* jshint esversion:8 */
-
- ((__CONTEXT__) => {
- 'use strict';
-
- const win = this instanceof Window ? this : window;
-
- // Create a unique key for the script and check if it is already running
- const hkey_script = 'nzsxclvflluv';
- if (win[hkey_script]) throw new Error('Duplicated Userscript Calling'); // avoid duplicated scripting
- win[hkey_script] = true;
-
- /** @type {globalThis.PromiseConstructor} */
- const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
- const PromiseExternal = ((resolve_, reject_) => {
- const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
- return class PromiseExternal extends Promise {
- constructor(cb = h) {
- super(cb);
- if (cb === h) {
- /** @type {(value: any) => void} */
- this.resolve = resolve_;
- /** @type {(reason?: any) => void} */
- this.reject = reject_;
- }
- }
- };
- })();
-
- // for future use
- /*
- const timeupdateDT = (() => {
-
- window.__j6YiAc__ = 1;
-
- document.addEventListener('timeupdate', () => {
- window.__j6YiAc__ = Date.now();
- }, true);
-
- let kz = -1;
- try {
- kz = top.__j6YiAc__;
- } catch (e) {
-
- }
-
- return kz >= 1 ? () => top.__j6YiAc__ : () => window.__j6YiAc__;
-
- })();
- */
-
- const cleanContext = async (win) => {
- const waitFn = requestAnimationFrame; // shall have been binded to window
- try {
- let mx = 16; // MAX TRIAL
- const frameId = 'vanillajs-iframe-v1'
- let frame = document.getElementById(frameId);
- let removeIframeFn = null;
- if (!frame) {
- frame = document.createElement('iframe');
- frame.id = frameId;
- const blobURL = typeof webkitCancelAnimationFrame === 'function' && typeof kagi === 'undefined' ? (frame.src = URL.createObjectURL(new Blob([], { type: 'text/html' }))) : null; // avoid Brave Crash
- frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe
- let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting)
- n.appendChild(frame);
- while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine
- const root = document.documentElement;
- root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL
- if (blobURL) Promise.resolve().then(() => URL.revokeObjectURL(blobURL));
-
- removeIframeFn = (setTimeout) => {
- const removeIframeOnDocumentReady = (e) => {
- e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
- e = n;
- n = win = removeIframeFn = 0;
- setTimeout ? setTimeout(() => e.remove(), 200) : e.remove();
- }
- if (!setTimeout || document.readyState !== 'loading') {
- removeIframeOnDocumentReady();
- } else {
- win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
- }
- }
- }
- while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn);
- const fc = frame.contentWindow;
- if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL
- try {
- const { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout } = fc;
- const res = { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout };
- for (let k in res) res[k] = res[k].bind(win); // necessary
- if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn);
- return res;
- } catch (e) {
- if (removeIframeFn) removeIframeFn();
- return null;
- }
- } catch (e) {
- console.warn(e);
- return null;
- }
- };
-
-
- const { _setAttribute, _insertBefore, _hasAttribute } = (() => {
- let _setAttribute = Element.prototype.setAttribute;
- try {
- _setAttribute = ShadyDOM.nativeMethods.setAttribute || _setAttribute;
- } catch (e) { }
- let _hasAttribute = Element.prototype.hasAttribute;
- try {
- _hasAttribute = ShadyDOM.nativeMethods.hasAttribute || _hasAttribute;
- } catch (e) { }
- let _insertBefore = Node.prototype.insertBefore;
- try {
- _insertBefore = ShadyDOM.nativeMethods.insertBefore || _insertBefore;
- } catch (e) { }
- return { _setAttribute, _insertBefore, _hasAttribute};
- })();
-
- cleanContext(win).then(__CONTEXT__ => {
-
- if (!__CONTEXT__) return null;
-
- const { setTimeout, setInterval, clearTimeout, clearInterval } = __CONTEXT__;
-
- /*
- /-** @type {Function|null} *-/
- // let afInterupter = null;
- */
-
- const getDMHelper = () => {
- let _dm = document.getElementById('d-m');
- if (!_dm) {
- _dm = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
- _dm.id = 'd-m';
- _insertBefore.call(document.documentElement, _dm, document.documentElement.firstChild);
- }
- const dm = _dm;
- dm._setAttribute = _setAttribute;
- dm._hasAttribute = _hasAttribute;
- let j = 0;
- let attributeName_;
- while (dm._hasAttribute(attributeName_ = `dm-${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`)) {
- // none
- }
- const attributeName = attributeName_;
- let sr = null;
- const mo = new MutationObserver(() => {
- const sr_ = sr;
- if (sr_ !== null) {
- sr = null;
- if (j > 8) j = 0;
- sr_.resolve();
- }
- });
- mo.observe(document, { childList: true, subtree: true, attributes: true });
- return () => {
- return sr || (sr = (dm._setAttribute(attributeName, ++j), (new PromiseExternal()))); // mutationcallback in next macrotask
- };
- };
-
- /** @type {(resolve: () => void)} */
- const dmSN = getDMHelper(); // dm will execute even if document is hidden
-
- (() => {
- let dmPromiseP, dmPromiseQ; // non-null
- dmPromiseP = dmPromiseQ = { resolved: true }; // initial state for !uP && !uQ
- let dmix = 0;
- const dmResolve = async (rX) => {
- await dmSN();
- rX.resolved = true;
- const t = dmix = (dmix & 1073741823) + 1;
- return rX.resolve(t), t;
- };
- const eFunc = async () => {
- const uP = !dmPromiseP.resolved ? dmPromiseP : null;
- const uQ = !dmPromiseQ.resolved ? dmPromiseQ : null;
- let t = 0;
- if (uP && uQ) {
- const t1 = await uP;
- const t2 = await uQ;
- t = ((t1 - t2) & 536870912) === 0 ? t1 : t2; // = 0 for t1 - t2 = [0, 536870911], [–1073741824, -536870913]
- } else {
- const vP = !uP ? (dmPromiseP = new PromiseExternal()) : null;
- const vQ = !uQ ? (dmPromiseQ = new PromiseExternal()) : null;
- if (uQ) await uQ; else if (uP) await uP;
- if (vP) t = await dmResolve(vP);
- if (vQ) t = await dmResolve(vQ);
- }
- return t;
- }
- const inExec = new Set();
- const wFunc = async (handler, wStore) => {
- try {
- const ct = Date.now();
- if (ct - wStore.dt < 800) {
- const cid = wStore.cid;
- inExec.add(cid);
- const t = await eFunc();
- const didNotRemove = inExec.delete(cid); // true for valid key
- if (!didNotRemove || t === wStore.lastExecution) return;
- wStore.lastExecution = t;
- }
- wStore.dt = ct;
- handler();
- } catch (e) {
- console.error(e);
- throw e;
- }
- };
- const sFunc = (propFunc) => {
- return (func, ms = 0, ...args) => {
- if (typeof func === 'function') { // ignore all non-function parameter (e.g. string)
- const wStore = { dt: Date.now() };
- return (wStore.cid = propFunc(wFunc, ms, (args.length > 0 ? func.bind(null, ...args) : func), wStore));
- } else {
- return propFunc(func, ms, ...args);
- }
- };
- };
- win.setTimeout = sFunc(setTimeout);
- win.setInterval = sFunc(setInterval);
-
- const dFunc = (propFunc) => {
- return (cid) => {
- if (cid) inExec.delete(cid) || propFunc(cid);
- };
- };
-
- win.clearTimeout = dFunc(clearTimeout);
- win.clearInterval = dFunc(clearInterval);
-
- try {
- win.setTimeout.toString = setTimeout.toString.bind(setTimeout);
- win.setInterval.toString = setInterval.toString.bind(setInterval);
- win.clearTimeout.toString = clearTimeout.toString.bind(clearTimeout);
- win.clearInterval.toString = clearInterval.toString.bind(clearInterval);
- } catch (e) { console.warn(e) }
-
- })();
-
- /*
- let mInterupter = null;
- setInterval(() => {
- if (mInterupter === afInterupter) {
- if (mInterupter !== null) afInterupter = mInterupter = (mInterupter(), null);
- } else {
- mInterupter = afInterupter;
- }
- }, 125);
- */
- });
-
- })(null);