YouTube: Audio Only

No Video Streaming

当前为 2024-05-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube: Audio Only
  3. // @description No Video Streaming
  4. // @namespace UserScript
  5. // @version 1.7.5
  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. // @run-at document-start
  17. // @license MIT
  18. // @compatible chrome
  19. // @compatible firefox
  20. // @compatible opera
  21. // @compatible edge
  22. // @compatible safari
  23. // @allFrames true
  24. //
  25. // ==/UserScript==
  26.  
  27. (async function () {
  28. 'use strict';
  29.  
  30. /** @type {globalThis.PromiseConstructor} */
  31. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  32.  
  33. if (typeof AbortSignal === 'undefined') throw new DOMException("Please update your browser.", "NotSupportedError");
  34.  
  35. async function confirm(message) {
  36. // Create the HTML for the dialog
  37.  
  38. if (!document.body) return;
  39.  
  40. let dialog = document.getElementById('confirmDialog794');
  41. if (!dialog) {
  42.  
  43. const dialogHTML = `
  44. <div id="confirmDialog794" class="dialog-style" style="display: block;">
  45. <div class="confirm-box">
  46. <p>${message}</p>
  47. <div class="confirm-buttons">
  48. <button id="confirmBtn">Confirm</button>
  49. <button id="cancelBtn">Cancel</button>
  50. </div>
  51. </div>
  52. </div>
  53. `;
  54.  
  55. // Append the dialog to the document body
  56. document.body.insertAdjacentHTML('beforeend', dialogHTML);
  57. dialog = document.getElementById('confirmDialog794');
  58.  
  59. }
  60.  
  61. // Return a promise that resolves or rejects based on the user's choice
  62. return new Promise((resolve) => {
  63. document.getElementById('confirmBtn').onclick = () => {
  64. resolve(true);
  65. cleanup();
  66. };
  67.  
  68. document.getElementById('cancelBtn').onclick = () => {
  69. resolve(false);
  70. cleanup();
  71. };
  72.  
  73. function cleanup() {
  74. dialog && dialog.remove();
  75. dialog = null;
  76. }
  77. });
  78. }
  79.  
  80.  
  81.  
  82. if (location.pathname === '/live_chat' || location.pathname === 'live_chat_replay') return;
  83.  
  84. const kEventListener = (evt) => {
  85. if (document.documentElement.hasAttribute('forceRefresh032')) {
  86. evt.stopImmediatePropagation();
  87. evt.stopPropagation();
  88. }
  89. }
  90. window.addEventListener('beforeunload', kEventListener, false);
  91.  
  92. const pageInjectionCode = function () {
  93.  
  94. const SHOW_VIDEO_STATIC_IMAGE = true;
  95.  
  96. if (typeof AbortSignal === 'undefined') throw new DOMException("Please update your browser.", "NotSupportedError");
  97.  
  98. const URL = window.URL || new Function('return URL')();
  99. const createObjectURL = URL.createObjectURL.bind(URL);
  100.  
  101. /** @type {globalThis.PromiseConstructor} */
  102. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  103.  
  104. const PromiseExternal = ((resolve_, reject_) => {
  105. const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
  106. return class PromiseExternal extends Promise {
  107. constructor(cb = h) {
  108. super(cb);
  109. if (cb === h) {
  110. /** @type {(value: any) => void} */
  111. this.resolve = resolve_;
  112. /** @type {(reason?: any) => void} */
  113. this.reject = reject_;
  114. }
  115. }
  116. };
  117. })();
  118.  
  119.  
  120.  
  121.  
  122.  
  123. const createPipeline = () => {
  124. let pipelineMutex = Promise.resolve();
  125. const pipelineExecution = fn => {
  126. return new Promise((resolve, reject) => {
  127. pipelineMutex = pipelineMutex.then(async () => {
  128. let res;
  129. try {
  130. res = await fn();
  131. } catch (e) {
  132. console.log('error_F1', e);
  133. reject(e);
  134. }
  135. resolve(res);
  136. }).catch(console.warn);
  137. });
  138. };
  139. return pipelineExecution;
  140. }
  141.  
  142. const observablePromise = (proc, timeoutPromise) => {
  143. let promise = null;
  144. return {
  145. obtain() {
  146. if (!promise) {
  147. promise = new Promise(resolve => {
  148. let mo = null;
  149. const f = () => {
  150. let t = proc();
  151. if (t) {
  152. mo.disconnect();
  153. mo.takeRecords();
  154. mo = null;
  155. resolve(t);
  156. }
  157. }
  158. mo = new MutationObserver(f);
  159. mo.observe(document, { subtree: true, childList: true })
  160. f();
  161. timeoutPromise && timeoutPromise.then(() => {
  162. resolve(null)
  163. });
  164. });
  165. }
  166. return promise
  167. }
  168. }
  169. }
  170.  
  171.  
  172. const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);
  173.  
  174. const prototypeInherit = (d, b) => {
  175. const m = Object.getOwnPropertyDescriptors(b);
  176. for (const p in m) {
  177. if (!Object.getOwnPropertyDescriptor(d, p)) {
  178. Object.defineProperty(d, p, m[p]);
  179. }
  180. }
  181. };
  182.  
  183. let setTimeout_ = setTimeout;
  184. let clearTimeout_ = clearTimeout;
  185.  
  186. const delayPn = delay => new Promise((fn => setTimeout_(fn, delay)));
  187.  
  188. const isWatchPageURL = (url) => {
  189. url = url || location;
  190. return location.pathname === '/watch' || location.pathname.startsWith('/live/')
  191. };
  192.  
  193. const mockEvent = (o, elem) => {
  194. o = o || {};
  195. elem = elem || null;
  196. return {
  197. preventDefault: () => { },
  198. stopPropagation: () => { },
  199. stopImmediatePropagation: () => { },
  200. returnValue: true,
  201. target: elem,
  202. srcElement: elem,
  203. defaultPrevented: false,
  204. cancelable: true,
  205. timeStamp: performance.now(),
  206. ...o
  207. }
  208. };
  209.  
  210.  
  211. const generalRegister = (prop, symbol, checker, pg) => {
  212. const objSet = new Set();
  213. let done = false;
  214. const f = (o) => {
  215. const ct = o.constructor;
  216. const proto = ct.prototype;
  217. if (!done && proto && ct !== Function && ct !== Object && checker(proto)) {
  218. done = true;
  219. delete Object.prototype[prop];
  220. objSet.delete(proto);
  221. objSet.delete(o);
  222. for (const obj of objSet) {
  223. obj[prop] = obj[symbol];
  224. delete obj[symbol];
  225. }
  226. objSet.clear();
  227. Object.defineProperty(proto, prop, pg);
  228. return proto;
  229. }
  230. return false;
  231. };
  232. Object.defineProperty(Object.prototype, prop, {
  233. get() {
  234. const p = f(this);
  235. if (p) {
  236. return p[prop];
  237. } else {
  238. return this[symbol];
  239. }
  240. },
  241. set(nv) {
  242. const p = f(this);
  243. if (p) {
  244. p[prop] = nv;
  245. } else {
  246. objSet.add(this);
  247. this[symbol] = nv;
  248. }
  249. return true;
  250. },
  251. enumerable: false,
  252. configurable: true
  253. });
  254.  
  255. };
  256.  
  257. const mediaNetworkStateReady = async (audio) => {
  258.  
  259. if (!(audio instanceof HTMLMediaElement)) {
  260. return '';
  261. }
  262. let done = false;
  263. const et = await Promise.race([
  264.  
  265. new Promise(resolve => {
  266. audio.addEventListener('timeupdate', (evt) => {
  267. !done && resolve && resolve(evt.type);
  268. resolve = null
  269. }, { once: true, capture: true, passive: true })
  270. }),
  271.  
  272. new Promise(resolve => {
  273. audio.addEventListener('waiting', (evt) => {
  274. !done && resolve && resolve(evt.type);
  275. resolve = null
  276. }, { once: true, capture: true, passive: true })
  277. }),
  278.  
  279. new Promise(resolve => {
  280. audio.addEventListener('loadstart', (evt) => {
  281. !done && resolve && resolve(evt.type);
  282. resolve = null
  283. }, { once: true, capture: true, passive: true })
  284. }),
  285.  
  286. new Promise(resolve => {
  287. audio.addEventListener('durationchange', (evt) => {
  288. !done && resolve && resolve(evt.type);
  289. resolve = null
  290. }, { once: true, capture: true, passive: true })
  291. })
  292.  
  293. ]);
  294. done = true;
  295. return et;
  296.  
  297. };
  298.  
  299. const updateLastActiveTimeAsync = (player_) => {
  300. // TBC
  301. Promise.resolve().then(() => {
  302. if (typeof player_.updateLastActiveTime === 'function') {
  303. player_.updateLastActiveTime();
  304. }
  305. });
  306. };
  307.  
  308. const attachOneTimeEvent = function (eventType, callback) {
  309. let kz = false;
  310. document.addEventListener(eventType, function (evt) {
  311. if (kz) return;
  312. kz = true;
  313. callback(evt);
  314. }, { capture: true, passive: true, once: true });
  315. }
  316.  
  317. function removeTempObjectProp01() {
  318. delete Object.prototype['kevlar_non_watch_unified_player'];
  319. delete Object.prototype['kevlar_unified_player'];
  320. }
  321.  
  322. function ytConfigFix(config__) {
  323. const config_ = config__;
  324.  
  325. if (config_) {
  326.  
  327. const playerKevlar = ((config_ || 0).WEB_PLAYER_CONTEXT_CONFIGS || 0).WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_WATCH || 0;
  328.  
  329. if (playerKevlar) {
  330.  
  331. // console.log(322, playerKevlar)
  332. playerKevlar.allowWoffleManagement = false;
  333. playerKevlar.cinematicSettingsAvailable = false;
  334. playerKevlar.showMiniplayerButton = false;
  335. playerKevlar.showMiniplayerUiWhenMinimized = false;
  336. playerKevlar.transparentBackground = false;
  337.  
  338. playerKevlar.enableCsiLogging = false;
  339. playerKevlar.externalFullscreen = false;
  340.  
  341. if (typeof playerKevlar.serializedExperimentFlags === 'string') {
  342. playerKevlar.serializedExperimentFlags = '';
  343. // playerKevlar.serializedExperimentFlags = playerKevlar.serializedExperimentFlags.replace(/[-\w]+=(\[\]|[.-\d]+|[_a-z]+|)(&|$)/g,'').replace(/&$/,'')
  344. }
  345.  
  346. if (typeof playerKevlar.serializedExperimentIds === 'string') {
  347. playerKevlar.serializedExperimentIds = '';
  348. // playerKevlar.serializedExperimentIds = playerKevlar.serializedExperimentIds.replace(/\d+\s*(,\s*|$)/g,'')
  349. }
  350.  
  351. }
  352.  
  353. removeTempObjectProp01();
  354.  
  355. let configs = config_.WEB_PLAYER_CONTEXT_CONFIGS || {};
  356. for (const [key, entry] of Object.entries(configs)) {
  357.  
  358. if (entry && typeof entry.serializedExperimentFlags === 'string' && entry.serializedExperimentFlags.length > 16) {
  359. // prevent idle playback failure
  360. 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) => {
  361. return a + '00' + '=' + b + c;
  362. });
  363.  
  364. }
  365.  
  366. }
  367.  
  368. const EXPERIMENT_FLAGS = config_.EXPERIMENT_FLAGS;
  369.  
  370. if (EXPERIMENT_FLAGS) {
  371. EXPERIMENT_FLAGS.kevlar_unified_player = true;
  372. EXPERIMENT_FLAGS.kevlar_non_watch_unified_player = true;
  373. }
  374.  
  375.  
  376. const EXPERIMENTS_FORCED_FLAGS = config_.EXPERIMENTS_FORCED_FLAGS;
  377.  
  378. if (EXPERIMENTS_FORCED_FLAGS) {
  379. EXPERIMENTS_FORCED_FLAGS.kevlar_unified_player = true;
  380. EXPERIMENTS_FORCED_FLAGS.kevlar_non_watch_unified_player = true;
  381. }
  382.  
  383. }
  384. }
  385.  
  386. Object.defineProperty(Object.prototype, 'kevlar_non_watch_unified_player', {
  387. get() {
  388. // console.log(501, this.constructor.prototype)
  389. return true;
  390. },
  391. set(nv) {
  392. return true;
  393. },
  394. enumerable: false,
  395. configurable: true
  396. });
  397.  
  398.  
  399. Object.defineProperty(Object.prototype, 'kevlar_unified_player', {
  400. get() {
  401. // console.log(501, this.constructor.prototype)
  402. return true;
  403. },
  404. set(nv) {
  405. return true;
  406. },
  407. enumerable: false,
  408. configurable: true
  409. });
  410.  
  411. let prr = new PromiseExternal();
  412. const prrPipeline = createPipeline();
  413. let stopAndReload = false;
  414.  
  415. let fa = 0;
  416.  
  417. let cv = null;
  418. let durationchangeForMobile = false;
  419. function fixThumbnailURL(src) {
  420. if (typeof src === 'string' && src.length >= 4) {
  421. let m = /\b[a-z0-9]{4,13}\.jpg\b/.exec(src);
  422. if (m && m[0]) {
  423. const t = m[0];
  424. let idx = src.indexOf(t);
  425. let nSrc = idx >= 0 ? src.substring(0, idx + t.length) : '';
  426. return nSrc;
  427. }
  428. }
  429. return src;
  430. }
  431.  
  432. const isDesktopSite = location.origin === 'https://www.youtube.com' && !location.pathname.startsWith('/embed/');
  433.  
  434. const getThumbnailUrlFromThumbnails = (thumbnails) => {
  435.  
  436. let thumbnailUrl = '';
  437. if (thumbnails && thumbnails.length >= 1) {
  438. const arr = thumbnails.map(e => {
  439. return e.url ? [e.width * e.height, e.url] : typeof e === 'string' ? [0, e] : [0, '']
  440. });
  441. arr.sort((a, b) => b[0] - a[0]);
  442. thumbnailUrl = arr[0][1]
  443. if (typeof thumbnailUrl === 'string') {
  444. thumbnailUrl = fixThumbnailURL(thumbnailUrl);
  445. }
  446. }
  447. return thumbnailUrl;
  448. }
  449.  
  450. const pmof = () => {
  451.  
  452. if (SHOW_VIDEO_STATIC_IMAGE) {
  453.  
  454. const medias = [...document.querySelectorAll('ytd-watch-flexy #player .html5-video-container .video-stream.html5-main-video')].filter(e => !e.closest('[hidden]'));
  455. if (medias.length !== 1) return;
  456. const mediaElement = medias[0];
  457.  
  458. const container = mediaElement ? mediaElement.closest('.html5-video-container') : null;
  459. if (!container) return;
  460.  
  461. let thumbnailUrl = '';
  462. const ytdPage = container.closest('ytd-watch-flexy');
  463. if (ytdPage && ytdPage.is === 'ytd-watch-flexy') {
  464. const cnt = insp(ytdPage);
  465. let thumbnails = null;
  466. try {
  467. thumbnails = cnt.polymerController.__data.playerData.videoDetails.thumbnail.thumbnails
  468. // thumbnails = cnt.__data.watchNextData.playerOverlays.playerOverlayRenderer.autoplay.playerOverlayAutoplayRenderer.background.thumbnails
  469. } catch (e) { }
  470.  
  471. thumbnailUrl = getThumbnailUrlFromThumbnails(thumbnails);
  472. }
  473.  
  474.  
  475. if (thumbnailUrl && typeof thumbnailUrl === 'string') {
  476. container.style.setProperty('--audio-only-thumbnail-image', `url(${thumbnailUrl})`);
  477. } else {
  478. container.style.removeProperty('--audio-only-thumbnail-image')
  479. }
  480.  
  481. }
  482.  
  483.  
  484. }
  485. const pmo = new MutationObserver(pmof);
  486.  
  487. isDesktopSite && document.addEventListener('yt-navigate-finish', () => {
  488. const ytdWatchFlexy = document.querySelector('ytd-watch-flexy');
  489. if (ytdWatchFlexy) {
  490. pmo.observe(ytdWatchFlexy, { attributes: true });
  491. ytdWatchFlexy.setAttribute('ytzNavigateFinish', Date.now());
  492. }
  493. });
  494. document.addEventListener('durationchange', (evt) => {
  495. const target = (evt || 0).target;
  496. if (!(target instanceof HTMLMediaElement)) return;
  497. const targetClassList = target.classList || 0;
  498. const isPlayerVideo = typeof targetClassList.contains === 'function' ? targetClassList.contains('video-stream') && targetClassList.contains('html5-main-video') : false;
  499.  
  500. if (durationchangeForMobile || isPlayerVideo) {
  501. if (target.readyState !== 1) {
  502. fa = 1;
  503. } else {
  504. fa = 2;
  505. }
  506. }
  507.  
  508. if (isPlayerVideo) {
  509.  
  510. if (target.readyState === 1 && target.networkState === 2) {
  511. target.__spfgs__ = true;
  512. if (cv) {
  513. cv.resolve();
  514. cv = null;
  515. }
  516. } else {
  517. target.__spfgs__ = false;
  518. }
  519.  
  520. if (isDesktopSite) {
  521. const ytdWatchFlexy = document.querySelector('ytd-watch-flexy');
  522. if (ytdWatchFlexy) {
  523. ytdWatchFlexy.setAttribute('ytzMediaDurationChanged', Date.now());
  524. }
  525. }
  526.  
  527. if (onVideoChangeForMobile) {
  528. onVideoChangeForMobile();
  529. }
  530.  
  531. }
  532. }, true);
  533.  
  534.  
  535.  
  536. // XMLHttpRequest.prototype.open299 = XMLHttpRequest.prototype.open;
  537. /*
  538.  
  539. XMLHttpRequest.prototype.open2 = function(method, url, ...args){
  540.  
  541. if (typeof url === 'string' && url.length > 24 && url.includes('/videoplayback?') && url.replace('?', '&').includes('&source=')) {
  542. if (vcc !== vdd) {
  543. vdd = vcc;
  544. window.postMessage({ ZECxh: url.includes('source=yt_live_broadcast') }, "*");
  545. }
  546. }
  547.  
  548. return this.open299(method, url, ...args)
  549. }*/
  550.  
  551.  
  552.  
  553. // desktop only
  554. // document.addEventListener('yt-page-data-fetched', async (evt) => {
  555.  
  556. // const pageFetchedDataLocal = evt.detail;
  557. // let isLiveNow;
  558. // try {
  559. // isLiveNow = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.liveBroadcastDetails.isLiveNow;
  560. // } catch (e) { }
  561. // window.postMessage({ ZECxh: isLiveNow === true }, "*");
  562.  
  563. // }, false);
  564.  
  565. // return;
  566.  
  567. // let clickLockFn = null;
  568.  
  569.  
  570. let onVideoChangeForMobile = null;
  571.  
  572. let removeBottomOverlayForMobile = null;
  573.  
  574. let clickLockFn = null;
  575. let clickTarget = null;
  576. if (location.origin === 'https://m.youtube.com') {
  577.  
  578. EventTarget.prototype.addEventListener322 = EventTarget.prototype.addEventListener;
  579.  
  580. const dummyFn = () => { };
  581. EventTarget.prototype.addEventListener = function (evt, fn, opts) {
  582.  
  583. let hn = fn;
  584.  
  585. // if (evt === 'player-error') {
  586. // } else if (evt === 'player-detailed-error') {
  587. // } else if (evt === 'video-data-change') {
  588. // } else if (evt === 'player-state-change') {
  589. // } else
  590. if (evt === 'player-autonav-pause' || evt === 'visibilitychange') {
  591. evt += 'y'
  592. fn = dummyFn;
  593. } else if (evt === 'click' && this.id === 'movie_player') {
  594. clickLockFn = fn;
  595. clickTarget = this;
  596. }
  597. return this.addEventListener322(evt, hn, opts)
  598.  
  599. }
  600.  
  601. }
  602.  
  603.  
  604.  
  605. (() => {
  606.  
  607. XMLHttpRequest = (() => {
  608. const XMLHttpRequest_ = XMLHttpRequest;
  609. if ('__xmMc8__' in XMLHttpRequest_.prototype) return XMLHttpRequest_;
  610. const url0 = createObjectURL(new Blob([], { type: 'text/plain' }));
  611. const c = class XMLHttpRequest extends XMLHttpRequest_ {
  612. constructor(...args) {
  613. super(...args);
  614. }
  615. open(method, url, ...args) {
  616. let skip = false;
  617. if (!url || typeof url !== 'string') skip = true;
  618. else if (typeof url === 'string') {
  619. let turl = url[0] === '/' ? `.youtube.com${url}` : `${url}`;
  620. if (turl.includes('googleads') || turl.includes('doubleclick.net')) {
  621. skip = true;
  622. } else if (turl.includes('.youtube.com/pagead/')) {
  623. skip = true;
  624. } else if (turl.includes('.youtube.com/ptracking')) {
  625. skip = true;
  626. } else if (turl.includes('.youtube.com/api/stats/')) { // /api/stats/
  627. // skip = true; // for user activity logging e.g. watched videos
  628. } else if (turl.includes('play.google.com/log')) {
  629. skip = true;
  630. } else if (turl.includes('.youtube.com//?')) { // //?cpn=
  631. skip = true;
  632. }
  633. }
  634. if (!skip) {
  635. this.__xmMc8__ = 1;
  636. return super.open(method, url, ...args);
  637. } else {
  638. this.__xmMc8__ = 2;
  639. return super.open('GET', url0);
  640. }
  641. }
  642. send(...args) {
  643. if (this.__xmMc8__ === 1) {
  644. return super.send(...args);
  645. } else if (this.__xmMc8__ === 2) {
  646. return super.send();
  647. } else {
  648. console.log('xhr warning');
  649. return super.send(...args);
  650. }
  651. }
  652. }
  653. c.prototype.__xmMc8__ = 0;
  654. prototypeInherit(c.prototype, XMLHttpRequest_.prototype);
  655. return c;
  656. })();
  657.  
  658. const s7 = Symbol();
  659. const f7 = () => true;
  660.  
  661. !window.canRetry9048 && generalRegister('canRetry', s7, (p) => {
  662. 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'
  663. }, {
  664. get() {
  665. if ('logger' in this && 'policy' in this && 'xhr' && this) {
  666. 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"
  667. // OKAY !
  668. console.log('canRetry05 - ', this.errorMessage)
  669. return f7;
  670. }
  671. // console.log(this)
  672. console.log('canRetry02 - ', this.errorMessage, this)
  673. } else {
  674. console.log('canRetry ERR - ', this.errorMessage)
  675. }
  676. return this[s7];
  677. },
  678. set(nv) {
  679. this[s7] = nv;
  680. return true;
  681. },
  682. enumerable: false,
  683. configurable: true
  684. });
  685. window.canRetry9048 = 1;
  686.  
  687. })();
  688.  
  689. if (location.origin === 'https://www.youtube.com') {
  690.  
  691. if (location.pathname.startsWith('/embed/')) {
  692.  
  693. const ytEmbedReady = observablePromise(() => document.querySelector('#player > .ytp-embed')).obtain();
  694.  
  695. const embedConfigFix = async () => {
  696. while (true) {
  697. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  698. if (config_) {
  699. ytConfigFix(config_);
  700. break;
  701. }
  702. await delayPn(60);
  703. }
  704. };
  705.  
  706. ytEmbedReady.then(async (embedPlayer) => {
  707.  
  708. embedConfigFix();
  709.  
  710. const player_ = embedPlayer;
  711. // console.log(player_)
  712.  
  713. const asyncStateChange = async (audio, k) => {
  714. const refreshAllStaleEntitiesForNonReadyAudio = async () => {
  715. try {
  716. if (audio.readyState == 0) await player_.refreshAllStaleEntities();
  717. } catch (e) {
  718. }
  719. };
  720. const triggerPlaying = async () => {
  721. await player_.pauseVideo();
  722. await player_.playVideo();
  723. };
  724. const seekToLiveHeadForLiveStream = async () => {
  725. try {
  726. await player_.seekToLiveHead();
  727. if ((await player_.isAtLiveHead()) === true) {
  728. await player_.seekToStreamTime();
  729. return true;
  730. }
  731. } catch (e) {
  732. console.log('error_F3', e);
  733. }
  734. };
  735. const fixLiveAudioFn = async () => {
  736. if (audio.paused === true) {
  737. await player_.clearVideo(); // avoid error in live streaming
  738. await player_.clearQueue(); // avoid error in live streaming
  739. await delayPn(300);
  740. for (let i = 0; i < 3; i++) {
  741. if (audio.readyState === 0) {
  742. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  743. }
  744. }
  745. if (k === -1) {
  746. await refreshAllStaleEntitiesForNonReadyAudio();
  747. } else if (k === 3) {
  748. while (audio.readyState === 0) {
  749. await refreshAllStaleEntitiesForNonReadyAudio();
  750. await triggerPlaying();
  751. await delayPn(300);
  752. }
  753. }
  754. } else if (audio.paused === false) {
  755. if (!player_.isAtLiveHead()) {
  756. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  757. }
  758. while (audio.readyState === 0) {
  759. await refreshAllStaleEntitiesForNonReadyAudio();
  760. await triggerPlaying();
  761. await delayPn(300);
  762. }
  763. if (!player_.isAtLiveHead()) {
  764. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  765. }
  766. await refreshAllStaleEntitiesForNonReadyAudio();
  767. if (audio.readyState > 0 && audio.paused === true) {
  768. await triggerPlaying();
  769. }
  770. }
  771. }
  772. try {
  773. let ns23 = audio.networkState == 2 || audio.networkState == 3;
  774.  
  775. if (!ns23 && k === player_.getPlayerState()) {
  776. if (k === -1 && audio.readyState === 0) {
  777. const et = await mediaNetworkStateReady(audio);
  778. if (audio.isConnected === false || player_.getPlayerState() === 5) return;
  779. ns23 = audio.networkState == 2 || audio.networkState == 3;
  780. // console.log(503, ns23, et, player_.getPlayerState());
  781. if (player_.getPlayerState() !== -1) return;
  782. } else {
  783. console.log(507, k, audio.readyState, audio.networkState)
  784. }
  785. }
  786.  
  787. if (k === -1 && player_.getPlayerState() === -1 && audio.readyState === 0 && ns23) {
  788. await delayPn(200);
  789. if (k === -1 && player_.getPlayerState() === -1 && audio.readyState === 0 && ns23) {
  790. await fixLiveAudioFn();
  791. }
  792. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState === 1 && ns23 && audio.muted === false) {
  793. await seekToLiveHeadForLiveStream();
  794. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === false) {
  795. await delayPn(60);
  796. if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === false) {
  797. await fixLiveAudioFn();
  798. }
  799. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState === 1 && ns23 && audio.muted === true) {
  800. await seekToLiveHeadForLiveStream();
  801. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === true) {
  802. await delayPn(60);
  803. if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === true) {
  804. await fixLiveAudioFn();
  805. }
  806. }
  807.  
  808. } catch (e) {
  809. console.log('error_F4', e)
  810. }
  811.  
  812. };
  813.  
  814. // console.log(299, player_)
  815. const _onPlayerStateChange = (k) => {
  816. try {
  817. if (typeof k === 'number' && k === player_.getPlayerState()) {
  818.  
  819. const audio = document.querySelector('#player audio.video-stream.html5-main-video');
  820. if (audio) asyncStateChange(audio, k);
  821. }
  822. } catch (e) {
  823. console.log('error_F5', e)
  824. }
  825. };
  826.  
  827. player_.addEventListener('onStateChange', _onPlayerStateChange);
  828. const state0 = player_.getPlayerState();
  829. if (typeof state0 === 'number') {
  830. _onPlayerStateChange(state0);
  831. }
  832.  
  833. player_.addEventListener('onVideoProgress', () => {
  834. updateLastActiveTimeAsync(player_);
  835. });
  836.  
  837. // console.log(1231)
  838.  
  839. if (SHOW_VIDEO_STATIC_IMAGE) {
  840.  
  841. let displayImage = '';
  842. let html5Container = null;
  843.  
  844.  
  845. const moviePlayer = document.querySelector('#movie_player .html5-video-container .video-stream.html5-main-video');
  846. if (moviePlayer) {
  847. html5Container = moviePlayer.closest('.html5-video-container');
  848. }
  849.  
  850. if (html5Container) {
  851.  
  852. const overlayImage = document.querySelector('#movie_player .ytp-cued-thumbnail-overlay-image[style]');
  853. if (overlayImage) {
  854.  
  855. const cStyle = window.getComputedStyle(overlayImage);
  856. const cssImageValue = cStyle.backgroundImage;
  857. if (cssImageValue && typeof cssImageValue === 'string' && cssImageValue.startsWith('url(')) {
  858. displayImage = cssImageValue;
  859.  
  860. }
  861.  
  862. }
  863.  
  864. if (!displayImage) {
  865.  
  866. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  867. let embedded_player_response = null;
  868. if (config_) {
  869. embedded_player_response = ((config_.PLAYER_VARS || 0).embedded_player_response || 0)
  870. }
  871. if (embedded_player_response && typeof embedded_player_response === 'string') {
  872.  
  873. let idx1 = embedded_player_response.indexOf('"defaultThumbnail"');
  874. let idx2 = idx1 >= 0 ? embedded_player_response.lastIndexOf('"defaultThumbnail"') : -1;
  875.  
  876. if (idx1 === idx2 && idx1 > 0) {
  877.  
  878. let bk = 0;
  879. let j = -1;
  880. for (let i = idx1; i < embedded_player_response.length; i++) {
  881. if (i > idx1 + 40 && bk === 0) {
  882. j = i;
  883. break;
  884. }
  885. let t = embedded_player_response.charAt(i);
  886. if (t === '{') bk++;
  887. else if (t === '}') bk--;
  888. }
  889.  
  890. if (j > idx1) {
  891.  
  892. let defaultThumbnailString = embedded_player_response.substring(idx1, j);
  893. let defaultThumbnailObject = null;
  894.  
  895. try {
  896. defaultThumbnailObject = JSON.parse(`{${defaultThumbnailString}}`);
  897.  
  898. } catch (e) { }
  899.  
  900. const thumbnails = ((defaultThumbnailObject.defaultThumbnail || 0).thumbnails || 0);
  901.  
  902. if (thumbnails && thumbnails.length >= 1) {
  903.  
  904. let thumbnailUrl = getThumbnailUrlFromThumbnails(thumbnails);
  905.  
  906. if (thumbnailUrl && thumbnailUrl.length > 3) {
  907. displayImage = `url(${thumbnailUrl})`;
  908. }
  909. }
  910. }
  911.  
  912. }
  913.  
  914.  
  915. }
  916.  
  917.  
  918. }
  919.  
  920. if (displayImage) {
  921.  
  922. html5Container.style.setProperty('--audio-only-thumbnail-image', `${displayImage}`);
  923. } else {
  924. html5Container.style.removeProperty('--audio-only-thumbnail-image')
  925. }
  926.  
  927. }
  928.  
  929.  
  930. }
  931.  
  932. })
  933.  
  934.  
  935. } else {
  936.  
  937. attachOneTimeEvent('yt-action', () => {
  938. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  939. ytConfigFix(config_);
  940. });
  941.  
  942. const setupAudioPlaying = (player00_) => {
  943. const player_ = player00_;
  944. if (!player_) return;
  945. if (player_.__audio544__) return;
  946. player_.__audio544__ = 1;
  947. // console.log(1233, player_)
  948. const mediaCollection = document.getElementsByClassName('html5-main-video');
  949.  
  950. const stopAndReloadFn = async () => {
  951. let isLive = false;
  952. if (isWatchPageURL()) {
  953. const liveBtn = document.querySelector('.ytp-live-badge.ytp-button');
  954. try {
  955. if (liveBtn && !liveBtn.closest('[hidden]') && (liveBtn.textContent || '').trim().length > 0) {
  956. isLive = true;
  957. }
  958. } catch (e) { }
  959. }
  960. if (isLive) {
  961. player_.destroy();
  962. location.replace(location.href);
  963. await delayPn(8000);
  964. } else {
  965. // await player_.stopVideo();
  966. // await player_.updateVideoData();
  967. // try{
  968. // await player_.refreshAllStaleEntities();
  969. // }catch(e){}
  970. // await player_.playVideo();
  971. }
  972. };
  973. const asyncStateChange = async (audio, k) => {
  974.  
  975. const refreshAllStaleEntitiesForNonReadyAudio = async () => {
  976. try {
  977. if (audio.readyState == 0 && audio.isConnected === true) await player_.refreshAllStaleEntities();
  978. } catch (e) {
  979. }
  980. };
  981. const triggerPlaying = async () => {
  982. await player_.cancelPlayback();
  983. await player_.pauseVideo();
  984. await player_.playVideo();
  985. };
  986. const seekToLiveHeadForLiveStream = async () => {
  987. try {
  988. audio.isConnected === true && await player_.seekToLiveHead();
  989. if (audio.isConnected === true && (await player_.isAtLiveHead()) === true) {
  990. audio.isConnected === true && await player_.seekToStreamTime();
  991. return true;
  992. }
  993. } catch (e) {
  994. console.log('error_F7', e);
  995. }
  996. };
  997. const fixLiveAudioFn = async () => {
  998. if (stopAndReload) {
  999. stopAndReload = false;
  1000. await stopAndReloadFn();
  1001. }
  1002. if (audio.isConnected === true && audio.paused === true) {
  1003. await player_.clearVideo(); // avoid error in live streaming
  1004. await player_.clearQueue(); // avoid error in live streaming
  1005. await delayPn(300);
  1006. for (let i = 0; i < 3; i++) {
  1007. if (audio.readyState === 0 && audio.isConnected === true) {
  1008. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  1009. }
  1010. }
  1011. if (k === -1) {
  1012. await refreshAllStaleEntitiesForNonReadyAudio();
  1013. } else if (k === 3) {
  1014. while (audio.readyState === 0 && audio.isConnected === true) {
  1015. await refreshAllStaleEntitiesForNonReadyAudio();
  1016. await triggerPlaying();
  1017. await delayPn(300);
  1018. }
  1019. }
  1020. } else if (audio.isConnected === true && audio.paused === false) {
  1021. if (!player_.isAtLiveHead() && audio.isConnected === true) {
  1022. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  1023. }
  1024. while (audio.readyState === 0 && audio.isConnected === true) {
  1025. await refreshAllStaleEntitiesForNonReadyAudio();
  1026. await triggerPlaying();
  1027. await delayPn(300);
  1028. }
  1029. if (!player_.isAtLiveHead() && audio.isConnected === true) {
  1030. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  1031. }
  1032. await refreshAllStaleEntitiesForNonReadyAudio();
  1033. if (audio.readyState > 0 && audio.paused === true && audio.isConnected === true) {
  1034. await triggerPlaying();
  1035. }
  1036. }
  1037. }
  1038. try {
  1039.  
  1040. let ns23 = audio.networkState == 2 || audio.networkState == 3;
  1041.  
  1042. if (!ns23 && k === player_.getPlayerState()) {
  1043. if (k === -1 && audio.readyState === 0) {
  1044. const et = await mediaNetworkStateReady(audio);
  1045. if (audio.isConnected === false || player_.getPlayerState() === 5) return;
  1046. ns23 = audio.networkState == 2 || audio.networkState == 3;
  1047. console.log(513, ns23, et, player_.getPlayerState());
  1048. if (player_.getPlayerState() !== -1) return;
  1049. } else if (k === 3 && audio.readyState === 0 && audio.networkState === 0) {
  1050. const et = await Promise.race([mediaNetworkStateReady(audio), delayPn(800)]); // idk
  1051. if (audio.isConnected === false || player_.getPlayerState() === 5) return;
  1052. ns23 = audio.networkState == 2 || audio.networkState == 3;
  1053. console.log(514, ns23, et, player_.getPlayerState());
  1054. if (player_.getPlayerState() !== 3) return;
  1055. } else {
  1056. console.log(517, k, audio.readyState, audio.networkState) // 517 3 0 0 after tab sleeping
  1057. }
  1058. }
  1059.  
  1060. if (k === -1 && player_.getPlayerState() === -1 && audio.readyState === 0 && ns23) {
  1061. await delayPn(200);
  1062. if (k === -1 && player_.getPlayerState() === -1 && audio.readyState === 0 && ns23) {
  1063. await fixLiveAudioFn();
  1064. }
  1065. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState === 1 && ns23 && audio.muted === false) {
  1066. await seekToLiveHeadForLiveStream();
  1067. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === false) {
  1068. await delayPn(60);
  1069. if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === false) {
  1070. await fixLiveAudioFn();
  1071. }
  1072. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState === 1 && ns23 && audio.muted === true) {
  1073. await seekToLiveHeadForLiveStream();
  1074. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === true) {
  1075. await delayPn(60);
  1076. if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.muted === true) {
  1077. await fixLiveAudioFn();
  1078. }
  1079. }
  1080.  
  1081. } catch (e) {
  1082. console.log('error_F8', e)
  1083. }
  1084.  
  1085. };
  1086. let mid = 0;
  1087. const getAudioElement = () => {
  1088. if (mediaCollection.length === 0) return null;
  1089. if (mediaCollection.length > 1) {
  1090. const audios = [...mediaCollection].filter(e => e && !e.closest('[hidden]') && e.closest('ytd-player'));
  1091. if (audios.length === 1) {
  1092. return audios[0];
  1093. }
  1094. } else if (mediaCollection.length === 1) {
  1095. const e = mediaCollection[0];
  1096. if (e && !e.closest('[hidden]') && e.closest('ytd-player')) return e;
  1097. }
  1098. return null;
  1099. };
  1100. const _onPlayerStateChange = (k_) => {
  1101. const k = k_;
  1102. const ps = player_.getPlayerState();
  1103. if (stopAndReload) {
  1104. stopAndReload = false;
  1105. const audio = getAudioElement();
  1106. if (audio) {
  1107. prrPipeline(async () => {
  1108. await prr.then();
  1109. await stopAndReloadFn();
  1110. });
  1111. }
  1112. }
  1113. if (typeof k === 'number' && k === ps && ps !== 5) {
  1114.  
  1115. if (mid > 1e9) mid = 9;
  1116. const t = ++mid;
  1117. prrPipeline(async () => {
  1118. if (t !== mid) return;
  1119. await prr.then();
  1120. if (t !== mid) return;
  1121. const audio = getAudioElement();
  1122.  
  1123. if (audio && player_.getPlayerState() === ps) {
  1124. await asyncStateChange(audio, k);
  1125. }
  1126. });
  1127. }
  1128. };
  1129.  
  1130. player_.addEventListener('onStateChange', _onPlayerStateChange);
  1131. const state0 = player_.getPlayerState();
  1132. // console.log(221, state0)
  1133. if (typeof state0 === 'number') {
  1134. _onPlayerStateChange(state0);
  1135. }
  1136.  
  1137. player_.addEventListener('onVideoProgress', () => {
  1138. updateLastActiveTimeAsync(player_);
  1139. });
  1140.  
  1141. }
  1142.  
  1143. customElements.whenDefined('ytd-player').then(() => {
  1144. const dummy = document.querySelector('ytd-player') || document.createElement('ytd-player');
  1145. const cnt = insp(dummy);
  1146. const cProto = cnt.constructor.prototype;
  1147. cProto.createMainAppPlayer932_ = cProto.createMainAppPlayer_;
  1148. cProto.initPlayer932_ = cProto.initPlayer_;
  1149. const configFixBeforeCreate = () => {
  1150. try {
  1151. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  1152. if (config_) {
  1153. ytConfigFix(config_);
  1154. }
  1155. } catch (e) { }
  1156. }
  1157. cProto.createMainAppPlayer_ = function (a, b, c) {
  1158. configFixBeforeCreate();
  1159. let r = this.createMainAppPlayer932_(a, b, c);
  1160. try {
  1161. this.mainAppPlayer_.api.then(function (e) {
  1162. setupAudioPlaying(e);
  1163. })
  1164. } finally {
  1165. return r;
  1166. }
  1167. }
  1168. cProto.initPlayer_ = function (a) {
  1169. configFixBeforeCreate();
  1170. let r = this.initPlayer932_(a);
  1171. try {
  1172. r.then(() => {
  1173. setupAudioPlaying(this.player_);
  1174. })
  1175. } finally {
  1176. return r;
  1177. }
  1178. }
  1179. })
  1180.  
  1181. let useStopAndReload = !isWatchPageURL();
  1182. document.addEventListener('yt-navigate-start', () => {
  1183. prr = new PromiseExternal();
  1184. if (useStopAndReload) stopAndReload = true;
  1185. });
  1186.  
  1187. document.addEventListener('yt-navigate-cache', () => {
  1188. prr = new PromiseExternal();
  1189. if (useStopAndReload) stopAndReload = true;
  1190. });
  1191.  
  1192. document.addEventListener('yt-navigate-finish', () => {
  1193. prr.resolve();
  1194. });
  1195.  
  1196. }
  1197.  
  1198. } else if (location.origin === 'https://m.youtube.com') {
  1199.  
  1200. removeBottomOverlayForMobile = async (delay) => {
  1201.  
  1202.  
  1203. let closeBtnRenderer = document.querySelector('.ytm-bottom-sheet-overlay-renderer-close.icon-close');
  1204. if (closeBtnRenderer) {
  1205.  
  1206. const btn = closeBtnRenderer.querySelector('button');
  1207. const container = closeBtnRenderer.closest('#global-loader ~ .ytm-bottom-sheet-overlay-container');
  1208.  
  1209. if (container) {
  1210. container.style.visibility = 'collapse';
  1211. container.style.zIndex = '-1';
  1212. }
  1213. if (btn) {
  1214. if (delay) {
  1215. await delayPn(delay);
  1216. }
  1217. btn.click();
  1218. }
  1219. }
  1220.  
  1221. }
  1222.  
  1223.  
  1224. let lastPlayerInfoText = '';
  1225. let mz = 0;
  1226. onVideoChangeForMobile = async () => {
  1227.  
  1228.  
  1229. let html5Container = null;
  1230.  
  1231. const moviePlayer = document.querySelector('#player .html5-video-container .video-stream.html5-main-video');
  1232. if (moviePlayer) {
  1233. html5Container = moviePlayer.closest('.html5-video-container');
  1234. }
  1235. if (!html5Container) return;
  1236. let thumbnailUrl = '';
  1237.  
  1238. if (mz > 1e9) mz = 9;
  1239. let mt = ++mz;
  1240. const scriptText = await observablePromise(() => {
  1241. if (mt !== mz) return 1;
  1242. const t = document.querySelector('player-microformat-renderer.PlayerMicroformatRendererHost script[type="application/ld+json"]');
  1243. const tt = (t ? t.textContent : '') || '';
  1244. if (tt === lastPlayerInfoText) return;
  1245. return tt;
  1246. }).obtain();
  1247. if (typeof scriptText !== 'string') return; // 1
  1248. lastPlayerInfoText = scriptText;
  1249.  
  1250. if (!scriptText) return;
  1251.  
  1252.  
  1253. if (SHOW_VIDEO_STATIC_IMAGE) {
  1254.  
  1255. let idx1 = scriptText.indexOf('"thumbnailUrl"');
  1256. let idx2 = idx1 >= 0 ? scriptText.lastIndexOf('"thumbnailUrl"') : -1;
  1257.  
  1258. if (idx1 === idx2 && idx1 > 0) {
  1259.  
  1260. let bk = 0;
  1261. let j = -1;
  1262. for (let i = idx1; i < scriptText.length; i++) {
  1263. if (i > idx1 + 20 && bk === 0) {
  1264. j = i;
  1265. break;
  1266. }
  1267. let t = scriptText.charAt(i);
  1268. if (t === '[') bk++;
  1269. else if (t === ']') bk--;
  1270. else if (t === '{') bk++;
  1271. else if (t === '}') bk--;
  1272. }
  1273.  
  1274.  
  1275. if (j > idx1) {
  1276.  
  1277. let thumbnailUrlString = scriptText.substring(idx1, j);
  1278. let thumbnailUrlObject = null;
  1279.  
  1280. try {
  1281. thumbnailUrlObject = JSON.parse(`{${thumbnailUrlString}}`);
  1282.  
  1283. } catch (e) { }
  1284.  
  1285. const thumbnails = thumbnailUrlObject.thumbnailUrl;
  1286.  
  1287. if (thumbnails && thumbnails.length >= 1 && typeof thumbnails[0] === 'string') {
  1288. if (thumbnails[0] && thumbnails[0].length > 3) {
  1289. thumbnailUrl = thumbnails[0];
  1290. }
  1291. }
  1292. }
  1293.  
  1294. }
  1295.  
  1296. // const ytipr = (typeof ytInitialPlayerResponse !== 'undefined' ? ytInitialPlayerResponse : null) || 0;
  1297.  
  1298. // const thumbnails = (((ytipr.videoDetails || 0).thumbnail || 0).thumbnails || 0);
  1299.  
  1300. // if (thumbnails && thumbnails.length >= 1) {
  1301. // thumbnailUrl = getThumbnailUrlFromThumbnails(thumbnails);
  1302.  
  1303. // }
  1304. if (thumbnailUrl && typeof thumbnailUrl === 'string') {
  1305. html5Container.style.setProperty('--audio-only-thumbnail-image', `url(${thumbnailUrl})`);
  1306. } else {
  1307. html5Container.style.removeProperty('--audio-only-thumbnail-image')
  1308. }
  1309.  
  1310. }
  1311.  
  1312.  
  1313. if (removeBottomOverlayForMobile) await removeBottomOverlayForMobile(40);
  1314.  
  1315. await delayPn(80);
  1316. const audio = moviePlayer;
  1317. if (audio && audio.muted === true && audio.isConnected === true && audio.readyState >= 0 && audio.networkState >= 2 && audio.paused === false) {
  1318. await audio.click();
  1319. }
  1320.  
  1321. }
  1322.  
  1323. let player0 = null;
  1324. let mgg = null;
  1325. const mff = function (e) {
  1326. if (!player0) {
  1327. if (e && typeof ((e || 0).target || 0).getPlayerState === 'function') {
  1328. player0 = e.target
  1329. if (mgg) mgg();
  1330. }
  1331. }
  1332.  
  1333.  
  1334. // if (SHOW_VIDEO_STATIC_IMAGE && (e.type === 'player-state-change' || e.type === 'video-data-change')) {
  1335.  
  1336. // onVideoChangeForMobile();
  1337. // }
  1338.  
  1339. }
  1340.  
  1341. document.addEventListener('player-initialized', mff, true);
  1342. document.addEventListener('player-state-change', mff, true);
  1343. document.addEventListener('player-ad-state-change', mff, true);
  1344. document.addEventListener('player-detailed-error', mff, true);
  1345. document.addEventListener('player-error', mff, true);
  1346. document.addEventListener('on-play-autonav-video', mff, true);
  1347. document.addEventListener('on-play-previous-autonav-video', mff, true);
  1348. document.addEventListener('player-fullscreen-change', mff, true);
  1349. document.addEventListener('player-fullscreen-toggled', mff, true);
  1350. document.addEventListener('player-dom-paused', mff, true);
  1351. document.addEventListener('yt-show-toast', mff, true);
  1352. document.addEventListener('yt-innertube-command', mff, true);
  1353. document.addEventListener('yt-update-c3-companion', mff, true);
  1354. document.addEventListener('video-data-change', mff, true);
  1355. document.addEventListener('video-progress', mff, true);
  1356. document.addEventListener('local-media-change', mff, true);
  1357.  
  1358.  
  1359. let tc = false;
  1360. // let pw = null;
  1361. (async () => {
  1362.  
  1363. let player__;
  1364.  
  1365. const getAudioElement = () => {
  1366. const elm = player__ || player0;
  1367. const audio = elm && elm.isConnected === true ? HTMLElement.prototype.querySelector.call(elm, '.video-stream.html5-main-video') : null;
  1368. return audio;
  1369. }
  1370.  
  1371. const asyncStateChange = async (audio, k) => {
  1372. const player_ = player__;
  1373. if (!player_) return;
  1374. if (typeof player_.getPlayerState !== 'function') return;
  1375.  
  1376. const refreshAllStaleEntitiesForNonReadyAudio = async () => {
  1377. // try {
  1378. // if (audio.readyState == 0) await player_.refreshAllStaleEntities();
  1379. // } catch (e) {
  1380. // }
  1381. };
  1382. const triggerPlaying = async () => {
  1383. await player_.cancelPlayback();
  1384. await player_.pauseVideo();
  1385. await player_.playVideo();
  1386. };
  1387. const seekToLiveHeadForLiveStream = async () => {
  1388. try {
  1389. await player_.seekToLiveHead();
  1390. if ((await player_.isAtLiveHead()) === true) {
  1391. await player_.seekToStreamTime();
  1392. return true;
  1393. }
  1394. } catch (e) {
  1395. console.log('error_F9', e);
  1396. }
  1397. };
  1398. const fixLiveAudioFn = async () => {
  1399. if (audio.paused === true) {
  1400. await player_.clearVideo(); // avoid error in live streaming
  1401. await player_.clearQueue(); // avoid error in live streaming
  1402. await delayPn(300);
  1403. for (let i = 0; i < 3; i++) {
  1404. if (audio.readyState === 0) {
  1405. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  1406. }
  1407. }
  1408. if (k === -1) {
  1409. await refreshAllStaleEntitiesForNonReadyAudio();
  1410. } else if (k === 3) {
  1411. while (audio.readyState === 0) {
  1412. await refreshAllStaleEntitiesForNonReadyAudio();
  1413. await triggerPlaying();
  1414. await delayPn(300);
  1415. }
  1416. // console.log(8809,audio.readyState)
  1417. }
  1418. } else if (audio.paused === false) {
  1419. if (!player_.isAtLiveHead()) {
  1420. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  1421. }
  1422. while (audio.readyState === 0) {
  1423. await refreshAllStaleEntitiesForNonReadyAudio();
  1424. await triggerPlaying();
  1425. await delayPn(300);
  1426. }
  1427. if (!player_.isAtLiveHead()) {
  1428. if (await seekToLiveHeadForLiveStream()) await delayPn(60);
  1429. }
  1430. await refreshAllStaleEntitiesForNonReadyAudio();
  1431. if (audio.readyState > 0 && audio.paused === true) {
  1432. await triggerPlaying();
  1433. }
  1434. }
  1435.  
  1436. }
  1437. try {
  1438.  
  1439. let ns23 = audio.networkState == 2 || audio.networkState == 3
  1440. // console.log(127001, k, player_.getPlayerState(), audio.readyState, ns23, audio.muted)
  1441.  
  1442. if (!ns23 && k === player_.getPlayerState()) {
  1443. if (k === -1 && audio.readyState === 0) {
  1444. const et = await mediaNetworkStateReady(audio);
  1445. if (audio.isConnected === false || player_.getPlayerState() === 5) return;
  1446. ns23 = audio.networkState == 2 || audio.networkState == 3;
  1447. console.log(523, ns23, et, player_.getPlayerState());
  1448. if (player_.getPlayerState() !== -1) return;
  1449. } else {
  1450. console.log(527, k, audio.readyState, audio.networkState)
  1451. }
  1452. }
  1453.  
  1454. if (removeBottomOverlayForMobile) await removeBottomOverlayForMobile(300);
  1455.  
  1456. if (k === 3 && player_.getPlayerState() === 3 && audio.readyState > 0 && ns23 && audio.muted === true) {
  1457. tc = true;
  1458. }
  1459. if (k === -1 && player_.getPlayerState() === -1 && audio.readyState === 0 && ns23) {
  1460. await delayPn(200);
  1461. if (k === -1 && player_.getPlayerState() === -1 && audio.readyState === 0 && ns23) {
  1462. // console.log(8806)
  1463. await fixLiveAudioFn();
  1464. }
  1465. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState === 1 && ns23 && audio.muted === false) {
  1466. await seekToLiveHeadForLiveStream();
  1467. } else if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23) {
  1468. await delayPn(60);
  1469. if (k === 3 && player_.getPlayerState() === 3 && audio.readyState == 0 && ns23 && audio.paused === false) {
  1470. // console.log(8807)
  1471. await fixLiveAudioFn();
  1472. }
  1473.  
  1474. }
  1475.  
  1476. } catch (e) {
  1477. console.log('error_F10', e)
  1478. }
  1479.  
  1480. };
  1481. const _onPlayerStateChange = (e) => {
  1482. if (e && (e || 0).target) {
  1483. player__ = e.target
  1484. }
  1485. const player_ = player__;
  1486. try {
  1487. if (!player_) return;
  1488. let k = null;
  1489. if (e && e.detail && e.detail.state) {
  1490. k = e.detail.state
  1491. }
  1492. if (typeof player_.getPlayerState === 'function' && typeof k === 'number' && k === player_.getPlayerState()) {
  1493. const audio = getAudioElement();
  1494. if (audio) asyncStateChange(audio, k);
  1495. }
  1496. } catch (e) {
  1497. console.log('error_F11', e)
  1498. }
  1499. };
  1500.  
  1501. let idleAudioActivatePending = false;
  1502.  
  1503. const _onVideoProgress = (e) => {
  1504. if (e && (e || 0).target) {
  1505. player__ = e.target
  1506. }
  1507. const player_ = player__;
  1508. if (!player_) return;
  1509. updateLastActiveTimeAsync(player_);
  1510. if (tc) {
  1511. tc = false;
  1512. if (!idleAudioActivatePending) {
  1513. idleAudioActivatePending = true;
  1514. }
  1515. }
  1516. };
  1517.  
  1518. mgg = function () {
  1519. const player_ = player0;
  1520. if (player_) {
  1521. const state0 = player_.getPlayerState();
  1522. if (typeof state0 === 'number') {
  1523. _onPlayerStateChange({ type: 'player-state-change', target: player_, detail: { state: state0 } });
  1524. }
  1525. }
  1526. }
  1527.  
  1528. document.addEventListener('player-state-change', _onPlayerStateChange, true);
  1529.  
  1530. document.addEventListener('video-progress', _onVideoProgress, true);
  1531.  
  1532. })();
  1533.  
  1534. // document.addEventListener('DOMContentLoaded', (evt) => {
  1535. // const mo = new MutationObserver((mutations)=>{
  1536. // console.log(5899, mutations)
  1537. // });
  1538. // mo.observe(document, {subtree: true, childList: true})
  1539. // })
  1540.  
  1541. // window.addEventListener('onReady', (evt) => {
  1542. // console.log(6811)
  1543. // }, true);
  1544.  
  1545. // window.addEventListener('localmediachange', (evt) => {
  1546. // console.log(6812)
  1547. // }, true);
  1548.  
  1549. // window.addEventListener('onVideoDataChange', (evt) => {
  1550. // console.log(6813)
  1551. // }, true);
  1552.  
  1553. window.addEventListener('state-navigateend', async (evt) => {
  1554.  
  1555.  
  1556. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  1557. ytConfigFix(config_);
  1558.  
  1559. try {
  1560. if (clickLockFn && clickTarget) {
  1561.  
  1562. let a = HTMLElement.prototype.querySelector.call(clickTarget, '.video-stream.html5-main-video');
  1563. if (!a) return;
  1564.  
  1565. if (a.muted === true && a.__spfgs__ !== true && a.paused === true && a.networkState === 0 && a.readyState === 0) {
  1566.  
  1567. const pr = new Promise(resolve => {
  1568.  
  1569. document.addEventListener('player-state-change', resolve, { once: true, passive: true, capture: false });
  1570.  
  1571. }).then();
  1572.  
  1573. clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 }));
  1574. await delayPn(1);
  1575.  
  1576. if (a.muted === false && a.__spfgs__ !== true && a.paused === true && a.networkState === 0 && a.readyState === 0) {
  1577. clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 }));
  1578. await delayPn(1);
  1579. }
  1580.  
  1581. delayRun(pr);
  1582.  
  1583. }
  1584.  
  1585. }
  1586.  
  1587. } catch (e) { console.log('error_F12', e) }
  1588.  
  1589.  
  1590. }, false);
  1591.  
  1592.  
  1593.  
  1594. // document.addEventListener('volumechange', (evt) => {
  1595. // console.log('volumechange')
  1596. // }, true)
  1597. // document.addEventListener('play', (evt) => {
  1598. // console.log('play')
  1599. // }, true)
  1600.  
  1601.  
  1602. // document.addEventListener('player-initialized', (evt) => {
  1603. // console.log(evt.type)
  1604. // }, true)
  1605. // document.addEventListener('renderer-module-load-start', (evt) => {
  1606. // console.log(evt.type)
  1607. // }, true)
  1608. // document.addEventListener('video-data-change', (evt) => {
  1609. // console.log(evt.type)
  1610. // }, true)
  1611. // document.addEventListener('player-state-change', (evt) => {
  1612. // console.log(evt.type)
  1613. // }, true)
  1614. // document.addEventListener('updateui', (evt) => {
  1615. // console.log(evt.type)
  1616. // }, true)
  1617. // document.addEventListener('renderer-module-load-end', (evt) => {
  1618. // console.log(evt.type)
  1619. // }, true)
  1620.  
  1621. // document.addEventListener('player-autonav-pause', (evt) => {
  1622. // console.log(evt.type)
  1623. // }, true)
  1624.  
  1625.  
  1626.  
  1627. // document.addEventListener('player-ad-state-change', (evt) => {
  1628. // console.log(evt.type)
  1629. // }, true)
  1630.  
  1631. // document.addEventListener('player-detailed-error', (evt) => {
  1632. // console.log(evt.type)
  1633. // }, true)
  1634.  
  1635. // document.addEventListener('player-error', (evt) => {
  1636. // console.log(evt.type)
  1637. // }, true)
  1638.  
  1639. // document.addEventListener('on-play-autonav-video', (evt) => {
  1640. // console.log(evt.type)
  1641. // }, true)
  1642.  
  1643. // document.addEventListener('on-play-previous-autonav-video', (evt) => {
  1644. // console.log(evt.type)
  1645. // }, true)
  1646.  
  1647. // document.addEventListener('player-fullscreen-change', (evt) => {
  1648. // console.log(evt.type)
  1649. // }, true)
  1650.  
  1651. // document.addEventListener('player-fullscreen-toggled', (evt) => {
  1652. // console.log(evt.type)
  1653. // }, true)
  1654.  
  1655. // document.addEventListener('player-dom-paused', (evt) => {
  1656. // console.log(evt.type)
  1657. // }, true)
  1658.  
  1659. // document.addEventListener('yt-show-toast', (evt) => {
  1660. // console.log(evt.type)
  1661. // }, true)
  1662. // document.addEventListener('yt-innertube-command', (evt) => {
  1663. // console.log(evt.type)
  1664. // }, true)
  1665. // document.addEventListener('yt-update-c3-companion', (evt) => {
  1666. // console.log(evt.type)
  1667. // }, true)
  1668. // document.addEventListener('video-progress', (evt) => {
  1669. // // console.log(evt.type)
  1670. // }, true)
  1671. // document.addEventListener('localmediachange', (evt) => {
  1672. // console.log(evt.type)
  1673. // }, true)
  1674.  
  1675.  
  1676.  
  1677. // window.addEventListener('player-initialized', (evt) => {
  1678. // console.log(evt.type)
  1679. // }, true)
  1680. // window.addEventListener('renderer-module-load-start', (evt) => {
  1681. // console.log(evt.type)
  1682. // }, true)
  1683. // window.addEventListener('video-data-change', (evt) => {
  1684. // console.log(evt.type)
  1685. // }, true)
  1686. // window.addEventListener('player-state-change', (evt) => {
  1687. // console.log(evt.type)
  1688. // }, true)
  1689. // window.addEventListener('updateui', (evt) => {
  1690. // console.log(evt.type)
  1691. // }, true)
  1692. // window.addEventListener('renderer-module-load-end', (evt) => {
  1693. // console.log(evt.type)
  1694. // }, true)
  1695.  
  1696. // window.addEventListener('player-autonav-pause', (evt) => {
  1697. // console.log(evt.type)
  1698. // }, true)
  1699.  
  1700.  
  1701.  
  1702. // window.addEventListener('player-ad-state-change', (evt) => {
  1703. // console.log(evt.type)
  1704. // }, true)
  1705.  
  1706. // window.addEventListener('player-detailed-error', (evt) => {
  1707. // console.log(evt.type)
  1708. // }, true)
  1709.  
  1710. // window.addEventListener('player-error', (evt) => {
  1711. // console.log(evt.type)
  1712. // }, true)
  1713.  
  1714. // window.addEventListener('on-play-autonav-video', (evt) => {
  1715. // console.log(evt.type)
  1716. // }, true)
  1717.  
  1718. // window.addEventListener('on-play-previous-autonav-video', (evt) => {
  1719. // console.log(evt.type)
  1720. // }, true)
  1721.  
  1722. // window.addEventListener('player-fullscreen-change', (evt) => {
  1723. // console.log(evt.type)
  1724. // }, true)
  1725.  
  1726. // window.addEventListener('player-fullscreen-toggled', (evt) => {
  1727. // console.log(evt.type)
  1728. // }, true)
  1729.  
  1730. // window.addEventListener('player-dom-paused', (evt) => {
  1731. // console.log(evt.type)
  1732. // }, true)
  1733.  
  1734. // window.addEventListener('yt-show-toast', (evt) => {
  1735. // console.log(evt.type)
  1736. // }, true)
  1737. // window.addEventListener('yt-innertube-command', (evt) => {
  1738. // console.log(evt.type)
  1739. // }, true)
  1740. // window.addEventListener('yt-update-c3-companion', (evt) => {
  1741. // console.log(evt.type)
  1742. // }, true)
  1743. // window.addEventListener('video-progress', (evt) => {
  1744. // // console.log(evt.type)
  1745. // }, true)
  1746. // window.addEventListener('localmediachange', (evt) => {
  1747. // console.log(evt.type)
  1748. // }, true)
  1749.  
  1750.  
  1751.  
  1752. // document.addEventListener('player-error', (evt) => {
  1753. // console.log(3001, evt.type, evt)
  1754. // }, true)
  1755. // document.addEventListener('player-detailed-error', (evt) => {
  1756. // console.log(3002, evt.type, evt)
  1757. // }, true)
  1758.  
  1759.  
  1760.  
  1761. async function delayRun(pr) {
  1762.  
  1763. let q = document.querySelector('#movie_player');
  1764. if (!q) return;
  1765. let a = document.querySelector('.video-stream.html5-main-video');
  1766. if (!a) return;
  1767.  
  1768. await pr.then();
  1769.  
  1770. if (fa !== 1) {
  1771. return;
  1772. } else if (a.muted === true) {
  1773. return;
  1774. } else if (a.muted === false && a.readyState === 0 && a.networkState === 2) {
  1775. if (a.paused === false) return;
  1776. } else {
  1777. return;
  1778. }
  1779.  
  1780. if (document.querySelector('.player-controls-content')) return;
  1781.  
  1782. if (a.paused === true && a.muted === false && a.readyState === 0 && a.networkState === 2) {
  1783.  
  1784. clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 }));
  1785.  
  1786. }
  1787.  
  1788. if (a.paused === true && a.muted === false && a.networkState === 2 && a.readyState === 0) {
  1789.  
  1790. if (typeof clickTarget.seekToLiveHead === 'function') await clickTarget.seekToLiveHead();
  1791. if (typeof clickTarget.isAtLiveHead === 'function' && (await clickTarget.isAtLiveHead()) === true) {
  1792. if (typeof clickTarget.seekToStreamTime === 'function') await clickTarget.seekToStreamTime();
  1793. }
  1794. }
  1795.  
  1796. }
  1797.  
  1798. durationchangeForMobile = true;
  1799.  
  1800. }
  1801.  
  1802. attachOneTimeEvent('yt-action', function () {
  1803. const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0;
  1804. ytConfigFix(config_);
  1805. });
  1806.  
  1807. let prepared = false;
  1808. function prepare() {
  1809. if (prepared) return;
  1810. prepared = true;
  1811.  
  1812. if (typeof _yt_player !== 'undefined' && _yt_player && typeof _yt_player === 'object') {
  1813.  
  1814. for (const [k, v] of Object.entries(_yt_player)) {
  1815.  
  1816. const p = typeof v === 'function' ? v.prototype : 0;
  1817.  
  1818. if (p
  1819. && typeof p.clone === 'function'
  1820. && typeof p.get === 'function' && typeof p.set === 'function'
  1821. && typeof p.isEmpty === 'undefined' && typeof p.forEach === 'undefined'
  1822. && typeof p.clear === 'undefined'
  1823. ) {
  1824.  
  1825. key = k;
  1826.  
  1827. }
  1828.  
  1829. }
  1830.  
  1831. }
  1832.  
  1833. if (key) {
  1834.  
  1835. const ClassX = _yt_player[key];
  1836. _yt_player[key] = class extends ClassX {
  1837. constructor(...args) {
  1838.  
  1839. if (typeof args[0] === 'string' && args[0].startsWith('http://')) args[0] = '';
  1840. super(...args);
  1841.  
  1842. }
  1843. }
  1844. _yt_player[key].luX1Y = 1;
  1845. prototypeInherit(_yt_player[key].prototype, ClassX.prototype);
  1846. }
  1847.  
  1848. }
  1849. let s3 = Symbol();
  1850.  
  1851. generalRegister('deviceIsAudioOnly', s3, (p) => {
  1852. return typeof p.getPlayerType === 'function' && typeof p.getVideoEmbedCode === 'function' && typeof p.getVideoUrl === 'function' && !p.onCueRangeEnter && !p.getVideoData && !('ATTRIBUTE_NODE' in p)
  1853. }, {
  1854.  
  1855. get() {
  1856. return this[s3];
  1857. },
  1858. set(nv) {
  1859. if (typeof nv === 'boolean') this[s3] = true;
  1860. else this[s3] = undefined;
  1861. prepare();
  1862. return true;
  1863. },
  1864. enumerable: false,
  1865. configurable: true
  1866.  
  1867. });
  1868.  
  1869.  
  1870. let s1 = Symbol();
  1871. let s2 = Symbol();
  1872. Object.defineProperty(Object.prototype, 'defraggedFromSubfragments', {
  1873. get() {
  1874. // console.log(501, this.constructor.prototype)
  1875. return undefined;
  1876. },
  1877. set(nv) {
  1878. return true;
  1879. },
  1880. enumerable: false,
  1881. configurable: true
  1882. });
  1883.  
  1884. Object.defineProperty(Object.prototype, 'hasSubfragmentedFmp4', {
  1885. get() {
  1886. // console.log(502, this.constructor.prototype)
  1887. return this[s1];
  1888. },
  1889. set(nv) {
  1890. if (typeof nv === 'boolean') this[s1] = false;
  1891. else this[s1] = undefined;
  1892. return true;
  1893. },
  1894. enumerable: false,
  1895. configurable: true
  1896. });
  1897.  
  1898. Object.defineProperty(Object.prototype, 'hasSubfragmentedWebm', {
  1899. get() {
  1900. // console.log(503, this.constructor.prototype)
  1901. return this[s2];
  1902. },
  1903. set(nv) {
  1904. if (typeof nv === 'boolean') this[s2] = false;
  1905. else this[s2] = undefined;
  1906. return true;
  1907. },
  1908. enumerable: false,
  1909. configurable: true
  1910. });
  1911.  
  1912.  
  1913. const supportedFormatsConfig = () => {
  1914.  
  1915. function typeTest(type) {
  1916. if (typeof type === 'string' && type.startsWith('video/')) {
  1917. return false;
  1918. }
  1919. }
  1920.  
  1921. // return a custom MIME type checker that can defer to the original function
  1922. function makeModifiedTypeChecker(origChecker) {
  1923. // Check if a video type is allowed
  1924. return function (type) {
  1925. let res = undefined;
  1926. if (type === undefined) res = false;
  1927. else {
  1928. res = typeTest.call(this, type);
  1929. }
  1930. if (res === undefined) res = origChecker.apply(this, arguments);
  1931. return res;
  1932. };
  1933. }
  1934.  
  1935. // Override video element canPlayType() function
  1936. const proto = (HTMLVideoElement || 0).prototype;
  1937. if (proto && typeof proto.canPlayType == 'function') {
  1938. proto.canPlayType = makeModifiedTypeChecker(proto.canPlayType);
  1939. }
  1940.  
  1941. // Override media source extension isTypeSupported() function
  1942. const mse = window.MediaSource;
  1943. // Check for MSE support before use
  1944. if (mse && typeof mse.isTypeSupported == 'function') {
  1945. mse.isTypeSupported = makeModifiedTypeChecker(mse.isTypeSupported);
  1946. }
  1947.  
  1948. };
  1949.  
  1950. supportedFormatsConfig();
  1951. }
  1952.  
  1953. const isEnable = (typeof GM !== 'undefined' && typeof GM.getValue === 'function') ? (await GM.getValue("isEnable_aWsjF", true)) : null;
  1954. if (typeof isEnable !== 'boolean') throw new DOMException("Please Update your browser", "NotSupportedError");
  1955. if (isEnable) {
  1956. const element = document.createElement('button');
  1957. element.setAttribute('onclick', `(${pageInjectionCode})()`);
  1958. element.click();
  1959. }
  1960.  
  1961. GM_registerMenuCommand(`Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`, async function () {
  1962. await GM.setValue("isEnable_aWsjF", !isEnable);
  1963. document.documentElement.setAttribute('forceRefresh032', '');
  1964. location.reload();
  1965. });
  1966.  
  1967. let messageCount = 0;
  1968. let busy = false;
  1969. window.addEventListener('message', (evt) => {
  1970.  
  1971. const v = ((evt || 0).data || 0).ZECxh;
  1972. if (typeof v === 'boolean') {
  1973. if (messageCount > 1e9) messageCount = 9;
  1974. const t = ++messageCount;
  1975. if (v && isEnable) {
  1976. requestAnimationFrame(async () => {
  1977. if (t !== messageCount) return;
  1978. if (busy) return;
  1979. busy = true;
  1980. if (await confirm("Livestream is detected. Press OK to disable YouTube Audio Mode.")) {
  1981. await GM.setValue("isEnable_aWsjF", !isEnable);
  1982. document.documentElement.setAttribute('forceRefresh032', '');
  1983. location.reload();
  1984. }
  1985. busy = false;
  1986. });
  1987. }
  1988. }
  1989.  
  1990. });
  1991.  
  1992.  
  1993. const pLoad = new Promise(resolve => {
  1994. if (document.readyState !== 'loading') {
  1995. resolve();
  1996. } else {
  1997. window.addEventListener("DOMContentLoaded", resolve, false);
  1998. }
  1999. });
  2000.  
  2001.  
  2002. function contextmenuInfoItemAppearedFn(target) {
  2003.  
  2004. const btn = target.closest('.ytp-menuitem[role="menuitem"]');
  2005. if (!btn) return;
  2006. if (btn.parentNode.querySelector('.ytp-menuitem[role="menuitem"].audio-only-toggle-btn')) return;
  2007. document.documentElement.classList.add('with-audio-only-toggle-btn');
  2008. const newBtn = btn.cloneNode(true)
  2009. newBtn.querySelector('.ytp-menuitem-label').textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`;
  2010. newBtn.classList.add('audio-only-toggle-btn');
  2011. btn.parentNode.insertBefore(newBtn, btn.nextSibling);
  2012. newBtn.addEventListener('click', async () => {
  2013. await GM.setValue("isEnable_aWsjF", !isEnable);
  2014. document.documentElement.setAttribute('forceRefresh032', '');
  2015. location.reload();
  2016. });
  2017. let t;
  2018. let h = 0;
  2019. t = btn.closest('.ytp-panel-menu[style*="height"]');
  2020. if (t) t.style.height = t.scrollHeight + 'px';
  2021. t = btn.closest('.ytp-panel[style*="height"]');
  2022. if (t) t.style.height = (h = t.scrollHeight) + 'px';
  2023. t = btn.closest('.ytp-popup.ytp-contextmenu[style*="height"]');
  2024. if (t && h > 0) t.style.height = h + 'px';
  2025. }
  2026.  
  2027.  
  2028. function mobileMenuItemAppearedFn(target) {
  2029.  
  2030. const btn = target.closest('ytm-menu-item');
  2031. if (!btn) return;
  2032. if (btn.parentNode.querySelector('ytm-menu-item.audio-only-toggle-btn')) return;
  2033. document.documentElement.classList.add('with-audio-only-toggle-btn');
  2034. const newBtn = btn.cloneNode(true);
  2035. newBtn.querySelector('.menu-item-button').textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`;
  2036. newBtn.classList.add('audio-only-toggle-btn');
  2037. btn.parentNode.insertBefore(newBtn, btn.nextSibling);
  2038. newBtn.addEventListener('click', async () => {
  2039. await GM.setValue("isEnable_aWsjF", !isEnable);
  2040. document.documentElement.setAttribute('forceRefresh032', '');
  2041. location.reload();
  2042. });
  2043. }
  2044.  
  2045.  
  2046. pLoad.then(() => {
  2047.  
  2048. document.addEventListener('animationstart', (evt) => {
  2049. const animationName = evt.animationName;
  2050. if (!animationName) return;
  2051.  
  2052. if (animationName === 'contextmenuInfoItemAppeared') contextmenuInfoItemAppearedFn(evt.target);
  2053. if (animationName === 'mobileMenuItemAppeared') mobileMenuItemAppearedFn(evt.target);
  2054.  
  2055. }, true);
  2056.  
  2057. const cssForEnabled = isEnable ? `
  2058.  
  2059. .html5-video-player {
  2060. background-color: black;
  2061. }
  2062.  
  2063. [style*="--audio-only-thumbnail-image"]{
  2064. background-image: var(--audio-only-thumbnail-image);
  2065. object-fit: contain;
  2066. background-position: center;
  2067. background-size: contain;
  2068. background-repeat: no-repeat;
  2069. }
  2070. .html5-video-player.ended-mode [style*="--audio-only-thumbnail-image"]{
  2071. background-image: none;
  2072. }
  2073.  
  2074. .html5-video-player.ytp-ce-shown .html5-video-container {
  2075. opacity: 0.5;
  2076. transition: opacity 0.5s;
  2077. }
  2078.  
  2079. ytd-video-preview #media-container div#player-container,
  2080. ytd-video-preview #media-container div#thumbnail-container{
  2081. transition: initial !important;
  2082. transition-duration:0ms !important;
  2083. transition-delay:0ms !important;
  2084. }
  2085. ytd-video-preview #media-container div#thumbnail-container{
  2086. /* pointer-events:none !important; */
  2087. opacity:0;
  2088. /* z-index:-1; */
  2089. }
  2090. ytd-video-preview #media-container div#player-container,
  2091. ytd-video-preview #media-container div#inline-preview-player{
  2092. background-color:transparent !important;
  2093. background-image:none !important;
  2094. }
  2095.  
  2096. #movie_player > .html5-video-container:not(:empty) {
  2097. box-sizing: border-box;
  2098. height: 100%;
  2099. }
  2100.  
  2101. #movie_player [style*="--audio-only-thumbnail-image"] ~ .ytp-cued-thumbnail-overlay > .ytp-cued-thumbnail-overlay-image[style*="background-image"] {
  2102. opacity: 0;
  2103. }
  2104.  
  2105. `: "";
  2106.  
  2107. const style = document.createElement('style');
  2108. style.id = 'fm9v0';
  2109. style.textContent = `
  2110.  
  2111. ${cssForEnabled}
  2112.  
  2113. @keyframes mobileMenuItemAppeared {
  2114. 0% {
  2115. background-position-x: 3px;
  2116. }
  2117. 100% {
  2118. background-position-x: 4px;
  2119. }
  2120. }
  2121. ytm-select.player-speed-settings ~ ytm-menu-item:last-of-type {
  2122. animation: mobileMenuItemAppeared 1ms linear 0s 1 normal forwards;
  2123. }
  2124. @keyframes contextmenuInfoItemAppeared {
  2125. 0% {
  2126. background-position-x: 3px;
  2127. }
  2128. 100% {
  2129. background-position-x: 4px;
  2130. }
  2131. }
  2132. .ytp-contextmenu .ytp-menuitem[role="menuitem"] path[d^="M22 34h4V22h-4v12zm2-30C12.95"]{
  2133. animation: contextmenuInfoItemAppeared 1ms linear 0s 1 normal forwards;
  2134. }
  2135. #confirmDialog794 {
  2136. z-index:999999 !important;
  2137. display: none;
  2138. /* Hidden by default */
  2139. position: fixed;
  2140. /* Stay in place */
  2141. z-index: 1;
  2142. /* Sit on top */
  2143. left: 0;
  2144. top: 0;
  2145. width: 100%;
  2146. /* Full width */
  2147. height: 100%;
  2148. /* Full height */
  2149. overflow: auto;
  2150. /* Enable scroll if needed */
  2151. background-color: rgba(0,0,0,0.4);
  2152. /* Black w/ opacity */
  2153. }
  2154. #confirmDialog794 .confirm-box {
  2155. position:relative;
  2156. color: black;
  2157. z-index:999999 !important;
  2158. background-color: #fefefe;
  2159. margin: 15% auto;
  2160. /* 15% from the top and centered */
  2161. padding: 20px;
  2162. border: 1px solid #888;
  2163. width: 30%;
  2164. /* Could be more or less, depending on screen size */
  2165. box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
  2166. }
  2167. #confirmDialog794 .confirm-buttons {
  2168. text-align: right;
  2169. }
  2170. #confirmDialog794 button {
  2171. margin-left: 10px;
  2172. }
  2173. `
  2174. document.head.appendChild(style);
  2175.  
  2176. if (false && isEnable) {
  2177. let mzId = 0;
  2178.  
  2179. let mz = 0;
  2180. const mof = async () => {
  2181. mzId && clearInterval(mzId);
  2182. if (mz > 1e9) mz = 9;
  2183. const mt = ++mz;
  2184.  
  2185. let q = document.querySelector('#video-preview > ytd-video-preview.style-scope.ytd-app');
  2186. if (!q) return;
  2187. if (q.hasAttribute('active') && !q.hasAttribute('hidden')) {
  2188.  
  2189. } else {
  2190. return;
  2191. }
  2192.  
  2193.  
  2194. let inlinePreviewPlayer = null;
  2195. const ss = [HTMLElement.prototype.querySelector.call(q, '#inline-preview-player')].filter(e => e && !e.closest('[hidden]'));
  2196. if (ss && ss.length === 1) {
  2197. inlinePreviewPlayer = ss[0];
  2198. }
  2199. if (!inlinePreviewPlayer) return;
  2200.  
  2201. const f = () => {
  2202. if (mz !== mt || !(q.hasAttribute('active') && !q.hasAttribute('hidden')) || !(inlinePreviewPlayer && inlinePreviewPlayer.isConnected === true)) {
  2203. mzId && clearInterval(mzId);
  2204. mzId = 0;
  2205. return;
  2206. }
  2207.  
  2208. const s = inlinePreviewPlayer;
  2209. s.classList.remove('ytp-hide-inline-preview-progress-bar');
  2210. s.classList.remove('ytp-hide-inline-preview-audio-controls');
  2211. s.classList.add('ytp-show-inline-preview-progress-bar');
  2212. s.classList.add('ytp-show-inline-preview-audio-controls');
  2213. s.classList.remove('ytp-autohide');
  2214. if (q.hasAttribute('hide-volume-controls')) {
  2215. q.removeAttribute('hide-volume-controls')
  2216. }
  2217.  
  2218. if (s.classList.contains('playing-mode') && !q.hasAttribute('playing')) {
  2219. q.setAttribute('playing', '')
  2220. }
  2221. }
  2222. mzId = setInterval(f, 40);
  2223. f();
  2224.  
  2225. }
  2226. const mo = new MutationObserver(mof);
  2227. document.addEventListener('yt-navigate-finish', async function () {
  2228.  
  2229. for (const s of document.querySelectorAll('ytd-video-preview')) {
  2230. mo.observe(s, {
  2231. attributes: true,
  2232. attributeFilter: ["hidden", "active"],
  2233. attributeOldValue: false
  2234. });
  2235. mof();
  2236. }
  2237.  
  2238. }, false);
  2239.  
  2240. }
  2241. })
  2242.  
  2243.  
  2244. })();