YouTube JS Engine Tamer

To enhance YouTube performance by modifying YouTube JS Engine

当前为 2023-08-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube JS Engine Tamer
  3. // @namespace UserScripts
  4. // @match https://www.youtube.com/*
  5. // @version 0.4.5
  6. // @license MIT
  7. // @author CY Fung
  8. // @icon https://github.com/cyfung1031/userscript-supports/raw/main/icons/yt-engine.png
  9. // @description To enhance YouTube performance by modifying YouTube JS Engine
  10. // @grant none
  11. // @run-at document-start
  12. // @unwrap
  13. // @inject-into page
  14. // @allFrames true
  15. // ==/UserScript==
  16.  
  17. (() => {
  18.  
  19. const NATIVE_CANVAS_ANIMATION = true; // for #cinematics
  20. const FIX_schedulerInstanceInstance_ = true;
  21. const FIX_yt_player = true;
  22. const FIX_Animation_n_timeline = true;
  23. const NO_PRELOAD_GENERATE_204 = false;
  24. const CHANGE_appendChild = true;
  25.  
  26. const FIX_error_many_stack = true; // should be a bug caused by uBlock Origin
  27. const FIX_error_many_stack_keepAliveDuration = 200; // ms
  28. const FIX_error_many_stack_keepAliveDuration_check_if_n_larger_than = 8;
  29.  
  30. /*
  31. window.addEventListener('edm',()=>{
  32. let p = [...this.onerror.errorTokens][0].token; (()=>{ console.log(p); throw new Error(p);console.log(334,p) })()
  33. });
  34.  
  35. window.addEventListener('edn',()=>{
  36. let p = [...this.onerror.errorTokens][0].token+"X"; (()=>{ console.log(p); throw new Error(p);console.log(334,p) })()
  37. });
  38. window.addEventListener('edr',()=>{
  39. let p = '123'; (()=>{ console.log(p); throw new Error(p);console.log(334,p) })()
  40. });
  41. */
  42.  
  43.  
  44. ; (() => {
  45.  
  46. if (FIX_error_many_stack && self instanceof Window) {
  47. // infinite stack due to matchesStackTrace inside objectPrune of AdsBlock
  48.  
  49. const pdK = Object.getOwnPropertyDescriptor(window, 'onerror');
  50. if (!pdK || (pdK.get && pdK.configurable)) {
  51.  
  52. } else {
  53. return;
  54. }
  55.  
  56. let unsupportErrorFix = false;
  57.  
  58. let firstHook = true;
  59. let busy33 = false;
  60.  
  61. let state = 0;
  62.  
  63. if (pdK) {
  64. delete window['onerror'];
  65. }
  66.  
  67. const pd = {
  68. get() {
  69. const stack = (new Error()).stack;
  70. // targetStack = stack;
  71. let isGetExceptionToken = stack.indexOf('getExceptionToken') >= 0;
  72. state = isGetExceptionToken ? 1 : 0;
  73. delete Window.prototype['onerror'];
  74. let r = pdK ? pdK.get.call(this) : this.onerror;
  75. Object.defineProperty(Window.prototype, 'onerror', pd);
  76. // console.log('onerror get', r)
  77. return r;
  78. },
  79. set(nv) {
  80. const stack = (new Error()).stack;
  81. let isGetExceptionToken = stack.indexOf('getExceptionToken') >= 0;
  82. state = state === 1 && isGetExceptionToken ? 2 : 0;
  83. /** @type {string?} */
  84. let sToken = null;
  85. if (unsupportErrorFix || busy33) {
  86.  
  87. } else if (typeof nv === 'function' && state === 2) {
  88. if (firstHook) {
  89. firstHook = false;
  90. console.groupCollapsed('Infinite onerror Bug Found');
  91. console.log(location.href);
  92. console.log(stack);
  93. console.log(nv);
  94. console.groupEnd();
  95. }
  96. let _token = null;
  97. busy33 = true;
  98. String.prototype.includes76 = String.prototype.includes;
  99. String.prototype.includes = function (token) {
  100. _token = token;
  101. return true;
  102. }
  103. nv('token');
  104. String.prototype.includes = String.prototype.includes76;
  105. sToken = _token;
  106. busy33 = false;
  107. if (typeof sToken !== 'string') {
  108. unsupportErrorFix = true;
  109. }
  110. }
  111. delete Window.prototype['onerror'];
  112. if (typeof sToken === 'string' && sToken.length > 1) {
  113. /** @type {string} */
  114. const token = sToken;
  115. /** @type {OnErrorEventHandler & {errorTokens: Set<string>?} } */
  116. const currentOnerror = pdK ? pdK.get.call(this) : this.onerror;
  117.  
  118. const now = Date.now();
  119. const tokenEntry = {
  120. token,
  121. expired: now + FIX_error_many_stack_keepAliveDuration
  122. }
  123. /** @typedef {typeof tokenEntry} TokenEntry */
  124.  
  125. /** @type {Set<TokenEntry>} */
  126. const errorTokens = currentOnerror.errorTokens;
  127.  
  128. if (errorTokens) {
  129. if (errorTokens.size > FIX_error_many_stack_keepAliveDuration_check_if_n_larger_than) {
  130. for (const entry of errorTokens) {
  131. if (entry.expired < now) {
  132. errorTokens.delete(entry);
  133. }
  134. }
  135. }
  136. errorTokens.add(tokenEntry)
  137. } else {
  138. /** @type {Set<TokenEntry>} */
  139. const errorTokens = new Set([tokenEntry]);
  140. /** @type {OnErrorEventHandler & {errorTokens: Set<string>} } */
  141. const newOnerror = ((oe) => {
  142. const r = function (msg, ...args) {
  143. if (typeof msg === 'string' && errorTokens.size > 0) {
  144. for (const entry of errorTokens) {
  145. if (msg.includes(entry.token)) return true;
  146. }
  147. }
  148. if (typeof oe === 'function') {
  149. return oe.apply(this, arguments);
  150. }
  151. };
  152. r.errorTokens = errorTokens;
  153. return r;
  154. })(currentOnerror);
  155.  
  156. if (pdK && pdK.set) pdK.set.call(this, newOnerror);
  157. else this.onerror = newOnerror;
  158. }
  159. } else {
  160. if (pdK && pdK.set) pdK.set.call(this, nv);
  161. else this.onerror = nv;
  162. }
  163. Object.defineProperty(Window.prototype, 'onerror', pd);
  164.  
  165. // console.log('onerror set', nv)
  166. return true;
  167. },
  168. enumerable: true,
  169. configurable: true
  170. }
  171.  
  172. Object.defineProperty(Window.prototype, 'onerror', pd);
  173.  
  174.  
  175. }
  176.  
  177.  
  178. })();
  179.  
  180.  
  181. // << if FIX_yt_player >>
  182.  
  183. // credit to @nopeless (https://greasyfork.org/scripts/471489-youtube-player-perf/)
  184. const PERF_471489_ = true;
  185. // PERF_471489_ is not exactly the same to Youtube Player perf v0.7
  186. // This script uses a much gentle way to tamer the JS engine instead.
  187.  
  188. // << end >>
  189.  
  190. const steppingScaleN = 200; // transform: scaleX(k/N); 0<k<N
  191.  
  192. const Promise = (async () => { })().constructor;
  193.  
  194. let isMainWindow = false;
  195. try {
  196. isMainWindow = window.document === window.top.document
  197. } catch (e) { }
  198.  
  199. let NO_PRELOAD_GENERATE_204_BYPASS = NO_PRELOAD_GENERATE_204 ? false : true;
  200.  
  201. const onRegistryReady = (callback) => {
  202. if (typeof customElements === 'undefined') {
  203. if (!('__CE_registry' in document)) {
  204. // https://github.com/webcomponents/polyfills/
  205. Object.defineProperty(document, '__CE_registry', {
  206. get() {
  207. // return undefined
  208. },
  209. set(nv) {
  210. if (typeof nv == 'object') {
  211. delete this.__CE_registry;
  212. this.__CE_registry = nv;
  213. this.dispatchEvent(new CustomEvent(EVENT_KEY_ON_REGISTRY_READY));
  214. }
  215. return true;
  216. },
  217. enumerable: false,
  218. configurable: true
  219. })
  220. }
  221. let eventHandler = (evt) => {
  222. document.removeEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  223. const f = callback;
  224. callback = null;
  225. eventHandler = null;
  226. f();
  227. };
  228. document.addEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  229. } else {
  230. callback();
  231. }
  232. };
  233.  
  234. const getZq = (_yt_player) => {
  235.  
  236. const w = 'Zq';
  237.  
  238. let arr = [];
  239.  
  240. for (const [k, v] of Object.entries(_yt_player)) {
  241.  
  242. const p = typeof v === 'function' ? v.prototype : 0;
  243. if (p
  244. && typeof p.start === 'function' && p.start.length === 0
  245. && typeof p.isActive === 'function' && p.isActive.length === 0
  246. && typeof p.stop === 'function' && p.stop.length === 0
  247. && !p.isComplete && !p.getStatus && !p.getResponseHeader && !p.getLastError
  248. && !p.send && !p.abort
  249. && !p.sample && !p.initialize && !p.fail && !p.getName
  250. // && !p.dispose && !p.isDisposed
  251.  
  252. ) {
  253. arr = addProtoToArr(_yt_player, k, arr) || arr;
  254.  
  255.  
  256. }
  257.  
  258. }
  259.  
  260. if (arr.length === 0) {
  261.  
  262. console.warn(`Key does not exist. [${w}]`);
  263. } else {
  264.  
  265. console.log(`[${w}]`, arr);
  266. return arr[0];
  267. }
  268.  
  269.  
  270.  
  271.  
  272. }
  273.  
  274.  
  275. const getVG = (_yt_player) => {
  276. const w = 'VG';
  277.  
  278. let arr = [];
  279.  
  280. for (const [k, v] of Object.entries(_yt_player)) {
  281.  
  282. const p = typeof v === 'function' ? v.prototype : 0;
  283. if (p
  284. && typeof p.show === 'function' && p.show.length === 1
  285. && typeof p.hide === 'function' && p.hide.length === 0
  286. && typeof p.stop === 'function' && p.stop.length === 0) {
  287.  
  288. arr = addProtoToArr(_yt_player, k, arr) || arr;
  289.  
  290. }
  291.  
  292. }
  293.  
  294.  
  295. if (arr.length === 0) {
  296.  
  297. console.warn(`Key does not exist. [${w}]`);
  298. } else {
  299.  
  300. console.log(`[${w}]`, arr);
  301. return arr[0];
  302. }
  303.  
  304.  
  305.  
  306. }
  307.  
  308.  
  309. const getzo = (_yt_player) => {
  310. const w = 'zo';
  311.  
  312. let arr = [];
  313.  
  314. for (const [k, v] of Object.entries(_yt_player)) {
  315.  
  316. if (
  317. typeof v === 'function' && v.length === 3 && k.length < 3
  318. && (v + "").includes("a.style[b]=c")
  319. ) {
  320.  
  321. arr.push(k);
  322.  
  323. }
  324.  
  325. }
  326.  
  327.  
  328. if (arr.length === 0) {
  329.  
  330. console.warn(`Key does not exist. [${w}]`);
  331. } else {
  332.  
  333. console.log(`[${w}]`, arr);
  334. return arr[0];
  335. }
  336.  
  337. }
  338.  
  339. const addProtoToArr = (parent, key, arr) => {
  340.  
  341.  
  342. let isChildProto = false;
  343. for (const sr of arr) {
  344. if (parent[key].prototype instanceof parent[sr]) {
  345. isChildProto = true;
  346. break;
  347. }
  348. }
  349.  
  350. if (isChildProto) return;
  351.  
  352. arr = arr.filter(sr => {
  353. if (parent[sr].prototype instanceof parent[key]) {
  354. return false;
  355. }
  356. return true;
  357. });
  358.  
  359. arr.push(key);
  360.  
  361. return arr;
  362.  
  363.  
  364. }
  365.  
  366. const getuG = (_yt_player) => {
  367.  
  368. const w = 'uG';
  369.  
  370. let arr = [];
  371.  
  372. for (const [k, v] of Object.entries(_yt_player)) {
  373.  
  374.  
  375. const p = typeof v === 'function' ? v.prototype : 0;
  376.  
  377. if (p
  378. && typeof p.createElement === 'function' && p.createElement.length === 2
  379. && typeof p.detach === 'function' && p.detach.length === 0
  380. && typeof p.update === 'function' && p.update.length === 1
  381. && typeof p.updateValue === 'function' && p.updateValue.length === 2
  382. ) {
  383.  
  384. arr = addProtoToArr(_yt_player, k, arr) || arr;
  385.  
  386. }
  387.  
  388. }
  389.  
  390.  
  391.  
  392.  
  393.  
  394. if (arr.length === 0) {
  395.  
  396. console.warn(`Key does not exist. [${w}]`);
  397. } else {
  398.  
  399. console.log(`[${w}]`, arr);
  400. return arr[0];
  401. }
  402.  
  403. }
  404.  
  405.  
  406.  
  407. // << if FIX_schedulerInstanceInstance_ >>
  408.  
  409. let idleFrom = Date.now() + 2700;
  410. let slowMode = false;
  411.  
  412. let ytEvented = false;
  413.  
  414.  
  415. function setupEvents() {
  416.  
  417. document.addEventListener('yt-navigate', () => {
  418.  
  419. ytEvented = true;
  420. slowMode = false;
  421. idleFrom = Date.now() + 2700;
  422.  
  423. });
  424. document.addEventListener('yt-navigate-start', () => {
  425.  
  426. ytEvented = true;
  427. slowMode = false;
  428. idleFrom = Date.now() + 2700;
  429.  
  430. });
  431.  
  432. document.addEventListener('yt-page-type-changed', () => {
  433.  
  434. ytEvented = true;
  435. slowMode = false;
  436. idleFrom = Date.now() + 1700;
  437.  
  438. });
  439.  
  440.  
  441. document.addEventListener('yt-player-updated', () => {
  442.  
  443. ytEvented = true;
  444. slowMode = false;
  445. idleFrom = Date.now() + 1700;
  446.  
  447. });
  448.  
  449.  
  450. document.addEventListener('yt-page-data-fetched', () => {
  451.  
  452. ytEvented = true;
  453. slowMode = false;
  454. idleFrom = Date.now() + 1700;
  455.  
  456. });
  457.  
  458. document.addEventListener('yt-navigate-finish', () => {
  459.  
  460. ytEvented = true;
  461. slowMode = false;
  462. let t = Date.now() + 700;
  463. if (t > idleFrom) idleFrom = t;
  464.  
  465. });
  466.  
  467. document.addEventListener('yt-page-data-updated', () => {
  468.  
  469. ytEvented = true;
  470. slowMode = false;
  471. let t = Date.now() + 700;
  472. if (t > idleFrom) idleFrom = t;
  473.  
  474. });
  475.  
  476. document.addEventListener('yt-watch-comments-ready', () => {
  477.  
  478. ytEvented = true;
  479. slowMode = false;
  480. let t = Date.now() + 700;
  481. if (t > idleFrom) idleFrom = t;
  482.  
  483. });
  484. }
  485.  
  486.  
  487. // << end >>
  488.  
  489. const cleanContext = async (win) => {
  490. const waitFn = requestAnimationFrame; // shall have been binded to window
  491. try {
  492. let mx = 16; // MAX TRIAL
  493. const frameId = 'vanillajs-iframe-v1';
  494. /** @type {HTMLIFrameElement | null} */
  495. let frame = document.getElementById(frameId);
  496. let removeIframeFn = null;
  497. if (!frame) {
  498. frame = document.createElement('iframe');
  499. frame.id = 'vanillajs-iframe-v1';
  500. frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe
  501. let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting)
  502. n.appendChild(frame);
  503. while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine
  504. const root = document.documentElement;
  505. root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL
  506. removeIframeFn = (setTimeout) => {
  507. const removeIframeOnDocumentReady = (e) => {
  508. e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
  509. win = null;
  510. setTimeout(() => {
  511. n.remove();
  512. n = null;
  513. }, 200);
  514. }
  515. if (document.readyState !== 'loading') {
  516. removeIframeOnDocumentReady();
  517. } else {
  518. win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
  519. }
  520. }
  521. }
  522. while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn);
  523. const fc = frame.contentWindow;
  524. if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL
  525. const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, requestIdleCallback, getComputedStyle } = fc;
  526. const res = { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, requestIdleCallback, getComputedStyle };
  527. for (let k in res) res[k] = res[k].bind(win); // necessary
  528. if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn);
  529. res.animate = fc.HTMLElement.prototype.animate;
  530. return res;
  531. } catch (e) {
  532. console.warn(e);
  533. return null;
  534. }
  535. };
  536.  
  537.  
  538. const promiseForCustomYtElementsReady = new Promise(onRegistryReady);
  539.  
  540. cleanContext(window).then(__CONTEXT__ => {
  541. if (!__CONTEXT__) return null;
  542.  
  543. const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, animate, requestIdleCallback, getComputedStyle } = __CONTEXT__;
  544.  
  545.  
  546.  
  547. let rafPromiseForTickers = null;
  548.  
  549. const getRafPromiseForTickers = () => rafPromiseForTickers || (rafPromiseForTickers = new Promise(resolve => {
  550. requestAnimationFrame(hRes => {
  551. rafPromiseForTickers = null;
  552. resolve(hRes);
  553. });
  554. }));
  555.  
  556. const getForegroundPromise = () => {
  557. if (document.visibilityState === 'visible') {
  558. return Promise.resolve();
  559. } else {
  560. return getRafPromiseForTickers();
  561. }
  562. };
  563.  
  564. NO_PRELOAD_GENERATE_204_BYPASS || promiseForCustomYtElementsReady.then(() => {
  565. setTimeout(() => {
  566. NO_PRELOAD_GENERATE_204_BYPASS = true;
  567. }, 1270);
  568. });
  569.  
  570. const promiseForTamerTimeout = new Promise(resolve => {
  571. promiseForCustomYtElementsReady.then(() => {
  572. customElements.whenDefined('ytd-app').then(() => {
  573. setTimeout(resolve, 1200);
  574. });
  575. });
  576. setTimeout(resolve, 3000);
  577. });
  578.  
  579.  
  580. class RAFHub {
  581. constructor() {
  582. /** @type {number} */
  583. this.startAt = 8170;
  584. /** @type {number} */
  585. this.counter = 0;
  586. /** @type {number} */
  587. this.rid = 0;
  588. /** @type {Map<number, FrameRequestCallback>} */
  589. this.funcs = new Map();
  590. const funcs = this.funcs;
  591. /** @type {FrameRequestCallback} */
  592. this.bCallback = this.mCallback.bind(this);
  593. this.pClear = () => funcs.clear();
  594. }
  595. /** @param {DOMHighResTimeStamp} highResTime */
  596. mCallback(highResTime) {
  597. this.rid = 0;
  598. Promise.resolve().then(this.pClear);
  599. this.funcs.forEach(func => Promise.resolve(highResTime).then(func).catch(console.warn));
  600. }
  601. /** @param {FrameRequestCallback} f */
  602. request(f) {
  603. if (this.counter > 1e9) this.counter = 9;
  604. let cid = this.startAt + (++this.counter);
  605. this.funcs.set(cid, f);
  606. if (this.rid === 0) this.rid = requestAnimationFrame(this.bCallback);
  607. return cid;
  608. }
  609. /** @param {number} cid */
  610. cancel(cid) {
  611. cid = +cid;
  612. if (cid > 0) {
  613. if (cid <= this.startAt) {
  614. return cancelAnimationFrame(cid);
  615. }
  616. if (this.rid > 0) {
  617. this.funcs.delete(cid);
  618. if (this.funcs.size === 0) {
  619. cancelAnimationFrame(this.rid);
  620. this.rid = 0;
  621. }
  622. }
  623. }
  624. }
  625. }
  626.  
  627.  
  628.  
  629. NATIVE_CANVAS_ANIMATION && (() => {
  630.  
  631. HTMLCanvasElement.prototype.animate = animate;
  632.  
  633. let cid = setInterval(() => {
  634. HTMLCanvasElement.prototype.animate = animate;
  635. }, 1);
  636.  
  637. promiseForTamerTimeout.then(() => {
  638. clearInterval(cid)
  639. });
  640.  
  641. })();
  642.  
  643. CHANGE_appendChild && (() => {
  644.  
  645. HTMLElement.prototype.appendChild73 = HTMLElement.prototype.appendChild;
  646. HTMLElement.prototype.appendChild = function (a) {
  647. if (!NO_PRELOAD_GENERATE_204_BYPASS && document.head === this) {
  648. for (let node = this.firstElementChild; node instanceof HTMLElement; node = node.nextElementSibling) {
  649. if (node.nodeName === 'LINK' && node.rel === 'preload' && node.as === 'fetch' && !node.__m848__) {
  650. node.__m848__ = 1;
  651. node.rel = 'prefetch'; // see https://github.com/GoogleChromeLabs/quicklink
  652. }
  653. }
  654. }
  655. if (a instanceof DocumentFragment) {
  656. if (a.firstElementChild === null) return a;
  657. }
  658. return this.appendChild73.apply(this, arguments)
  659. }
  660.  
  661.  
  662. })();
  663.  
  664.  
  665. FIX_schedulerInstanceInstance_ && (async () => {
  666.  
  667.  
  668. const schedulerInstanceInstance_ = await new Promise(resolve => {
  669.  
  670. let cid = setInterval(() => {
  671. let t = (((window || 0).ytglobal || 0).schedulerInstanceInstance_ || 0);
  672. if (t) {
  673.  
  674. clearInterval(cid);
  675. resolve(t);
  676. }
  677. }, 1);
  678. promiseForTamerTimeout.then(() => {
  679. resolve(null)
  680. });
  681. });
  682.  
  683. if (!schedulerInstanceInstance_) return;
  684.  
  685.  
  686. if (!ytEvented) {
  687. idleFrom = Date.now() + 2700;
  688. slowMode = false; // integrity
  689. }
  690.  
  691. const checkOK = typeof schedulerInstanceInstance_.start === 'function' && !schedulerInstanceInstance_.start991 && !schedulerInstanceInstance_.stop && !schedulerInstanceInstance_.cancel && !schedulerInstanceInstance_.terminate && !schedulerInstanceInstance_.interupt;
  692. if (checkOK) {
  693.  
  694. schedulerInstanceInstance_.start991 = schedulerInstanceInstance_.start;
  695.  
  696. let requestingFn = null;
  697. let requestingArgs = null;
  698. let requestingDT = 0;
  699.  
  700. // let timerId = null;
  701. const entries = [];
  702. const f = function () {
  703. requestingFn = this.fn;
  704. requestingArgs = [...arguments];
  705. requestingDT = Date.now();
  706. entries.push({
  707. fn: requestingFn,
  708. args: requestingArgs,
  709. t: requestingDT
  710. });
  711. // if (Date.now() < idleFrom) {
  712. // timerId = this.fn.apply(window, arguments);
  713. // } else {
  714. // timerId = this.fn.apply(window, arguments);
  715.  
  716. // }
  717. // timerId = 12377;
  718. return 12377;
  719. }
  720.  
  721.  
  722. const fakeFns = [
  723. f.bind({ fn: requestAnimationFrame }),
  724. f.bind({ fn: setInterval }),
  725. f.bind({ fn: setTimeout }),
  726. f.bind({ fn: requestIdleCallback })
  727. ]
  728.  
  729.  
  730.  
  731.  
  732. let timerResolve = null;
  733. setInterval(() => {
  734. timerResolve && timerResolve();
  735. timerResolve = null;
  736. if (!slowMode && Date.now() > idleFrom) slowMode = true;
  737. }, 250);
  738.  
  739. let mzt = 0;
  740.  
  741. let fnSelectorProp = null;
  742.  
  743. schedulerInstanceInstance_.start = function () {
  744.  
  745. const mk1 = window.requestAnimationFrame
  746. const mk2 = window.setInterval
  747. const mk3 = window.setTimeout
  748. const mk4 = window.requestIdleCallback
  749.  
  750. const tThis = this['$$12378$$'] || this;
  751.  
  752.  
  753. window.requestAnimationFrame = fakeFns[0]
  754. window.setInterval = fakeFns[1]
  755. window.setTimeout = fakeFns[2]
  756. window.requestIdleCallback = fakeFns[3]
  757.  
  758. fnSelectorProp = null;
  759.  
  760.  
  761. tThis.start991.call(new Proxy(tThis, {
  762. get(target, prop, receiver) {
  763. if (prop === '$$12377$$') return true;
  764. if (prop === '$$12378$$') return target;
  765.  
  766. // console.log('get',prop)
  767. return target[prop]
  768. },
  769. set(target, prop, value, receiver) {
  770. // console.log('set', prop, value)
  771.  
  772.  
  773. if (value >= 1 && value <= 4) fnSelectorProp = prop;
  774. if (value === 12377 && fnSelectorProp) {
  775.  
  776. const originalSelection = target[fnSelectorProp];
  777. const timerIdProp = prop;
  778.  
  779. /*
  780.  
  781.  
  782. case 1:
  783. var a = this.K;
  784. this.g = this.I ? window.requestIdleCallback(a, {
  785. timeout: 3E3
  786. }) : window.setTimeout(a, ma);
  787. break;
  788. case 2:
  789. this.g = window.setTimeout(this.M, this.N);
  790. break;
  791. case 3:
  792. this.g = window.requestAnimationFrame(this.L);
  793. break;
  794. case 4:
  795. this.g = window.setTimeout(this.J, 0)
  796. }
  797.  
  798. */
  799.  
  800. const doForegroundSlowMode = () => {
  801.  
  802. const tir = ++mzt;
  803. const f = requestingArgs[0];
  804.  
  805.  
  806. getForegroundPromise().then(() => {
  807.  
  808.  
  809. new Promise(r => {
  810. timerResolve = r
  811. }).then(() => {
  812. if (target[timerIdProp] === -tir) f();
  813. });
  814.  
  815. })
  816.  
  817. target[fnSelectorProp] = 931;
  818. target[prop] = -tir;
  819. }
  820.  
  821. if (target[fnSelectorProp] === 2 && requestingFn === setTimeout) {
  822. if (slowMode && !(requestingArgs[1] > 250)) {
  823.  
  824. doForegroundSlowMode();
  825.  
  826. } else {
  827. target[prop] = setTimeout.apply(window, requestingArgs);
  828.  
  829. }
  830.  
  831. } else if (target[fnSelectorProp] === 3 && requestingFn === requestAnimationFrame) {
  832.  
  833. if (slowMode) {
  834.  
  835. doForegroundSlowMode();
  836.  
  837. } else {
  838. target[prop] = requestAnimationFrame.apply(window, requestingArgs);
  839. }
  840.  
  841.  
  842. } else if (target[fnSelectorProp] === 4 && requestingFn === setTimeout && !requestingArgs[1]) {
  843.  
  844. const f = requestingArgs[0];
  845. const tir = ++mzt;
  846. Promise.resolve().then(() => {
  847. if (target[timerIdProp] === -tir) f();
  848. });
  849. target[fnSelectorProp] = 930;
  850. target[prop] = -tir;
  851.  
  852. } else if (target[fnSelectorProp] === 1 && (requestingFn === requestIdleCallback || requestingFn === setTimeout)) {
  853.  
  854. doForegroundSlowMode();
  855.  
  856. } else {
  857. // target[prop] = timerId;
  858. target[fnSelectorProp] = 0;
  859. target[prop] = 0;
  860. }
  861.  
  862. // *****
  863. // console.log('[[set]]', slowMode , prop, value, `fnSelectorProp: ${originalSelection} -> ${target[fnSelectorProp]}`)
  864. } else {
  865.  
  866. target[prop] = value;
  867. }
  868. // console.log('set',prop,value)
  869. return true;
  870. }
  871. }));
  872.  
  873. fnSelectorProp = null;
  874.  
  875.  
  876. window.requestAnimationFrame = mk1;
  877. window.setInterval = mk2
  878. window.setTimeout = mk3
  879. window.requestIdleCallback = mk4;
  880.  
  881.  
  882.  
  883. }
  884.  
  885. schedulerInstanceInstance_.start.toString = function () {
  886. return schedulerInstanceInstance_.start991.toString();
  887. }
  888.  
  889. // const funcNames = [...(schedulerInstanceInstance_.start + "").matchAll(/[\(,]this\.(\w{1,2})[,\)]/g)].map(e => e[1]).map(prop => ({
  890. // prop,
  891. // value: schedulerInstanceInstance_[prop],
  892. // type: typeof schedulerInstanceInstance_[prop]
  893.  
  894. // }));
  895. // console.log('fcc', funcNames)
  896.  
  897.  
  898.  
  899.  
  900. }
  901. })();
  902.  
  903.  
  904. FIX_yt_player && (async () => {
  905.  
  906.  
  907.  
  908. const rafHub = new RAFHub();
  909.  
  910.  
  911. const _yt_player = await new Promise(resolve => {
  912.  
  913. let cid = setInterval(() => {
  914. let t = (((window || 0)._yt_player || 0) || 0);
  915. if (t) {
  916.  
  917. clearInterval(cid);
  918. resolve(t);
  919. }
  920. }, 1);
  921.  
  922. promiseForTamerTimeout.then(() => {
  923. resolve(null)
  924. });
  925.  
  926. });
  927.  
  928.  
  929.  
  930. if (!_yt_player || typeof _yt_player !== 'object') return;
  931.  
  932.  
  933.  
  934. let keyZq = getZq(_yt_player);
  935. let keyVG = getVG(_yt_player);
  936. let buildVG = _yt_player[keyVG];
  937. let u = new buildVG({
  938. api: {},
  939. element: document.createElement('noscript'),
  940. api: {},
  941. hide: () => { }
  942. }, 250);
  943. const timeDelayConstructor = u.delay.constructor; // g.br
  944. // console.log(keyVG, u)
  945. // buildVG.prototype.show = function(){}
  946. // _yt_player[keyZq] = g.k
  947.  
  948. if (!keyZq) return;
  949.  
  950.  
  951. const g = _yt_player
  952. let k = keyZq
  953.  
  954. const gk = g[k];
  955. if (typeof gk !== 'function') return;
  956.  
  957. let dummyObject = new gk;
  958. let nilFunc = () => { };
  959.  
  960. let nilObj = {};
  961.  
  962. // console.log(1111111111)
  963.  
  964. let keyBoolD = '';
  965. let keyWindow = '';
  966. let keyFuncC = '';
  967. let keyCidj = '';
  968.  
  969. for (const [t, y] of Object.entries(dummyObject)) {
  970. if (y instanceof Window) keyWindow = t;
  971. }
  972.  
  973. const dummyObjectProxyHandler = {
  974. get(target, prop) {
  975. let v = target[prop]
  976. if (v instanceof Window && !keyWindow) {
  977. keyWindow = t;
  978. }
  979. let y = typeof v === 'function' ? nilFunc : typeof v === 'object' ? nilObj : v;
  980. if (prop === keyWindow) y = {
  981. requestAnimationFrame(f) {
  982. return 3;
  983. },
  984. cancelAnimationFrame() {
  985.  
  986. }
  987. }
  988. if (!keyFuncC && typeof v === 'function' && !(prop in target.constructor.prototype)) {
  989. keyFuncC = prop;
  990. }
  991. // console.log('[get]', prop, typeof target[prop])
  992.  
  993.  
  994. return y;
  995. },
  996. set(target, prop, value) {
  997.  
  998. if (typeof value === 'boolean' && !keyBoolD) {
  999. keyBoolD = prop;
  1000. }
  1001. if (typeof value === 'number' && !keyCidj && value >= 2) {
  1002. keyCidj = prop;
  1003. }
  1004.  
  1005. // console.log('[set]', prop, value)
  1006. target[prop] = value
  1007.  
  1008. return true;
  1009. }
  1010. };
  1011.  
  1012. dummyObject.start.call(new Proxy(dummyObject, dummyObjectProxyHandler))
  1013.  
  1014. /*
  1015. console.log({
  1016. keyBoolD,
  1017. keyFuncC,
  1018. keyWindow,
  1019. keyCidj
  1020. })
  1021.  
  1022. console.log( dummyObject[keyFuncC])
  1023.  
  1024.  
  1025. console.log(2222222222)
  1026. */
  1027.  
  1028.  
  1029.  
  1030.  
  1031. g[k].prototype.start = function () {
  1032. this.stop();
  1033. this[keyBoolD] = true;
  1034. this[keyCidj] = rafHub.request(this[keyFuncC]);
  1035. }
  1036. ;
  1037. g[k].prototype.stop = function () {
  1038. if (this.isActive() && this[keyCidj]) {
  1039. rafHub.cancel(this[keyCidj]);
  1040. }
  1041. this[keyCidj] = null
  1042. }
  1043.  
  1044.  
  1045. /*
  1046. g[k].start = function() {
  1047. this.stop();
  1048. this.D = true;
  1049. var a = requestAnimationFrame
  1050. , b = cancelAnimationFrame;
  1051. this.j = a.call(this.B, this.C)
  1052. }
  1053. ;
  1054. g[k].stop = function() {
  1055. if (this.isActive()) {
  1056. var a = requestAnimationFrame
  1057. , b = cancelAnimationFrame;
  1058. b.call(this.B, this.j)
  1059. }
  1060. this.j = null
  1061. }
  1062. */
  1063.  
  1064.  
  1065.  
  1066. const keyzo = PERF_471489_ ? getzo(_yt_player) : null;
  1067.  
  1068. if (keyzo) {
  1069.  
  1070. k = keyzo
  1071.  
  1072. const setCSSProp = (() => {
  1073.  
  1074. let animationPropCapable = false;
  1075. try {
  1076. const propName = "--ibxpf"
  1077. const value = 2;
  1078. const keyframes = [{
  1079. [propName]: value
  1080. }];
  1081. window.CSS.registerProperty({
  1082. name: "--ibxpf",
  1083. syntax: "<number>",
  1084. inherits: false,
  1085. initialValue: 1,
  1086. });
  1087. animationPropCapable = '1' === `${getComputedStyle(document.documentElement).getPropertyValue('--ibxpf')}`
  1088. } catch (e) { }
  1089.  
  1090. if (!animationPropCapable) {
  1091. return (element, cssProp, value) => {
  1092.  
  1093.  
  1094. element.style.setProperty(cssProp, value);
  1095.  
  1096. }
  1097. }
  1098.  
  1099. const propMaps = new Map();
  1100.  
  1101. function setCustomCSSProperty(element, propName, value) {
  1102. let wm = propMaps.get(propName);
  1103. if (!wm) {
  1104.  
  1105. try {
  1106. window.CSS.registerProperty({
  1107. name: propName,
  1108. syntax: "*",
  1109. inherits: false
  1110. });
  1111. } catch (e) {
  1112. console.warn(e);
  1113. }
  1114.  
  1115. propMaps.set(propName, (wm = new WeakMap()));
  1116. }
  1117.  
  1118. // Create the animation keyframes with the provided property and value
  1119. const keyframes = [{
  1120. [propName]: value
  1121. }];
  1122.  
  1123. let currentAnimation = wm.get(element);
  1124. if (currentAnimation) {
  1125.  
  1126. currentAnimation.effect.setKeyframes(keyframes);
  1127.  
  1128. } else {
  1129.  
  1130.  
  1131.  
  1132. // Set the animation on the element and immediately pause it
  1133. const animation = animate.call(element, keyframes, {
  1134. duration: 1, // Very short duration as we just want to set the value
  1135. fill: 'forwards',
  1136. iterationStart: 1,
  1137. iterations: 2,
  1138. direction: 'alternate'
  1139. });
  1140.  
  1141.  
  1142. // animation.currentTime = 1;
  1143. animation.pause();
  1144.  
  1145. wm.set(element, animation);
  1146.  
  1147.  
  1148. }
  1149.  
  1150. }
  1151.  
  1152. return setCustomCSSProperty;
  1153.  
  1154.  
  1155. })();
  1156.  
  1157.  
  1158. const attrUpdateFn = g[k];
  1159. g['$$original$$' + k] = attrUpdateFn;
  1160. g[k] = function (a, b, c) {
  1161.  
  1162. // console.log(140000, a, b, c);
  1163.  
  1164. let transformType = '';
  1165. let transformValue = 0;
  1166. let transformUnit = '';
  1167.  
  1168. let byPassDefaultFn = false;
  1169. if (b === "transform" && typeof c === 'string') {
  1170.  
  1171. byPassDefaultFn = true;
  1172.  
  1173. const aStyle = a.style;
  1174.  
  1175. // let beforeMq = aStyle.getPropertyValue('--mq-transform');
  1176. if (!(a instanceof HTMLElement)) return;
  1177. if (c.length === 0) {
  1178.  
  1179. } else if (c.startsWith('scalex(0.') || (c === 'scalex(0)' || c === 'scalex(1)')) {
  1180. let p = c.substring(7, c.length - 1);
  1181. let q = p.length >= 1 ? parseFloat(p) : -1;
  1182. if (q > -1e-5 && q < 1 + 1e-5) {
  1183. transformType = 'scalex'
  1184. transformValue = q;
  1185. transformUnit = '';
  1186. }
  1187.  
  1188.  
  1189. } else if (c.startsWith('translateX(') && c.endsWith('px)')) {
  1190.  
  1191. let p = c.substring(11, c.length - 3);
  1192. let q = p.length >= 1 ? parseFloat(p) : NaN;
  1193.  
  1194. if (typeof q === 'number' && !isNaN(q)) {
  1195. transformType = 'translateX'
  1196. transformValue = q;
  1197. transformUnit = 'px';
  1198. }
  1199.  
  1200.  
  1201. } else if (c.startsWith('scaley(0.') || (c === 'scaley(0)' || c === 'scaley(1)')) {
  1202. let p = c.substring(7, c.length - 1);
  1203. let q = p.length >= 1 ? parseFloat(p) : -1;
  1204. if (q > -1e-5 && q < 1 + 1e-5) {
  1205. transformType = 'scaley'
  1206. transformValue = q;
  1207. transformUnit = '';
  1208. }
  1209.  
  1210.  
  1211. } else if (c.startsWith('translateY(') && c.endsWith('px)')) {
  1212.  
  1213. let p = c.substring(11, c.length - 3);
  1214. let q = p.length >= 1 ? parseFloat(p) : NaN;
  1215.  
  1216. if (typeof q === 'number' && !isNaN(q)) {
  1217. transformType = 'translateY'
  1218. transformValue = q;
  1219. transformUnit = 'px';
  1220. }
  1221.  
  1222.  
  1223. }
  1224.  
  1225. if (transformType) {
  1226.  
  1227. if (transformType === 'scalex' || transformType === 'scaley') {
  1228.  
  1229. const q = transformValue;
  1230.  
  1231.  
  1232. /*
  1233.  
  1234. let vz = Math.round(steppingScaleN * q);
  1235. const customPropName = '--discrete-'+transformType
  1236.  
  1237. const currentValue = aStyle.getPropertyValue(customPropName);
  1238.  
  1239. const transform = (aStyle.transform || '');
  1240. const u = transform.includes(customPropName)
  1241. if (`${currentValue}` === `${vz}`) {
  1242. if (u) return;
  1243. }
  1244.  
  1245.  
  1246. setCSSProp(a,customPropName, vz);
  1247. // aStyle.setProperty(customPropName, vz)
  1248.  
  1249. let ck = '';
  1250.  
  1251. if (c.length === 9) ck = c;
  1252. else if (!u) ck = c.replace(/[.\d]+/, '0.5');
  1253.  
  1254. if (ck && beforeMq !== ck) {
  1255. aStyle.setProperty('--mq-transform', ck);
  1256. }
  1257.  
  1258. if (u) return;
  1259. c = `${transformType}(calc(var(--discrete-${transformType})/${steppingScaleN}))`;
  1260.  
  1261.  
  1262.  
  1263. */
  1264.  
  1265. const vz = +(Math.round(q * steppingScaleN) / steppingScaleN).toFixed(3);
  1266.  
  1267. c = `${transformType === 'scalex' ? 'scaleX' : 'scaleY'}(${vz})`
  1268. const cv = aStyle.transform;
  1269.  
  1270. // console.log(157, cv,c)
  1271.  
  1272. if (c === cv) return;
  1273. // console.log(257, cv,c)
  1274.  
  1275. aStyle.transform = c;
  1276.  
  1277. // return;
  1278.  
  1279. } else if (transformType === 'translateX' || transformType === 'translateY') {
  1280.  
  1281. const q = transformValue;
  1282.  
  1283. /*
  1284.  
  1285. let vz = q.toFixed(1);
  1286. const customPropName = '--discrete-'+transformType
  1287.  
  1288. const aStyle = a.style;
  1289. const currentValue = (aStyle.getPropertyValue(customPropName) || '').replace('px', '');
  1290.  
  1291.  
  1292. const transform = (aStyle.transform || '');
  1293. const u = transform.includes(customPropName)
  1294. if (parseFloat(currentValue).toFixed(1) === vz) {
  1295. if (u) return;
  1296. }
  1297.  
  1298. setCSSProp(a,customPropName, vz + 'px');
  1299. // aStyle.setProperty(customPropName, vz + 'px')
  1300.  
  1301. let ck = '';
  1302. if (c.length === 15) ck = c;
  1303. else if (!u) ck = c.replace(/[.\d]+/, '0.5');
  1304.  
  1305. if (ck && beforeMq !== ck) {
  1306. aStyle.setProperty('--mq-transform', ck);
  1307. }
  1308.  
  1309. if (u) return;
  1310. c = `${transformType}(var(--discrete-${transformType}))`;
  1311.  
  1312. */
  1313.  
  1314.  
  1315. const vz = +q.toFixed(1);
  1316.  
  1317. c = `${transformType}(${vz}${transformUnit})`
  1318. const cv = aStyle.transform;
  1319.  
  1320. // console.log(158, cv,c)
  1321.  
  1322. if (c === cv) return;
  1323. // console.log(258, cv,c)
  1324.  
  1325. aStyle.transform = c;
  1326.  
  1327. // return;
  1328.  
  1329. } else {
  1330. throw new Error();
  1331. }
  1332.  
  1333. } else {
  1334. // if(beforeMq) a.style.setProperty('--mq-transform', '');
  1335. const cv = aStyle.transform
  1336. if (!c && !cv) return;
  1337. else if (c === cv) return;
  1338. aStyle.transform = c;
  1339. // return;
  1340. }
  1341.  
  1342. } else if (b === "display") {
  1343.  
  1344. const cv = a.style.display;
  1345. if (!cv && !c) return;
  1346. if (cv === c) return;
  1347.  
  1348.  
  1349. } else if (b === "width") {
  1350.  
  1351. const cv = a.style.width;
  1352. if (!cv && !c) return;
  1353. if (cv === c) return;
  1354.  
  1355. }
  1356.  
  1357. // console.log(130000, a, b, c);
  1358.  
  1359. if (byPassDefaultFn) return;
  1360. return attrUpdateFn.call(this, a, b, c);
  1361. }
  1362.  
  1363.  
  1364. /*
  1365.  
  1366. g.zo = function(a, b, c) {
  1367. if ("string" === typeof b)
  1368. (b = yo(a, b)) && (a.style[b] = c);
  1369. else
  1370. for (var d in b) {
  1371. c = a;
  1372. var e = b[d]
  1373. , f = yo(c, d);
  1374. f && (c.style[f] = e)
  1375. }
  1376. }
  1377.  
  1378.  
  1379. */
  1380.  
  1381.  
  1382. }
  1383.  
  1384.  
  1385.  
  1386. const keyuG = PERF_471489_ ? getuG(_yt_player) : null;
  1387.  
  1388. if (keyuG) {
  1389.  
  1390. k = keyuG;
  1391.  
  1392. const gk = g[k];
  1393. const gkp = gk.prototype;
  1394.  
  1395.  
  1396. /** @type { Map<string, WeakMap<any, any>> } */
  1397. const ntLogs = new Map();
  1398.  
  1399. if (typeof gkp.updateValue === 'function' && gkp.updateValue.length === 2 && !gkp.updateValue31) {
  1400.  
  1401. gkp.updateValue31 = gkp.updateValue;
  1402. gkp.updateValue = function (a, b) {
  1403. if (typeof a !== 'string') return this.updateValue31(a, b);
  1404.  
  1405. const element = this.element;
  1406. if (!(element instanceof HTMLElement)) return this.updateValue31(a, b);
  1407.  
  1408. let ntLog = ntLogs.get(a);
  1409. if (!ntLog) ntLogs.set(a, (ntLog = new WeakMap()));
  1410.  
  1411. let cache = ntLog.get(element);
  1412. if (cache && cache.value === b) {
  1413. return;
  1414. }
  1415. if (!cache) {
  1416. this.__oldValueByUpdateValue__ = null;
  1417. ntLog.set(element, cache = { value: b });
  1418. } else {
  1419. this.__oldValueByUpdateValue__ = cache.value;
  1420. cache.value = b;
  1421. }
  1422.  
  1423.  
  1424. return this.updateValue31(a, b);
  1425. }
  1426.  
  1427.  
  1428. /*
  1429. g.k.update = function(a) {
  1430. for (var b = g.u(Object.keys(a)), c = b.next(); !c.done; c = b.next())
  1431. c = c.value,
  1432. this.updateValue(c, a[c])
  1433. }
  1434. ;
  1435. g.k.updateValue = function(a, b) {
  1436. (a = this.Td["{{" + a + "}}"]) && wG(this, a[0], a[1], b)
  1437. }
  1438. */
  1439.  
  1440.  
  1441. }
  1442.  
  1443.  
  1444. }
  1445.  
  1446.  
  1447.  
  1448.  
  1449. })();
  1450.  
  1451.  
  1452.  
  1453. FIX_Animation_n_timeline && (async () => {
  1454.  
  1455.  
  1456. const timeline = await new Promise(resolve => {
  1457.  
  1458. let cid = setInterval(() => {
  1459. let t = (((document || 0).timeline || 0) || 0);
  1460. if (t && typeof t._play === 'function') {
  1461.  
  1462. clearInterval(cid);
  1463. resolve(t);
  1464. }
  1465. }, 1);
  1466.  
  1467. promiseForTamerTimeout.then(() => {
  1468. resolve(null)
  1469. });
  1470.  
  1471. });
  1472.  
  1473.  
  1474. const Animation = await new Promise(resolve => {
  1475.  
  1476. let cid = setInterval(() => {
  1477. let t = (((window || 0).Animation || 0) || 0);
  1478. if (t && typeof t === 'function' && t.length === 2 && typeof t.prototype._updatePromises === 'function') {
  1479.  
  1480. clearInterval(cid);
  1481. resolve(t);
  1482. }
  1483. }, 1);
  1484.  
  1485. promiseForTamerTimeout.then(() => {
  1486. resolve(null)
  1487. });
  1488.  
  1489. });
  1490.  
  1491. if (!timeline) return;
  1492. if (!Animation) return;
  1493.  
  1494. const aniProto = Animation.prototype;
  1495.  
  1496. const getXroto = (x) => {
  1497. try {
  1498. return x.__proto__;
  1499. } catch (e) { }
  1500. return null;
  1501. }
  1502. const timProto = getXroto(timeline);
  1503. if (!timProto) return;
  1504. if (
  1505. (
  1506. typeof timProto.getAnimations === 'function' && typeof timProto.play === 'function' &&
  1507. typeof timProto._discardAnimations === 'function' && typeof timProto._play === 'function' &&
  1508. typeof timProto._updateAnimationsPromises === 'function' && !timProto.nofCQ &&
  1509. typeof aniProto._updatePromises === 'function' && !aniProto.nofYH
  1510. )
  1511.  
  1512. ) {
  1513.  
  1514. timProto.nofCQ = 1;
  1515. aniProto.nofYH = 1;
  1516.  
  1517. const originalAnimationsWithPromises = ((_updateAnimationsPromises) => {
  1518.  
  1519.  
  1520. /*
  1521. v.animationsWithPromises = v.animationsWithPromises.filter(function (c) {
  1522. return c._updatePromises();
  1523. });
  1524. */
  1525.  
  1526. const p = Array.prototype.filter;
  1527.  
  1528. let res = null;
  1529. Array.prototype.filter = function () {
  1530.  
  1531. res = this;
  1532. return this;
  1533.  
  1534. };
  1535.  
  1536. _updateAnimationsPromises.call({});
  1537.  
  1538. Array.prototype.filter = p;
  1539.  
  1540. if (res && typeof res.length === 'number') {
  1541. /** @type {any[]} */
  1542. const _res = res;
  1543. return _res;
  1544. }
  1545.  
  1546.  
  1547. return null;
  1548.  
  1549.  
  1550.  
  1551.  
  1552. })(timProto._updateAnimationsPromises);
  1553.  
  1554. if (!originalAnimationsWithPromises || typeof originalAnimationsWithPromises.length !== 'number') return;
  1555.  
  1556. // console.log('originalAnimationsWithPromises', originalAnimationsWithPromises)
  1557.  
  1558. aniProto._updatePromises31 = aniProto._updatePromises;
  1559.  
  1560. /*
  1561. aniProto._updatePromises = function(){
  1562. console.log('eff',this._oldPlayState, this.playState)
  1563. return this._updatePromises31.apply(this, arguments)
  1564. }
  1565. */
  1566.  
  1567. aniProto._updatePromises = function () {
  1568. var oldPlayState = this._oldPlayState;
  1569. var newPlayState = this.playState;
  1570. // console.log('ett', oldPlayState, newPlayState)
  1571. if (newPlayState !== oldPlayState) {
  1572. this._oldPlayState = newPlayState;
  1573. if (this._readyPromise) {
  1574. if ("idle" == newPlayState) {
  1575. this._rejectReadyPromise();
  1576. this._readyPromise = void 0;
  1577. } else if ("pending" == oldPlayState) {
  1578. this._resolveReadyPromise();
  1579. } else if ("pending" == newPlayState) {
  1580. this._readyPromise = void 0;
  1581. }
  1582. }
  1583. if (this._finishedPromise) {
  1584. if ("idle" == newPlayState) {
  1585. this._rejectFinishedPromise();
  1586. this._finishedPromise = void 0;
  1587. } else if ("finished" == newPlayState) {
  1588. this._resolveFinishedPromise();
  1589. } else if ("finished" == oldPlayState) {
  1590. this._finishedPromise = void 0;
  1591. }
  1592. }
  1593. }
  1594. return this._readyPromise || this._finishedPromise;
  1595. };
  1596.  
  1597.  
  1598. let restartWebAnimationsNextTickFlag = false;
  1599.  
  1600. const looperMethodT = () => {
  1601.  
  1602. const runnerFn = (hRes) => {
  1603. var b = timeline;
  1604. b.currentTime = hRes;
  1605. b._discardAnimations();
  1606. if (0 == b._animations.length) {
  1607. restartWebAnimationsNextTickFlag = false;
  1608. } else {
  1609. getRafPromiseForTickers().then(runnerFn);
  1610. }
  1611. }
  1612.  
  1613. const restartWebAnimationsNextTick = () => {
  1614. if (!restartWebAnimationsNextTickFlag) {
  1615. restartWebAnimationsNextTickFlag = true;
  1616. getRafPromiseForTickers().then(runnerFn);
  1617. }
  1618. }
  1619.  
  1620. return { restartWebAnimationsNextTick }
  1621. };
  1622.  
  1623.  
  1624. const looperMethodN = () => {
  1625.  
  1626. const acs = document.createElement('a-f');
  1627. acs.id = 'a-f';
  1628.  
  1629. const style = document.createElement('style');
  1630. style.textContent = `
  1631. @keyFrames aF1 {
  1632. 0% {
  1633. order: 0;
  1634. }
  1635. 100% {
  1636. order: 6;
  1637. }
  1638. }
  1639. #a-f[id] {
  1640. visibility: collapse !important;
  1641. position: fixed !important;
  1642. top: -100px !important;
  1643. left: -100px !important;
  1644. margin:0 !important;
  1645. padding:0 !important;
  1646. outline:0 !important;
  1647. border:0 !important;
  1648. z-index:-1 !important;
  1649. width: 0px !important;
  1650. height: 0px !important;
  1651. contain: strict !important;
  1652. pointer-events: none !important;
  1653. animation: 1ms steps(2) 0ms infinite alternate forwards running aF1 !important;
  1654. }
  1655. `;
  1656. (document.head || document.documentElement).appendChild(style);
  1657.  
  1658. document.documentElement.insertBefore(acs, document.documentElement.firstChild);
  1659.  
  1660. const _onanimationiteration = function (evt) {
  1661. const hRes = evt.timeStamp;
  1662. var b = timeline;
  1663. b.currentTime = hRes;
  1664. b._discardAnimations();
  1665. if (0 == b._animations.length) {
  1666. restartWebAnimationsNextTickFlag = false;
  1667. acs.onanimationiteration = null;
  1668. } else {
  1669. acs.onanimationiteration = _onanimationiteration;
  1670. }
  1671.  
  1672. }
  1673.  
  1674.  
  1675.  
  1676. const restartWebAnimationsNextTick = () => {
  1677. if (!restartWebAnimationsNextTickFlag) {
  1678. restartWebAnimationsNextTickFlag = true;
  1679. acs.onanimationiteration = _onanimationiteration;
  1680.  
  1681. }
  1682. }
  1683.  
  1684. return { restartWebAnimationsNextTick }
  1685. };
  1686.  
  1687.  
  1688.  
  1689. const { restartWebAnimationsNextTick } = ('onanimationiteration' in document.documentElement) ? looperMethodN() : looperMethodT();
  1690.  
  1691. timProto._play = function (c) {
  1692. c = new Animation(c, this);
  1693. this._animations.push(c);
  1694. restartWebAnimationsNextTick();
  1695. c._updatePromises();
  1696. c._animation.play();
  1697. c._updatePromises();
  1698. return c
  1699. }
  1700.  
  1701. const animationsWithPromisesMap = new Set(originalAnimationsWithPromises);
  1702. originalAnimationsWithPromises.length = 0;
  1703. originalAnimationsWithPromises.push = null;
  1704. originalAnimationsWithPromises.splice = null;
  1705. originalAnimationsWithPromises.slice = null;
  1706. originalAnimationsWithPromises.indexOf = null;
  1707. originalAnimationsWithPromises.unshift = null;
  1708. originalAnimationsWithPromises.shift = null;
  1709. originalAnimationsWithPromises.pop = null;
  1710. originalAnimationsWithPromises.filter = null;
  1711. originalAnimationsWithPromises.forEach = null;
  1712. originalAnimationsWithPromises.map = null;
  1713.  
  1714.  
  1715.  
  1716. const _updateAnimationsPromises = () => {
  1717. animationsWithPromisesMap.forEach(c => {
  1718. if (!c._updatePromises()) animationsWithPromisesMap.delete(c);
  1719. })
  1720. /*
  1721. v.animationsWithPromises = v.animationsWithPromises.filter(function (c) {
  1722. return c._updatePromises();
  1723. });
  1724. */
  1725. }
  1726.  
  1727. timProto._updateAnimationsPromises31 = timProto._updateAnimationsPromises;
  1728.  
  1729. timProto._updateAnimationsPromises = _updateAnimationsPromises;
  1730.  
  1731.  
  1732. let pdFinished = Object.getOwnPropertyDescriptor(aniProto, 'finished');
  1733. aniProto.__finished_native_get__ = pdFinished.get;
  1734. if (typeof pdFinished.get === 'function' && !pdFinished.set && pdFinished.configurable === true && pdFinished.enumerable === true) {
  1735.  
  1736.  
  1737. Object.defineProperty(aniProto, 'finished', {
  1738. get() {
  1739. this._finishedPromise || (!animationsWithPromisesMap.has(this) && animationsWithPromisesMap.add(this),
  1740. this._finishedPromise = new Promise((resolve, reject) => {
  1741. this._resolveFinishedPromise = function () {
  1742. resolve(this)
  1743. };
  1744. this._rejectFinishedPromise = function () {
  1745. reject({
  1746. type: DOMException.ABORT_ERR,
  1747. name: "AbortError"
  1748. })
  1749. };
  1750. }),
  1751. "finished" == this.playState && this._resolveFinishedPromise());
  1752. return this._finishedPromise
  1753. },
  1754. set: undefined,
  1755. enumerable: true,
  1756. configurable: true
  1757. });
  1758.  
  1759. }
  1760.  
  1761.  
  1762.  
  1763. let pdReady = Object.getOwnPropertyDescriptor(aniProto, 'ready');
  1764. aniProto.__ready_native_get__ = pdReady.get;
  1765. if (typeof pdReady.get === 'function' && !pdReady.set && pdReady.configurable === true && pdReady.enumerable === true) {
  1766.  
  1767. Object.defineProperty(aniProto, 'ready', {
  1768. get() {
  1769. this._readyPromise || (!animationsWithPromisesMap.has(this) && animationsWithPromisesMap.add(this),
  1770. this._readyPromise = new Promise((resolve, reject) => {
  1771. this._resolveReadyPromise = function () {
  1772. resolve(this)
  1773. };
  1774. this._rejectReadyPromise = function () {
  1775. reject({
  1776. type: DOMException.ABORT_ERR,
  1777. name: "AbortError"
  1778. })
  1779. };
  1780. }),
  1781. "pending" !== this.playState && this._resolveReadyPromise());
  1782. return this._readyPromise
  1783. },
  1784. set: undefined,
  1785. enumerable: true,
  1786. configurable: true
  1787. });
  1788.  
  1789. }
  1790.  
  1791.  
  1792.  
  1793.  
  1794. /*
  1795.  
  1796.  
  1797. function f(c) {
  1798. var b = v.timeline;
  1799. b.currentTime = c;
  1800. b._discardAnimations();
  1801. 0 == b._animations.length ? d = !1 : requestAnimationFrame(f)
  1802. }
  1803. var h = window.requestAnimationFrame;
  1804. window.requestAnimationFrame = function(c) {
  1805. return h(function(b) {
  1806. v.timeline._updateAnimationsPromises();
  1807. c(b);
  1808. v.timeline._updateAnimationsPromises()
  1809. })
  1810. }
  1811. ;
  1812. v.AnimationTimeline = function() {
  1813. this._animations = [];
  1814. this.currentTime = void 0
  1815. }
  1816. ;
  1817. v.AnimationTimeline.prototype = {
  1818. getAnimations: function() {
  1819. this._discardAnimations();
  1820. return this._animations.slice()
  1821. },
  1822. _updateAnimationsPromises: function() {
  1823. v.animationsWithPromises = v.animationsWithPromises.filter(function(c) {
  1824. return c._updatePromises()
  1825. })
  1826. },
  1827. _discardAnimations: function() {
  1828. this._updateAnimationsPromises();
  1829. this._animations = this._animations.filter(function(c) {
  1830. return "finished" != c.playState && "idle" != c.playState
  1831. })
  1832. },
  1833. _play: function(c) {
  1834. c = new v.Animation(c,this);
  1835. this._animations.push(c);
  1836. v.restartWebAnimationsNextTick();
  1837. c._updatePromises();
  1838. c._animation.play();
  1839. c._updatePromises();
  1840. return c
  1841. },
  1842. play: function(c) {
  1843. c && c.remove();
  1844. return this._play(c)
  1845. }
  1846. };
  1847. var d = !1;
  1848. v.restartWebAnimationsNextTick = function() {
  1849. d || (d = !0,
  1850. requestAnimationFrame(f))
  1851. }
  1852. ;
  1853. var a = new v.AnimationTimeline;
  1854. v.timeline = a;
  1855. try {
  1856. Object.defineProperty(window.document, "timeline", {
  1857. configurable: !0,
  1858. get: function() {
  1859. return a
  1860. }
  1861. })
  1862. } catch (c) {}
  1863. try {
  1864. window.document.timeline = a
  1865. } catch (c) {}
  1866.  
  1867. */
  1868.  
  1869.  
  1870.  
  1871. /*
  1872.  
  1873. var g = window.getComputedStyle;
  1874. Object.defineProperty(window, "getComputedStyle", {
  1875. configurable: !0,
  1876. enumerable: !0,
  1877. value: function() {
  1878. v.timeline._updateAnimationsPromises();
  1879. var e = g.apply(this, arguments);
  1880. h() && (e = g.apply(this, arguments));
  1881. v.timeline._updateAnimationsPromises();
  1882. return e
  1883. }
  1884. });
  1885.  
  1886. */
  1887.  
  1888.  
  1889.  
  1890.  
  1891. }
  1892.  
  1893.  
  1894.  
  1895.  
  1896. })();
  1897.  
  1898.  
  1899.  
  1900. });
  1901.  
  1902.  
  1903. setupEvents();
  1904.  
  1905.  
  1906.  
  1907. if (isMainWindow) {
  1908.  
  1909. console.groupCollapsed(
  1910. "%cYouTube JS Engine Tamer",
  1911. "background-color: #EDE43B ; color: #000 ; font-weight: bold ; padding: 4px ;"
  1912. );
  1913.  
  1914. console.log("Script is loaded.");
  1915. console.log("This script changes the core mechanisms of the YouTube JS engine.");
  1916.  
  1917. console.log("This script is experimental and subject to further changes.");
  1918.  
  1919. console.log("This might boost your YouTube performance.");
  1920.  
  1921. console.log("CAUTION: This might break your YouTube.");
  1922.  
  1923. console.groupEnd();
  1924.  
  1925. }
  1926.  
  1927.  
  1928. })();