YouTube: Audio Only

No Video Streaming

当前为 2025-01-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube: Audio Only
  3. // @description No Video Streaming
  4. // @namespace UserScript
  5. // @version 2.1.8
  6. // @author CY Fung
  7. // @match https://www.youtube.com/*
  8. // @match https://www.youtube.com/embed/*
  9. // @match https://www.youtube-nocookie.com/embed/*
  10. // @match https://m.youtube.com/*
  11. // @exclude /^https?://\S+\.(txt|png|jpg|jpeg|gif|xml|svg|manifest|log|ini)[^\/]*$/
  12. // @icon https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/YouTube-Audio-Only.png
  13. // @grant GM_registerMenuCommand
  14. // @grant GM.setValue
  15. // @grant GM.getValue
  16. // @grant GM.listValues
  17. // @grant GM.deleteValue
  18. // @run-at document-start
  19. // @require https://cdn.jsdelivr.net/gh/cyfung1031/userscript-supports@5d83d154956057bdde19e24f95b332cb9a78fcda/library/default-trusted-type-policy.js
  20. // @license MIT
  21. // @compatible chrome
  22. // @compatible firefox
  23. // @compatible opera
  24. // @compatible edge
  25. // @compatible safari
  26. // @allFrames true
  27. //
  28. // ==/UserScript==
  29.  
  30. (async function () {
  31. 'use strict';
  32.  
  33.  
  34. const defaultPolicy = (typeof trustedTypes !== 'undefined' && trustedTypes.defaultPolicy) || { createHTML: s => s };
  35. function createHTML(s) {
  36. return defaultPolicy.createHTML(s);
  37. }
  38.  
  39. let trustHTMLErr = null;
  40. try {
  41. document.createElement('div').innerHTML = createHTML('1');
  42. } catch (e) {
  43. trustHTMLErr = e;
  44. }
  45.  
  46. if (trustHTMLErr) {
  47. console.log(`trustHTMLErr`, trustHTMLErr);
  48. trustHTMLErr(); // exit userscript
  49. }
  50.  
  51. /** @type {globalThis.PromiseConstructor} */
  52. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  53.  
  54. if (typeof AbortSignal === 'undefined') throw new DOMException("Please update your browser.", "NotSupportedError");
  55.  
  56. async function confirm(message) {
  57. // Create the HTML for the dialog
  58.  
  59. if (!document.body) return;
  60.  
  61. let dialog = document.getElementById('confirmDialog794');
  62. if (!dialog) {
  63.  
  64. const dialogHTML = `
  65. <div id="confirmDialog794" class="dialog-style" style="display: block;">
  66. <div class="confirm-box">
  67. <p>${message}</p>
  68. <div class="confirm-buttons">
  69. <button id="confirmBtn">Confirm</button>
  70. <button id="cancelBtn">Cancel</button>
  71. </div>
  72. </div>
  73. </div>
  74. `;
  75.  
  76. // Append the dialog to the document body
  77. document.body.insertAdjacentHTML('beforeend', createHTML(dialogHTML));
  78. dialog = document.getElementById('confirmDialog794');
  79.  
  80. }
  81.  
  82. // Return a promise that resolves or rejects based on the user's choice
  83. return new Promise((resolve) => {
  84. document.getElementById('confirmBtn').onclick = () => {
  85. resolve(true);
  86. cleanup();
  87. };
  88.  
  89. document.getElementById('cancelBtn').onclick = () => {
  90. resolve(false);
  91. cleanup();
  92. };
  93.  
  94. function cleanup() {
  95. dialog && dialog.remove();
  96. dialog = null;
  97. }
  98. });
  99. }
  100.  
  101.  
  102.  
  103. if (location.pathname === '/live_chat' || location.pathname === 'live_chat_replay') return;
  104.  
  105. const kEventListener = (evt) => {
  106. if (document.documentElement.hasAttribute('forceRefresh032')) {
  107. evt.stopImmediatePropagation();
  108. evt.stopPropagation();
  109. }
  110. }
  111. window.addEventListener('beforeunload', kEventListener, false);
  112.  
  113. const pageInjectionCode = function () {
  114.  
  115. let debugFlg001 = false;
  116. // let debugFlg002 = false;
  117. // let globalPlayer = null;
  118. const SHOW_VIDEO_STATIC_IMAGE = true;
  119. const PATCH_MEDIA_PUBLISH = true;
  120. const PATCH_MEDIA_PLAYPAUSE = true;
  121.  
  122. if (typeof AbortSignal === 'undefined') throw new DOMException("Please update your browser.", "NotSupportedError");
  123.  
  124. const URL = window.URL || new Function('return URL')();
  125. const createObjectURL = URL.createObjectURL.bind(URL);
  126.  
  127. /** @type {globalThis.PromiseConstructor} */
  128. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  129.  
  130. const PromiseExternal = ((resolve_, reject_) => {
  131. const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
  132. return class PromiseExternal extends Promise {
  133. constructor(cb = h) {
  134. super(cb);
  135. if (cb === h) {
  136. /** @type {(value: any) => void} */
  137. this.resolve = resolve_;
  138. /** @type {(reason?: any) => void} */
  139. this.reject = reject_;
  140. }
  141. }
  142. };
  143. })();
  144.  
  145. const [setTimeout_, clearTimeout_] = [setTimeout, clearTimeout];
  146.  
  147. /* globals WeakRef:false */
  148.  
  149. /** @type {(o: Object | null) => WeakRef | null} */
  150. const mWeakRef = typeof WeakRef === 'function' ? (o => o ? new WeakRef(o) : null) : (o => o || null);
  151.  
  152. /** @type {(wr: Object | null) => Object | null} */
  153. const kRef = (wr => (wr && wr.deref) ? wr.deref() : wr);
  154.  
  155. const isIterable = (x) => Symbol.iterator in Object(x);
  156.  
  157.  
  158. let byPassSync = false;
  159. let byPassNonFatalError = false;
  160. let skipPlayPause = 0;
  161. let byPassPublishPatch = false;
  162.  
  163. const dmo = {};
  164. const qzk = Symbol();
  165.  
  166.  
  167. const observablePromise = (proc, timeoutPromise) => {
  168. let promise = null;
  169. return {
  170. obtain() {
  171. if (!promise) {
  172. promise = new Promise(resolve => {
  173. let mo = null;
  174. const f = () => {
  175. let t = proc();
  176. if (t) {
  177. mo.disconnect();
  178. mo.takeRecords();
  179. mo = null;
  180. resolve(t);
  181. }
  182. }
  183. mo = new MutationObserver(f);
  184. mo.observe(document, { subtree: true, childList: true })
  185. f();
  186. timeoutPromise && timeoutPromise.then(() => {
  187. resolve(null)
  188. });
  189. });
  190. }
  191. return promise
  192. }
  193. }
  194. }
  195.  
  196.  
  197. const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);
  198.  
  199. const prototypeInherit = (d, b) => {
  200. const m = Object.getOwnPropertyDescriptors(b);
  201. for (const p in m) {
  202. if (!Object.getOwnPropertyDescriptor(d, p)) {
  203. Object.defineProperty(d, p, m[p]);
  204. }
  205. }
  206. };
  207.  
  208. const delayPn = delay => new Promise((fn => setTimeout_(fn, delay)));
  209.  
  210. const mockEvent = (o, elem) => {
  211. o = o || {};
  212. elem = elem || null;
  213. return {
  214. preventDefault: () => { },
  215. stopPropagation: () => { },
  216. stopImmediatePropagation: () => { },
  217. returnValue: true,
  218. target: elem,
  219. srcElement: elem,
  220. defaultPrevented: false,
  221. cancelable: true,
  222. timeStamp: performance.now(),
  223. ...o
  224. }
  225. };
  226.  
  227.  
  228. const generalRegister = (prop, symbol, checker, pg) => {
  229. const objSet = new Set();
  230. let done = false;
  231. const f = (o) => {
  232. const ct = o.constructor;
  233. const proto = ct.prototype;
  234. if (!done && proto && ct !== Function && ct !== Object && checker(proto)) {
  235. done = true;
  236. delete Object.prototype[prop];
  237. objSet.delete(proto);
  238. objSet.delete(o);
  239. for (const obj of objSet) {
  240. obj[prop] = obj[symbol];
  241. delete obj[symbol];
  242. }
  243. objSet.clear();
  244. Object.defineProperty(proto, prop, pg);
  245. return proto;
  246. }
  247. return false;
  248. };
  249. Object.defineProperty(Object.prototype, prop, {
  250. get() {
  251. const p = f(this);
  252. if (p) {
  253. return p[prop];
  254. } else {
  255. return this[symbol];
  256. }
  257. },
  258. set(nv) {
  259. const p = f(this);
  260. if (p) {
  261. p[prop] = nv;
  262. } else {
  263. objSet.add(this);
  264. this[symbol] = nv;
  265. }
  266. return true;
  267. },
  268. enumerable: false,
  269. configurable: true
  270. });
  271.  
  272. };
  273.  
  274.  
  275. const attachOneTimeEvent = function (eventType, callback) {
  276. let kz = false;
  277. document.addEventListener(eventType, function (evt) {
  278. if (kz) return;
  279. kz = true;
  280. callback(evt);
  281. }, { capture: true, passive: true, once: true });
  282. }
  283.  
  284. const evaluateInternalAppScore = (internalApp) => {
  285.  
  286.  
  287. let r = 0;
  288. if (!internalApp || typeof internalApp !== 'object') {
  289. return -999;
  290. }
  291.  
  292. if (internalApp.app) r -= 100;
  293.  
  294. if (!('mediaElement' in internalApp)) r -= 500;
  295.  
  296. if (!('videoData' in internalApp)) r -= 50;
  297.  
  298. if (!('playerState' in internalApp)) r -= 50;
  299.  
  300. if ('getVisibilityState' in internalApp) r += 20;
  301. if ('visibility' in internalApp) r += 40;
  302. if ('isBackground' in internalApp) r += 40;
  303. if ('publish' in internalApp) r += 10;
  304.  
  305.  
  306. if (('playerType' in internalApp)) r += 10;
  307. if (('playbackRate' in internalApp)) r += 10;
  308. if (('playerState' in internalApp)) r += 10;
  309. if (typeof (internalApp.playerState || 0) === 'object') r += 50;
  310.  
  311.  
  312. return r;
  313.  
  314.  
  315.  
  316. }
  317.  
  318.  
  319. const { remapString } = (() => {
  320.  
  321. function shuffleArray(array) {
  322. for (let i = array.length - 1; i > 0; i--) {
  323. const j = Math.floor(Math.random() * (i + 1));
  324. [array[i], array[j]] = [array[j], array[i]];
  325. }
  326. return array;
  327. }
  328.  
  329. /**
  330. * Create a deterministic "random" mapping from 'a'..'z' -> shuffled letters.
  331. * Returns a Map for O(1) lookups.
  332. */
  333. function createRandomAlphabetMap() {
  334. const baseAlphabet = "abcdefghijklmnopqrstuvwxyz";
  335. const letters = baseAlphabet.split("");
  336.  
  337.  
  338. // Shuffle letters with that seeded generator
  339. const shuffledLetters = shuffleArray(letters);
  340.  
  341. // Build the Map
  342. const map = new Map();
  343. for (let i = 0, l = baseAlphabet.length; i < l; i++) {
  344. map.set(baseAlphabet[i], shuffledLetters[i]);
  345. map.set(baseAlphabet[i].toUpperCase(), shuffledLetters[i].toUpperCase());
  346. }
  347. return map;
  348. }
  349.  
  350. // Create the random map once at initialization
  351. let randomAlphabetMap = null;
  352.  
  353. /**
  354. * Remaps alphabetic letters in a string according to randomAlphabetMap.
  355. * Preserves the case of letters and leaves non-alphabet characters unchanged.
  356. */
  357. function remapString(input) {
  358. if (!randomAlphabetMap) return input;
  359. let result = new Array(input.length);
  360. let i = 0;
  361. for (const char of input) {
  362. result[i++] = randomAlphabetMap.get(char) || char;
  363. }
  364. return result.join('');
  365. }
  366.  
  367. const listA = [
  368. "error",
  369. "internalvideodatachange",
  370. "statechange",
  371. "SEEK_TO",
  372. "videoelementevent",
  373. "onLoadedMetadata",
  374. "progresssync",
  375. "onVideoProgress",
  376. "SEEK_COMPLETE",
  377. "playbackstarted",
  378. "onLoadProgress",
  379. "nonfatalerror",
  380. "internalAbandon",
  381. "internalvideoformatchange",
  382. "internalaudioformatchange",
  383. "playbackready",
  384. "mediasourceattached",
  385. "beginseeking",
  386. "endseeking"
  387. ];
  388.  
  389. const mdA = listA.join('|');
  390.  
  391. loop1:
  392. for (let tryCount = 8; tryCount > 0; tryCount--) {
  393. randomAlphabetMap = createRandomAlphabetMap();
  394. const listB = listA.map(remapString);
  395. const mdB = listB.join('|');
  396. for (const a of listA) {
  397. if (mdB.includes(a)) {
  398. randomAlphabetMap = null;
  399. continue loop1;
  400. }
  401. }
  402. for (const b of listB) {
  403. if (mdA.includes(b)) {
  404. randomAlphabetMap = null;
  405. continue loop1;
  406. }
  407. }
  408. break;
  409. }
  410. if (!randomAlphabetMap) {
  411. console.error('randomAlphabetMap is not available.')
  412. }
  413.  
  414. return { remapString };
  415. })();
  416.  
  417.  
  418. function removeTempObjectProp01() {
  419. delete Object.prototype['kevlar_non_watch_unified_player'];
  420. delete Object.prototype['kevlar_unified_player'];
  421. }
  422.  
  423. function ytConfigFix(config__) {
  424. const config_ = config__;
  425.  
  426. if (config_) {
  427.  
  428. const playerKevlar = ((config_ || 0).WEB_PLAYER_CONTEXT_CONFIGS || 0).WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_WATCH || 0;
  429.  
  430. if (playerKevlar) {
  431.  
  432. // console.log(322, playerKevlar)
  433. playerKevlar.allowWoffleManagement = false;
  434. playerKevlar.cinematicSettingsAvailable = false;
  435. playerKevlar.showMiniplayerButton = false;
  436. playerKevlar.showMiniplayerUiWhenMinimized = false;
  437. playerKevlar.transparentBackground = false;
  438.  
  439. playerKevlar.enableCsiLogging = false;
  440. playerKevlar.externalFullscreen = false;
  441.  
  442. if (typeof playerKevlar.serializedExperimentFlags === 'string') {
  443. playerKevlar.serializedExperimentFlags = '';
  444. // playerKevlar.serializedExperimentFlags = playerKevlar.serializedExperimentFlags.replace(/[-\w]+=(\[\]|[.-\d]+|[_a-z]+|)(&|$)/g,'').replace(/&$/,'')
  445. }
  446.  
  447. if (typeof playerKevlar.serializedExperimentIds === 'string') {
  448. playerKevlar.serializedExperimentIds = '';
  449. // playerKevlar.serializedExperimentIds = playerKevlar.serializedExperimentIds.replace(/\d+\s*(,\s*|$)/g,'')
  450. }
  451.  
  452. }
  453.  
  454. removeTempObjectProp01();
  455.  
  456. let configs = config_.WEB_PLAYER_CONTEXT_CONFIGS || {};
  457. for (const [key, entry] of Object.entries(configs)) {
  458.  
  459. if (entry && typeof entry.serializedExperimentFlags === 'string' && entry.serializedExperimentFlags.length > 16) {
  460. // prevent idle playback failure
  461. entry.serializedExperimentFlags = entry.serializedExperimentFlags.replace(/\b(html5_check_for_idle_network_interval_ms|html5_trigger_loader_when_idle_network|html5_sabr_fetch_on_idle_network_preloaded_players|html5_autonav_cap_idle_secs|html5_autonav_quality_cap|html5_disable_client_autonav_cap_for_onesie|html5_idle_rate_limit_ms|html5_sabr_fetch_on_idle_network_preloaded_players|html5_webpo_idle_priority_job|html5_server_playback_start_policy|html5_check_video_data_errors_before_playback_start|html5_check_unstarted|html5_check_queue_on_data_loaded)=([-_\w]+)(\&|$)/g, (_, a, b, c) => {
  462. return a + '00' + '=' + b + c;
  463. });
  464.  
  465. }
  466.  
  467. }
  468.  
  469. const EXPERIMENT_FLAGS = config_.EXPERIMENT_FLAGS;
  470.  
  471. if (EXPERIMENT_FLAGS) {
  472. EXPERIMENT_FLAGS.kevlar_unified_player = true;
  473. EXPERIMENT_FLAGS.kevlar_non_watch_unified_player = true;
  474. }
  475.  
  476.  
  477. const EXPERIMENTS_FORCED_FLAGS = config_.EXPERIMENTS_FORCED_FLAGS;
  478.  
  479. if (EXPERIMENTS_FORCED_FLAGS) {
  480. EXPERIMENTS_FORCED_FLAGS.kevlar_unified_player = true;
  481. EXPERIMENTS_FORCED_FLAGS.kevlar_non_watch_unified_player = true;
  482. }
  483.  
  484. }
  485. }
  486.  
  487. Object.defineProperty(Object.prototype, 'kevlar_non_watch_unified_player', {
  488. get() {
  489. // console.log(501, this.constructor.prototype)
  490. return true;
  491. },
  492. set(nv) {
  493. return true;
  494. },
  495. enumerable: false,
  496. configurable: true
  497. });
  498.  
  499.  
  500. Object.defineProperty(Object.prototype, 'kevlar_unified_player', {
  501. get() {
  502. // console.log(501, this.constructor.prototype)
  503. return true;
  504. },
  505. set(nv) {
  506. return true;
  507. },
  508. enumerable: false,
  509. configurable: true
  510. });
  511.  
  512. // let prr = new PromiseExternal();
  513. // const prrPipeline = createPipeline();
  514. // let stopAndReload = false;
  515.  
  516. let fa = 0;
  517.  
  518. let cv = null;
  519. let durationchangeForMobile = false;
  520. function fixThumbnailURL(src) {
  521. if (typeof src === 'string' && src.length >= 4) {
  522. let m = /\b[a-z0-9]{4,13}\.jpg\b/.exec(src);
  523. if (m && m[0]) {
  524. const t = m[0];
  525. let idx = src.indexOf(t);
  526. let nSrc = idx >= 0 ? src.substring(0, idx + t.length) : '';
  527. return nSrc;
  528. }
  529. }
  530. return src;
  531. }
  532.  
  533. const isDesktopSite = location.origin === 'https://www.youtube.com' && !location.pathname.startsWith('/embed/');
  534.  
  535. const getThumbnailUrlFromThumbnails = (thumbnails) => {
  536.  
  537. let thumbnailUrl = '';
  538. if (thumbnails && thumbnails.length >= 1) {
  539. const arr = thumbnails.map(e => {
  540. return e.url ? [e.width * e.height, e.url] : typeof e === 'string' ? [0, e] : [0, '']
  541. });
  542. arr.sort((a, b) => b[0] - a[0]);
  543. thumbnailUrl = arr[0][1]
  544. if (typeof thumbnailUrl === 'string') {
  545. thumbnailUrl = fixThumbnailURL(thumbnailUrl);
  546. }
  547. }
  548. return thumbnailUrl;
  549. }
  550.  
  551. const pmof = () => {
  552.  
  553. if (SHOW_VIDEO_STATIC_IMAGE) {
  554.  
  555. const medias = [...document.querySelectorAll('ytd-watch-flexy #player .html5-video-container .video-stream.html5-main-video')].filter(e => !e.closest('[hidden]'));
  556. if (medias.length !== 1) return;
  557. const mediaElm = medias[0];
  558.  
  559. const container = mediaElm ? mediaElm.closest('.html5-video-container') : null;
  560. if (!container) return;
  561.  
  562. let thumbnailUrl = '';
  563. const ytdPage = container.closest('ytd-watch-flexy');
  564. if (ytdPage && ytdPage.is === 'ytd-watch-flexy') {
  565. const cnt = insp(ytdPage);
  566. let thumbnails = null;
  567. try {
  568. thumbnails = cnt.polymerController.__data.playerData.videoDetails.thumbnail.thumbnails
  569. // thumbnails = cnt.__data.watchNextData.playerOverlays.playerOverlayRenderer.autoplay.playerOverlayAutoplayRenderer.background.thumbnails
  570. } catch (e) { }
  571.  
  572. thumbnailUrl = getThumbnailUrlFromThumbnails(thumbnails);
  573. }
  574.  
  575.  
  576. if (thumbnailUrl && typeof thumbnailUrl === 'string') {
  577. container.style.setProperty('--audio-only-thumbnail-image', `url(${thumbnailUrl})`);
  578. } else {
  579. container.style.removeProperty('--audio-only-thumbnail-image')
  580. }
  581.  
  582. }
  583.  
  584.  
  585. }
  586. const pmo = new MutationObserver(pmof);
  587.  
  588. isDesktopSite && document.addEventListener('yt-navigate-finish', () => {
  589. const ytdWatchFlexy = document.querySelector('ytd-watch-flexy');
  590. if (ytdWatchFlexy) {
  591. pmo.observe(ytdWatchFlexy, { attributes: true });
  592. ytdWatchFlexy.setAttribute('ytzNavigateFinish', Date.now());
  593. }
  594. });
  595. document.addEventListener('durationchange', (evt) => {
  596. const target = (evt || 0).target;
  597. if (!(target instanceof HTMLMediaElement)) return;
  598. const targetClassList = target.classList || 0;
  599. const isPlayerVideo = typeof targetClassList.contains === 'function' ? targetClassList.contains('video-stream') && targetClassList.contains('html5-main-video') : false;
  600.  
  601. if (durationchangeForMobile || isPlayerVideo) {
  602. if (target.readyState !== 1) {
  603. fa = 1;
  604. } else {
  605. fa = 2;
  606. }
  607. }
  608.  
  609. if (isPlayerVideo) {
  610.  
  611. if (target.readyState === 1 && target.networkState === 2) {
  612. target.__spfgs__ = true;
  613. if (cv) {
  614. cv.resolve();
  615. cv = null;
  616. }
  617. } else {
  618. target.__spfgs__ = false;
  619. }
  620.  
  621. if (isDesktopSite) {
  622. const ytdWatchFlexy = document.querySelector('ytd-watch-flexy');
  623. if (ytdWatchFlexy) {
  624. ytdWatchFlexy.setAttribute('ytzMediaDurationChanged', Date.now());
  625. }
  626. }
  627.  
  628. if (onVideoChangeForMobile) {
  629. onVideoChangeForMobile();
  630. }
  631.  
  632. }
  633. }, true);
  634.  
  635.  
  636.  
  637. // XMLHttpRequest.prototype.open299 = XMLHttpRequest.prototype.open;
  638. /*
  639.  
  640. XMLHttpRequest.prototype.open2 = function(method, url, ...args){
  641.  
  642. if (typeof url === 'string' && url.length > 24 && url.includes('/videoplayback?') && url.replace('?', '&').includes('&source=')) {
  643. if (vcc !== vdd) {
  644. vdd = vcc;
  645. window.postMessage({ ZECxh: url.includes('source=yt_live_broadcast') }, "*");
  646. }
  647. }
  648.  
  649. return this.open299(method, url, ...args)
  650. }*/
  651.  
  652.  
  653.  
  654. // desktop only
  655. // document.addEventListener('yt-page-data-fetched', async (evt) => {
  656.  
  657. // const pageFetchedDataLocal = evt.detail;
  658. // let isLiveNow;
  659. // try {
  660. // isLiveNow = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.liveBroadcastDetails.isLiveNow;
  661. // } catch (e) { }
  662. // window.postMessage({ ZECxh: isLiveNow === true }, "*");
  663.  
  664. // }, false);
  665.  
  666. // return;
  667.  
  668. // let clickLockFn = null;
  669.  
  670.  
  671. let onVideoChangeForMobile = null;
  672.  
  673. let removeBottomOverlayForMobile = null;
  674.  
  675. let clickLockFn = null;
  676. let clickTarget = null;
  677. if (location.origin === 'https://m.youtube.com') {
  678.  
  679. EventTarget.prototype.addEventListener322 = EventTarget.prototype.addEventListener;
  680.  
  681. const dummyFn = () => { };
  682. EventTarget.prototype.addEventListener = function (evt, fn, opts) {
  683.  
  684. let hn = fn;
  685.  
  686. // if (evt === 'player-error') {
  687. // } else if (evt === 'player-detailed-error') {
  688. // } else if (evt === 'video-data-change') {
  689. // } else if (evt === 'player-state-change') {
  690. // } else
  691. if (evt === 'player-autonav-pause' || evt === 'visibilitychange') {
  692. evt += 'y'
  693. fn = dummyFn;
  694. } else if (evt === 'click' && this.id === 'movie_player') {
  695. clickLockFn = fn;
  696. clickTarget = this;
  697. }
  698. return this.addEventListener322(evt, hn, opts)
  699.  
  700. }
  701.  
  702. }
  703.  
  704.  
  705.  
  706. (() => {
  707.  
  708. XMLHttpRequest = (() => {
  709. const XMLHttpRequest_ = XMLHttpRequest;
  710. if ('__xmMc8__' in XMLHttpRequest_.prototype) return XMLHttpRequest_;
  711. const url0 = createObjectURL(new Blob([], { type: 'text/plain' }));
  712. const c = class XMLHttpRequest extends XMLHttpRequest_ {
  713. constructor(...args) {
  714. super(...args);
  715. }
  716. open(method, url, ...args) {
  717. let skip = false;
  718. if (!url || typeof url !== 'string') skip = true;
  719. else if (typeof url === 'string') {
  720. let turl = url[0] === '/' ? `.youtube.com${url}` : `${url}`;
  721. if (turl.includes('googleads') || turl.includes('doubleclick.net')) {
  722. skip = true;
  723. } else if (turl.includes('.youtube.com/pagead/')) {
  724. skip = true;
  725. } else if (turl.includes('.youtube.com/ptracking')) {
  726. skip = true;
  727. } else if (turl.includes('.youtube.com/api/stats/')) { // /api/stats/
  728. // skip = true; // for user activity logging e.g. watched videos
  729. } else if (turl.includes('play.google.com/log')) {
  730. skip = true;
  731. } else if (turl.includes('.youtube.com//?')) { // //?cpn=
  732. skip = true;
  733. }
  734. }
  735. if (!skip) {
  736. this.__xmMc8__ = 1;
  737. return super.open(method, url, ...args);
  738. } else {
  739. this.__xmMc8__ = 2;
  740. return super.open('GET', url0);
  741. }
  742. }
  743. send(...args) {
  744. if (this.__xmMc8__ === 1) {
  745. return super.send(...args);
  746. } else if (this.__xmMc8__ === 2) {
  747. return super.send();
  748. } else {
  749. console.log('xhr warning');
  750. return super.send(...args);
  751. }
  752. }
  753. }
  754. c.prototype.__xmMc8__ = 0;
  755. prototypeInherit(c.prototype, XMLHttpRequest_.prototype);
  756. return c;
  757. })();
  758.  
  759. const s7 = Symbol();
  760. const f7 = () => true;
  761.  
  762. !window.canRetry9048 && generalRegister('canRetry', s7, (p) => {
  763. return typeof p.onStateChange === 'function' && typeof p.dispose === 'function' && typeof p.hide === 'undefined' && typeof p.show === 'undefined' && typeof p.isComplete === 'undefined' && typeof p.getDuration === 'undefined'
  764. }, {
  765. get() {
  766. if ('logger' in this && 'policy' in this && 'xhr' && this) {
  767. if (this.errorMessage && typeof this.errorMessage === 'string' && this.errorMessage.includes('XMLHttpRequest') && this.errorMessage.includes('Invalid URL')) { // "SyntaxError_Failed to execute 'open' on 'XMLHttpRequest': Invalid URL"
  768. // OKAY !
  769. console.log('canRetry05 - ', this.errorMessage)
  770. return f7;
  771. }
  772. // console.log(this)
  773. console.log('canRetry02 - ', this.errorMessage, this)
  774. } else {
  775. console.log('canRetry ERR - ', this.errorMessage)
  776. }
  777. return this[s7];
  778. },
  779. set(nv) {
  780. this[s7] = nv;
  781. return true;
  782. },
  783. enumerable: false,
  784. configurable: true
  785. });
  786. window.canRetry9048 = 1;
  787.  
  788. })();
  789.  
  790.  
  791. const updateLastActiveTimeAsync_ = (player_) => {
  792. if (player_ && typeof player_.updateLastActiveTime === 'function') {
  793. player_.updateLastActiveTime();
  794. }
  795. };
  796.  
  797. const updateLastActiveTimeAsync = (evt) => {
  798. Promise.resolve(evt?.updateLastActiveTime ? evt : evt?.target).then(updateLastActiveTimeAsync_);
  799. };
  800.  
  801.  
  802.  
  803. const { setupAudioPlaying, internalAppPTFn, standardAppPTFn, playerDapPTFn } = (() => {
  804.  
  805. // playerApp: external API [ external use ]
  806. // playerDap: internal player ( with this.app and this.state ) [ the internal interface for both app and state ]
  807. // standardApp: .app of internal player [without isBackground, with fn getVideoDate(), etc]
  808. // internalApp: internal controller inside standardApp (normally non-accessible) [with isBackground, data field videoData, etc]
  809.  
  810. // window.gt1 -> playerApp
  811. // window.gt11 -> playerDap
  812. // window.gt2 -> standardApp
  813. // window.gt3 -> internalApp
  814.  
  815. let key_mediaElementT = '';
  816.  
  817. let key_yn = '';
  818. let key_nS = '';
  819.  
  820. let key_L1 = ''; // playerDap -> internalDap
  821.  
  822. let listAllPublish = false;
  823. let promiseSeek = null;
  824.  
  825. let internalAppXT = null;
  826. let standardAppXT = null;
  827. let playerAppXT = null;
  828. let playerDapXT = null;
  829.  
  830.  
  831.  
  832. /*
  833. const __wmObjectRefs__ = new WeakMap();
  834. class WeakRefSet extends Set {
  835. constructor() {
  836. super();
  837. }
  838. add(obj) {
  839. if (typeof (obj || 0) === 'object') {
  840. let ref = __wmObjectRefs__.get(obj);
  841. if (!ref) {
  842. __wmObjectRefs__.set(obj, (ref = mWeakRef(obj)));
  843. }
  844. super.add(ref);
  845. }
  846. return this;
  847. }
  848. delete(obj) {
  849. if (!obj) return null;
  850. const ref = __wmObjectRefs__.get(obj);
  851. if (ref) {
  852. if(kRef(ref)) return super.delete(ref);
  853. super.delete(ref);
  854. return false;
  855. }
  856. return false;
  857. }
  858. *[Symbol.iterator]() {
  859. for (const value of super.values()) {
  860. const obj = (kRef(value) || null);
  861. if (!obj) {
  862. super.delete(value);
  863. continue;
  864. }
  865. yield obj;
  866. }
  867. }
  868. has(obj) {
  869. if (!obj) return null;
  870. const ref = __wmObjectRefs__.get(obj);
  871. if (!ref) return false;
  872. if (kRef(ref)) return super.has(ref);
  873. super.delete(ref);
  874. return false;
  875. }
  876. }
  877. */
  878.  
  879. const internalAppUT = new Set();
  880. const standardAppUT = new Set();
  881. const playerAppUT = new Set();
  882. const playerDapUT = new Set();
  883. let dirtyMark = 1 | 2 | 4 | 8;
  884.  
  885.  
  886. let playerDapPTDone = false;
  887. // let playerAppPTDone = false;
  888. let standardAppPTDone = false;
  889. let internalAppPTDone = false;
  890.  
  891.  
  892. window.gtz = () => {
  893. return {
  894. internalAppUT, standardAppUT, playerAppUT, playerDapUT, dirtyMark
  895. }
  896. }
  897.  
  898. const getMediaElement = () => {
  899.  
  900. const internalApp = internalAppXM();
  901. const standardApp = standardAppXM();
  902.  
  903. let t;
  904.  
  905. if (t = internalApp?.mediaElement?.[key_mediaElementT]) return t;
  906.  
  907.  
  908. if (t = standardApp?.mediaElement?.[key_mediaElementT]) return t;
  909.  
  910. return null;
  911.  
  912.  
  913.  
  914. }
  915.  
  916. const internalApp_ZZ_sync = function () {
  917. if (byPassSync) {
  918. return;
  919. }
  920. return this.sync9383(...arguments)
  921. };
  922.  
  923. const updateInternalAppFn_ = () => {
  924.  
  925. const internalApp = internalAppXT;
  926. if (internalApp && !internalApp.__s4538__) {
  927. if (internalApp.mediaElement) internalApp.__s4538__ = true;
  928.  
  929. const arr = Object.entries(internalApp).filter(e => e[1] && typeof e[1].sync === 'function');
  930. for (const [key, o] of arr) {
  931. const p = o.__proto__ || o;
  932. if (!p.sync9383 && typeof p.sync === 'function') {
  933. p.sync9383 = p.sync;
  934. p.sync = internalApp_ZZ_sync;
  935. }
  936. }
  937.  
  938. if (!key_yn || !key_nS) {
  939.  
  940. for (const [key, value] of Object.entries(internalApp)) {
  941. if (!key_yn && typeof (value || 0) === 'object' && value.experiments && value.experiments.flags && !isIterable(value)) {
  942. key_yn = key;
  943. console.log(1959, 'key_yn', key_yn)
  944. } else if (!key_nS && typeof (value || 0) === 'object' && 'videoTrack' in value && 'audioTrack' in value && 'isSuspended' in value && !isIterable(value)) {
  945. key_nS = key;
  946. console.log(1959, 'key_nS', key_nS)
  947. }
  948. }
  949.  
  950. }
  951.  
  952. if (!key_mediaElementT) {
  953. const iaMedia = internalApp.mediaElement || 0;
  954. // console.log(1959, internalApp, iaMedia)
  955.  
  956. if (internalApp && typeof iaMedia === 'object') {
  957. for (const [key, value] of Object.entries(iaMedia)) {
  958. if (value instanceof HTMLMediaElement) {
  959. key_mediaElementT = key;
  960. console.log(1959, 'key_mediaElementT', key_mediaElementT)
  961. }
  962. }
  963. }
  964.  
  965. }
  966.  
  967. }
  968.  
  969.  
  970. if (!internalAppPTDone) {
  971. const proto = internalApp ? internalApp.__proto__ : null;
  972. if (proto) {
  973. internalAppPTDone = true;
  974. internalAppPTFn(proto);
  975. }
  976. }
  977.  
  978. }
  979.  
  980. const updateInternalAppFn = (x) => {
  981. if (x !== internalAppXT) {
  982. dirtyMark = 1 | 2 | 4 | 8;
  983. internalAppUT.add(x);
  984. internalAppXT = x;
  985. // videoData
  986. // stopVideo
  987. // pauseVideo
  988.  
  989. }
  990. updateInternalAppFn_();
  991. }
  992.  
  993. window.gt3 = () => internalAppXM();
  994. const internalAppXM = () => {
  995. if (!(dirtyMark & 4)) return internalAppXT;
  996. if (!key_mediaElementT) return internalAppXT;
  997. let result = null;
  998. for (const p of internalAppUT) {
  999. const iaMediaP = p.mediaElement;
  1000. if (!iaMediaP) {
  1001. internalAppUT.delete(p);
  1002. } else {
  1003. const element = iaMediaP[key_mediaElementT];
  1004. if (element instanceof Element) {
  1005. if (!element.isConnected) {
  1006. // valid entry but audio is not on the page
  1007.  
  1008. } else if (element.closest('[hidden]')) {
  1009.  
  1010. } else if (result === null) {
  1011. result = p;
  1012. }
  1013. }
  1014. }
  1015. }
  1016. if (!result) return result;
  1017. internalAppUT.add(result);
  1018. internalAppXT = result;
  1019. updateInternalAppFn_();
  1020. if (dirtyMark & 4) dirtyMark -= 4;
  1021. return result;
  1022. }
  1023.  
  1024. const updateStandardAppFn_ = () => {
  1025. const standardAppXT_ = standardAppXT;
  1026. if (!standardAppPTDone) {
  1027. const proto = standardAppXT_ ? standardAppXT_.__proto__ : null;
  1028. if (proto) {
  1029. standardAppPTDone = true;
  1030. standardAppPTFn(proto);
  1031. }
  1032. }
  1033. }
  1034.  
  1035. const updateStandardAppFn = (x) => {
  1036. if (x !== standardAppXT) {
  1037. dirtyMark = 1 | 2 | 4 | 8;
  1038. standardAppUT.add(x);
  1039. standardAppXT = x;
  1040. // isAtLiveHead
  1041. // cancelPlayback
  1042. // stopVideo
  1043. // pauseVideo
  1044. }
  1045. updateStandardAppFn_(x);
  1046. }
  1047. window.gt2 = () => standardAppXM();
  1048.  
  1049. const loadVideoByPlayerVarsP20 = {};
  1050. const loadVideoByPlayerVarsQ20 = new Map();
  1051.  
  1052.  
  1053. const standardAppXM = () => {
  1054.  
  1055. if (!(dirtyMark & 2)) return standardAppXT;
  1056.  
  1057. const internalApp = internalAppXM();
  1058. if (!internalApp) return standardAppXT;
  1059. const iaMedia = internalApp.mediaElement;
  1060.  
  1061.  
  1062. let result = null;
  1063. for (const p of standardAppUT) {
  1064. const iaMediaP = p.mediaElement;
  1065. if (!iaMediaP) {
  1066. standardAppUT.delete(p);
  1067. } else {
  1068. if (iaMediaP === iaMedia) result = p;
  1069. }
  1070. }
  1071. if (!result) return result;
  1072. standardAppUT.add(result);
  1073. standardAppXT = result;
  1074. updateStandardAppFn_();
  1075. if (dirtyMark & 2) dirtyMark -= 2;
  1076. return result;
  1077.  
  1078. }
  1079.  
  1080. const updatePlayerDapFn_ = () => {
  1081.  
  1082. const playerD_ = playerDapXT;
  1083. if (!playerD_.__onVideoProgressF381__) {
  1084. playerD_.__onVideoProgressF381__ = true;
  1085. try {
  1086. playerD_.removeEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop
  1087. } catch (e) { }
  1088. playerD_.addEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop
  1089. }
  1090.  
  1091. if (!playerDapPTDone) {
  1092. const proto = playerD_ ? playerD_.__proto__ : null;
  1093. if (proto) {
  1094. playerDapPTDone = true;
  1095. playerDapPTFn(proto);
  1096. }
  1097. }
  1098.  
  1099. const standardApp_ = playerD_.app || 0;
  1100. if (standardApp_) {
  1101. updateStandardAppFn(standardApp_);
  1102. }
  1103. }
  1104.  
  1105. const updatePlayerDapFn = (x) => {
  1106. if (x !== playerDapXT) {
  1107. dirtyMark = 1 | 2 | 4 | 8;
  1108. // console.log('updatePlayerDapFn')
  1109. playerDapUT.add(x);
  1110. playerDapXT = x;
  1111. }
  1112. updatePlayerDapFn_(x);
  1113.  
  1114. }
  1115.  
  1116. window.gt11 = () => {
  1117. return playerDapXM();
  1118. }
  1119. const playerDapXM = () => {
  1120.  
  1121. if (!(dirtyMark & 8)) return playerDapXT;
  1122. const standardApp = standardAppXM();
  1123. if (!standardApp) return playerDapXT;
  1124. let result = null;
  1125. for (const p of playerDapUT) {
  1126. if (!p.app || !p.app.mediaElement) playerDapUT.delete(p);
  1127. else if (p.app === standardApp) result = p;
  1128. }
  1129. if (!result) return result;
  1130. playerDapUT.add(result);
  1131. playerDapXT = result;
  1132. updatePlayerDapFn_();
  1133. if (dirtyMark & 8) dirtyMark -= 8;
  1134. return result;
  1135. }
  1136.  
  1137. const updatePlayerAppFn_ = () => {
  1138.  
  1139. const player_ = playerAppXT;
  1140.  
  1141.  
  1142. if (!player_.__s4539__ || !player_.__s4549__) {
  1143. player_.__s4539__ = true;
  1144.  
  1145.  
  1146. if (!player_.__onVideoProgressF381__ && typeof player_.addEventListener === 'function') {
  1147. player_.__onVideoProgressF381__ = true;
  1148. try {
  1149. player_.removeEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop
  1150. } catch (e) { }
  1151. player_.addEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop
  1152. }
  1153.  
  1154. const playerPT = player_.__proto__;
  1155. if (playerPT && typeof playerPT.getPlayerStateObject === 'function' && !playerPT.getPlayerStateObject949) {
  1156. playerPT.getPlayerStateObject949 = playerPT.getPlayerStateObject;
  1157. playerPT.getPlayerStateObject = function () {
  1158. updatePlayerAppFn(this);
  1159. return this.getPlayerStateObject949(...arguments);
  1160. }
  1161. } else if (player_ && typeof player_.getPlayerStateObject === 'function' && !player_.getPlayerStateObject949) {
  1162. player_.getPlayerStateObject949 = player_.getPlayerStateObject;
  1163. player_.getPlayerStateObject = function () {
  1164. updatePlayerAppFn(this);
  1165. return this.getPlayerStateObject949(...arguments);
  1166. }
  1167. }
  1168.  
  1169.  
  1170.  
  1171. // globalPlayer = mWeakRef(player_);
  1172. // window.gp3 = player_;
  1173.  
  1174.  
  1175. let playerDap_ = null;
  1176. {
  1177.  
  1178.  
  1179. const objectSets = new Set();
  1180. Function.prototype.apply129 = Function.prototype.apply;
  1181. Function.prototype.apply = function () {
  1182. objectSets.add([this, ...arguments]);
  1183. return this.apply129(...arguments)
  1184. }
  1185. player_.getPlayerState();
  1186.  
  1187. Function.prototype.apply = Function.prototype.apply129;
  1188.  
  1189. console.log(39912, [...objectSets]);
  1190. let filteredObjects = [...objectSets].filter(e => {
  1191. return Object(e[1]).getPlayerState === e[0]
  1192. });
  1193. console.log(39914, filteredObjects);
  1194.  
  1195. if (filteredObjects.length > 1) {
  1196. filteredObjects = filteredObjects.filter((e) => !(e[1] instanceof Node));
  1197. }
  1198.  
  1199. if (filteredObjects.length === 1) {
  1200. playerDap_ = filteredObjects[0][1];
  1201. }
  1202.  
  1203. objectSets.clear();
  1204. filteredObjects.length = 0;
  1205.  
  1206. }
  1207. {
  1208.  
  1209.  
  1210. let internalApp_ = null;
  1211. if (playerDap_ && playerDap_.app && playerDap_.state) {
  1212. const playerDapP_ = playerDap_.__proto__;
  1213. if (playerDapP_ && (playerDapP_.stopVideo || playerDapP_.pauseVideo) && (playerDapP_.playVideo)) {
  1214. if (!key_L1) {
  1215. const listOfPossibles = [];
  1216. for (const [key, value] of Object.entries(playerDapP_)) {
  1217. if (typeof value === 'function' && value.length === 0 && `${value}`.endsWith('(this.app)}')) { // return g.O5(this.app)
  1218. let m = null;
  1219. try {
  1220. m = playerDap_[key]()
  1221. } catch (e) { }
  1222. if (typeof (m || 0) === 'object') {
  1223. listOfPossibles.push([key, m, evaluateInternalAppScore(m)]);
  1224. }
  1225. }
  1226. }
  1227.  
  1228. if (listOfPossibles.length >= 2) {
  1229. listOfPossibles.sort((a, b) => {
  1230. return b[2] - a[2];
  1231. })
  1232. }
  1233. if (listOfPossibles.length >= 1) {
  1234. key_L1 = listOfPossibles[0][0];
  1235. internalApp_ = listOfPossibles[0][1];
  1236. console.log('[yt-audio-only] key_L1', key_L1);
  1237. }
  1238. listOfPossibles.length = 0;
  1239. // key_L1 = '';
  1240. }
  1241. updatePlayerDapFn(playerDap_);
  1242. }
  1243. }
  1244.  
  1245. if (key_L1) {
  1246. const internalApp = internalApp_ || playerDap_[key_L1]();
  1247. if (internalApp) {
  1248. updateInternalAppFn(internalApp);
  1249. player_.__s4549__ = true;
  1250. }
  1251. }
  1252. }
  1253.  
  1254.  
  1255. setupFns();
  1256.  
  1257.  
  1258. }
  1259.  
  1260. }
  1261.  
  1262. // player could be just a DOM element without __proto__
  1263. // will this update fail?
  1264. const updatePlayerAppFn = (x) => {
  1265. if (x !== playerAppXT) {
  1266. dirtyMark = 1 | 2 | 4 | 8;
  1267. // console.log('updatePlayerAppFn')
  1268. playerAppUT.add(x);
  1269. playerAppXT = x;
  1270. }
  1271. updatePlayerAppFn_();
  1272. }
  1273. const playerAppXM = () => {
  1274.  
  1275. if (!(dirtyMark & 1)) return playerAppXT;
  1276.  
  1277. const standardApp = standardAppXM();
  1278. if (!standardApp) return playerAppXT;
  1279.  
  1280. const playerAppUA = [...playerAppUT];
  1281. loadVideoByPlayerVarsQ20.clear();
  1282. for (let i = 0; i < playerAppUA.length; i++) {
  1283. const playerApp = playerAppUA[i];
  1284. loadVideoByPlayerVarsP20.index = i;
  1285. try {
  1286. playerApp.loadVideoByPlayerVars(loadVideoByPlayerVarsP20, 0, 0);
  1287. } catch (e) { }
  1288. loadVideoByPlayerVarsP20.index = -1;
  1289. }
  1290. window.loadVideoByPlayerVarsQ20 = loadVideoByPlayerVarsQ20;
  1291.  
  1292. const j = loadVideoByPlayerVarsQ20.get(standardApp);
  1293.  
  1294. const result = Number.isFinite(j) && j >= 0 ? playerAppUA[j] : null;
  1295.  
  1296. const idxSet = new Set(loadVideoByPlayerVarsQ20.values());
  1297.  
  1298. for (let i = 0; i < playerAppUA.length; i++) {
  1299. if (!idxSet.has(i)) playerAppUT.delete(playerAppUA[i]);
  1300. }
  1301. // loadVideoByPlayerVarsQ20.clear();
  1302. if (!result) return result;
  1303. playerAppUT.add(result);
  1304. playerAppXT = result;
  1305. updatePlayerAppFn_();
  1306. if (dirtyMark & 1) dirtyMark -= 1;
  1307. return result;
  1308.  
  1309. }
  1310. window.gt1 = () => playerAppXM();
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316. const playerDapPTFn = (playerDapPT_) => {
  1317.  
  1318. const playerDapPT = playerDapPT_;
  1319.  
  1320.  
  1321. if (playerDapPT && typeof playerDapPT.getPlayerStateObject === 'function' && !playerDapPT.getPlayerStateObject949) {
  1322.  
  1323. playerDapPT.getPlayerStateObject949 = playerDapPT.getPlayerStateObject;
  1324. playerDapPT.getPlayerStateObject = function () {
  1325. updatePlayerDapFn(this);
  1326. return this.getPlayerStateObject949(...arguments);
  1327. };
  1328.  
  1329. }
  1330. };
  1331.  
  1332.  
  1333. const standardAppPTFn = (standardAppPT_) => {
  1334.  
  1335. const standardAppPT = standardAppPT_;
  1336.  
  1337. if (standardAppPT && typeof standardAppPT.loadVideoByPlayerVars === 'function' && !standardAppPT.loadVideoByPlayerVars311) {
  1338.  
  1339. let lastRecord = [];
  1340.  
  1341. standardAppPT.loadVideoByPlayerVars311 = standardAppPT.loadVideoByPlayerVars;
  1342.  
  1343. standardAppPT.loadVideoByPlayerVars = function (p, C, V, N, H) {
  1344. if (p === loadVideoByPlayerVarsP20) {
  1345. // console.log('loadVideoByPlayerVarsP20', p, p.index)
  1346. loadVideoByPlayerVarsQ20.set(this, p.index);
  1347. return;
  1348. }
  1349. updateStandardAppFn(this)
  1350. if (p && typeof p === 'object') {
  1351.  
  1352. const { adPlacements, adSlots } = p.raw_player_response || {};
  1353. if (isIterable(adPlacements)) adPlacements.length = 0;
  1354. if (isIterable(adSlots)) adSlots.length = 0;
  1355.  
  1356. lastRecord.length = 0;
  1357. lastRecord.push(...[p, C, V, N, H]);
  1358. console.log('lastRecord 03022', [...lastRecord])
  1359. }
  1360.  
  1361. return this.loadVideoByPlayerVars311(...arguments);
  1362. }
  1363. }
  1364.  
  1365.  
  1366. };
  1367.  
  1368.  
  1369.  
  1370. const { internalAppPTFn } = (() => {
  1371.  
  1372. const flags_ = {}
  1373. let qma = 0;
  1374. const flagOn_ = (flags, key, bool) => {
  1375. flags_[key] = flags[key];
  1376. flags[key] = typeof flags[key] === 'boolean' ? bool : `${bool}`;
  1377. }
  1378. const flagOn = () => {
  1379. // return;
  1380. const internalApp = internalAppXM();
  1381. if (!key_yn) return;
  1382. const flags = internalApp?.[key_yn]?.experiments?.flags || 0;
  1383. if (!flags) return;
  1384. if (qma < 0) return;
  1385. qma++;
  1386. if (qma > 1) return;
  1387. flagOn_(flags, 'html5_enable_ssap_autoplay_debug_logging', false);
  1388. // flagOn_(flags, 'enable_visit_advertiser_support_on_ipad_mweb', false);
  1389. // flagOn_(flags, 'html5_shorts_onesie_mismatched_fix', false);
  1390. // flagOn_(flags, 'html5_early_media_for_drm', false);
  1391. // flagOn_(flags, 'allow_vp9_1080p_mq_enc', false);
  1392. // flagOn_(flags, 'html5_onesie_preload_use_content_owner', false);
  1393. flagOn_(flags, 'html5_exponential_memory_for_sticky', false);
  1394. // flagOn_(flags, 'html5_perf_cap_override_sticky', false);
  1395. // flagOn_(flags, 'html5_perserve_av1_perf_cap', false);
  1396. // flagOn_(flags, 'html5_disable_low_pipeline', false);
  1397. flagOn_(flags, 'html5_publish_all_cuepoints', false);
  1398. flagOn_(flags, 'html5_ultra_low_latency_subsegment_readahead', false);
  1399. // flagOn_(flags, 'html5_disable_move_pssh_to_moov', false);
  1400. flagOn_(flags, 'html5_sunset_aac_high_codec_family', false);
  1401. // flagOn_(flags, 'html5_enable_ssap_seteos', false);
  1402.  
  1403. // flagOn_(flags, 'html5_catch_errors_for_rollback', false);
  1404. // flagOn_(flags, 'html5_sabr_enable_utc_seek_requests', false);
  1405. // flagOn_(flags, 'html5_sabr_enable_live_clock_offset', false);
  1406. // flagOn_(flags, 'html5_disable_client_resume_policy_for_sabr', false);
  1407. flagOn_(flags, 'html5_trigger_loader_when_idle_network', false);
  1408.  
  1409. flagOn_(flags, 'web_key_moments_markers', false);
  1410. flagOn_(flags, 'embeds_use_parent_visibility_in_ve_logging', false);
  1411. flagOn_(flags, 'html5_onesie', false);
  1412. qma = 1;
  1413. }
  1414.  
  1415. const flagOff = () => {
  1416.  
  1417. // return;
  1418. const internalApp = internalAppXM();
  1419. if (!key_yn) return;
  1420. const flags = internalApp?.[key_yn]?.experiments?.flags || 0;
  1421. if (!flags) return;
  1422. if (qma <= 0) return;
  1423. qma--;
  1424. if (qma > 1) return;
  1425. for (const [key, value] of Object.entries(flags_)) {
  1426. flags[key] = value;
  1427. }
  1428. qma = 0;
  1429. }
  1430.  
  1431.  
  1432. const internalAppPTFn = (internalAppPT_) => {
  1433.  
  1434. const internalAppPT = internalAppPT_;
  1435.  
  1436.  
  1437. if (internalAppPT && internalAppPT.playVideo && !internalAppPT.playVideo9391) {
  1438. internalAppPT.playVideo9391 = internalAppPT.playVideo;
  1439.  
  1440. internalAppPT.playVideo = function (p, C) {
  1441. updateInternalAppFn(this);
  1442. console.log(`[yt-audio-only] internalApp.playVideo; skipPlayPause=${skipPlayPause ? 1 : 0}`);
  1443. try {
  1444. flagOn();
  1445. return this.playVideo9391(...arguments);
  1446. } catch (e) {
  1447. console.warn(e);
  1448. } finally {
  1449. flagOff();
  1450. }
  1451. }
  1452. internalAppPT.playVideo.toString = internalAppPT.playVideo9391.toString.bind(internalAppPT.playVideo9391);
  1453.  
  1454.  
  1455.  
  1456. }
  1457.  
  1458.  
  1459. if (internalAppPT && internalAppPT.pauseVideo && !internalAppPT.pauseVideo9391) {
  1460.  
  1461. internalAppPT.pauseVideo9391 = internalAppPT.pauseVideo;
  1462.  
  1463. internalAppPT.pauseVideo = function (p) {
  1464. updateInternalAppFn(this);
  1465. console.log(`[yt-audio-only] internalApp.pauseVideo; skipPlayPause=${skipPlayPause ? 1 : 0}`);
  1466. try {
  1467. flagOn();
  1468. return this.pauseVideo9391(...arguments);
  1469. } catch (e) {
  1470. console.warn(e);
  1471. } finally {
  1472. flagOff();
  1473. }
  1474. }
  1475. internalAppPT.pauseVideo.toString = internalAppPT.pauseVideo9391.toString.bind(internalAppPT.pauseVideo9391);
  1476.  
  1477.  
  1478. }
  1479.  
  1480.  
  1481. if (internalAppPT && internalAppPT.stopVideo && !internalAppPT.stopVideo9391) {
  1482.  
  1483. internalAppPT.stopVideo9391 = internalAppPT.stopVideo;
  1484.  
  1485. internalAppPT.stopVideo = function () {
  1486. updateInternalAppFn(this);
  1487. console.log(`[yt-audio-only] internalApp.stopVideo; skipPlayPause=${skipPlayPause ? 1 : 0}`);
  1488. try {
  1489. flagOn();
  1490. return this.stopVideo9391(...arguments);
  1491. } catch (e) {
  1492. console.warn(e);
  1493. } finally {
  1494. flagOff();
  1495. }
  1496. }
  1497. internalAppPT.stopVideo.toString = internalAppPT.stopVideo9391.toString.bind(internalAppPT.stopVideo9391);
  1498.  
  1499.  
  1500. }
  1501.  
  1502. if (internalAppPT && internalAppPT.isBackground && !internalAppPT.isBackground9391) {
  1503. internalAppPT.isBackground9391 = internalAppPT.isBackground;
  1504.  
  1505. const f = () => false;
  1506. internalAppPT.isBackground = function () {
  1507. try {
  1508. if (this.visibility.isBackground !== f) this.visibility.isBackground = f;
  1509. return f();
  1510. } catch (e) {
  1511. }
  1512. return false;
  1513. }
  1514.  
  1515. }
  1516.  
  1517. if (internalAppPT && internalAppPT.sendAbandonmentPing && !internalAppPT.sendAbandonmentPing9391) {
  1518. internalAppPT.sendAbandonmentPing9391 = internalAppPT.sendAbandonmentPing;
  1519.  
  1520. internalAppPT.sendAbandonmentPing = function () {
  1521.  
  1522.  
  1523.  
  1524.  
  1525.  
  1526. console.log('[yt-audio-only] sendAbandonmentPing');
  1527.  
  1528. const internalApp = this;
  1529. const iaMedia = internalApp ? internalApp.mediaElement : null;
  1530. if (iaMedia) {
  1531. iaMedia.__publishStatus17__ = 0;
  1532. iaMedia.__publishStatus18__ = 0;
  1533. }
  1534.  
  1535. byPassSync = false;
  1536. skipPlayPause = 0;
  1537. byPassNonFatalError = true;
  1538. byPassPublishPatch = true;
  1539.  
  1540. dirtyMark = 1 | 2 | 4 | 8;
  1541.  
  1542. return this.sendAbandonmentPing9391(...arguments);
  1543. }
  1544. }
  1545.  
  1546.  
  1547.  
  1548. if (internalAppPT && internalAppPT.publish && !internalAppPT.publish48) {
  1549.  
  1550.  
  1551. internalAppPT.publish48 = internalAppPT.publish;
  1552.  
  1553. if (PATCH_MEDIA_PUBLISH) {
  1554.  
  1555.  
  1556.  
  1557. const printObject = (b) => {
  1558. return JSON.stringify(Object.entries(b || {}).filter(e => typeof (e[1] || 0) !== 'object'));
  1559. };
  1560.  
  1561.  
  1562. const errorRS = remapString('error');
  1563.  
  1564. internalAppPT.publish33 = async function (a, b) {
  1565. // console.log(3888, a,b);
  1566.  
  1567.  
  1568. if (byPassPublishPatch) return;
  1569. const isLoaded = await dmo.isLoadedW();
  1570. if (!isLoaded) return;
  1571.  
  1572. // window.gt6 = this;
  1573. const player_ = dmo.playerDapXM() || dmo.playerAppXM();
  1574. if (!player_) return;
  1575.  
  1576.  
  1577. const stateObject = dmo.getPlayerWrappedStateObject();
  1578.  
  1579.  
  1580.  
  1581. let publishStatus = 0;
  1582. const iaMedia = this.mediaElement;
  1583.  
  1584. if (!stateObject) return;
  1585.  
  1586. if (stateObject.isUnstarted === true) {
  1587.  
  1588. } else if (iaMedia.__publishStatus17__ >= 100 && iaMedia.__publishStatus17__ < 300) {
  1589.  
  1590. if (iaMedia.__publishStatus18__ < Date.now()) {
  1591. iaMedia.__publishStatus17__ = 0;
  1592. iaMedia.__publishStatus18__ = 0;
  1593. return;
  1594. }
  1595. } else {
  1596. return;
  1597. }
  1598.  
  1599.  
  1600. let kb = false;
  1601.  
  1602. const audio = dmo.getMediaElement();
  1603.  
  1604. if (a === 'internalaudioformatchange' && typeof (b.author || 0) === 'string' && iaMedia) {
  1605.  
  1606. kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true);
  1607.  
  1608. byPassSync = false;
  1609. skipPlayPause = 0;
  1610.  
  1611. // byPassSync = true;
  1612. byPassNonFatalError = true;
  1613. await dmo.clearVideoAndQueue();
  1614. await dmo.refreshAllStaleEntitiesForNonReadyAudio();
  1615. byPassNonFatalError = false;
  1616. // byPassSync = false;
  1617. // await cancelPlayback();
  1618. publishStatus = iaMedia.__publishStatus17__ = 100;
  1619.  
  1620. console.log(`[yt-audio-only] publish (internalaudioformatchange, =>100)`);
  1621. iaMedia.__publishStatus18__ = Date.now() + 240;
  1622. if (audio) {
  1623. if (audio[qzk] > 1e9) audio[qzk] = 9;
  1624. audio[qzk] = (audio[qzk] || 0) + 1;
  1625. }
  1626. }
  1627.  
  1628.  
  1629. if (this.mediaElement && audio && a !== 'internalvideoformatchange') {
  1630.  
  1631.  
  1632.  
  1633. if (a.includes('error') || a.includes(errorRS)) {
  1634.  
  1635. if (!iaMedia.__publishStatus17__ || iaMedia.__publishStatus17__ < 200) {
  1636.  
  1637. kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true);
  1638.  
  1639. byPassSync = false;
  1640. skipPlayPause = 0;
  1641. // byPassSync = true;
  1642. byPassNonFatalError = true;
  1643. await dmo.clearVideoAndQueue(); // avoid error in live streaming
  1644. await dmo.refreshAllStaleEntitiesForNonReadyAudio();
  1645. byPassNonFatalError = false;
  1646. // byPassSync = false;
  1647.  
  1648. console.log(`[yt-audio-only] publish (*error*, <200)`);
  1649. }
  1650.  
  1651.  
  1652. } else {
  1653.  
  1654. iaMedia.__publishStatus17__ = iaMedia.__publishStatus17__ || 100;
  1655. iaMedia.__publishStatus18__ = iaMedia.__publishStatus18__ || (Date.now() + 240);
  1656.  
  1657. // const utv = player_.isAtLiveHead();
  1658.  
  1659.  
  1660. if (iaMedia.__publishStatus17__ === 100) {
  1661. kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true);
  1662. byPassNonFatalError = true;
  1663. await dmo.refreshAllStaleEntitiesForNonReadyAudio();
  1664. byPassNonFatalError = false;
  1665. console.log(`[yt-audio-only] publish (***, =100)`);
  1666. }
  1667. if (iaMedia.__publishStatus17__ === 100 && audio.duration > 0 /* && (dmo.getPlayerStateInt() === 3 || dmo.getPlayerStateInt() === 2) */) {
  1668.  
  1669. iaMedia.__publishStatus17__ = 200
  1670.  
  1671. kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true);
  1672.  
  1673. byPassSync = true;
  1674. skipPlayPause = 3;
  1675. byPassNonFatalError = true;
  1676. await dmo.cancelPlayback();
  1677. await dmo.playVideo();
  1678. byPassNonFatalError = false;
  1679. skipPlayPause = 0;
  1680. byPassSync = false;
  1681. await dmo.seekToLiveHeadForLiveStream();
  1682.  
  1683.  
  1684. await dmo.playVideo();
  1685.  
  1686. console.log(`[yt-audio-only] publish (***, duration>0, stateInt=3, =100, =>200)`);
  1687. iaMedia.__publishStatus18__ = Date.now() + 240;
  1688.  
  1689. }
  1690.  
  1691.  
  1692.  
  1693. if (a === 'onLoadedMetadata' && iaMedia.__publishStatus17__ === 200) {
  1694. iaMedia.__publishStatus17__ = 201;
  1695. console.log(`[yt-audio-only] publish (onLoadedMetadata, =200, =>201)`);
  1696. iaMedia.__publishStatus18__ = Date.now() + 240;
  1697. }
  1698. if (a === 'videoelementevent' && b.type === 'loadedmetadata' && iaMedia.__publishStatus17__ === 201) {
  1699. iaMedia.__publishStatus17__ = 202;
  1700. console.log(`[yt-audio-only] publish (videoelementevent.loadedmetadata, =201, =>202)`);
  1701. iaMedia.__publishStatus18__ = Date.now() + 240;
  1702. }
  1703. if (a === 'videoelementevent' && b.type === 'progress' && iaMedia.__publishStatus17__ === 202) {
  1704.  
  1705. iaMedia.__publishStatus17__ = 203;
  1706. // window.debug_mfk = this;
  1707. // window.debug_mfp = player_;
  1708. console.log(`[yt-audio-only] publish (videoelementevent.progress, =202, =>203)`);
  1709. iaMedia.__publishStatus18__ = Date.now() + 240;
  1710. }
  1711. if (iaMedia.__publishStatus17__ === 203 && audio && audio.readyState === 1) {
  1712.  
  1713. // byPassSync = true;
  1714. iaMedia.__publishStatus17__ = 204;
  1715.  
  1716. kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true);
  1717.  
  1718. byPassSync = true;
  1719. skipPlayPause = 3;
  1720. byPassNonFatalError = true;
  1721. await dmo.pauseVideo();
  1722. await dmo.playVideo();
  1723. byPassNonFatalError = false;
  1724. skipPlayPause = 0;
  1725. byPassSync = false;
  1726. console.log('[yt-audio-only] publish skipPlayPause 10002', iaMedia.__publishStatus17__, skipPlayPause);
  1727. await dmo.seekToLiveHeadForLiveStream();
  1728. // byPassSync = false;
  1729.  
  1730. console.log('[yt-audio-only] publish skipPlayPause 10003', iaMedia.__publishStatus17__, skipPlayPause);
  1731. await dmo.playVideo();
  1732.  
  1733. console.log(`[yt-audio-only] publish (***, audio.readyState=1, =203, =>204)`);
  1734. iaMedia.__publishStatus18__ = Date.now() + 240;
  1735.  
  1736. console.log('[yt-audio-only] publish skipPlayPause 10004',iaMedia.__publishStatus17__, skipPlayPause);
  1737.  
  1738. }
  1739.  
  1740.  
  1741. if (iaMedia.__publishStatus17__ < 300 && iaMedia.__publishStatus17__ >= 200 && a === 'videoelementevent' && b.type === 'timeupdate' && !audio.paused && audio.readyState >= 4 && audio.duration > 0) {
  1742. iaMedia.__publishStatus17__ = 300;
  1743. if (!dmo.isAtLiveHeadW()) {
  1744. kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true);
  1745. await dmo.seekToLiveHeadForLiveStream();
  1746. }
  1747.  
  1748. console.log(`[yt-audio-only] publish (videoelementevent.timeupdate, {audio playing}, [200, 300), =>300)`);
  1749. iaMedia.__publishStatus18__ = Date.now() + 240;
  1750. }
  1751.  
  1752.  
  1753. }
  1754.  
  1755.  
  1756. publishStatus = iaMedia.__publishStatus17__;
  1757.  
  1758. if (debugFlg001) console.log('gkps0 publish | ' + publishStatus, a, printObject(b))
  1759.  
  1760. }
  1761. }
  1762.  
  1763. }
  1764.  
  1765. internalAppPT.publish = function (p, C) {
  1766. if (promiseSeek) {
  1767. if (p === 'videoelementevent' && C && C.type === 'playing') {
  1768. promiseSeek.resolve();
  1769. } else if (p === 'SEEK_COMPLETE') {
  1770. promiseSeek.resolve();
  1771. }
  1772. }
  1773.  
  1774. let qb = false;
  1775. if (byPassSync || (byPassNonFatalError && p === 'nonfatalerror')) {
  1776. qb = true;
  1777. }
  1778. if (qb) {
  1779. arguments[0] = p = typeof p === 'string' ? remapString(p) : p;
  1780. }
  1781.  
  1782.  
  1783. if (listAllPublish) console.log('[yt-audio-only] list publish', p, C)
  1784. if (this.publish33) {
  1785. try {
  1786. if (dmo.ready) this.publish33(p, C);
  1787. } catch (e) {
  1788. console.warn(e);
  1789. }
  1790. }
  1791. return this.publish48(...arguments);
  1792. }
  1793.  
  1794. }
  1795.  
  1796.  
  1797.  
  1798.  
  1799. if (!internalAppPT.setMediaElement661 && typeof internalAppPT.setMediaElement === 'function') {
  1800. internalAppPT.setMediaElement661 = internalAppPT.setMediaElement;
  1801. internalAppPT.setMediaElement = function (p) {
  1802. updateInternalAppFn(this);
  1803. console.log('setMediaElement', p)
  1804. return this.setMediaElement661(...arguments);
  1805. }
  1806. }
  1807.  
  1808.  
  1809.  
  1810. }
  1811.  
  1812. return { internalAppPTFn }
  1813.  
  1814.  
  1815. })();
  1816.  
  1817.  
  1818.  
  1819. let setupFnsB = false;
  1820. const setupFns = () => {
  1821. if (setupFnsB) return;
  1822. setupFnsB = true;
  1823.  
  1824. try {
  1825.  
  1826. const clearVideoAndQueue = async () => { // avoid error in live streaming
  1827. const player_ = playerAppXM();
  1828. const playerD_ = playerDapXM();
  1829. const standardApp = standardAppXM();
  1830. if (standardApp && standardApp.clearQueue) {
  1831. return await standardApp.clearQueue();
  1832. } else if (playerD_ && playerD_.clearQueue) {
  1833. return await playerD_.clearQueue();
  1834. } else if (player_ && player_.clearQueue) {
  1835. return await player_.clearQueue();
  1836. } else {
  1837. return null;
  1838. }
  1839. }
  1840.  
  1841. const cancelPlayback = async () => {
  1842.  
  1843. const player_ = playerAppXM();
  1844. const playerD_ = playerDapXM();
  1845. const standardApp = standardAppXM();
  1846. const internalApp = internalAppXM();
  1847.  
  1848. if (internalApp && internalApp.stopVideo && internalApp.pauseVideo && !internalApp.cancelPlayback) {
  1849. return await internalApp.stopVideo();
  1850. } else if (standardApp && standardApp.cancelPlayback) {
  1851. return await standardApp.cancelPlayback();
  1852. } else if (playerD_ && playerD_.cancelPlayback) {
  1853. return await playerD_.cancelPlayback();
  1854. } else if (player_ && player_.cancelPlayback) {
  1855. return await player_.cancelPlayback();
  1856. } else {
  1857. return null;
  1858. }
  1859. }
  1860.  
  1861. const pauseVideo = async () => {
  1862.  
  1863.  
  1864. const player_ = playerAppXM();
  1865. const playerD_ = playerDapXM();
  1866. const standardApp = standardAppXM();
  1867. const internalApp = internalAppXM();
  1868.  
  1869. if (internalApp && internalApp.stopVideo && internalApp.pauseVideo && !internalApp.cancelPlayback) {
  1870. return await internalApp.pauseVideo();
  1871. } else if (standardApp && standardApp.pauseVideo) {
  1872. return await standardApp.pauseVideo();
  1873. } else if (playerD_ && playerD_.pauseVideo) {
  1874. return await playerD_.pauseVideo();
  1875. } else if (player_ && player_.pauseVideo) {
  1876. return await player_.pauseVideo();
  1877. } else {
  1878. return null
  1879. }
  1880. }
  1881.  
  1882. const playVideo = async () => {
  1883.  
  1884. const player_ = playerAppXM();
  1885. const playerD_ = playerDapXM();
  1886. const standardApp = standardAppXM();
  1887. const internalApp = internalAppXM();
  1888.  
  1889. if (internalApp && internalApp.stopVideo && internalApp.pauseVideo && !internalApp.cancelPlayback && internalApp.playVideo) {
  1890. return await internalApp.playVideo();
  1891. } else if (standardApp && standardApp.playVideo) {
  1892. return await standardApp.playVideo();
  1893. } else if (playerD_ && playerD_.playVideo) {
  1894. return await playerD_.playVideo();
  1895. } else if (player_ && player_.playVideo) {
  1896. return await player_.playVideo();
  1897. } else {
  1898. return null
  1899. }
  1900. }
  1901.  
  1902. const isAtLiveHeadW = async () => {
  1903.  
  1904. const player_ = playerAppXM();
  1905. const playerD_ = playerDapXM();
  1906. const standardApp = standardAppXM();
  1907. const internalApp = internalAppXM();
  1908.  
  1909.  
  1910. if (internalApp && internalApp.isAtLiveHead) {
  1911. return await internalApp.isAtLiveHead()
  1912. } else if (standardApp && standardApp.isAtLiveHead) {
  1913. return await standardApp.isAtLiveHead()
  1914. } else if (playerD_ && playerD_.isAtLiveHead) {
  1915. return await playerD_.isAtLiveHead()
  1916. } else if (player_ && player_.isAtLiveHead) {
  1917. return await player_.isAtLiveHead()
  1918. } else {
  1919. return null;
  1920. }
  1921. }
  1922.  
  1923. const getInternalVideoData = () => {
  1924.  
  1925. const internalApp = internalAppXM();
  1926. if (internalApp && internalApp.videoData) {
  1927. return internalApp.videoData;
  1928. }
  1929. const standardApp = standardAppXM();
  1930. if (standardApp && typeof standardApp.getVideoData === 'function') {
  1931. return standardApp.getVideoData();
  1932. }
  1933. return null;
  1934.  
  1935. }
  1936.  
  1937.  
  1938. const isAdW = async () => {
  1939.  
  1940. const vd = getInternalVideoData() || 0;
  1941.  
  1942. if (vd && typeof vd.isAd === 'function') {
  1943. return await vd.isAd();
  1944. } else if (vd && typeof vd.isAd === 'boolean') {
  1945.  
  1946. return vd.isAd;
  1947.  
  1948. } else {
  1949. return null;
  1950. }
  1951. }
  1952.  
  1953. const isLoadedW = async () => {
  1954.  
  1955. const vd = getInternalVideoData() || 0;
  1956.  
  1957. if (vd && typeof vd.isLoaded === 'function') {
  1958. return await vd.isLoaded();
  1959. } else if (vd && typeof vd.isLoaded === 'boolean') {
  1960.  
  1961. return vd.isLoaded;
  1962.  
  1963. } else {
  1964. return null;
  1965. }
  1966.  
  1967. }
  1968.  
  1969. const getPlayerWrappedStateObject = () => {
  1970.  
  1971.  
  1972. // g.h.oD = function(p) {
  1973. // p = this.app.getPlayerStateObject(p);
  1974. // return {
  1975. // isBuffering: g.r(p, 1),
  1976. // isCued: p.isCued(),
  1977. // isDomPaused: g.r(p, 1024),
  1978. // isEnded: g.r(p, 2),
  1979. // isError: g.r(p, 128),
  1980. // isOrWillBePlaying: p.isOrWillBePlaying(),
  1981. // isPaused: p.isPaused(),
  1982. // isPlaying: p.isPlaying(),
  1983. // isSeeking: g.r(p, 16),
  1984. // isUiSeeking: g.r(p, 32),
  1985. // isUnstarted: g.r(p, 64)
  1986. // }
  1987. // }
  1988.  
  1989.  
  1990. const standardApp = standardAppXM();
  1991. const playerD_ = playerDapXM();
  1992. const player_ = playerAppXM();
  1993. const app = standardApp || playerD_;
  1994. if (app && typeof app.getPlayerStateObject === 'function') {
  1995. const fo = app.getPlayerStateObject();
  1996. const flag = fo ? (fo.state || 0) : 0;
  1997. return {
  1998. isBuffering: (flag & 1) === 1,
  1999. isCued: (flag & 64) === 64 && (flag & 8) === 0 && (flag & 4) === 0,
  2000. isDomPaused: (flag & 1024) === 1024,
  2001. isEnded: (flag & 2) === 2,
  2002. isError: (flag & 128) === 128,
  2003. isOrWillBePlaying: (flag & 8) === 8 && (flag & 2) === 0 && (flag & 1024) === 0,
  2004. isPaused: (flag & 4) === 4,
  2005. isPlaying: (flag & 8) === 8 && (flag & 512) === 0 && (flag & 64) === 0 && (flag & 2) === 0,
  2006. isSeeking: (flag & 16) === 16,
  2007. isUiSeeking: (flag & 32) === 32,
  2008. isUnstarted: (flag & 64) === 64,
  2009. };
  2010. } else if (player_ && typeof player_.getPlayerStateObject === 'function') {
  2011. return player_.getPlayerStateObject();
  2012. } else {
  2013. return {};
  2014. }
  2015.  
  2016. }
  2017.  
  2018. const getPlayerStateInt = () => {
  2019.  
  2020. const playerD_ = playerDapXM();
  2021. const player_ = playerAppXM();
  2022.  
  2023. if (playerD_ && typeof playerD_.getPlayerState === 'function') {
  2024. return playerD_.getPlayerState();
  2025.  
  2026. } else if (player_ && typeof player_.getPlayerState === 'function') {
  2027. return player_.getPlayerState();
  2028.  
  2029. } else {
  2030. return null;
  2031. }
  2032. }
  2033.  
  2034. const updateAtPublish = (x) => {
  2035. dirtyMark = 1 | 2 | 4 | 8;
  2036. updateInternalAppFn(x);
  2037. }
  2038.  
  2039. const refreshAllStaleEntitiesForNonReadyAudio = async () => {
  2040.  
  2041. const player_ = playerAppXM(); // player or xj
  2042. if (!player_) return;
  2043. const audio = getMediaElement();
  2044. try {
  2045. // byPassSync = true;
  2046. if (audio.readyState == 0 && audio.isConnected === true) await player_.refreshAllStaleEntities();
  2047. // byPassSync = false;
  2048. } catch (e) {
  2049. }
  2050. };
  2051. const seekToLiveHeadForLiveStream = async () => {
  2052. const player_ = playerDapXM() || playerAppXM(); // player or xj
  2053. const audio = getMediaElement();
  2054. try {
  2055. audio.isConnected === true && await player_.seekToLiveHead();
  2056. if (audio.isConnected === true && (await player_.isAtLiveHead()) === true) {
  2057. audio.isConnected === true && await player_.seekToStreamTime();
  2058. return true;
  2059. }
  2060. } catch (e) {
  2061. console.log('error_F7', e);
  2062. }
  2063. };
  2064.  
  2065. const trySeekToLiveHead = async () => {
  2066. const player_ = playerDapXM() || playerAppXM(); // player or xj
  2067. try {
  2068. await player_.seekToLiveHead();
  2069. if ((await player_.isAtLiveHead()) === true) {
  2070. await player_.seekToStreamTime();
  2071. }
  2072. } catch (e) { }
  2073. }
  2074.  
  2075. Object.assign(dmo, { clearVideoAndQueue, cancelPlayback, pauseVideo, playVideo, isAtLiveHeadW, updateAtPublish, refreshAllStaleEntitiesForNonReadyAudio, seekToLiveHeadForLiveStream, ready: true, isLoadedW, getMediaElement, playerAppXM, standardAppXM, internalAppXM, playerDapXM, getPlayerStateInt, getPlayerWrappedStateObject, getInternalVideoData });
  2076.  
  2077.  
  2078.  
  2079. const getPublishStatus17 = () => {
  2080.  
  2081. const internalApp = internalAppXM();
  2082. const iaMedia = internalApp ? internalApp.mediaElement : null;
  2083. return iaMedia ? iaMedia.__publishStatus17__ : null;
  2084. }
  2085.  
  2086. const shouldWaitPublish = () => {
  2087. let waitPublish = false;
  2088. const internalApp = internalAppXM();
  2089. const iaMedia = internalApp ? internalApp.mediaElement : null;
  2090. const stateObject = getPlayerWrappedStateObject();
  2091. if (stateObject && stateObject.isUnstarted === true) {
  2092. waitPublish = true;
  2093. } else if (iaMedia && iaMedia.__publishStatus17__ >= 100 && iaMedia.__publishStatus17__ < 300) {
  2094. waitPublish = true;
  2095. } else {
  2096. waitPublish = false;
  2097. }
  2098. return waitPublish;
  2099. }
  2100.  
  2101. let playBusy = 0;
  2102. if (!HTMLAudioElement.prototype.play3828 && !HTMLAudioElement.prototype.pause3828 && PATCH_MEDIA_PLAYPAUSE) {
  2103.  
  2104.  
  2105. HTMLAudioElement.prototype.pause3828 = HTMLAudioElement.prototype.pause;
  2106. HTMLAudioElement.prototype.pause = function () {
  2107. if (skipPlayPause & 2) return;
  2108.  
  2109. if (getMediaElement() === this) {
  2110.  
  2111. const internalApp = internalAppXM();
  2112. const iaMedia = internalApp ? internalApp.mediaElement : null;
  2113. if (iaMedia) {
  2114. iaMedia.__publishStatus17__ = 0;
  2115. iaMedia.__publishStatus18__ = 0;
  2116. }
  2117. }
  2118.  
  2119. if (playBusy > 0){
  2120.  
  2121. return this.pause3828();
  2122. }else{
  2123. const audio= this;
  2124.  
  2125. if (audio[qzk] > 1e9) audio[qzk] = 9;
  2126. const lzt = audio[qzk] ? ++audio[qzk] : (audio[qzk] = 1);
  2127. return this.pause3828();
  2128. }
  2129.  
  2130. }
  2131.  
  2132.  
  2133. HTMLAudioElement.prototype.play3828 = HTMLAudioElement.prototype.play;
  2134. HTMLAudioElement.prototype.play = async function () {
  2135. if (skipPlayPause & 1) return;
  2136.  
  2137. if (playBusy > 0) return await this.play3828();
  2138.  
  2139. const audio = this;
  2140.  
  2141. if (audio[qzk] > 1e9) audio[qzk] = 9;
  2142. const lzt = audio[qzk] ? ++audio[qzk] : (audio[qzk] = 1);
  2143.  
  2144. console.log(`[yt-audio-only] video.play01 {${lzt}}`);
  2145. if (getMediaElement() !== this) {
  2146. dirtyMark = 1 | 2 | 4 | 8;
  2147. }
  2148.  
  2149.  
  2150. const internalApp = internalAppXM();
  2151. if (!internalApp.mediaElement) return await this.play3828();
  2152. if (audio !== getMediaElement()) return await this.play3828();
  2153.  
  2154.  
  2155. console.log(`[yt-audio-only] video.play02 {${lzt}}`, getPublishStatus17())
  2156. // if ((await isAdW()) === true) return;
  2157.  
  2158.  
  2159. let isAtLiveHead = await isAtLiveHeadW();
  2160. Promise.resolve().then(async () => {
  2161.  
  2162. if(lzt !== audio[qzk]) return;
  2163. dirtyMark = 1 | 2 | 4 | 8;
  2164.  
  2165.  
  2166. // between play02 and play03, < publish (***, duration>0, stateInt=3, =100, =>200) > should occur
  2167. console.log(`[yt-audio-only] video.play03 {${lzt}}`, getPublishStatus17())
  2168.  
  2169.  
  2170.  
  2171. if (!shouldWaitPublish()) {
  2172. await delayPn(80);
  2173. dirtyMark = 1 | 2 | 4 | 8;
  2174. if(lzt !== audio[qzk]) return;
  2175. }
  2176.  
  2177.  
  2178. if (shouldWaitPublish()) {
  2179. await delayPn(400);
  2180. dirtyMark = 1 | 2 | 4 | 8;
  2181. if(lzt !== audio[qzk]) return;
  2182. }
  2183.  
  2184. const publishStatus1701 = getPublishStatus17();
  2185.  
  2186.  
  2187. console.log(`[yt-audio-only] video.play04 {${lzt}}`, publishStatus1701);
  2188.  
  2189. if (getMediaElement() !== this) {
  2190. dirtyMark = 1 | 2 | 4 | 8;
  2191. }
  2192. if (internalApp !== internalAppXM()) return;
  2193. if (!internalApp.mediaElement) return;
  2194. if (audio !== getMediaElement()) return;
  2195. const stateObject = getPlayerWrappedStateObject();
  2196.  
  2197. if (stateObject.isDomPaused && stateObject.isBuffering && !stateObject.isOrWillBePlaying && !stateObject.isPaused && !stateObject.isPlaying && !stateObject.isSeeking && stateObject.isUnstarted) {
  2198. // allow case; would fall into (publishStatus1701 > 200 && publishStatus1701 < 300) case
  2199. } else {
  2200. if (stateObject.isOrWillBePlaying === false || stateObject.isPaused === true || stateObject.isEnded === true) return;
  2201. }
  2202.  
  2203. console.log(`[yt-audio-only] video.play05 {${lzt}}`, publishStatus1701);
  2204.  
  2205. console.log(1293, stateObject);
  2206.  
  2207. let bool = false;
  2208. if (stateObject.isBuffering && !stateObject.isEnded && !stateObject.isError && stateObject.isSeeking && stateObject.isUnstarted && !stateObject.isCued) {
  2209. bool = true;
  2210. } else if (stateObject.isOrWillBePlaying && stateObject.isSeeking && !stateObject.isCued && stateObject.isPlaying) {
  2211. bool = true;
  2212. } else if (publishStatus1701 > 200 && publishStatus1701 < 300){
  2213. // loadedmetadata done
  2214. bool = true;
  2215. }
  2216.  
  2217.  
  2218. if (!isAtLiveHead && stateObject.isUnstarted === true && stateObject.isOrWillBePlaying) {
  2219. const vd = getInternalVideoData();
  2220. if (vd.isLivePlayback && vd.isLiveHeadPlayable) {
  2221. console.log('isAtLiveHead: false -> true')
  2222. isAtLiveHead = true;
  2223. }
  2224. }
  2225.  
  2226. console.log(3882, bool, isAtLiveHead)
  2227.  
  2228. if (bool) {
  2229.  
  2230. console.log(`[yt-audio-only] video.play06 {${lzt}}`, publishStatus1701);
  2231.  
  2232. if (internalApp !== internalAppXM()) return;
  2233. if (!internalApp.mediaElement) return;
  2234.  
  2235. playBusy++;
  2236.  
  2237. console.log(`[yt-audio-only] video.play07 {${lzt}}`, publishStatus1701);
  2238.  
  2239. // byPassSync = true;
  2240. byPassNonFatalError = true;
  2241. byPassPublishPatch = true;
  2242. if ((await isLoadedW()) === false) {
  2243.  
  2244. console.log(`[yt-audio-only] video.play07.1 {${lzt}}`, "isLoadedW = false");
  2245. await clearVideoAndQueue();
  2246. await cancelPlayback();
  2247. } else {
  2248. console.log(`[yt-audio-only] video.play07.1 {${lzt}}`, "isLoadedW = true");
  2249. await cancelPlayback();
  2250. }
  2251. await delayPn(80); // wait some time for byPassNonFatalError and byPassPublishPatch
  2252. byPassNonFatalError = false;
  2253. byPassPublishPatch = false;
  2254. dirtyMark = 1 | 2 | 4 | 8;
  2255.  
  2256. console.log(`[yt-audio-only] video.play08 {${lzt}}`, getPublishStatus17());
  2257.  
  2258.  
  2259. // await delayPn(40);
  2260. // await audio.pause();
  2261.  
  2262. const promiseSeek_ = promiseSeek = new PromiseExternal();
  2263.  
  2264.  
  2265. // listAllPublish = true;
  2266. if (isAtLiveHead) {
  2267. console.log(`[yt-audio-only] video.play08.1 {${lzt}}`, getPublishStatus17());
  2268. await trySeekToLiveHead();
  2269. dirtyMark = 1 | 2 | 4 | 8;
  2270. console.log(`[yt-audio-only] video.play08.2 {${lzt}}`, getPublishStatus17());
  2271. }
  2272.  
  2273. // await delayPn(40);
  2274.  
  2275. console.log(`[yt-audio-only] video.play09 {${lzt}}`, getPublishStatus17());
  2276. const qX = getPlayerWrappedStateObject();
  2277. if (qX.isBuffering || qX.isSeeking || qX.isUnstarted) {
  2278. console.log(`[yt-audio-only] video.play09.1 {${lzt}}`, getPublishStatus17());
  2279. await playVideo();
  2280. dirtyMark = 1 | 2 | 4 | 8;
  2281. console.log(`[yt-audio-only] video.play09.2 {${lzt}}`, getPublishStatus17());
  2282. }
  2283.  
  2284. await delayPn(80); // wait sometime for playBusy
  2285.  
  2286. // byPassSync = false;
  2287. playBusy--;
  2288.  
  2289. if(lzt !== audio[qzk]) return; // abnormal
  2290.  
  2291. if(promiseSeek_ !== promiseSeek) return; // abnormal
  2292.  
  2293. console.log(`[yt-audio-only] video.play10 {${lzt}}`, getPublishStatus17());
  2294. const r = await Promise.race([promiseSeek_, delayPn(400).then(() => 123)]);
  2295. promiseSeek = null;
  2296.  
  2297. if (getPlayerWrappedStateObject().isDomPaused) {
  2298. console.log('manual playing is required') // found in Firefox
  2299. return;
  2300. }
  2301.  
  2302. if(lzt !== audio[qzk]) return; // normal
  2303.  
  2304. console.log(`[yt-audio-only] video.play11 {${lzt}}`, getPublishStatus17(), r);
  2305.  
  2306. // ----- play safe ----
  2307.  
  2308. let stateObject;
  2309. let tryCount = 8;
  2310. while (tryCount--) {
  2311. stateObject = getPlayerWrappedStateObject();
  2312. if (!stateObject.isSeeking || stateObject.isError || stateObject.isEnded || stateObject.isPaused || r === 123) break;
  2313. await delayPn(80);
  2314. if (lzt !== audio[qzk]) return;
  2315. }
  2316. // wait for [80ms, 640ms]
  2317.  
  2318. if (lzt !== audio[qzk]) return;
  2319.  
  2320. if (stateObject.isPlaying && stateObject.isOrWillBePlaying) return; // normal checking
  2321. if (stateObject.isError || stateObject.isEnded) return; // error checking
  2322.  
  2323. // retry
  2324.  
  2325. console.log(`[yt-audio-only] video.play12 {${lzt}}`, getPublishStatus17(), r, {...stateObject});
  2326.  
  2327. if (!r && stateObject && !stateObject.isOrWillBePlaying && !stateObject.isPlaying && stateObject.isPaused) {
  2328. // wait for the playing case
  2329. await delayPn(80);
  2330. if (lzt !== audio[qzk]) return;
  2331. stateObject = getPlayerWrappedStateObject();
  2332. console.log(`[yt-audio-only] video.play12.1 {${lzt}}`, getPublishStatus17(), r, {...stateObject});
  2333. }
  2334.  
  2335. console.log(`[yt-audio-only] video.play13 {${lzt}}`, getPublishStatus17(), r, {...stateObject});
  2336.  
  2337. if (stateObject && !stateObject.isSeeking) {
  2338. if (stateObject.isError || stateObject.isEnded) {
  2339. } else if (stateObject.isOrWillBePlaying && stateObject.isPlaying && !stateObject.isPaused) {
  2340. } else {
  2341.  
  2342. console.log(`[yt-audio-only] video.play13.1 {${lzt}}`, getPublishStatus17(), r, {...stateObject});
  2343. try {
  2344. // listAllPublish = false;
  2345. dirtyMark = 1 | 2 | 4 | 8;
  2346. await playVideo();
  2347. } catch (e) {
  2348. }
  2349. }
  2350. }
  2351.  
  2352.  
  2353. // ----- play safe ----
  2354.  
  2355. }
  2356.  
  2357.  
  2358.  
  2359. }).catch(console.warn);
  2360.  
  2361.  
  2362. try {
  2363. dirtyMark = 1 | 2 | 4 | 8;
  2364. playBusy++;
  2365.  
  2366. return await this.play3828();
  2367. } catch (e) {
  2368.  
  2369. } finally {
  2370.  
  2371.  
  2372. playBusy--;
  2373. dirtyMark = 1 | 2 | 4 | 8;
  2374. }
  2375.  
  2376.  
  2377.  
  2378. }
  2379.  
  2380.  
  2381. }
  2382.  
  2383.  
  2384.  
  2385. console.log('[yt-audio-only] DONE')
  2386.  
  2387. } catch (e) {
  2388. console.warn(e);
  2389. }
  2390.  
  2391.  
  2392.  
  2393.  
  2394. }
  2395.  
  2396. const setupAudioPlaying = (player00_) => {
  2397.  
  2398. // console.log(5939,player00_);
  2399.  
  2400. try {
  2401. const player_ = player00_;
  2402. if (!player_) return;
  2403. if (player_.__audio544__) return;
  2404. player_.__audio544__ = 1;
  2405.  
  2406. updatePlayerAppFn(player_);
  2407.  
  2408. } catch (e) {
  2409. console.warn(e);
  2410. }
  2411. }
  2412.  
  2413. if (!window.__ugAtg3747__) {
  2414. window.__ugAtg3747__ = true;
  2415. const updateLastActiveTimeGeneral = () => {
  2416. // player_ -> yuu
  2417. const player_ = playerDapXM() || playerAppXM();
  2418. if (player_) player_.updateLastActiveTime();
  2419. };
  2420. document.addEventListener('timeupdate', updateLastActiveTimeGeneral, true);
  2421. }
  2422.  
  2423. return { setupAudioPlaying, internalAppPTFn, standardAppPTFn, playerDapPTFn };
  2424.  
  2425. })();
  2426.  
  2427.  
  2428. if (location.origin === 'https://www.youtube.com') {
  2429.  
  2430.  
  2431.  
  2432. if (location.pathname.startsWith('/embed/')) {
  2433.  
  2434. // youtube embed
  2435.  
  2436. const ytEmbedReady = observablePromise(() => document.querySelector('#player > .ytp-embed')).obtain();
  2437.  
  2438. const embedConfigFix = (async () => {
  2439. while (true) {
  2440. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  2441. if (config_) {
  2442. ytConfigFix(config_);
  2443. break;
  2444. }
  2445. await delayPn(60);
  2446. }
  2447. });
  2448.  
  2449. ytEmbedReady.then(async (embedPlayer) => {
  2450.  
  2451. embedConfigFix();
  2452.  
  2453. const player_ = embedPlayer;
  2454. console.log(5919, player_)
  2455.  
  2456. setupAudioPlaying(player_); // dekstop embed
  2457.  
  2458.  
  2459. if (SHOW_VIDEO_STATIC_IMAGE) {
  2460.  
  2461. let displayImage = '';
  2462. let html5Container = null;
  2463.  
  2464.  
  2465. const moviePlayer = document.querySelector('#movie_player .html5-video-container .video-stream.html5-main-video');
  2466. if (moviePlayer) {
  2467. html5Container = moviePlayer.closest('.html5-video-container');
  2468. }
  2469.  
  2470. if (html5Container) {
  2471.  
  2472. const overlayImage = document.querySelector('#movie_player .ytp-cued-thumbnail-overlay-image[style]');
  2473. if (overlayImage) {
  2474.  
  2475. const cStyle = window.getComputedStyle(overlayImage);
  2476. const cssImageValue = cStyle.backgroundImage;
  2477. if (cssImageValue && typeof cssImageValue === 'string' && cssImageValue.startsWith('url(')) {
  2478. displayImage = cssImageValue;
  2479.  
  2480. }
  2481.  
  2482. }
  2483.  
  2484. if (!displayImage) {
  2485.  
  2486. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  2487. let embedded_player_response = null;
  2488. if (config_) {
  2489. embedded_player_response = ((config_.PLAYER_VARS || 0).embedded_player_response || 0)
  2490. }
  2491. if (embedded_player_response && typeof embedded_player_response === 'string') {
  2492.  
  2493. let idx1 = embedded_player_response.indexOf('"defaultThumbnail"');
  2494. let idx2 = idx1 >= 0 ? embedded_player_response.lastIndexOf('"defaultThumbnail"') : -1;
  2495.  
  2496. if (idx1 === idx2 && idx1 > 0) {
  2497.  
  2498. let bk = 0;
  2499. let j = -1;
  2500. for (let i = idx1; i < embedded_player_response.length; i++) {
  2501. if (i > idx1 + 40 && bk === 0) {
  2502. j = i;
  2503. break;
  2504. }
  2505. let t = embedded_player_response.charAt(i);
  2506. if (t === '{') bk++;
  2507. else if (t === '}') bk--;
  2508. }
  2509.  
  2510. if (j > idx1) {
  2511.  
  2512. let defaultThumbnailString = embedded_player_response.substring(idx1, j);
  2513. let defaultThumbnailObject = null;
  2514.  
  2515. try {
  2516. defaultThumbnailObject = JSON.parse(`{${defaultThumbnailString}}`);
  2517.  
  2518. } catch (e) { }
  2519.  
  2520. const thumbnails = ((defaultThumbnailObject.defaultThumbnail || 0).thumbnails || 0);
  2521.  
  2522. if (thumbnails && thumbnails.length >= 1) {
  2523.  
  2524. let thumbnailUrl = getThumbnailUrlFromThumbnails(thumbnails);
  2525.  
  2526. if (thumbnailUrl && thumbnailUrl.length > 3) {
  2527. displayImage = `url(${thumbnailUrl})`;
  2528. }
  2529. }
  2530. }
  2531.  
  2532. }
  2533.  
  2534.  
  2535. }
  2536.  
  2537.  
  2538. }
  2539.  
  2540. if (displayImage) {
  2541.  
  2542. html5Container.style.setProperty('--audio-only-thumbnail-image', `${displayImage}`);
  2543. } else {
  2544. html5Container.style.removeProperty('--audio-only-thumbnail-image')
  2545. }
  2546.  
  2547. }
  2548.  
  2549.  
  2550. }
  2551.  
  2552. });
  2553.  
  2554.  
  2555. } else {
  2556.  
  2557.  
  2558. // youtube normal
  2559.  
  2560. attachOneTimeEvent('yt-action', () => {
  2561. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  2562. ytConfigFix(config_);
  2563. });
  2564.  
  2565. let r3 = new PromiseExternal();
  2566. document.addEventListener('yt-action', () => {
  2567. let u = document.querySelector('ytd-watch-flexy');
  2568. if (u && typeof insp(u).calculateCurrentPlayerSize_ === 'function') {
  2569. r3.resolve(u);
  2570. }
  2571.  
  2572. }, true);
  2573.  
  2574. r3.then((watchFlexy) => {
  2575. // for offline video, without audio -> so no size
  2576.  
  2577. if (!watchFlexy) return;
  2578. const cnt = insp(watchFlexy);
  2579. if (typeof cnt.calculateCurrentPlayerSize_ === 'function' && !cnt.calculateCurrentPlayerSize3991_) {
  2580.  
  2581. cnt.calculateCurrentPlayerSize3991_ = cnt.calculateCurrentPlayerSize_;
  2582. cnt.calculateCurrentPlayerSize_ = function () {
  2583. const r = this.calculateCurrentPlayerSize3991_(...arguments);
  2584.  
  2585. if (r && r.width > 10 && !Number.isFinite(r.height)) {
  2586. r.height = Math.round(r.width / 16 * 9);
  2587. }
  2588. return r;
  2589.  
  2590. }
  2591.  
  2592. }
  2593.  
  2594. });
  2595.  
  2596.  
  2597.  
  2598. customElements.whenDefined('ytd-player').then(() => {
  2599. const dummy = document.querySelector('ytd-player') || document.createElement('ytd-player');
  2600. const cnt = insp(dummy);
  2601. const cProto = cnt.constructor.prototype;
  2602. cProto.createMainAppPlayer932_ = cProto.createMainAppPlayer_;
  2603. cProto.initPlayer932_ = cProto.initPlayer_;
  2604. const configFixBeforeCreate = () => {
  2605. try {
  2606. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  2607. if (config_) {
  2608. ytConfigFix(config_);
  2609. }
  2610. } catch (e) { }
  2611. }
  2612. cProto.createMainAppPlayer_ = function (a, b, c) {
  2613. configFixBeforeCreate();
  2614. let r = this.createMainAppPlayer932_(a, b, c);
  2615. try {
  2616. (async () => {
  2617. const e = await this.mainAppPlayer_.api;
  2618. setupAudioPlaying(e); // desktop normal
  2619. })();
  2620. } finally {
  2621. return r;
  2622. }
  2623. }
  2624. cProto.initPlayer_ = function (a) {
  2625. configFixBeforeCreate();
  2626. let r = this.initPlayer932_(a);
  2627. try {
  2628. (async () => {
  2629. const e = await r;
  2630. setupAudioPlaying(this.player_); // desktop normal
  2631. })();
  2632. } finally {
  2633. return r;
  2634. }
  2635. }
  2636. });
  2637.  
  2638. }
  2639.  
  2640.  
  2641. } else if (location.origin === 'https://m.youtube.com') {
  2642.  
  2643. removeBottomOverlayForMobile = async (delay) => {
  2644.  
  2645.  
  2646. let closeBtnRenderer = document.querySelector('.ytm-bottom-sheet-overlay-renderer-close.icon-close');
  2647. if (closeBtnRenderer) {
  2648.  
  2649. const btn = closeBtnRenderer.querySelector('button');
  2650. const container = closeBtnRenderer.closest('#global-loader ~ .ytm-bottom-sheet-overlay-container');
  2651.  
  2652. if (container) {
  2653. container.style.visibility = 'collapse';
  2654. container.style.zIndex = '-1';
  2655. }
  2656. if (btn) {
  2657. if (delay) {
  2658. await delayPn(delay);
  2659. }
  2660. btn.click();
  2661. }
  2662. }
  2663.  
  2664. }
  2665.  
  2666. const getAppJSON = () => {
  2667. let t;
  2668. t = document.querySelector('player-microformat-renderer.PlayerMicroformatRendererHost script[type="application/ld+json"]');
  2669. if (t) return t;
  2670. t = document.querySelector('player-microformat-renderer.playerMicroformatRendererHost script[type="application/ld+json"]');
  2671. if (t) return t;
  2672.  
  2673. return null;
  2674.  
  2675. }
  2676.  
  2677.  
  2678. let lastPlayerInfoText = '';
  2679. let mz = 0;
  2680. onVideoChangeForMobile = async () => {
  2681.  
  2682.  
  2683. let html5Container = null;
  2684.  
  2685. const moviePlayer = document.querySelector('#player .html5-video-container .video-stream.html5-main-video');
  2686. if (moviePlayer) {
  2687. html5Container = moviePlayer.closest('.html5-video-container');
  2688. }
  2689.  
  2690. console.log('STx00', html5Container)
  2691. if (!html5Container) return;
  2692. let thumbnailUrl = '';
  2693.  
  2694. if (mz > 1e9) mz = 9;
  2695. let mt = ++mz;
  2696.  
  2697. const scriptText = await observablePromise(() => {
  2698. if (mt !== mz) return 1;
  2699. const t = getAppJSON();
  2700. const tt = (t ? t.textContent : '') || '';
  2701. if (tt === lastPlayerInfoText) return;
  2702. return tt;
  2703. }).obtain();
  2704. if (typeof scriptText !== 'string') return; // 1
  2705. lastPlayerInfoText = scriptText;
  2706.  
  2707. if (!scriptText) return;
  2708.  
  2709.  
  2710. if (SHOW_VIDEO_STATIC_IMAGE) {
  2711. console.log('STx01')
  2712.  
  2713. let idx1 = scriptText.indexOf('"thumbnailUrl"');
  2714. let idx2 = idx1 >= 0 ? scriptText.lastIndexOf('"thumbnailUrl"') : -1;
  2715.  
  2716. if (idx1 === idx2 && idx1 > 0) {
  2717.  
  2718. let bk = 0;
  2719. let j = -1;
  2720. for (let i = idx1; i < scriptText.length; i++) {
  2721. if (i > idx1 + 20 && bk === 0) {
  2722. j = i;
  2723. break;
  2724. }
  2725. let t = scriptText.charAt(i);
  2726. if (t === '[') bk++;
  2727. else if (t === ']') bk--;
  2728. else if (t === '{') bk++;
  2729. else if (t === '}') bk--;
  2730. }
  2731.  
  2732.  
  2733. if (j > idx1) {
  2734.  
  2735. let thumbnailUrlString = scriptText.substring(idx1, j);
  2736. let thumbnailUrlObject = null;
  2737.  
  2738. try {
  2739. thumbnailUrlObject = JSON.parse(`{${thumbnailUrlString}}`);
  2740.  
  2741. } catch (e) { }
  2742.  
  2743. const thumbnails = thumbnailUrlObject.thumbnailUrl;
  2744.  
  2745. if (thumbnails && thumbnails.length >= 1 && typeof thumbnails[0] === 'string') {
  2746. if (thumbnails[0] && thumbnails[0].length > 3) {
  2747. thumbnailUrl = thumbnails[0];
  2748. }
  2749. }
  2750. }
  2751.  
  2752. }
  2753. console.log('STx02', thumbnailUrl);
  2754.  
  2755. if (thumbnailUrl && typeof thumbnailUrl === 'string') {
  2756. html5Container.style.setProperty('--audio-only-thumbnail-image', `url(${thumbnailUrl})`);
  2757. } else {
  2758. html5Container.style.removeProperty('--audio-only-thumbnail-image')
  2759. }
  2760.  
  2761. }
  2762.  
  2763.  
  2764. if (removeBottomOverlayForMobile) await removeBottomOverlayForMobile(40);
  2765.  
  2766. await delayPn(80);
  2767. const audio = moviePlayer;
  2768. if (audio && audio.muted === true && audio.isConnected === true && audio.readyState >= 0 && audio.networkState >= 2 && audio.paused === false) {
  2769. await audio.click();
  2770. }
  2771.  
  2772. }
  2773.  
  2774. let player0 = null;
  2775. const mff = function (e) {
  2776. const target = (e || 0).target || 0;
  2777. if (target !== player0 && target && typeof target.getPlayerState === 'function') {
  2778. player0 = target;
  2779. setupAudioPlaying(target); // mobile
  2780. }
  2781. }
  2782.  
  2783. document.addEventListener('player-initialized', mff, true);
  2784. document.addEventListener('player-state-change', mff, true);
  2785. document.addEventListener('player-ad-state-change', mff, true);
  2786. document.addEventListener('player-detailed-error', mff, true);
  2787. document.addEventListener('player-error', mff, true);
  2788. document.addEventListener('on-play-autonav-video', mff, true);
  2789. document.addEventListener('on-play-previous-autonav-video', mff, true);
  2790. document.addEventListener('player-fullscreen-change', mff, true);
  2791. document.addEventListener('player-fullscreen-toggled', mff, true);
  2792. document.addEventListener('player-dom-paused', mff, true);
  2793. document.addEventListener('yt-show-toast', mff, true);
  2794. document.addEventListener('yt-innertube-command', mff, true);
  2795. document.addEventListener('yt-update-c3-companion', mff, true);
  2796. document.addEventListener('video-data-change', mff, true);
  2797. document.addEventListener('video-progress', mff, true);
  2798. document.addEventListener('local-media-change', mff, true);
  2799.  
  2800.  
  2801.  
  2802. document.addEventListener('video-progress', updateLastActiveTimeAsync, true); // mobile
  2803.  
  2804.  
  2805.  
  2806. // document.addEventListener('DOMContentLoaded', (evt) => {
  2807. // const mo = new MutationObserver((mutations)=>{
  2808. // console.log(5899, mutations)
  2809. // });
  2810. // mo.observe(document, {subtree: true, childList: true})
  2811. // })
  2812.  
  2813. // window.addEventListener('onReady', (evt) => {
  2814. // console.log(6811)
  2815. // }, true);
  2816.  
  2817. // window.addEventListener('localmediachange', (evt) => {
  2818. // console.log(6812)
  2819. // }, true);
  2820.  
  2821. // window.addEventListener('onVideoDataChange', (evt) => {
  2822. // console.log(6813)
  2823. // }, true);
  2824.  
  2825. window.addEventListener('state-navigateend', async (evt) => {
  2826.  
  2827. delayPn(200).then(() => {
  2828. if (!getAppJSON()) {
  2829. console.log('[mobile youtube audio only] getAppJSON fails.', document.querySelectorAll('script[type="application/ld+json"]').length);
  2830. }
  2831. });
  2832.  
  2833. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  2834. ytConfigFix(config_);
  2835.  
  2836. try {
  2837. if (clickLockFn && clickTarget) {
  2838.  
  2839. let a = HTMLElement.prototype.querySelector.call(clickTarget, '.video-stream.html5-main-video');
  2840. if (!a) return;
  2841.  
  2842. if (a.muted === true && a.__spfgs__ !== true && a.paused === true && a.networkState === 0 && a.readyState === 0) {
  2843.  
  2844. const pr = new Promise(resolve => {
  2845.  
  2846. document.addEventListener('player-state-change', resolve, { once: true, passive: true, capture: false });
  2847.  
  2848. }).then();
  2849.  
  2850. clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 }));
  2851. await delayPn(1);
  2852.  
  2853. if (a.muted === false && a.__spfgs__ !== true && a.paused === true && a.networkState === 0 && a.readyState === 0) {
  2854. clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 }));
  2855. await delayPn(1);
  2856. }
  2857.  
  2858. delayRun(pr);
  2859.  
  2860. }
  2861.  
  2862. }
  2863.  
  2864. } catch (e) { console.log('error_F12', e) }
  2865.  
  2866.  
  2867. }, false);
  2868.  
  2869.  
  2870.  
  2871. // document.addEventListener('volumechange', (evt) => {
  2872. // console.log('volumechange')
  2873. // }, true)
  2874. // document.addEventListener('play', (evt) => {
  2875. // console.log('play')
  2876. // }, true)
  2877.  
  2878.  
  2879. // document.addEventListener('player-initialized', (evt) => {
  2880. // console.log(evt.type)
  2881. // }, true)
  2882. // document.addEventListener('renderer-module-load-start', (evt) => {
  2883. // console.log(evt.type)
  2884. // }, true)
  2885. // document.addEventListener('video-data-change', (evt) => {
  2886. // console.log(evt.type)
  2887. // }, true)
  2888. // document.addEventListener('player-state-change', (evt) => {
  2889. // console.log(evt.type)
  2890. // }, true)
  2891. // document.addEventListener('updateui', (evt) => {
  2892. // console.log(evt.type)
  2893. // }, true)
  2894. // document.addEventListener('renderer-module-load-end', (evt) => {
  2895. // console.log(evt.type)
  2896. // }, true)
  2897.  
  2898. // document.addEventListener('player-autonav-pause', (evt) => {
  2899. // console.log(evt.type)
  2900. // }, true)
  2901.  
  2902.  
  2903.  
  2904. // document.addEventListener('player-ad-state-change', (evt) => {
  2905. // console.log(evt.type)
  2906. // }, true)
  2907.  
  2908. // document.addEventListener('player-detailed-error', (evt) => {
  2909. // console.log(evt.type)
  2910. // }, true)
  2911.  
  2912. // document.addEventListener('player-error', (evt) => {
  2913. // console.log(evt.type)
  2914. // }, true)
  2915.  
  2916. // document.addEventListener('on-play-autonav-video', (evt) => {
  2917. // console.log(evt.type)
  2918. // }, true)
  2919.  
  2920. // document.addEventListener('on-play-previous-autonav-video', (evt) => {
  2921. // console.log(evt.type)
  2922. // }, true)
  2923.  
  2924. // document.addEventListener('player-fullscreen-change', (evt) => {
  2925. // console.log(evt.type)
  2926. // }, true)
  2927.  
  2928. // document.addEventListener('player-fullscreen-toggled', (evt) => {
  2929. // console.log(evt.type)
  2930. // }, true)
  2931.  
  2932. // document.addEventListener('player-dom-paused', (evt) => {
  2933. // console.log(evt.type)
  2934. // }, true)
  2935.  
  2936. // document.addEventListener('yt-show-toast', (evt) => {
  2937. // console.log(evt.type)
  2938. // }, true)
  2939. // document.addEventListener('yt-innertube-command', (evt) => {
  2940. // console.log(evt.type)
  2941. // }, true)
  2942. // document.addEventListener('yt-update-c3-companion', (evt) => {
  2943. // console.log(evt.type)
  2944. // }, true)
  2945. // document.addEventListener('video-progress', (evt) => {
  2946. // // console.log(evt.type)
  2947. // }, true)
  2948. // document.addEventListener('localmediachange', (evt) => {
  2949. // console.log(evt.type)
  2950. // }, true)
  2951.  
  2952.  
  2953.  
  2954. // window.addEventListener('player-initialized', (evt) => {
  2955. // console.log(evt.type)
  2956. // }, true)
  2957. // window.addEventListener('renderer-module-load-start', (evt) => {
  2958. // console.log(evt.type)
  2959. // }, true)
  2960. // window.addEventListener('video-data-change', (evt) => {
  2961. // console.log(evt.type)
  2962. // }, true)
  2963. // window.addEventListener('player-state-change', (evt) => {
  2964. // console.log(evt.type)
  2965. // }, true)
  2966. // window.addEventListener('updateui', (evt) => {
  2967. // console.log(evt.type)
  2968. // }, true)
  2969. // window.addEventListener('renderer-module-load-end', (evt) => {
  2970. // console.log(evt.type)
  2971. // }, true)
  2972.  
  2973. // window.addEventListener('player-autonav-pause', (evt) => {
  2974. // console.log(evt.type)
  2975. // }, true)
  2976.  
  2977.  
  2978.  
  2979. // window.addEventListener('player-ad-state-change', (evt) => {
  2980. // console.log(evt.type)
  2981. // }, true)
  2982.  
  2983. // window.addEventListener('player-detailed-error', (evt) => {
  2984. // console.log(evt.type)
  2985. // }, true)
  2986.  
  2987. // window.addEventListener('player-error', (evt) => {
  2988. // console.log(evt.type)
  2989. // }, true)
  2990.  
  2991. // window.addEventListener('on-play-autonav-video', (evt) => {
  2992. // console.log(evt.type)
  2993. // }, true)
  2994.  
  2995. // window.addEventListener('on-play-previous-autonav-video', (evt) => {
  2996. // console.log(evt.type)
  2997. // }, true)
  2998.  
  2999. // window.addEventListener('player-fullscreen-change', (evt) => {
  3000. // console.log(evt.type)
  3001. // }, true)
  3002.  
  3003. // window.addEventListener('player-fullscreen-toggled', (evt) => {
  3004. // console.log(evt.type)
  3005. // }, true)
  3006.  
  3007. // window.addEventListener('player-dom-paused', (evt) => {
  3008. // console.log(evt.type)
  3009. // }, true)
  3010.  
  3011. // window.addEventListener('yt-show-toast', (evt) => {
  3012. // console.log(evt.type)
  3013. // }, true)
  3014. // window.addEventListener('yt-innertube-command', (evt) => {
  3015. // console.log(evt.type)
  3016. // }, true)
  3017. // window.addEventListener('yt-update-c3-companion', (evt) => {
  3018. // console.log(evt.type)
  3019. // }, true)
  3020. // window.addEventListener('video-progress', (evt) => {
  3021. // // console.log(evt.type)
  3022. // }, true)
  3023. // window.addEventListener('localmediachange', (evt) => {
  3024. // console.log(evt.type)
  3025. // }, true)
  3026.  
  3027.  
  3028.  
  3029. // document.addEventListener('player-error', (evt) => {
  3030. // console.log(3001, evt.type, evt)
  3031. // }, true)
  3032. // document.addEventListener('player-detailed-error', (evt) => {
  3033. // console.log(3002, evt.type, evt)
  3034. // }, true)
  3035.  
  3036.  
  3037.  
  3038. async function delayRun(pr) {
  3039.  
  3040. let q = document.querySelector('#movie_player');
  3041. if (!q) return;
  3042. let a = document.querySelector('.video-stream.html5-main-video');
  3043. if (!a) return;
  3044.  
  3045. await pr.then();
  3046.  
  3047. if (fa !== 1) {
  3048. return;
  3049. } else if (a.muted === true) {
  3050. return;
  3051. } else if (a.muted === false && a.readyState === 0 && a.networkState === 2) {
  3052. if (a.paused === false) return;
  3053. } else {
  3054. return;
  3055. }
  3056.  
  3057. if (document.querySelector('.player-controls-content')) return;
  3058.  
  3059. if (a.paused === true && a.muted === false && a.readyState === 0 && a.networkState === 2) {
  3060.  
  3061. clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 }));
  3062.  
  3063. }
  3064.  
  3065. if (a.paused === true && a.muted === false && a.networkState === 2 && a.readyState === 0) {
  3066.  
  3067. if (typeof clickTarget.seekToLiveHead === 'function') await clickTarget.seekToLiveHead();
  3068. if (typeof clickTarget.isAtLiveHead === 'function' && (await clickTarget.isAtLiveHead()) === true) {
  3069. if (typeof clickTarget.seekToStreamTime === 'function') await clickTarget.seekToStreamTime();
  3070. }
  3071. }
  3072.  
  3073. }
  3074.  
  3075. durationchangeForMobile = true;
  3076.  
  3077. }
  3078.  
  3079.  
  3080. attachOneTimeEvent('yt-action', function () {
  3081. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  3082. ytConfigFix(config_);
  3083. });
  3084.  
  3085. let prepared = false;
  3086. function prepare() {
  3087. if (prepared) return;
  3088. prepared = true;
  3089.  
  3090. if (typeof _yt_player !== 'undefined' && _yt_player && typeof _yt_player === 'object') {
  3091.  
  3092. for (const [k, v] of Object.entries(_yt_player)) {
  3093.  
  3094. const p = typeof v === 'function' ? v.prototype : 0;
  3095.  
  3096. if (p
  3097. && typeof p.clone === 'function'
  3098. && typeof p.get === 'function' && typeof p.set === 'function'
  3099. && typeof p.isEmpty === 'undefined' && typeof p.forEach === 'undefined'
  3100. && typeof p.clear === 'undefined'
  3101. ) {
  3102.  
  3103. key = k;
  3104.  
  3105. }
  3106.  
  3107. }
  3108.  
  3109. }
  3110.  
  3111. if (key) {
  3112.  
  3113. const ClassX = _yt_player[key];
  3114. _yt_player[key] = class extends ClassX {
  3115. constructor(...args) {
  3116.  
  3117. if (typeof args[0] === 'string' && args[0].startsWith('http://')) args[0] = '';
  3118. super(...args);
  3119.  
  3120. }
  3121. }
  3122. _yt_player[key].luX1Y = 1;
  3123. prototypeInherit(_yt_player[key].prototype, ClassX.prototype);
  3124. }
  3125.  
  3126. }
  3127. let s3 = Symbol();
  3128.  
  3129. generalRegister('deviceIsAudioOnly', s3, (p) => {
  3130. return typeof p.getPlayerType === 'function' && typeof p.getVideoEmbedCode === 'function' && typeof p.getVideoUrl === 'function' && !p.onCueRangeEnter && !p.getVideoData && !('ATTRIBUTE_NODE' in p)
  3131. }, {
  3132.  
  3133. get() {
  3134. return this[s3];
  3135. },
  3136. set(nv) {
  3137. if (typeof nv === 'boolean') this[s3] = true;
  3138. else this[s3] = undefined;
  3139. prepare();
  3140. return true;
  3141. },
  3142. enumerable: false,
  3143. configurable: true
  3144.  
  3145. });
  3146.  
  3147.  
  3148. let s1 = Symbol();
  3149. let s2 = Symbol();
  3150. Object.defineProperty(Object.prototype, 'defraggedFromSubfragments', {
  3151. get() {
  3152. // console.log(501, this.constructor.prototype)
  3153. return undefined;
  3154. },
  3155. set(nv) {
  3156. return true;
  3157. },
  3158. enumerable: false,
  3159. configurable: true
  3160. });
  3161.  
  3162. Object.defineProperty(Object.prototype, 'hasSubfragmentedFmp4', {
  3163. get() {
  3164. // console.log(502, this.constructor.prototype)
  3165. return this[s1];
  3166. },
  3167. set(nv) {
  3168. if (typeof nv === 'boolean') this[s1] = false;
  3169. else this[s1] = undefined;
  3170. return true;
  3171. },
  3172. enumerable: false,
  3173. configurable: true
  3174. });
  3175.  
  3176. Object.defineProperty(Object.prototype, 'hasSubfragmentedWebm', {
  3177. get() {
  3178. // console.log(503, this.constructor.prototype)
  3179. return this[s2];
  3180. },
  3181. set(nv) {
  3182. if (typeof nv === 'boolean') this[s2] = false;
  3183. else this[s2] = undefined;
  3184. return true;
  3185. },
  3186. enumerable: false,
  3187. configurable: true
  3188. });
  3189.  
  3190.  
  3191. const supportedFormatsConfig = () => {
  3192.  
  3193. function typeTest(type) {
  3194. if (typeof type === 'string' && type.startsWith('video/')) {
  3195. return false;
  3196. }
  3197. }
  3198.  
  3199. // return a custom MIME type checker that can defer to the original function
  3200. function makeModifiedTypeChecker(origChecker) {
  3201. // Check if a video type is allowed
  3202. return function (type) {
  3203. let res = undefined;
  3204. if (type === undefined) res = false;
  3205. else {
  3206. res = typeTest.call(this, type);
  3207. }
  3208. if (res === undefined) res = origChecker.apply(this, arguments);
  3209. return res;
  3210. };
  3211. }
  3212.  
  3213. // Override video element canPlayType() function
  3214. const proto = (HTMLVideoElement || 0).prototype;
  3215. if (proto && typeof proto.canPlayType == 'function') {
  3216. proto.canPlayType = makeModifiedTypeChecker(proto.canPlayType);
  3217. }
  3218.  
  3219. // Override media source extension isTypeSupported() function
  3220. const mse = window.MediaSource;
  3221. // Check for MSE support before use
  3222. if (mse && typeof mse.isTypeSupported == 'function') {
  3223. mse.isTypeSupported = makeModifiedTypeChecker(mse.isTypeSupported);
  3224. }
  3225.  
  3226. };
  3227.  
  3228. supportedFormatsConfig();
  3229.  
  3230.  
  3231. ; (async () => {
  3232.  
  3233.  
  3234. const _yt_player_observable = observablePromise(() => {
  3235. return (((window || 0)._yt_player || 0) || 0);
  3236. });
  3237.  
  3238.  
  3239. const addProtoToArr = (parent, key, arr) => {
  3240.  
  3241.  
  3242. let isChildProto = false;
  3243. for (const sr of arr) {
  3244. if (parent[key].prototype instanceof parent[sr]) {
  3245. isChildProto = true;
  3246. break;
  3247. }
  3248. }
  3249.  
  3250. if (isChildProto) return;
  3251.  
  3252. arr = arr.filter(sr => {
  3253. if (parent[sr].prototype instanceof parent[key]) {
  3254. return false;
  3255. }
  3256. return true;
  3257. });
  3258.  
  3259. arr.push(key);
  3260.  
  3261. return arr;
  3262.  
  3263.  
  3264. };
  3265.  
  3266. const getEntriesForPlayerInterfaces = (_yt_player) => {
  3267.  
  3268. const entries = Object.entries(_yt_player);
  3269.  
  3270. const arr = new Array(entries.length);
  3271. let arrI = 0;
  3272.  
  3273. for (const entry of entries) {
  3274. const [k, v] = entry;
  3275.  
  3276. const p = typeof v === 'function' ? v.prototype : 0;
  3277. if (p) {
  3278.  
  3279. const b = (
  3280. typeof p.cancelPlayback === 'function' ||
  3281. typeof p.stopVideo === 'function' ||
  3282. typeof p.pauseVideo === 'function' ||
  3283. typeof p.playVideo === 'function' ||
  3284. typeof p.getPlayerStateObject === 'function'
  3285. );
  3286. if (b) arr[arrI++] = entry;
  3287. }
  3288. }
  3289.  
  3290. arr.length = arrI;
  3291. return arr;
  3292.  
  3293.  
  3294. }
  3295.  
  3296.  
  3297. const getKeyPlayerDap = (_yt_player, filteredEntries) => {
  3298. // one is quu (this.app.getPlayerStateObject(p))
  3299. // one is standardApp (return this.getPresentingPlayerType()===3?R$(this.C7).g7:g.O5(this,p).getPlayerState())
  3300.  
  3301.  
  3302. const w = 'keyPlayerDap';
  3303.  
  3304. let arr = [];
  3305. let brr = new Map();
  3306.  
  3307. for (const [k, v] of filteredEntries) {
  3308.  
  3309. const p = typeof v === 'function' ? v.prototype : 0;
  3310. if (p) {
  3311.  
  3312. let q = 0;
  3313.  
  3314. if (typeof p.cancelPlayback === 'function') q += 50;
  3315. if (typeof p.stopVideo === 'function') q += 50;
  3316. if (typeof p.pauseVideo === 'function') q += 50;
  3317. if (typeof p.playVideo === 'function') q += 50;
  3318. if (typeof p.getPlayerStateObject === 'function') q += 50;
  3319.  
  3320. if (q < 250) continue;
  3321.  
  3322. if (typeof p.cancelPlayback === 'function' && p.cancelPlayback.length === 0) q += 20;
  3323. if (typeof p.stopVideo === 'function' && p.stopVideo.length === 1) q += 20;
  3324. if (typeof p.pauseVideo === 'function' && p.pauseVideo.length === 1) q += 20;
  3325. if (typeof p.playVideo === 'function' && p.playVideo.length === 2) q += 20;
  3326. if (typeof p.getPlayerStateObject === 'function' && p.getPlayerStateObject.length === 1) q += 20;
  3327.  
  3328.  
  3329. if (typeof p.isBackground === 'function') q -= 5;
  3330. if (typeof p.isBackground === 'function' && p.isBackground.length === 0) q -= 2;
  3331.  
  3332. if (typeof p.getPlaybackRate === 'function') q += 25;
  3333. if (typeof p.getPlaybackRate === 'function' && p.getPlaybackRate.length === 0) q += 15;
  3334.  
  3335. if (typeof p.publish === 'function') q += 25;
  3336. if (typeof p.publish === 'function' && p.publish.length === 1) q += 15;
  3337.  
  3338. if (typeof p.addEventListener === 'function') q += 40;
  3339. if (typeof p.addEventListener === 'function' && p.addEventListener.length === 2) q += 25;
  3340. if (typeof p.removeEventListener === 'function') q += 40;
  3341. if (typeof p.removeEventListener === 'function' && p.removeEventListener.length === 2) q += 25;
  3342.  
  3343. if (q > 0) arr = addProtoToArr(_yt_player, k, arr) || arr;
  3344.  
  3345. if (q > 0) brr.set(k, q);
  3346.  
  3347. }
  3348.  
  3349.  
  3350. }
  3351.  
  3352. if (arr.length === 0) {
  3353.  
  3354. console.warn(`[yt-audio-only] (key-extraction) Key does not exist (1). [${w}]`);
  3355. } else {
  3356.  
  3357. arr = arr.map(key => [key, (brr.get(key) || 0)]);
  3358.  
  3359. if (arr.length > 1) arr.sort((a, b) => b[1] - a[1]);
  3360.  
  3361. let match = null;
  3362. for (const [key, _] of arr) {
  3363. const p = _yt_player[key].prototype
  3364. const f = (p ? p.getPlayerStateObject : null) || 0;
  3365. if (f) {
  3366. const o = {};
  3367. const w = new Proxy({}, {
  3368. get(target, p) {
  3369. o[p] = 1;
  3370. return w;
  3371. },
  3372. set(target, p, v) {
  3373. return true;
  3374. }
  3375. });
  3376. try {
  3377. f.call(w)
  3378. } catch (e) { }
  3379. if (o.app) {
  3380. match = key;
  3381. }
  3382. }
  3383. }
  3384.  
  3385.  
  3386. if (!match) {
  3387.  
  3388. console.warn(`[yt-audio-only] (key-extraction) Key does not exist (2). [${w}]`);
  3389.  
  3390. } else {
  3391. return match;
  3392. }
  3393.  
  3394. }
  3395.  
  3396.  
  3397.  
  3398. }
  3399.  
  3400. const getKeyStandardApp = (_yt_player, filteredEntries) => {
  3401. // one is quu (this.app.getPlayerStateObject(p))
  3402. // one is standardApp (return this.getPresentingPlayerType()===3?R$(this.C7).g7:g.O5(this,p).getPlayerState())
  3403.  
  3404.  
  3405. const w = 'keyStandardApp';
  3406.  
  3407. let arr = [];
  3408. let brr = new Map();
  3409.  
  3410. for (const [k, v] of filteredEntries) {
  3411.  
  3412. const p = typeof v === 'function' ? v.prototype : 0;
  3413. if (p) {
  3414.  
  3415. let q = 0;
  3416.  
  3417. if (typeof p.cancelPlayback === 'function') q += 50;
  3418. if (typeof p.stopVideo === 'function') q += 50;
  3419. if (typeof p.pauseVideo === 'function') q += 50;
  3420. if (typeof p.playVideo === 'function') q += 50;
  3421. if (typeof p.getPlayerStateObject === 'function') q += 50;
  3422.  
  3423. if (q < 250) continue;
  3424.  
  3425. if (typeof p.cancelPlayback === 'function' && p.cancelPlayback.length === 2) q += 20;
  3426. if (typeof p.stopVideo === 'function' && p.stopVideo.length === 1) q += 20;
  3427. if (typeof p.pauseVideo === 'function' && p.pauseVideo.length === 2) q += 20;
  3428. if (typeof p.playVideo === 'function' && p.playVideo.length === 2) q += 20;
  3429. if (typeof p.getPlayerStateObject === 'function' && p.getPlayerStateObject.length === 1) q += 20;
  3430.  
  3431.  
  3432. if (typeof p.isBackground === 'function') q -= 5;
  3433. if (typeof p.isBackground === 'function' && p.isBackground.length === 0) q -= 2;
  3434.  
  3435. if (typeof p.getPlaybackRate === 'function') q -= 5;
  3436. if (typeof p.getPlaybackRate === 'function' && p.getPlaybackRate.length === 0) q -= 2;
  3437.  
  3438. if (typeof p.publish === 'function') q -= 5;
  3439. if (typeof p.publish === 'function' && p.publish.length === 2) q -= 2;
  3440.  
  3441. if (typeof p.addEventListener === 'function') q -= 5;
  3442. if (typeof p.addEventListener === 'function' && p.addEventListener.length === 2) q -= 2;
  3443. if (typeof p.removeEventListener === 'function') q -= 5;
  3444. if (typeof p.removeEventListener === 'function' && p.removeEventListener.length === 2) q -= 2;
  3445.  
  3446.  
  3447. if (q > 0) arr = addProtoToArr(_yt_player, k, arr) || arr;
  3448.  
  3449. if (q > 0) brr.set(k, q);
  3450.  
  3451. }
  3452.  
  3453.  
  3454. }
  3455.  
  3456. if (arr.length === 0) {
  3457.  
  3458. console.warn(`[yt-audio-only] (key-extraction) Key does not exist (1). [${w}]`);
  3459. } else {
  3460.  
  3461. arr = arr.map(key => [key, (brr.get(key) || 0)]);
  3462.  
  3463. if (arr.length > 1) arr.sort((a, b) => b[1] - a[1]);
  3464.  
  3465. let match = null;
  3466. for (const [key, _] of arr) {
  3467. const p = _yt_player[key].prototype
  3468. const f = (p ? p.getPlayerStateObject : null) || 0;
  3469. if (f) {
  3470. const o = {};
  3471. const w = new Proxy({}, {
  3472. get(target, p) {
  3473. o[p] = 1;
  3474. return w;
  3475. },
  3476. set(target, p, v) {
  3477. return true;
  3478. }
  3479. });
  3480. try {
  3481. f.call(w)
  3482. } catch (e) { }
  3483. if (!o.app) {
  3484. match = key;
  3485. }
  3486. }
  3487. }
  3488.  
  3489.  
  3490. if (!match) {
  3491.  
  3492. console.warn(`[yt-audio-only] (key-extraction) Key does not exist (2). [${w}]`);
  3493.  
  3494. } else {
  3495. return match;
  3496. }
  3497.  
  3498. }
  3499.  
  3500.  
  3501.  
  3502. }
  3503.  
  3504.  
  3505. const getKeyInternalApp = (_yt_player, filteredEntries) => {
  3506. // internalApp
  3507.  
  3508. const w = 'keyInternalApp';
  3509.  
  3510. let arr = [];
  3511. let brr = new Map();
  3512.  
  3513. for (const [k, v] of filteredEntries) {
  3514.  
  3515. const p = typeof v === 'function' ? v.prototype : 0;
  3516. if (p) {
  3517.  
  3518. let q = 0;
  3519.  
  3520. if (typeof p.stopVideo === 'function') q += 1;
  3521. if (typeof p.playVideo === 'function') q += 1;
  3522. if (typeof p.pauseVideo === 'function') q += 1;
  3523.  
  3524. if (q < 2) continue;
  3525.  
  3526. if (typeof p.isBackground === 'function') q += 120;
  3527. if (typeof p.getPlaybackRate === 'function') q += 50;
  3528. // if (typeof p.publish === 'function') q += 50;
  3529. if (typeof p.isAtLiveHead === 'function') q += 50;
  3530. if (typeof p.getVideoData === 'function') q += 10;
  3531. if (typeof p.getVolume === 'function') q += 10;
  3532. if (typeof p.getStreamTimeOffset === 'function') q += 10;
  3533. if (typeof p.getPlayerType === 'function') q += 10;
  3534. if (typeof p.getPlayerState === 'function') q += 10;
  3535. if (typeof p.getPlayerSize === 'function') q += 10;
  3536. if (typeof p.cancelPlayback === 'function') q -= 4;
  3537.  
  3538. if (q < 10) continue;
  3539.  
  3540. if ('mediaElement' in p) q += 50;
  3541. if ('videoData' in p) q += 50;
  3542. if ('visibility' in p) q += 50;
  3543.  
  3544. if (typeof p.isBackground === 'function' && p.isBackground.length === 0) q += 20;
  3545. if (typeof p.getPlaybackRate === 'function' && p.getPlaybackRate.length === 0) q += 20;
  3546. if (typeof p.publish === 'function' && p.publish.length === 2) q += 18;
  3547. if (typeof p.isAtLiveHead === 'function' && p.isAtLiveHead.length === 2) q += 18;
  3548.  
  3549. if (q > 0) arr = addProtoToArr(_yt_player, k, arr) || arr;
  3550.  
  3551. if (q > 0) brr.set(k, q);
  3552.  
  3553. }
  3554.  
  3555.  
  3556. }
  3557.  
  3558. if (arr.length === 0) {
  3559.  
  3560. console.warn(`[yt-audio-only] (key-extraction) Key does not exist. [${w}]`);
  3561. } else {
  3562.  
  3563. arr = arr.map(key => [key, (brr.get(key) || 0)]);
  3564.  
  3565. if (arr.length > 1) arr.sort((a, b) => b[1] - a[1]);
  3566.  
  3567. if (arr.length > 2) console.log(`[yt-audio-only] (key-extraction) [${w}]`, arr);
  3568. return arr[0][0];
  3569. }
  3570.  
  3571.  
  3572.  
  3573. };
  3574.  
  3575.  
  3576. (async () => {
  3577. // rAf scheduling
  3578.  
  3579. const _yt_player = await _yt_player_observable.obtain();
  3580.  
  3581. if (!_yt_player || typeof _yt_player !== 'object') return;
  3582.  
  3583. window.ktg = _yt_player;
  3584.  
  3585. // console.log(keys0)
  3586.  
  3587. const entriesForPlayerInterfaces = getEntriesForPlayerInterfaces(_yt_player);
  3588.  
  3589. const keyPlayerDap = getKeyPlayerDap(_yt_player, entriesForPlayerInterfaces)
  3590. const keyStandardApp = getKeyStandardApp(_yt_player, entriesForPlayerInterfaces)
  3591. const keyInternalApp = getKeyInternalApp(_yt_player, entriesForPlayerInterfaces);
  3592.  
  3593. console.log('[yt-audio-only] key obtained', [keyPlayerDap, keyStandardApp, keyInternalApp]);
  3594.  
  3595. if (!keyPlayerDap || !keyStandardApp || !keyInternalApp) {
  3596. console.warn('[yt-audio-only] key failure', [keyPlayerDap, keyStandardApp, keyInternalApp]);
  3597. }
  3598.  
  3599.  
  3600. if (keyPlayerDap) {
  3601. const playerDapCT = _yt_player[keyPlayerDap];
  3602. if (typeof playerDapCT === 'function') {
  3603. const playerDapPT = playerDapCT.prototype;
  3604. playerDapPTFn(playerDapPT);
  3605. }
  3606. }
  3607.  
  3608.  
  3609. if (keyStandardApp) {
  3610. const standardAppCT = _yt_player[keyStandardApp];
  3611. if (typeof standardAppCT === 'function') {
  3612. const standardAppPT = standardAppCT.prototype;
  3613. standardAppPTFn(standardAppPT);
  3614. }
  3615. }
  3616.  
  3617. if (keyInternalApp) {
  3618. const internalAppCT = _yt_player[keyInternalApp];
  3619. if (typeof internalAppCT === 'function') {
  3620. const internalAppPT = internalAppCT.prototype;
  3621. internalAppPTFn(internalAppPT);
  3622. }
  3623. }
  3624.  
  3625.  
  3626.  
  3627. })();
  3628.  
  3629. })();
  3630.  
  3631.  
  3632. //# sourceURL=debug://userscript/yt-audio-only.js
  3633.  
  3634.  
  3635. }
  3636.  
  3637. const getVideoIdByURL = () => {
  3638. // It's almost certainly going to stay at 11 characters. The individual characters come from a set of 64 possibilities (A-Za-z0-9_-).
  3639. // base64 form; 26+26+10+2; 64^len
  3640. // Math.pow(64,11) = 73786976294838210000
  3641.  
  3642. const url = new URL(location.href);
  3643. let m;
  3644.  
  3645. if (m = /^\/watch\?v=([A-Za-z0-9_-]+)/.exec(`${url.pathname}?v=${url.searchParams.get('v')}`)) return `${m[1]}`;
  3646. if (m = /^\/live\/([A-Za-z0-9_-]+)/.exec(url.pathname)) return `${m[1]}`;
  3647.  
  3648. if (m = /^\/embed\/live_stream\?channel=([A-Za-z0-9_-]+)/.exec(`${url.pathname}?channel=${url.searchParams.get('channel')}`)) return `L:${m[1]}`;
  3649. if (m = /^\/embed\/([A-Za-z0-9_-]+)/.exec(url.pathname)) return `${m[1]}`;
  3650.  
  3651. if (m = /^\/channel\/([A-Za-z0-9_-]+)\/live\b/.exec(url.pathname)) return `L:${m[1]}`;
  3652. if (url.hostname === 'youtu.be' && (m = /\/([A-Za-z0-9_-]+)/.exec(url.pathname))) return `${m[1]}`;
  3653.  
  3654. return '';
  3655.  
  3656. };
  3657.  
  3658. const getVideoIdByElement = () => {
  3659. const videoIdElements = [...document.querySelectorAll('[video-id]')].filter(v => !v.closest('[hidden]'));
  3660. const videoId = videoIdElements.length > 0 ? videoIdElements[0].getAttribute('video-id') : null;
  3661. return videoId || '';
  3662. };
  3663.  
  3664. const getEnableValue = async () => {
  3665. const videoId = getVideoIdByURL() || getVideoIdByElement();
  3666. const siteVal = videoId ? await GM.getValue(`isEnable_aWsjF_${videoId}`, null) : null;
  3667. return (siteVal !== null) ? siteVal : await GM.getValue("isEnable_aWsjF", true);
  3668. };
  3669.  
  3670. const setEnableVal = async (val) => {
  3671. const videoId = getVideoIdByURL() || getVideoIdByElement();
  3672. if (videoId) {
  3673. try {
  3674. const cv = await GM.getValue(`isEnable_aWsjF_${videoId}`, null);
  3675. if (typeof cv === typeof val) await GM.setValue(`isEnable_aWsjF_${videoId}`, val);
  3676. } catch (e) { }
  3677. }
  3678. await GM.setValue("isEnable_aWsjF", val);
  3679. }
  3680.  
  3681. const isEnable = (typeof GM !== 'undefined' && typeof GM.getValue === 'function') ? await getEnableValue() : null;
  3682. if (typeof isEnable !== 'boolean') throw new DOMException("Please Update your browser", "NotSupportedError");
  3683. if (isEnable) {
  3684. const element = document.createElement('button');
  3685. element.setAttribute('onclick', createHTML(`(${pageInjectionCode})()`));
  3686. element.click();
  3687. }
  3688.  
  3689. GM_registerMenuCommand(`Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`, async function () {
  3690. await setEnableVal(!isEnable);
  3691. await GM.setValue('lastCheck_bWsm5', Date.now());
  3692. document.documentElement.setAttribute('forceRefresh032', '');
  3693. location.reload();
  3694. });
  3695.  
  3696. let messageCount = 0;
  3697. let busy = false;
  3698. window.addEventListener('message', (evt) => {
  3699.  
  3700. const v = ((evt || 0).data || 0).ZECxh;
  3701. if (typeof v === 'boolean') {
  3702. if (messageCount > 1e9) messageCount = 9;
  3703. const t = ++messageCount;
  3704. if (v && isEnable) {
  3705. requestAnimationFrame(async () => {
  3706. if (t !== messageCount) return;
  3707. if (busy) return;
  3708. busy = true;
  3709. if (await confirm("Livestream is detected. Press OK to disable YouTube Audio Mode.")) {
  3710. await setEnableVal(!isEnable);
  3711. await GM.setValue('lastCheck_bWsm5', Date.now());
  3712. document.documentElement.setAttribute('forceRefresh032', '');
  3713. location.reload();
  3714. }
  3715. busy = false;
  3716. });
  3717. }
  3718. }
  3719.  
  3720. });
  3721.  
  3722.  
  3723. const pLoad = new Promise(resolve => {
  3724. if (document.readyState !== 'loading') {
  3725. resolve();
  3726. } else {
  3727. window.addEventListener("DOMContentLoaded", resolve, false);
  3728. }
  3729. });
  3730.  
  3731.  
  3732. function contextmenuInfoItemAppearedFn(target) {
  3733.  
  3734. const btn = target.closest('.ytp-menuitem[role="menuitem"]');
  3735. if (!btn) return;
  3736. if (btn.parentNode.querySelector('.ytp-menuitem[role="menuitem"].audio-only-toggle-btn')) return;
  3737. document.documentElement.classList.add('with-audio-only-toggle-btn');
  3738. const newBtn = btn.cloneNode(true)
  3739. newBtn.querySelector('.ytp-menuitem-label').textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`;
  3740. newBtn.classList.add('audio-only-toggle-btn');
  3741. btn.parentNode.insertBefore(newBtn, btn.nextSibling);
  3742. newBtn.addEventListener('click', async (evt) => {
  3743. try {
  3744. evt.stopPropagation();
  3745. evt.stopImmediatePropagation();
  3746. } catch (e) { }
  3747. await setEnableVal(!isEnable);
  3748. await GM.setValue('lastCheck_bWsm5', Date.now());
  3749. document.documentElement.setAttribute('forceRefresh032', '');
  3750. location.reload();
  3751. });
  3752. let t;
  3753. let h = 0;
  3754. t = btn.closest('.ytp-panel-menu[style*="height"]');
  3755. if (t) t.style.height = t.scrollHeight + 'px';
  3756. t = btn.closest('.ytp-panel[style*="height"]');
  3757. if (t) t.style.height = (h = t.scrollHeight) + 'px';
  3758. t = btn.closest('.ytp-popup.ytp-contextmenu[style*="height"]');
  3759. if (t && h > 0) t.style.height = h + 'px';
  3760. }
  3761.  
  3762.  
  3763. function mobileMenuItemAppearedFn(target) {
  3764.  
  3765. const btn = target.closest('ytm-menu-item');
  3766. if (!btn) return;
  3767. if (btn.parentNode.querySelector('ytm-menu-item.audio-only-toggle-btn')) return;
  3768. document.documentElement.classList.add('with-audio-only-toggle-btn');
  3769. const newBtn = btn.cloneNode(true);
  3770. newBtn.querySelector('.menu-item-button').textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`;
  3771. newBtn.classList.add('audio-only-toggle-btn');
  3772. btn.parentNode.insertBefore(newBtn, btn.nextSibling);
  3773. newBtn.addEventListener('click', async (evt) => {
  3774. try {
  3775. evt.stopPropagation();
  3776. evt.stopImmediatePropagation();
  3777. } catch (e) { }
  3778. await setEnableVal(!isEnable);
  3779. await GM.setValue('lastCheck_bWsm5', Date.now());
  3780. document.documentElement.setAttribute('forceRefresh032', '');
  3781. location.reload();
  3782. });
  3783. }
  3784.  
  3785. const lastEntry = (arr) => {
  3786. return arr.length > 0 ? arr[arr.length - 1] : null;
  3787. }
  3788.  
  3789. function mobileMenuItemAppearedV2Fn(target) {
  3790.  
  3791. const btn = target.closest('yt-list-item-view-model');
  3792. if (!(btn instanceof HTMLElement)) return;
  3793. if (btn.parentNode.querySelector('yt-list-item-view-model.audio-only-toggle-btn')) return;
  3794. const parentNode = btn.closest('player-settings-menu');
  3795. if (!parentNode) return;
  3796. let qt = 1E9;
  3797. let targetBtnO = lastEntry([...parentNode.getElementsByTagName(btn.nodeName)].filter(e => e.parentElement === btn.parentElement).map((elm) => {
  3798. const count = elm.getElementsByTagName('*').length;
  3799. if (count < qt) qt = count;
  3800. return {
  3801. elm: elm,
  3802. count: count
  3803. }
  3804. }).filter((o) => o.count === qt));
  3805.  
  3806. const targetBtn = targetBtnO && targetBtnO.elm instanceof HTMLElement ? targetBtnO.elm : btn;
  3807.  
  3808.  
  3809. const newBtn = targetBtn.cloneNode(true);
  3810. if (newBtn instanceof HTMLElement) {
  3811. document.documentElement.classList.add('with-audio-only-toggle-btn');
  3812.  
  3813. let newBtnContentElm = newBtn;
  3814. let layerCN = 8;
  3815. while (newBtnContentElm.childElementCount === 1 && layerCN--) {
  3816. newBtnContentElm = newBtnContentElm.firstElementChild;
  3817. }
  3818. if (!(newBtnContentElm instanceof HTMLElement)) newBtnContentElm = newBtn;
  3819. let t;
  3820. if (t = lastEntry(newBtnContentElm.querySelectorAll('span[role="text"]'))) {
  3821. newBtnContentElm = t;
  3822. newBtnContentElm.classList.add('audio-only-toggle-btn-content2');
  3823. } else if (t = lastEntry(newBtnContentElm.querySelectorAll('[role="text"]'))) {
  3824. newBtnContentElm = t;
  3825. newBtnContentElm.classList.add('audio-only-toggle-btn-content2');
  3826. } else if (t = lastEntry(newBtnContentElm.querySelectorAll('span'))) {
  3827. newBtnContentElm = t;
  3828. newBtnContentElm.classList.add('audio-only-toggle-btn-content2');
  3829. } else if (t = lastEntry(newBtnContentElm.querySelector('.yt-core-attributed-string'))) {
  3830. newBtnContentElm = t;
  3831. newBtnContentElm.classList.add('audio-only-toggle-btn-content2');
  3832. }
  3833. newBtnContentElm.textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`;
  3834. newBtn.classList.add('audio-only-toggle-btn');
  3835. newBtnContentElm.classList.add('audio-only-toggle-btn-content');
  3836. btn.parentNode.insertBefore(newBtn, btn.nextSibling);
  3837. newBtn.addEventListener('click', async (evt) => {
  3838. try {
  3839. evt.stopPropagation();
  3840. evt.stopImmediatePropagation();
  3841. } catch (e) { }
  3842. await setEnableVal(!isEnable);
  3843. await GM.setValue('lastCheck_bWsm5', Date.now());
  3844. document.documentElement.setAttribute('forceRefresh032', '');
  3845. location.reload();
  3846. });
  3847. const contentWrapper = newBtn.closest('#content-wrapper');
  3848. if (contentWrapper) {
  3849. contentWrapper.style.height = 'unset';
  3850. contentWrapper.style.maxHeight = 'unset';
  3851. }
  3852. }
  3853. }
  3854.  
  3855. pLoad.then(() => {
  3856.  
  3857. document.addEventListener('animationstart', (evt) => {
  3858. const animationName = evt.animationName;
  3859. if (!animationName) return;
  3860.  
  3861. if (animationName === 'contextmenuInfoItemAppeared') contextmenuInfoItemAppearedFn(evt.target);
  3862. if (animationName === 'mobileMenuItemAppeared') mobileMenuItemAppearedFn(evt.target);
  3863. if (animationName === 'mobileMenuItemAppearedV2') mobileMenuItemAppearedV2Fn(evt.target);
  3864.  
  3865. }, true);
  3866.  
  3867. const cssForEnabled = isEnable ? `
  3868.  
  3869. .html5-video-player {
  3870. background-color: black;
  3871. }
  3872.  
  3873. [style*="--audio-only-thumbnail-image"]{
  3874. background-image: var(--audio-only-thumbnail-image);
  3875. object-fit: contain;
  3876. background-position: center;
  3877. background-size: contain;
  3878. background-repeat: no-repeat;
  3879. }
  3880. .html5-video-player.ended-mode [style*="--audio-only-thumbnail-image"]{
  3881. background-image: none;
  3882. }
  3883.  
  3884. .html5-video-player.ytp-ce-shown .html5-video-container {
  3885. opacity: 0.5;
  3886. transition: opacity 0.5s;
  3887. }
  3888.  
  3889. ytd-video-preview #media-container div#player-container,
  3890. ytd-video-preview #media-container div#thumbnail-container{
  3891. transition: initial !important;
  3892. transition-duration:0ms !important;
  3893. transition-delay:0ms !important;
  3894. }
  3895. ytd-video-preview #media-container div#thumbnail-container{
  3896. /* pointer-events:none !important; */
  3897. opacity:0;
  3898. /* z-index:-1; */
  3899. }
  3900. ytd-video-preview #media-container div#player-container,
  3901. ytd-video-preview #media-container div#inline-preview-player{
  3902. background-color:transparent !important;
  3903. background-image:none !important;
  3904. }
  3905.  
  3906. #movie_player > .html5-video-container:not(:empty) {
  3907. box-sizing: border-box;
  3908. height: 100%;
  3909. }
  3910.  
  3911. #movie_player [style*="--audio-only-thumbnail-image"] ~ .ytp-cued-thumbnail-overlay > .ytp-cued-thumbnail-overlay-image[style*="background-image"] {
  3912. opacity: 0;
  3913. }
  3914.  
  3915. #movie_player [style*="--audio-only-thumbnail-image"]::before {
  3916. content: '';
  3917. display: block;
  3918. position: absolute;
  3919. left: 0;
  3920. top: 0;
  3921. bottom: 0;
  3922. right: 0;
  3923. /* background: transparent; */
  3924.  
  3925.  
  3926. /* We use multiple backgrounds: one gradient per side */
  3927. background:
  3928. /* Left border gradient */
  3929. linear-gradient(to right, rgba(0,0,0,0.4), transparent) left center,
  3930. /* Right border gradient */
  3931. linear-gradient(to left, rgba(0,0,0,0.4), transparent) right center,
  3932. /* Top border gradient */
  3933. linear-gradient(to bottom, rgba(0,0,0,0.4), transparent) center top,
  3934. /* Bottom border gradient */
  3935. linear-gradient(to top, rgba(0,0,0,0.4), transparent) center bottom;
  3936.  
  3937. /* Prevents repetition of gradients */
  3938. background-repeat: no-repeat;
  3939.  
  3940. /* Set the size of each gradient "border" */
  3941. background-size:
  3942. 12% 100%, /* left border width and full height */
  3943. 12% 100%, /* right border width and full height */
  3944. 100% 12%, /* top border full width and small height */
  3945. 100% 12%; /* bottom border full width and small height */
  3946.  
  3947. /* Optional: a base background color inside the element */
  3948. /* background-color: #fff; */
  3949. /* background-color: var(--blinker-fmw83-bgc, transparent); */
  3950.  
  3951. opacity: var(--fmw83-opacity, 1);
  3952.  
  3953. pointer-events: none !important;
  3954. z-index:-1;
  3955.  
  3956. }
  3957.  
  3958. /*
  3959. @keyframes blinker-fmw83 {
  3960. 0%, 60%, 100% {
  3961. opacity: 1;
  3962. }
  3963. 30% {
  3964. opacity: 0.96;
  3965. }
  3966. }
  3967. */
  3968.  
  3969.  
  3970. #movie_player.playing-mode [style*="--audio-only-thumbnail-image"]{
  3971. /* animation: blinker-fmw83 1.74s linear infinite; */
  3972. --fmw83-opacity: 0.6;
  3973.  
  3974. }
  3975.  
  3976. #global-loader ytw-scrim {
  3977. display: none;
  3978. }
  3979.  
  3980. `: "";
  3981.  
  3982. const style = document.createElement('style');
  3983. style.id = 'fm9v0';
  3984. style.textContent = `
  3985.  
  3986. ${cssForEnabled}
  3987.  
  3988. @keyframes mobileMenuItemAppeared {
  3989. 0% {
  3990. background-position-x: 3px;
  3991. }
  3992. 100% {
  3993. background-position-x: 4px;
  3994. }
  3995. }
  3996.  
  3997. @keyframes mobileMenuItemAppearedV2 {
  3998. 0% {
  3999. background-position-x: 3px;
  4000. }
  4001. 100% {
  4002. background-position-x: 4px;
  4003. }
  4004. }
  4005. ytm-select.player-speed-settings ~ ytm-menu-item:last-of-type {
  4006. animation: mobileMenuItemAppeared 1ms linear 0s 1 normal forwards;
  4007. }
  4008.  
  4009. player-settings-menu > yt-list-item-view-model:last-of-type {
  4010. animation: mobileMenuItemAppearedV2 1ms linear 0s 1 normal forwards;
  4011. }
  4012.  
  4013.  
  4014. player-settings-menu .audio-only-toggle-btn-content {
  4015. padding: 14px 24px;
  4016. box-sizing: border-box;
  4017. font-size: 130%;
  4018. }
  4019.  
  4020. player-settings-menu .audio-only-toggle-btn-content2 {
  4021. padding: 0;
  4022. box-sizing: border-box;
  4023. font-size: inherit;
  4024. }
  4025.  
  4026.  
  4027. @keyframes contextmenuInfoItemAppeared {
  4028. 0% {
  4029. background-position-x: 3px;
  4030. }
  4031. 100% {
  4032. background-position-x: 4px;
  4033. }
  4034. }
  4035. .ytp-contextmenu .ytp-menuitem[role="menuitem"] path[d^="M22 34h4V22h-4v12zm2-30C12.95"]{
  4036. animation: contextmenuInfoItemAppeared 1ms linear 0s 1 normal forwards;
  4037. }
  4038. #confirmDialog794 {
  4039. z-index:999999 !important;
  4040. display: none;
  4041. /* Hidden by default */
  4042. position: fixed;
  4043. /* Stay in place */
  4044. z-index: 1;
  4045. /* Sit on top */
  4046. left: 0;
  4047. top: 0;
  4048. width: 100%;
  4049. /* Full width */
  4050. height: 100%;
  4051. /* Full height */
  4052. overflow: auto;
  4053. /* Enable scroll if needed */
  4054. background-color: rgba(0,0,0,0.4);
  4055. /* Black w/ opacity */
  4056. }
  4057. #confirmDialog794 .confirm-box {
  4058. position:relative;
  4059. color: black;
  4060. z-index:999999 !important;
  4061. background-color: #fefefe;
  4062. margin: 15% auto;
  4063. /* 15% from the top and centered */
  4064. padding: 20px;
  4065. border: 1px solid #888;
  4066. width: 30%;
  4067. /* Could be more or less, depending on screen size */
  4068. box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
  4069. }
  4070. #confirmDialog794 .confirm-buttons {
  4071. text-align: right;
  4072. }
  4073. #confirmDialog794 button {
  4074. margin-left: 10px;
  4075. }
  4076.  
  4077. `
  4078. document.head.appendChild(style);
  4079.  
  4080. });
  4081.  
  4082.  
  4083. const pNavigateFinished = new Promise(resolve => {
  4084. document.addEventListener('yt-navigate-finish', resolve, true);
  4085. });
  4086.  
  4087. pNavigateFinished.then(() => {
  4088. const inputs = document.querySelectorAll('#masthead input[type="text"][name]');
  4089.  
  4090. let lastInputTextValue = null;
  4091. let busy = false;
  4092. let disableMonitoring = false;
  4093. const setGV = async (val) => {
  4094.  
  4095. const videoId = getVideoIdByURL() || getVideoIdByElement();
  4096. if (videoId) {
  4097. const cgv = await GM.getValue(`isEnable_aWsjF_${videoId}`, null);
  4098. if (cgv !== val || isEnable !== val) {
  4099. disableMonitoring = true;
  4100. await GM.setValue(`isEnable_aWsjF_${videoId}`, val);
  4101. await GM.setValue('lastCheck_bWsm5', Date.now());
  4102. document.documentElement.setAttribute('forceRefresh032', '');
  4103. location.reload();
  4104. }
  4105.  
  4106. }
  4107. }
  4108. const checkTextChangeF = async (evt) => {
  4109. busy = false;
  4110. const inputElem = (evt || 0).target;
  4111. if (inputElem instanceof HTMLInputElement && !disableMonitoring) {
  4112. const cv = inputElem.value;
  4113. if (cv === lastInputTextValue) return;
  4114. lastInputTextValue = cv;
  4115. if (cv === 'vvv') {
  4116.  
  4117. await setGV(false);
  4118.  
  4119. } else if (cv === 'aaa') {
  4120.  
  4121. await setGV(true);
  4122.  
  4123. }
  4124. }
  4125. }
  4126. const checkTextChange = (evt) => {
  4127. if (busy) return;
  4128. busy = true;
  4129. Promise.resolve(evt).then(checkTextChangeF)
  4130. };
  4131. for (const input of inputs) {
  4132. input.addEventListener('input', checkTextChange, false);
  4133. input.addEventListener('keydown', checkTextChange, false);
  4134. input.addEventListener('keyup', checkTextChange, false);
  4135. input.addEventListener('keypress', checkTextChange, false);
  4136. input.addEventListener('change', checkTextChange, false);
  4137. }
  4138. });
  4139.  
  4140. const autoCleanUpKey = async () => {
  4141.  
  4142. const lastCheck = await GM.getValue('lastCheck_bWsm5', null) || 0;
  4143. if (Date.now() - lastCheck < 16000) return; // 16s
  4144. GM.setValue('lastCheck_bWsm5', Date.now());
  4145. pLoad.then(async () => {
  4146. const rArr = [];
  4147. const arr = await GM.listValues();
  4148. const cv = await GM.getValue("isEnable_aWsjF", null);
  4149. const fn = async (entry) => {
  4150. try {
  4151. if (typeof entry === 'string' && entry.length > 15 && entry.startsWith('isEnable_aWsjF_')) {
  4152. const res = await GM.getValue(entry, null);
  4153. if (typeof res === 'boolean' && res === cv) {
  4154. await GM.deleteValue(entry);
  4155. rArr.push(entry);
  4156. }
  4157. }
  4158. } catch (e) {
  4159. console.warn(e);
  4160. }
  4161. }
  4162. arr.length > 1 && (await Promise.all(arr.map(fn)));
  4163. rArr.length > 0 && console.log('[YouTube Audio Only] autoCleanUpKey', rArr);
  4164. });
  4165. };
  4166.  
  4167. autoCleanUpKey();
  4168.  
  4169.  
  4170.  
  4171.  
  4172.  
  4173. })();
  4174.