YouTube: Audio Only

No Video Streaming

当前为 2024-04-10 提交的版本,查看 最新版本

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