YouTube: Audio Only

No Video Streaming

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

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