YouTube: Audio Only

No Video Streaming

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

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