YouTube: Audio Only

No Video Streaming

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

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址