YouTube JS Engine Tamer

To enhance YouTube performance by modifying YouTube JS Engine

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

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