// ==UserScript== // @name YouTube: Audio Only // @description No Video Streaming // @namespace UserScript // @version 2.1.24 // @author CY Fung // @match https://www.youtube.com/* // @match https://www.youtube.com/embed/* // @match https://www.youtube-nocookie.com/embed/* // @match https://m.youtube.com/* // @exclude /^https?://\S+\.(txt|png|jpg|jpeg|gif|xml|svg|manifest|log|ini)[^\/]*$/ // @icon https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/YouTube-Audio-Only.png // @grant GM_registerMenuCommand // @grant GM.setValue // @grant GM.getValue // @grant GM.listValues // @grant GM.deleteValue // @run-at document-start // @require https://cdn.jsdelivr.net/gh/cyfung1031/userscript-supports@5d83d154956057bdde19e24f95b332cb9a78fcda/library/default-trusted-type-policy.js // @license MIT // @compatible chrome // @compatible firefox // @compatible opera // @compatible edge // @compatible safari // @allFrames true // // @downloadURL none // ==/UserScript== (async function () { 'use strict'; const defaultPolicy = (typeof trustedTypes !== 'undefined' && trustedTypes.defaultPolicy) || { createHTML: s => s }; function createHTML(s) { return defaultPolicy.createHTML(s); } let trustHTMLErr = null; try { document.createElement('div').innerHTML = createHTML('1'); } catch (e) { trustHTMLErr = e; } if (trustHTMLErr) { console.log(`trustHTMLErr`, trustHTMLErr); trustHTMLErr(); // exit userscript } /** @type {globalThis.PromiseConstructor} */ const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve. if (typeof AbortSignal === 'undefined') throw new DOMException("Please update your browser.", "NotSupportedError"); async function confirm(message) { // Create the HTML for the dialog if (!document.body) return; let dialog = document.getElementById('confirmDialog794'); if (!dialog) { const dialogHTML = `

${message}

`; // Append the dialog to the document body document.body.insertAdjacentHTML('beforeend', createHTML(dialogHTML)); dialog = document.getElementById('confirmDialog794'); } // Return a promise that resolves or rejects based on the user's choice return new Promise((resolve) => { document.getElementById('confirmBtn').onclick = () => { resolve(true); cleanup(); }; document.getElementById('cancelBtn').onclick = () => { resolve(false); cleanup(); }; function cleanup() { dialog && dialog.remove(); dialog = null; } }); } if (location.pathname === '/live_chat' || location.pathname === 'live_chat_replay') return; const kEventListener = (evt) => { if (document.documentElement.hasAttribute('forceRefresh032')) { evt.stopImmediatePropagation(); evt.stopPropagation(); } } window.addEventListener('beforeunload', kEventListener, false); const pageInjectionCode = function () { let debugFlg001 = false; // let debugFlg002 = false; // let globalPlayer = null; const SHOW_VIDEO_STATIC_IMAGE = true; const PATCH_MEDIA_PUBLISH = true; const PATCH_MEDIA_PLAYPAUSE = true; if (typeof AbortSignal === 'undefined') throw new DOMException("Please update your browser.", "NotSupportedError"); const URL = window.URL || new Function('return URL')(); const createObjectURL = URL.createObjectURL.bind(URL); /** @type {globalThis.PromiseConstructor} */ const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve. const PromiseExternal = ((resolve_, reject_) => { const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject }; return class PromiseExternal extends Promise { constructor(cb = h) { super(cb); if (cb === h) { /** @type {(value: any) => void} */ this.resolve = resolve_; /** @type {(reason?: any) => void} */ this.reject = reject_; } } }; })(); const [setTimeout_, clearTimeout_] = [setTimeout, clearTimeout]; /* globals WeakRef:false */ /** @type {(o: Object | null) => WeakRef | null} */ const mWeakRef = typeof WeakRef === 'function' ? (o => o ? new WeakRef(o) : null) : (o => o || null); /** @type {(wr: Object | null) => Object | null} */ const kRef = (wr => (wr && wr.deref) ? wr.deref() : wr); const isIterable = (x) => Symbol.iterator in Object(x); let byPassSync = false; let byPassNonFatalError = false; let skipPlayPause = 0; let byPassPublishPatch = false; let dirtyMark = 1 | 2 | 4 | 8; const dmo = {}; const qzk = Symbol(); const observablePromise = (proc, timeoutPromise) => { let promise = null; return { obtain() { if (!promise) { promise = new Promise(resolve => { let mo = null; const f = () => { let t = proc(); if (t) { mo.disconnect(); mo.takeRecords(); mo = null; resolve(t); } } mo = new MutationObserver(f); mo.observe(document, { subtree: true, childList: true }) f(); timeoutPromise && timeoutPromise.then(() => { resolve(null) }); }); } return promise } } } const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0); const prototypeInherit = (d, b) => { const m = Object.getOwnPropertyDescriptors(b); for (const p in m) { if (!Object.getOwnPropertyDescriptor(d, p)) { Object.defineProperty(d, p, m[p]); } } }; const delayPn = delay => new Promise((fn => setTimeout_(fn, delay))); const mockEvent = (o, elem) => { o = o || {}; elem = elem || null; return { preventDefault: () => { }, stopPropagation: () => { }, stopImmediatePropagation: () => { }, returnValue: true, target: elem, srcElement: elem, defaultPrevented: false, cancelable: true, timeStamp: performance.now(), ...o } }; const generalRegister = (prop, symbol, checker, pg) => { const objSet = new Set(); let done = false; const f = (o) => { const ct = o.constructor; const proto = ct.prototype; if (!done && proto && ct !== Function && ct !== Object && checker(proto)) { done = true; delete Object.prototype[prop]; objSet.delete(proto); objSet.delete(o); for (const obj of objSet) { obj[prop] = obj[symbol]; delete obj[symbol]; } objSet.clear(); Object.defineProperty(proto, prop, pg); return proto; } return false; }; Object.defineProperty(Object.prototype, prop, { get() { const p = f(this); if (p) { return p[prop]; } else { return this[symbol]; } }, set(nv) { const p = f(this); if (p) { p[prop] = nv; } else { objSet.add(this); this[symbol] = nv; } return true; }, enumerable: false, configurable: true }); }; const attachOneTimeEvent = function (eventType, callback) { let kz = false; document.addEventListener(eventType, function (evt) { if (kz) return; kz = true; callback(evt); }, { capture: true, passive: true, once: true }); } const evaluateInternalAppScore = (internalApp) => { let r = 0; if (!internalApp || typeof internalApp !== 'object') { return -999; } if (internalApp.app) r -= 100; if (!('mediaElement' in internalApp)) r -= 500; if (!('videoData' in internalApp)) r -= 50; if (!('playerState' in internalApp)) r -= 50; if ('getVisibilityState' in internalApp) r += 20; if ('visibility' in internalApp) r += 40; if ('isBackground' in internalApp) r += 40; if ('publish' in internalApp) r += 10; if (('playerType' in internalApp)) r += 10; if (('playbackRate' in internalApp)) r += 10; if (('playerState' in internalApp)) r += 10; if (typeof (internalApp.playerState || 0) === 'object') r += 50; return r; } const { remapString } = (() => { function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } /** * Create a deterministic "random" mapping from 'a'..'z' -> shuffled letters. * Returns a Map for O(1) lookups. */ function createRandomAlphabetMap() { const baseAlphabet = "abcdefghijklmnopqrstuvwxyz"; const letters = baseAlphabet.split(""); // Shuffle letters with that seeded generator const shuffledLetters = shuffleArray(letters); // Build the Map const map = new Map(); for (let i = 0, l = baseAlphabet.length; i < l; i++) { map.set(baseAlphabet[i], shuffledLetters[i]); map.set(baseAlphabet[i].toUpperCase(), shuffledLetters[i].toUpperCase()); } return map; } // Create the random map once at initialization let randomAlphabetMap = null; /** * Remaps alphabetic letters in a string according to randomAlphabetMap. * Preserves the case of letters and leaves non-alphabet characters unchanged. */ function remapString(input) { if (!randomAlphabetMap) return input; let result = new Array(input.length); let i = 0; for (const char of input) { result[i++] = randomAlphabetMap.get(char) || char; } return result.join(''); } const listA = [ "error", "internalvideodatachange", "statechange", "SEEK_TO", "videoelementevent", "onLoadedMetadata", "progresssync", "onVideoProgress", "SEEK_COMPLETE", "playbackstarted", "onLoadProgress", "nonfatalerror", "internalAbandon", "internalvideoformatchange", "internalaudioformatchange", "playbackready", "mediasourceattached", "beginseeking", "endseeking" ]; const mdA = listA.join('|'); loop1: for (let tryCount = 8; tryCount > 0; tryCount--) { randomAlphabetMap = createRandomAlphabetMap(); const listB = listA.map(remapString); const mdB = listB.join('|'); for (const a of listA) { if (mdB.includes(a)) { randomAlphabetMap = null; continue loop1; } } for (const b of listB) { if (mdA.includes(b)) { randomAlphabetMap = null; continue loop1; } } break; } if (!randomAlphabetMap) { console.error('randomAlphabetMap is not available.') } return { remapString }; })(); function removeTempObjectProp01() { delete Object.prototype['kevlar_non_watch_unified_player']; delete Object.prototype['kevlar_unified_player']; } function ytConfigFix(config__) { const config_ = config__; if (config_) { const playerKevlar = ((config_ || 0).WEB_PLAYER_CONTEXT_CONFIGS || 0).WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_WATCH || 0; if (playerKevlar) { // console.log(322, playerKevlar) playerKevlar.allowWoffleManagement = false; playerKevlar.cinematicSettingsAvailable = false; playerKevlar.showMiniplayerButton = false; playerKevlar.showMiniplayerUiWhenMinimized = false; playerKevlar.transparentBackground = false; playerKevlar.enableCsiLogging = false; playerKevlar.externalFullscreen = false; if (typeof playerKevlar.serializedExperimentFlags === 'string') { playerKevlar.serializedExperimentFlags = ''; // playerKevlar.serializedExperimentFlags = playerKevlar.serializedExperimentFlags.replace(/[-\w]+=(\[\]|[.-\d]+|[_a-z]+|)(&|$)/g,'').replace(/&$/,'') } if (typeof playerKevlar.serializedExperimentIds === 'string') { playerKevlar.serializedExperimentIds = ''; // playerKevlar.serializedExperimentIds = playerKevlar.serializedExperimentIds.replace(/\d+\s*(,\s*|$)/g,'') } } removeTempObjectProp01(); let configs = config_.WEB_PLAYER_CONTEXT_CONFIGS || {}; for (const [key, entry] of Object.entries(configs)) { if (entry && typeof entry.serializedExperimentFlags === 'string' && entry.serializedExperimentFlags.length > 16) { // prevent idle playback failure 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) => { return a + '00' + '=' + b + c; }); } } const EXPERIMENT_FLAGS = config_.EXPERIMENT_FLAGS; if (EXPERIMENT_FLAGS) { EXPERIMENT_FLAGS.kevlar_unified_player = true; EXPERIMENT_FLAGS.kevlar_non_watch_unified_player = true; } const EXPERIMENTS_FORCED_FLAGS = config_.EXPERIMENTS_FORCED_FLAGS; if (EXPERIMENTS_FORCED_FLAGS) { EXPERIMENTS_FORCED_FLAGS.kevlar_unified_player = true; EXPERIMENTS_FORCED_FLAGS.kevlar_non_watch_unified_player = true; } } } Object.defineProperty(Object.prototype, 'kevlar_non_watch_unified_player', { get() { // console.log(501, this.constructor.prototype) return true; }, set(nv) { return true; }, enumerable: false, configurable: true }); Object.defineProperty(Object.prototype, 'kevlar_unified_player', { get() { // console.log(501, this.constructor.prototype) return true; }, set(nv) { return true; }, enumerable: false, configurable: true }); // let prr = new PromiseExternal(); // const prrPipeline = createPipeline(); // let stopAndReload = false; let fa = 0; let cv = null; let durationchangeForMobile = false; function fixThumbnailURL(src) { if (typeof src === 'string' && src.length >= 4) { let m = /\b[a-z0-9]{4,13}\.jpg\b/.exec(src); if (m && m[0]) { const t = m[0]; let idx = src.indexOf(t); let nSrc = idx >= 0 ? src.substring(0, idx + t.length) : ''; return nSrc; } } return src; } const isDesktopSite = location.origin === 'https://www.youtube.com' && !location.pathname.startsWith('/embed/'); const getThumbnailUrlFromThumbnails = (thumbnails) => { let thumbnailUrl = ''; if (thumbnails && thumbnails.length >= 1) { const arr = thumbnails.map(e => { return e.url ? [e.width * e.height, e.url] : typeof e === 'string' ? [0, e] : [0, ''] }); arr.sort((a, b) => b[0] - a[0]); thumbnailUrl = arr[0][1] if (typeof thumbnailUrl === 'string') { thumbnailUrl = fixThumbnailURL(thumbnailUrl); } } return thumbnailUrl; } const staticImageMap = new Map(); const delayedUpdateStaticImage = (target) => { dmo.delayedUpdateStaticImage && dmo.delayedUpdateStaticImage(target); } const pmof = () => { if (SHOW_VIDEO_STATIC_IMAGE) { let medias = [...document.querySelectorAll('ytd-watch-flexy #player .html5-video-container .video-stream.html5-main-video')].filter(e => !e.closest('[hidden]')); if(medias.length === 0) medias = [...document.querySelectorAll('ytd-watch-flexy .html5-video-container .video-stream.html5-main-video')].filter(e => !e.closest('[hidden]')); if (medias.length !== 1) return; const mediaElm = medias[0]; const container = mediaElm ? mediaElm.closest('.html5-video-container') : null; if (!container) return; const movie_player = mediaElm.closest('#movie_player, #masthead-player'); let videoId = ''; try { videoId = movie_player && insp(movie_player).getVideoData().video_id; } catch (e) { } let thumbnailUrl = ''; if (videoId) { thumbnailUrl = staticImageMap.get(videoId); } if (!thumbnailUrl) { const ytdPage = container.closest('ytd-watch-flexy'); if (ytdPage && ytdPage.is === 'ytd-watch-flexy') { const cnt = insp(ytdPage); let thumbnails = null; let videoDetails = null; try { videoDetails = insp(cnt).__data.playerData.videoDetails; thumbnails = videoDetails.thumbnail.thumbnails; // thumbnails = cnt.__data.watchNextData.playerOverlays.playerOverlayRenderer.autoplay.playerOverlayAutoplayRenderer.background.thumbnails } catch (e) { } thumbnailUrl = getThumbnailUrlFromThumbnails(thumbnails); if (videoId && thumbnailUrl && typeof thumbnailUrl === 'string' && videoId === videoDetails.videoId ) { staticImageMap.set(videoId, thumbnailUrl); } } } if (thumbnailUrl && typeof thumbnailUrl === 'string') { container.style.setProperty('--audio-only-thumbnail-image', `url(${thumbnailUrl})`); } else { container.style.removeProperty('--audio-only-thumbnail-image') } } } const pmo = new MutationObserver(pmof); isDesktopSite && document.addEventListener('yt-navigate-finish', () => { const ytdWatchFlexy = document.querySelector('ytd-watch-flexy'); if (ytdWatchFlexy) { pmo.observe(ytdWatchFlexy, { attributes: true }); ytdWatchFlexy.setAttribute('ytzNavigateFinish', Date.now()); } }); document.addEventListener('durationchange', (evt) => { const target = (evt || 0).target; if (!(target instanceof HTMLMediaElement)) return; dirtyMark = 1 | 2 | 4 | 8; target.__lastTouch582__ = Date.now(); const targetClassList = target.classList || 0; const isPlayerVideo = typeof targetClassList.contains === 'function' ? targetClassList.contains('video-stream') && targetClassList.contains('html5-main-video') : false; delayedUpdateStaticImage(target); if (durationchangeForMobile || isPlayerVideo) { if (target.readyState !== 1) { fa = 1; } else { fa = 2; } } if (isPlayerVideo) { if (target.readyState === 1 && target.networkState === 2) { target.__spfgs__ = true; if (cv) { cv.resolve(); cv = null; } } else { target.__spfgs__ = false; } if (isDesktopSite) { const ytdWatchFlexy = document.querySelector('ytd-watch-flexy'); if (ytdWatchFlexy) { ytdWatchFlexy.setAttribute('ytzMediaDurationChanged', Date.now()); } } if (onVideoChangeForMobile) { onVideoChangeForMobile(); } } }, true); // XMLHttpRequest.prototype.open299 = XMLHttpRequest.prototype.open; /* XMLHttpRequest.prototype.open2 = function(method, url, ...args){ if (typeof url === 'string' && url.length > 24 && url.includes('/videoplayback?') && url.replace('?', '&').includes('&source=')) { if (vcc !== vdd) { vdd = vcc; window.postMessage({ ZECxh: url.includes('source=yt_live_broadcast') }, "*"); } } return this.open299(method, url, ...args) }*/ // desktop only // document.addEventListener('yt-page-data-fetched', async (evt) => { // const pageFetchedDataLocal = evt.detail; // let isLiveNow; // try { // isLiveNow = pageFetchedDataLocal.pageData.playerResponse.microformat.playerMicroformatRenderer.liveBroadcastDetails.isLiveNow; // } catch (e) { } // window.postMessage({ ZECxh: isLiveNow === true }, "*"); // }, false); // return; // let clickLockFn = null; let onVideoChangeForMobile = null; let removeBottomOverlayForMobile = null; let clickLockFn = null; let clickTarget = null; if (location.origin === 'https://m.youtube.com') { EventTarget.prototype.addEventListener322 = EventTarget.prototype.addEventListener; const dummyFn = () => { }; EventTarget.prototype.addEventListener = function (evt, fn, opts) { let hn = fn; // if (evt === 'player-error') { // } else if (evt === 'player-detailed-error') { // } else if (evt === 'video-data-change') { // } else if (evt === 'player-state-change') { // } else if (evt === 'player-autonav-pause' || evt === 'visibilitychange') { evt += 'y' fn = dummyFn; } else if (evt === 'click' && (this.id === 'movie_player' || this.id === 'masthead-player')) { clickLockFn = fn; clickTarget = this; } return this.addEventListener322(evt, hn, opts) } } (() => { XMLHttpRequest = (() => { const XMLHttpRequest_ = XMLHttpRequest; if ('__xmMc8__' in XMLHttpRequest_.prototype) return XMLHttpRequest_; const url0 = createObjectURL(new Blob([], { type: 'text/plain' })); const c = class XMLHttpRequest extends XMLHttpRequest_ { constructor(...args) { super(...args); } open(method, url, ...args) { let skip = false; if (!url || typeof url !== 'string') skip = true; else if (typeof url === 'string') { let turl = url[0] === '/' ? `.youtube.com${url}` : `${url}`; if (turl.includes('googleads') || turl.includes('doubleclick.net')) { skip = true; } else if (turl.includes('.youtube.com/pagead/')) { skip = true; } else if (turl.includes('.youtube.com/ptracking')) { skip = true; } else if (turl.includes('.youtube.com/api/stats/')) { // /api/stats/ // skip = true; // for user activity logging e.g. watched videos } else if (turl.includes('play.google.com/log')) { skip = true; } else if (turl.includes('.youtube.com//?')) { // //?cpn= skip = true; } } if (!skip) { this.__xmMc8__ = 1; return super.open(method, url, ...args); } else { this.__xmMc8__ = 2; return super.open('GET', url0); } } send(...args) { if (this.__xmMc8__ === 1) { return super.send(...args); } else if (this.__xmMc8__ === 2) { return super.send(); } else { console.log('xhr warning'); return super.send(...args); } } } c.prototype.__xmMc8__ = 0; prototypeInherit(c.prototype, XMLHttpRequest_.prototype); return c; })(); const s7 = Symbol(); const f7 = () => true; !window.canRetry9048 && generalRegister('canRetry', s7, (p) => { 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' }, { get() { if ('logger' in this && 'policy' in this && 'xhr' && this) { 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" // OKAY ! console.log('canRetry05 - ', this.errorMessage) return f7; } // console.log(this) console.log('canRetry02 - ', this.errorMessage, this) } else { console.log('canRetry ERR - ', this.errorMessage) } return this[s7]; }, set(nv) { this[s7] = nv; return true; }, enumerable: false, configurable: true }); window.canRetry9048 = 1; })(); const updateLastActiveTimeAsync_ = (player_) => { if (player_ && typeof player_.updateLastActiveTime === 'function') { player_.updateLastActiveTime(); } }; const updateLastActiveTimeAsync = (evt) => { Promise.resolve(evt?.updateLastActiveTime ? evt : evt?.target).then(updateLastActiveTimeAsync_); }; const { setupAudioPlaying, internalAppPTFn, standardAppPTFn, playerDapPTFn } = (() => { // playerApp: external API [ external use ] // playerDap: internal player ( with this.app and this.state ) [ the internal interface for both app and state ] // standardApp: .app of internal player [without isBackground, with fn getVideoDate(), etc] // internalApp: internal controller inside standardApp (normally non-accessible) [with isBackground, data field videoData, etc] // window.gt1 -> playerApp // window.gt11 -> playerDap // window.gt2 -> standardApp // window.gt3 -> internalApp let key_mediaElementT = ''; let key_yn = ''; let key_nS = ''; let key_L1 = ''; // playerDap -> internalDap let listAllPublish = false; let promiseSeek = null; let internalAppXT = null; let standardAppXT = null; let playerAppXT = null; let playerDapXT = null; /* const __wmObjectRefs__ = new WeakMap(); class WeakRefSet extends Set { constructor() { super(); } add(obj) { if (typeof (obj || 0) === 'object') { let ref = __wmObjectRefs__.get(obj); if (!ref) { __wmObjectRefs__.set(obj, (ref = mWeakRef(obj))); } super.add(ref); } return this; } delete(obj) { if (!obj) return null; const ref = __wmObjectRefs__.get(obj); if (ref) { if(kRef(ref)) return super.delete(ref); super.delete(ref); return false; } return false; } *[Symbol.iterator]() { for (const value of super.values()) { const obj = (kRef(value) || null); if (!obj) { super.delete(value); continue; } yield obj; } } has(obj) { if (!obj) return null; const ref = __wmObjectRefs__.get(obj); if (!ref) return false; if (kRef(ref)) return super.has(ref); super.delete(ref); return false; } } */ const internalAppUT = new Set(); const standardAppUT = new Set(); const playerAppUT = new Set(); const playerDapUT = new Set(); let playerDapPTDone = false; // let playerAppPTDone = false; let standardAppPTDone = false; let internalAppPTDone = false; window.gtz = () => { return { internalAppUT, standardAppUT, playerAppUT, playerDapUT, dirtyMark } } const getMediaElement = () => { const internalApp = internalAppXM(); const standardApp = standardAppXM(); let t; if (t = internalApp?.mediaElement?.[key_mediaElementT]) return t; if (t = standardApp?.mediaElement?.[key_mediaElementT]) return t; return null; } const internalApp_ZZ_sync = function () { if (byPassSync) { return; } return this.sync9383(...arguments) }; const updateInternalAppFn_ = () => { const internalApp = internalAppXT; if (internalApp && !internalApp.__s4538__) { if (internalApp.mediaElement) internalApp.__s4538__ = true; const arr = Object.entries(internalApp).filter(e => e[1] && typeof e[1].sync === 'function'); for (const [key, o] of arr) { const p = o.__proto__ || o; if (!p.sync9383 && typeof p.sync === 'function') { p.sync9383 = p.sync; p.sync = internalApp_ZZ_sync; } } if (!key_yn || !key_nS) { for (const [key, value] of Object.entries(internalApp)) { if (!key_yn && typeof (value || 0) === 'object' && value.experiments && value.experiments.flags && !isIterable(value)) { key_yn = key; console.log(1959, 'key_yn', key_yn) } else if (!key_nS && typeof (value || 0) === 'object' && 'videoTrack' in value && 'audioTrack' in value && 'isSuspended' in value && !isIterable(value)) { key_nS = key; console.log(1959, 'key_nS', key_nS) } } } if (!key_mediaElementT) { const iaMedia = internalApp.mediaElement || 0; // console.log(1959, internalApp, iaMedia) if (internalApp && typeof iaMedia === 'object') { for (const [key, value] of Object.entries(iaMedia)) { if (value instanceof HTMLMediaElement) { key_mediaElementT = key; console.log(1959, 'key_mediaElementT', key_mediaElementT) } } } } } if (!internalAppPTDone) { const proto = internalApp ? internalApp.__proto__ : null; if (proto) { internalAppPTDone = true; internalAppPTFn(proto); } } } const updateInternalAppFn = (x) => { if (x !== internalAppXT) { dirtyMark = 1 | 2 | 4 | 8; internalAppUT.add(x); internalAppXT = x; // videoData // stopVideo // pauseVideo } updateInternalAppFn_(); } window.gt3 = () => internalAppXM(); window.gt3x = ()=>internalAppUT; const internalAppXM = () => { if (!(dirtyMark & 4)) return internalAppXT; if (!key_mediaElementT) return internalAppXT; let result = null; const possibleResults = []; for (const p of internalAppUT) { const iaMediaP = p.mediaElement; if (!iaMediaP) { // internalAppUT.delete(p); } else { const element = iaMediaP[key_mediaElementT]; if (element instanceof Element) { if (element instanceof HTMLMediaElement && Number.isNaN(element.duration)) { } else if (!element.isConnected) { // valid entry but audio is not on the page } else if (element.closest('[hidden]')) { } else if (result === null && element.duration > 0) { possibleResults.push([p, (element.__lastTouch582__ || 0), element.duration, (element.paused?1:0)]); // 3600 ads might be added } } } } if (possibleResults.length > 0) { if (possibleResults.length === 1) result = possibleResults[0][0]; else { possibleResults.sort((a, b) => { let t = (b[1] - a[1]); if (t < 360 && t > -360) t = 0; if (t > 0 || t < 0) return t; if (b[3] && !a[3]) return -1; if (!b[3] && a[3]) return 1; return (b[2] - a[2]); }); result = possibleResults[0][0]; } possibleResults.length = 0; } if (!result) return result; if (!internalAppUT.has(result)) { for (const p of internalAppUT) { const iaMediaP = p.mediaElement; if (!iaMediaP) { internalAppUT.delete(p); } } internalAppUT.add(result); } internalAppXT = result; updateInternalAppFn_(); if (dirtyMark & 4) dirtyMark -= 4; return result; } const updateStandardAppFn_ = () => { const standardAppXT_ = standardAppXT; if (!standardAppPTDone) { const proto = standardAppXT_ ? standardAppXT_.__proto__ : null; if (proto) { standardAppPTDone = true; standardAppPTFn(proto); } } } const updateStandardAppFn = (x) => { if (x !== standardAppXT) { dirtyMark = 1 | 2 | 4 | 8; standardAppUT.add(x); standardAppXT = x; // isAtLiveHead // cancelPlayback // stopVideo // pauseVideo } updateStandardAppFn_(x); } window.gt2 = () => standardAppXM(); const loadVideoByPlayerVarsP20 = {}; const loadVideoByPlayerVarsQ20 = new Map(); const standardAppXM = () => { if (!(dirtyMark & 2)) return standardAppXT; const internalApp = internalAppXM(); if (!internalApp) return standardAppXT; const iaMedia = internalApp.mediaElement; let result = null; for (const p of standardAppUT) { const iaMediaP = p.mediaElement; if (!iaMediaP) { // standardAppUT.delete(p); } else { if (iaMediaP === iaMedia) result = p; } } if (!result) return result; if (!standardAppUT.has(result)) { for (const p of standardAppUT) { const iaMediaP = p.mediaElement; if (!iaMediaP) { standardAppUT.delete(p); } } standardAppUT.add(result); } standardAppXT = result; updateStandardAppFn_(); if (dirtyMark & 2) dirtyMark -= 2; return result; } const updatePlayerDapFn_ = () => { const playerD_ = playerDapXT; if (!playerD_.__onVideoProgressF381__) { playerD_.__onVideoProgressF381__ = true; try { playerD_.removeEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop } catch (e) { } playerD_.addEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop } if (!playerDapPTDone) { const proto = playerD_ ? playerD_.__proto__ : null; if (proto) { playerDapPTDone = true; playerDapPTFn(proto); } } const standardApp_ = playerD_.app || 0; if (standardApp_) { updateStandardAppFn(standardApp_); } } const updatePlayerDapFn = (x) => { if (x !== playerDapXT) { dirtyMark = 1 | 2 | 4 | 8; // console.log('updatePlayerDapFn') playerDapUT.add(x); playerDapXT = x; } updatePlayerDapFn_(x); } window.gt11 = () => { return playerDapXM(); } const playerDapXM = () => { if (!(dirtyMark & 8)) return playerDapXT; const standardApp = standardAppXM(); if (!standardApp) return playerDapXT; let result = null; for (const p of playerDapUT) { if (!p.app || !p.app.mediaElement) { // playerDapUT.delete(p); } else if (p.app === standardApp) result = p; } if (!result) return result; playerDapUT.add(result); playerDapXT = result; updatePlayerDapFn_(); if (dirtyMark & 8) dirtyMark -= 8; return result; } const updatePlayerAppFn_ = () => { const player_ = playerAppXT; if (!player_.__s4539__ || !player_.__s4549__) { player_.__s4539__ = true; if (!player_.__onVideoProgressF381__ && typeof player_.addEventListener === 'function') { player_.__onVideoProgressF381__ = true; try { player_.removeEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop } catch (e) { } player_.addEventListener('onVideoProgress', updateLastActiveTimeAsync); // desktop } const playerPT = player_.__proto__; if (playerPT && typeof playerPT.getPlayerStateObject === 'function' && !playerPT.getPlayerStateObject949) { playerPT.getPlayerStateObject949 = playerPT.getPlayerStateObject; playerPT.getPlayerStateObject = function () { updatePlayerAppFn(this); return this.getPlayerStateObject949(...arguments); } } else if (player_ && typeof player_.getPlayerStateObject === 'function' && !player_.getPlayerStateObject949) { player_.getPlayerStateObject949 = player_.getPlayerStateObject; player_.getPlayerStateObject = function () { updatePlayerAppFn(this); return this.getPlayerStateObject949(...arguments); } } // globalPlayer = mWeakRef(player_); // window.gp3 = player_; let playerDap_ = null; { const objectSets = new Set(); Function.prototype.apply129 = Function.prototype.apply; Function.prototype.apply = function () { objectSets.add([this, ...arguments]); return this.apply129(...arguments) } player_.getPlayerState(); Function.prototype.apply = Function.prototype.apply129; console.log(39912, [...objectSets]); let filteredObjects = [...objectSets].filter(e => { return Object(e[1]).getPlayerState === e[0] }); console.log(39914, filteredObjects); if (filteredObjects.length > 1) { filteredObjects = filteredObjects.filter((e) => !(e[1] instanceof Node)); } if (filteredObjects.length === 1) { playerDap_ = filteredObjects[0][1]; } objectSets.clear(); filteredObjects.length = 0; } { let internalApp_ = null; if (playerDap_ && playerDap_.app && playerDap_.state) { const playerDapP_ = playerDap_.__proto__; if (playerDapP_ && (playerDapP_.stopVideo || playerDapP_.pauseVideo) && (playerDapP_.playVideo)) { if (!key_L1) { const listOfPossibles = []; for (const [key, value] of Object.entries(playerDapP_)) { if (typeof value === 'function' && value.length === 0 && `${value}`.endsWith('(this.app)}')) { // return g.O5(this.app) let m = null; try { m = playerDap_[key]() } catch (e) { } if (typeof (m || 0) === 'object') { listOfPossibles.push([key, m, evaluateInternalAppScore(m)]); } } } if (listOfPossibles.length >= 2) { listOfPossibles.sort((a, b) => { return b[2] - a[2]; }) } if (listOfPossibles.length >= 1) { key_L1 = listOfPossibles[0][0]; internalApp_ = listOfPossibles[0][1]; console.log('[yt-audio-only] key_L1', key_L1); } listOfPossibles.length = 0; // key_L1 = ''; } updatePlayerDapFn(playerDap_); } } if (key_L1) { const internalApp = internalApp_ || playerDap_[key_L1](); if (internalApp) { updateInternalAppFn(internalApp); player_.__s4549__ = true; } } } setupFns(); } } // player could be just a DOM element without __proto__ // will this update fail? const updatePlayerAppFn = (x) => { if (x !== playerAppXT) { dirtyMark = 1 | 2 | 4 | 8; // console.log('updatePlayerAppFn') playerAppUT.add(x); playerAppXT = x; } updatePlayerAppFn_(); } const playerAppXM = () => { if (!(dirtyMark & 1)) return playerAppXT; const standardApp = standardAppXM(); if (!standardApp) return playerAppXT; const playerAppUA = [...playerAppUT]; loadVideoByPlayerVarsQ20.clear(); for (let i = 0; i < playerAppUA.length; i++) { const playerApp = playerAppUA[i]; loadVideoByPlayerVarsP20.index = i; try { playerApp.loadVideoByPlayerVars(loadVideoByPlayerVarsP20, 0, 0); } catch (e) { } loadVideoByPlayerVarsP20.index = -1; } window.loadVideoByPlayerVarsQ20 = loadVideoByPlayerVarsQ20; const j = loadVideoByPlayerVarsQ20.get(standardApp); const result = Number.isFinite(j) && j >= 0 ? playerAppUA[j] : null; const idxSet = new Set(loadVideoByPlayerVarsQ20.values()); for (let i = 0; i < playerAppUA.length; i++) { if (!idxSet.has(i)) playerAppUT.delete(playerAppUA[i]); } // loadVideoByPlayerVarsQ20.clear(); if (!result) return result; playerAppUT.add(result); playerAppXT = result; updatePlayerAppFn_(); if (dirtyMark & 1) dirtyMark -= 1; return result; } window.gt1 = () => playerAppXM(); const playerDapPTFn = (playerDapPT_) => { const playerDapPT = playerDapPT_; if (playerDapPT && typeof playerDapPT.getPlayerStateObject === 'function' && !playerDapPT.getPlayerStateObject949) { playerDapPT.getPlayerStateObject949 = playerDapPT.getPlayerStateObject; playerDapPT.getPlayerStateObject = function () { updatePlayerDapFn(this); return this.getPlayerStateObject949(...arguments); }; } }; const standardAppPTFn = (standardAppPT_) => { const standardAppPT = standardAppPT_; if (standardAppPT && typeof standardAppPT.loadVideoByPlayerVars === 'function' && !standardAppPT.loadVideoByPlayerVars311) { let lastRecord = []; standardAppPT.loadVideoByPlayerVars311 = standardAppPT.loadVideoByPlayerVars; standardAppPT.loadVideoByPlayerVars = function (p, C, V, N, H) { if (p === loadVideoByPlayerVarsP20) { // console.log('loadVideoByPlayerVarsP20', p, p.index) loadVideoByPlayerVarsQ20.set(this, p.index); return; } try { // update static image here! updateStandardAppFn(this) if (p && typeof p === 'object') { const { adPlacements, adSlots } = p.raw_player_response || {}; if (isIterable(adPlacements)) adPlacements.length = 0; if (isIterable(adSlots)) adSlots.length = 0; lastRecord.length = 0; lastRecord.push(...[p, C, V, N, H]); console.log('lastRecord 03022', [...lastRecord]) const videoDetails = ((p || 0).raw_player_response || 0).videoDetails || 0; if (videoDetails) { const thumbnails = (videoDetails.thumbnail || 0).thumbnails || 0; const url = thumbnails ? getThumbnailUrlFromThumbnails(thumbnails) : ''; const videoId = videoDetails.videoId; videoId && url && typeof url === 'string' && typeof videoId === 'string' && staticImageMap.set(videoId, url); // console.log('staticImageMap set', videoId, url); } dirtyMark = 1 | 2 | 4 | 8; } } catch (e) { console.warn(e); } return this.loadVideoByPlayerVars311(...arguments); } } }; const { internalAppPTFn } = (() => { const flags_ = {} let qma = 0; const flagOn_ = (flags, key, bool) => { flags_[key] = flags[key]; flags[key] = typeof flags[key] === 'boolean' ? bool : `${bool}`; } const flagOn = () => { // return; const internalApp = internalAppXM(); if (!key_yn) return; const flags = internalApp?.[key_yn]?.experiments?.flags || 0; if (!flags) return; if (qma < 0) return; qma++; if (qma > 1) return; flagOn_(flags, 'html5_enable_ssap_autoplay_debug_logging', false); // flagOn_(flags, 'enable_visit_advertiser_support_on_ipad_mweb', false); // flagOn_(flags, 'html5_shorts_onesie_mismatched_fix', false); // flagOn_(flags, 'html5_early_media_for_drm', false); // flagOn_(flags, 'allow_vp9_1080p_mq_enc', false); // flagOn_(flags, 'html5_onesie_preload_use_content_owner', false); flagOn_(flags, 'html5_exponential_memory_for_sticky', false); // flagOn_(flags, 'html5_perf_cap_override_sticky', false); // flagOn_(flags, 'html5_perserve_av1_perf_cap', false); // flagOn_(flags, 'html5_disable_low_pipeline', false); flagOn_(flags, 'html5_publish_all_cuepoints', false); flagOn_(flags, 'html5_ultra_low_latency_subsegment_readahead', false); // flagOn_(flags, 'html5_disable_move_pssh_to_moov', false); flagOn_(flags, 'html5_sunset_aac_high_codec_family', false); // flagOn_(flags, 'html5_enable_ssap_seteos', false); // flagOn_(flags, 'html5_catch_errors_for_rollback', false); // flagOn_(flags, 'html5_sabr_enable_utc_seek_requests', false); // flagOn_(flags, 'html5_sabr_enable_live_clock_offset', false); // flagOn_(flags, 'html5_disable_client_resume_policy_for_sabr', false); flagOn_(flags, 'html5_trigger_loader_when_idle_network', false); flagOn_(flags, 'web_key_moments_markers', false); flagOn_(flags, 'embeds_use_parent_visibility_in_ve_logging', false); flagOn_(flags, 'html5_onesie', false); qma = 1; } const flagOff = () => { // return; const internalApp = internalAppXM(); if (!key_yn) return; const flags = internalApp?.[key_yn]?.experiments?.flags || 0; if (!flags) return; if (qma <= 0) return; qma--; if (qma > 1) return; for (const [key, value] of Object.entries(flags_)) { flags[key] = value; } qma = 0; } const internalAppPTFn = (internalAppPT_) => { const internalAppPT = internalAppPT_; if (internalAppPT && internalAppPT.playVideo && !internalAppPT.playVideo9391) { internalAppPT.playVideo9391 = internalAppPT.playVideo; internalAppPT.playVideo = function (p, C) { updateInternalAppFn(this); console.log(`[yt-audio-only] internalApp.playVideo; skipPlayPause=${skipPlayPause}`); try { flagOn(); return this.playVideo9391(...arguments); } catch (e) { console.warn(e); } finally { flagOff(); } } internalAppPT.playVideo.toString = internalAppPT.playVideo9391.toString.bind(internalAppPT.playVideo9391); } if (internalAppPT && internalAppPT.pauseVideo && !internalAppPT.pauseVideo9391) { internalAppPT.pauseVideo9391 = internalAppPT.pauseVideo; internalAppPT.pauseVideo = function (p) { updateInternalAppFn(this); console.log(`[yt-audio-only] internalApp.pauseVideo; skipPlayPause=${skipPlayPause}`); try { flagOn(); return this.pauseVideo9391(...arguments); } catch (e) { console.warn(e); } finally { flagOff(); } } internalAppPT.pauseVideo.toString = internalAppPT.pauseVideo9391.toString.bind(internalAppPT.pauseVideo9391); } if (internalAppPT && internalAppPT.stopVideo && !internalAppPT.stopVideo9391) { internalAppPT.stopVideo9391 = internalAppPT.stopVideo; internalAppPT.stopVideo = function () { updateInternalAppFn(this); console.log(`[yt-audio-only] internalApp.stopVideo; skipPlayPause=${skipPlayPause ? 1 : 0}`); try { flagOn(); return this.stopVideo9391(...arguments); } catch (e) { console.warn(e); } finally { flagOff(); } } internalAppPT.stopVideo.toString = internalAppPT.stopVideo9391.toString.bind(internalAppPT.stopVideo9391); } if (internalAppPT && internalAppPT.isBackground && !internalAppPT.isBackground9391) { internalAppPT.isBackground9391 = internalAppPT.isBackground; const f = () => false; internalAppPT.isBackground = function () { try { if (this.visibility.isBackground !== f) this.visibility.isBackground = f; return f(); } catch (e) { } return false; } } if (internalAppPT && internalAppPT.sendAbandonmentPing && !internalAppPT.sendAbandonmentPing9391) { internalAppPT.sendAbandonmentPing9391 = internalAppPT.sendAbandonmentPing; internalAppPT.sendAbandonmentPing = function () { console.log('[yt-audio-only] sendAbandonmentPing'); const internalApp = this; const iaMedia = internalApp ? internalApp.mediaElement : null; if (iaMedia) { iaMedia.__publishStatus17__ = 0; iaMedia.__publishStatus18__ = 0; } dirtyMark = 1 | 2 | 4 | 8; return this.sendAbandonmentPing9391(...arguments); } } if (internalAppPT && internalAppPT.publish && !internalAppPT.publish48) { internalAppPT.publish48 = internalAppPT.publish; if (PATCH_MEDIA_PUBLISH) { const printObject = (b) => { return JSON.stringify(Object.entries(b || {}).filter(e => typeof (e[1] || 0) !== 'object')); }; const errorRS = remapString('error'); internalAppPT.publish33 = async function (a, b) { // console.log(3888, a,b); if (byPassPublishPatch) return; const isLoaded = await dmo.isLoadedW(); if (!isLoaded) return; // window.gt6 = this; const player_ = dmo.playerDapXM() || dmo.playerAppXM(); if (!player_) return; const stateObject = dmo.getPlayerWrappedStateObject(); let publishStatus = 0; const iaMedia = this.mediaElement; if (!stateObject || !iaMedia) return; if (stateObject.isUnstarted === true) { } else if (iaMedia && iaMedia.__publishStatus17__ >= 100 && iaMedia.__publishStatus17__ < 300) { if (iaMedia.__publishStatus18__ < Date.now()) { iaMedia.__publishStatus17__ = 0; iaMedia.__publishStatus18__ = 0; return; } } else { return; } let kb = false; const audio = dmo.getMediaElement(); if (a === 'internalaudioformatchange' && typeof (b.author || 0) === 'string' && iaMedia) { skipPlayPause = 0 playBusy = 0; kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true); byPassSync = false; skipPlayPause = 0; // byPassSync = true; byPassNonFatalError = true; await dmo.clearVideoAndQueue(); await dmo.refreshAllStaleEntitiesForNonReadyAudio(); byPassNonFatalError = false; // byPassSync = false; // await cancelPlayback(); publishStatus = iaMedia.__publishStatus17__ = 100; console.log(`[yt-audio-only] publish (internalaudioformatchange, =>100)`); iaMedia.__publishStatus18__ = Date.now() + 240; // if (audio) { // if (audio[qzk] > 1e9) audio[qzk] = 9; // audio[qzk] = (audio[qzk] || 0) + 1; // } } if (this.mediaElement && audio && a !== 'internalvideoformatchange') { if (a.includes('error') || a.includes(errorRS)) { if (!iaMedia.__publishStatus17__ || iaMedia.__publishStatus17__ < 200) { kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true); byPassSync = false; skipPlayPause = 0; // byPassSync = true; byPassNonFatalError = true; await dmo.clearVideoAndQueue(); // avoid error in live streaming await dmo.refreshAllStaleEntitiesForNonReadyAudio(); byPassNonFatalError = false; // byPassSync = false; console.log(`[yt-audio-only] publish (*error*, <200)`); } } else { iaMedia.__publishStatus17__ = iaMedia.__publishStatus17__ || 100; iaMedia.__publishStatus18__ = iaMedia.__publishStatus18__ || (Date.now() + 240); // const utv = player_.isAtLiveHead(); if (iaMedia.__publishStatus17__ === 100) { kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true); byPassNonFatalError = true; await dmo.refreshAllStaleEntitiesForNonReadyAudio(); byPassNonFatalError = false; console.log(`[yt-audio-only] publish (***, =100)`); } if (iaMedia.__publishStatus17__ === 100 && audio.duration > 0 /* && (dmo.getPlayerStateInt() === 3 || dmo.getPlayerStateInt() === 2) */) { iaMedia.__publishStatus17__ = 200 kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true); byPassSync = true; skipPlayPause = 3; byPassNonFatalError = true; await dmo.cancelPlayback(); await dmo.playVideo(); byPassNonFatalError = false; skipPlayPause = 0; byPassSync = false; await dmo.seekToLiveHeadForLiveStream(); await dmo.playVideo(); console.log(`[yt-audio-only] publish (***, duration>0, stateInt=3, =100, =>200)`); iaMedia.__publishStatus18__ = Date.now() + 240; } if (a === 'onLoadedMetadata' && iaMedia.__publishStatus17__ === 200) { iaMedia.__publishStatus17__ = 201; console.log(`[yt-audio-only] publish (onLoadedMetadata, =200, =>201)`); iaMedia.__publishStatus18__ = Date.now() + 240; } if (a === 'videoelementevent' && b.type === 'loadedmetadata' && iaMedia.__publishStatus17__ === 201) { iaMedia.__publishStatus17__ = 202; console.log(`[yt-audio-only] publish (videoelementevent.loadedmetadata, =201, =>202)`); iaMedia.__publishStatus18__ = Date.now() + 240; } if (a === 'videoelementevent' && b.type === 'progress' && iaMedia.__publishStatus17__ === 202) { iaMedia.__publishStatus17__ = 203; // window.debug_mfk = this; // window.debug_mfp = player_; console.log(`[yt-audio-only] publish (videoelementevent.progress, =202, =>203)`); iaMedia.__publishStatus18__ = Date.now() + 240; } if (iaMedia.__publishStatus17__ === 203 && audio && audio.readyState === 1) { // byPassSync = true; iaMedia.__publishStatus17__ = 204; kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true); byPassSync = true; skipPlayPause = 3; byPassNonFatalError = true; await dmo.pauseVideo(); await dmo.playVideo(); byPassNonFatalError = false; skipPlayPause = 0; byPassSync = false; console.log('[yt-audio-only] publish skipPlayPause 10002', iaMedia.__publishStatus17__, skipPlayPause); await dmo.seekToLiveHeadForLiveStream(); // byPassSync = false; console.log('[yt-audio-only] publish skipPlayPause 10003', iaMedia.__publishStatus17__, skipPlayPause); await dmo.playVideo(); console.log(`[yt-audio-only] publish (***, audio.readyState=1, =203, =>204)`); iaMedia.__publishStatus18__ = Date.now() + 240; console.log('[yt-audio-only] publish skipPlayPause 10004', iaMedia.__publishStatus17__, skipPlayPause); } if (iaMedia.__publishStatus17__ < 300 && iaMedia.__publishStatus17__ >= 200 && a === 'videoelementevent' && b.type === 'timeupdate' && !audio.paused && audio.readyState >= 4 && audio.duration > 0) { iaMedia.__publishStatus17__ = 300; if (!dmo.isAtLiveHeadW()) { kb = kb ? true : ((dmo.updateAtPublish && dmo.updateAtPublish(this)), true); await dmo.seekToLiveHeadForLiveStream(); } console.log(`[yt-audio-only] publish (videoelementevent.timeupdate, {audio playing}, [200, 300), =>300)`); iaMedia.__publishStatus18__ = Date.now() + 240; } } publishStatus = iaMedia.__publishStatus17__; if (debugFlg001) console.log('gkps0 publish | ' + publishStatus, a, printObject(b)) } } } internalAppPT.publish = function (p, C) { if (promiseSeek) { if (p === 'videoelementevent' && C && C.type === 'playing') { promiseSeek.resolve(); } else if (p === 'SEEK_COMPLETE') { promiseSeek.resolve(); } } let qb = false; if (byPassSync || (byPassNonFatalError && p === 'nonfatalerror')) { qb = true; } if (qb) { arguments[0] = p = typeof p === 'string' ? remapString(p) : p; } if (listAllPublish) console.log('[yt-audio-only] list publish', p, C) if (this.publish33) { try { if (dmo.ready) this.publish33(p, C); } catch (e) { console.warn(e); } } return this.publish48(...arguments); } } if (!internalAppPT.setMediaElement661 && typeof internalAppPT.setMediaElement === 'function') { internalAppPT.setMediaElement661 = internalAppPT.setMediaElement; internalAppPT.setMediaElement = function (p) { dirtyMark = 1 | 2 | 4 | 8; updateInternalAppFn(this); console.log('setMediaElement', p) const mediaEm = p && key_mediaElementT ? p[key_mediaElementT] : null; if (mediaEm) mediaEm.__lastTouch582__ = Date.now(); delayedUpdateStaticImage(getMediaElement()); return this.setMediaElement661(...arguments); } } } return { internalAppPTFn } })(); let setupFnsB = false; const setupFns = () => { if (setupFnsB) return; setupFnsB = true; try { const clearVideoAndQueue = async () => { // avoid error in live streaming const player_ = playerAppXM(); const playerD_ = playerDapXM(); const standardApp = standardAppXM(); if (standardApp && standardApp.clearQueue) { return await standardApp.clearQueue(); } else if (playerD_ && playerD_.clearQueue) { return await playerD_.clearQueue(); } else if (player_ && player_.clearQueue) { return await player_.clearQueue(); } else { return null; } } const cancelPlayback = async () => { const player_ = playerAppXM(); const playerD_ = playerDapXM(); const standardApp = standardAppXM(); const internalApp = internalAppXM(); if (internalApp && internalApp.stopVideo && internalApp.pauseVideo && !internalApp.cancelPlayback) { return await internalApp.stopVideo(); } else if (standardApp && standardApp.cancelPlayback) { return await standardApp.cancelPlayback(); } else if (playerD_ && playerD_.cancelPlayback) { return await playerD_.cancelPlayback(); } else if (player_ && player_.cancelPlayback) { return await player_.cancelPlayback(); } else { return null; } } const pauseVideo = async () => { const player_ = playerAppXM(); const playerD_ = playerDapXM(); const standardApp = standardAppXM(); const internalApp = internalAppXM(); if (internalApp && internalApp.stopVideo && internalApp.pauseVideo && !internalApp.cancelPlayback) { return await internalApp.pauseVideo(); } else if (standardApp && standardApp.pauseVideo) { return await standardApp.pauseVideo(); } else if (playerD_ && playerD_.pauseVideo) { return await playerD_.pauseVideo(); } else if (player_ && player_.pauseVideo) { return await player_.pauseVideo(); } else { return null } } const playVideo = async () => { const player_ = playerAppXM(); const playerD_ = playerDapXM(); const standardApp = standardAppXM(); const internalApp = internalAppXM(); if (internalApp && internalApp.stopVideo && internalApp.pauseVideo && !internalApp.cancelPlayback && internalApp.playVideo) { return await internalApp.playVideo(); } else if (standardApp && standardApp.playVideo) { return await standardApp.playVideo(); } else if (playerD_ && playerD_.playVideo) { return await playerD_.playVideo(); } else if (player_ && player_.playVideo) { return await player_.playVideo(); } else { return null } } const isAtLiveHeadW = async () => { const player_ = playerAppXM(); const playerD_ = playerDapXM(); const standardApp = standardAppXM(); const internalApp = internalAppXM(); if (internalApp && internalApp.isAtLiveHead) { return await internalApp.isAtLiveHead() } else if (standardApp && standardApp.isAtLiveHead) { return await standardApp.isAtLiveHead() } else if (playerD_ && playerD_.isAtLiveHead) { return await playerD_.isAtLiveHead() } else if (player_ && player_.isAtLiveHead) { return await player_.isAtLiveHead() } else { return null; } } const getInternalVideoData = () => { const internalApp = internalAppXM(); if (internalApp && internalApp.videoData) { return internalApp.videoData; } const standardApp = standardAppXM(); if (standardApp && typeof standardApp.getVideoData === 'function') { return standardApp.getVideoData(); } return null; } const isAdW = async () => { const vd = getInternalVideoData() || 0; if (vd && typeof vd.isAd === 'function') { return await vd.isAd(); } else if (vd && typeof vd.isAd === 'boolean') { return vd.isAd; } else { return null; } } const isLoadedW = async () => { const vd = getInternalVideoData() || 0; if (vd && typeof vd.isLoaded === 'function') { return await vd.isLoaded(); } else if (vd && typeof vd.isLoaded === 'boolean') { return vd.isLoaded; } else { return null; } } const getPlayerWrappedStateObject = () => { // g.h.oD = function(p) { // p = this.app.getPlayerStateObject(p); // return { // isBuffering: g.r(p, 1), // isCued: p.isCued(), // isDomPaused: g.r(p, 1024), // isEnded: g.r(p, 2), // isError: g.r(p, 128), // isOrWillBePlaying: p.isOrWillBePlaying(), // isPaused: p.isPaused(), // isPlaying: p.isPlaying(), // isSeeking: g.r(p, 16), // isUiSeeking: g.r(p, 32), // isUnstarted: g.r(p, 64) // } // } const standardApp = standardAppXM(); const playerD_ = playerDapXM(); const player_ = playerAppXM(); const app = standardApp || playerD_; if (app && typeof app.getPlayerStateObject === 'function') { const fo = app.getPlayerStateObject(); const flag = fo ? (fo.state || 0) : 0; return { isBuffering: (flag & 1) === 1, isCued: (flag & 64) === 64 && (flag & 8) === 0 && (flag & 4) === 0, isDomPaused: (flag & 1024) === 1024, isEnded: (flag & 2) === 2, isError: (flag & 128) === 128, isOrWillBePlaying: (flag & 8) === 8 && (flag & 2) === 0 && (flag & 1024) === 0, isPaused: (flag & 4) === 4, isPlaying: (flag & 8) === 8 && (flag & 512) === 0 && (flag & 64) === 0 && (flag & 2) === 0, isSeeking: (flag & 16) === 16, isUiSeeking: (flag & 32) === 32, isUnstarted: (flag & 64) === 64, }; } else if (player_ && typeof player_.getPlayerStateObject === 'function') { return player_.getPlayerStateObject(); } else { return {}; } } const getPlayerStateInt = () => { const playerD_ = playerDapXM(); const player_ = playerAppXM(); if (playerD_ && typeof playerD_.getPlayerState === 'function') { return playerD_.getPlayerState(); } else if (player_ && typeof player_.getPlayerState === 'function') { return player_.getPlayerState(); } else { return null; } } const updateAtPublish = (x) => { dirtyMark = 1 | 2 | 4 | 8; updateInternalAppFn(x); } const refreshAllStaleEntitiesForNonReadyAudio = async () => { const player_ = playerAppXM(); // player or xj if (!player_) return; const audio = getMediaElement(); try { // byPassSync = true; if (audio.readyState == 0 && audio.isConnected === true) await player_.refreshAllStaleEntities(); // byPassSync = false; } catch (e) { } }; const seekToLiveHeadForLiveStream = async () => { const player_ = playerDapXM() || playerAppXM(); // player or xj const audio = getMediaElement(); try { audio.isConnected === true && await player_.seekToLiveHead(); if (audio.isConnected === true && (await player_.isAtLiveHead()) === true) { audio.isConnected === true && await player_.seekToStreamTime(); return true; } } catch (e) { console.log('error_F7', e); } }; const trySeekToLiveHead = async () => { const player_ = playerDapXM() || playerAppXM(); // player or xj try { await player_.seekToLiveHead(); if ((await player_.isAtLiveHead()) === true) { await player_.seekToStreamTime(); } } catch (e) { } } let u75 = 0; const delayedUpdateStaticImage = async (target) => { if (u75 > 1e9) u75 = 9; const t75 = ++u75; await delayPn(40); if (t75 !== u75) return; const date0 = Date.now(); const mediaEm = target; if (!mediaEm || mediaEm.isConnected === false) return; let movie_player, h5vc; while (Date.now() - date0 < 800) { movie_player = mediaEm.closest('#movie_player, #masthead-player'); h5vc = mediaEm.closest('.html5-video-container'); if (movie_player && h5vc) break; await delayPn(40); if (t75 !== u75) return; } if (!movie_player || !h5vc) return; if (!mediaEm || mediaEm.isConnected === false) return; if (movie_player.querySelectorAll('video, audio').length !== 1) return; if (h5vc.querySelectorAll('video, audio').length !== 1) return; let videoId = ''; try { videoId = movie_player && insp(movie_player).getVideoData().video_id; } catch (e) { } if (!videoId) return; let thumbnailUrl = ''; if (videoId) { thumbnailUrl = staticImageMap.get(videoId); } if (!thumbnailUrl) return; const displayImage = `url(${thumbnailUrl})`; h5vc.style.setProperty('--audio-only-thumbnail-image', `${displayImage}`); } Object.assign(dmo, { clearVideoAndQueue, cancelPlayback, pauseVideo, playVideo, isAtLiveHeadW, updateAtPublish, refreshAllStaleEntitiesForNonReadyAudio, seekToLiveHeadForLiveStream, ready: true, isLoadedW, getMediaElement, playerAppXM, standardAppXM, internalAppXM, playerDapXM, getPlayerStateInt, getPlayerWrappedStateObject, getInternalVideoData, delayedUpdateStaticImage }); const getPublishStatus17 = () => { const internalApp = internalAppXM(); const iaMedia = internalApp ? internalApp.mediaElement : null; return iaMedia ? iaMedia.__publishStatus17__ : null; } const shouldWaitPublish = () => { let waitPublish = false; const internalApp = internalAppXM(); const iaMedia = internalApp ? internalApp.mediaElement : null; const stateObject = getPlayerWrappedStateObject(); if (stateObject && stateObject.isUnstarted === true) { waitPublish = true; } else if (iaMedia && iaMedia.__publishStatus17__ >= 100 && iaMedia.__publishStatus17__ < 300) { waitPublish = true; } else { waitPublish = false; } return waitPublish; } let playBusy = 0; if (!HTMLAudioElement.prototype.play3828 && !HTMLAudioElement.prototype.pause3828 && PATCH_MEDIA_PLAYPAUSE) { HTMLAudioElement.prototype.pause3828 = HTMLAudioElement.prototype.pause; HTMLAudioElement.prototype.pause = function () { if (skipPlayPause & 2) return; if (getMediaElement() === this) { const internalApp = internalAppXM(); const iaMedia = internalApp ? internalApp.mediaElement : null; if (iaMedia) { iaMedia.__publishStatus17__ = 0; iaMedia.__publishStatus18__ = 0; } } if (playBusy > 0) { return this.pause3828(); } else { const audio = this; if (audio[qzk] > 1e9) audio[qzk] = 9; const lzt = audio[qzk] ? ++audio[qzk] : (audio[qzk] = 1); return this.pause3828(); } } HTMLAudioElement.prototype.play3828 = HTMLAudioElement.prototype.play; HTMLAudioElement.prototype.play = async function () { if (skipPlayPause & 1) return; if (playBusy > 0) return await this.play3828(); const audio = this; if (audio[qzk] > 1e9) audio[qzk] = 9; const lzt = audio[qzk] ? ++audio[qzk] : (audio[qzk] = 1); console.log(`[yt-audio-only] video.play01 {${lzt}}`); if (getMediaElement() !== this) { dirtyMark = 1 | 2 | 4 | 8; } if (getPublishStatus17() === null) { // video switching -> ad media 3600 console.log('wait for mediaElement') await delayPn(400); if (lzt !== audio[qzk]) return; } if (audio !== getMediaElement()) { // video switching -> ad media 3600 console.log('wait for correct mediaElement') await delayPn(400); if (lzt !== audio[qzk]) return; } console.log(`[yt-audio-only] video.play02 {${lzt}}`, getPublishStatus17()) // if ((await isAdW()) === true) return; const internalApp = internalAppXM(); let isAtLiveHead = await isAtLiveHeadW(); // window.dmo = dmo; (internalApp || 0).mediaElement && audio === getMediaElement() && Promise.resolve().then(async () => { // if(audio.isConnected === false) return; if (lzt !== audio[qzk]) return; dirtyMark = 1 | 2 | 4 | 8; // between play02 and play03, < publish (***, duration>0, stateInt=3, =100, =>200) > should occur console.log(`[yt-audio-only] video.play03 {${lzt}}`, getPublishStatus17()) if (!shouldWaitPublish()) { await delayPn(80); dirtyMark = 1 | 2 | 4 | 8; if (lzt !== audio[qzk]) return; } if (shouldWaitPublish()) { await delayPn(400); dirtyMark = 1 | 2 | 4 | 8; if (lzt !== audio[qzk]) return; } // if(audio.isConnected === false) return; const publishStatus1701 = getPublishStatus17(); console.log(`[yt-audio-only] video.play04 {${lzt}}`, publishStatus1701); if (getMediaElement() !== this) { dirtyMark = 1 | 2 | 4 | 8; } if (internalApp !== internalAppXM()) return; if (!internalApp.mediaElement) return; if (audio !== getMediaElement()) return; const stateObject = getPlayerWrappedStateObject(); if (stateObject.isDomPaused && stateObject.isBuffering && !stateObject.isOrWillBePlaying && !stateObject.isPaused && !stateObject.isPlaying && !stateObject.isSeeking && stateObject.isUnstarted) { // allow case; would fall into (publishStatus1701 > 200 && publishStatus1701 < 300) case } else if (stateObject.isDomPaused && stateObject.isBuffering && !stateObject.isOrWillBePlaying && !stateObject.isPaused && !stateObject.isPlaying && stateObject.isSeeking && stateObject.isUnstarted) { // allow case; would fall into (publishStatus1701 > 200 && publishStatus1701 < 300) case } else { if (stateObject.isOrWillBePlaying === false || stateObject.isPaused === true || stateObject.isEnded === true) { console.log('[yt-audio-only] leave 00', stateObject) if (publishStatus1701 === 300 && (await isLoadedW()) === true && stateObject.isPaused && !stateObject.isOrWillBePlaying && !stateObject.isEnded && stateObject.isBuffering && !isAtLiveHead && !skipPlayPause && !byPassPublishPatch && !byPassNonFatalError) { console.log('[yt-audio-only] leave 01', stateObject) if (lzt !== audio[qzk]) return; console.log('[yt-audio-only] leave 02', stateObject) // guess - paused before. switching video -> remains paused status await cancelPlayback(); await delayPn(80); await playVideo(); } return; } } console.log(`[yt-audio-only] video.play05 {${lzt}}`, publishStatus1701); console.log(1293, stateObject); let bool = false; if (stateObject.isBuffering && !stateObject.isEnded && !stateObject.isError && stateObject.isSeeking && stateObject.isUnstarted && !stateObject.isCued) { bool = true; } else if (stateObject.isOrWillBePlaying && stateObject.isSeeking && !stateObject.isCued && stateObject.isPlaying) { bool = true; } else if (publishStatus1701 > 200 && publishStatus1701 < 300) { // loadedmetadata done bool = true; } if (!isAtLiveHead && stateObject.isUnstarted === true && stateObject.isOrWillBePlaying) { const vd = getInternalVideoData(); if (vd.isLivePlayback && vd.isLiveHeadPlayable) { console.log('isAtLiveHead: false -> true') isAtLiveHead = true; } } console.log(3882, bool, isAtLiveHead) if (bool) { console.log(`[yt-audio-only] video.play06 {${lzt}}`, publishStatus1701); if (internalApp !== internalAppXM()) return; if (!internalApp.mediaElement) return; // if(audio.isConnected === false) return; playBusy++; console.log(`[yt-audio-only] video.play07 {${lzt}}`, publishStatus1701); // if (!audio.closest('ytd-miniplayer')) { // byPassSync = true; byPassNonFatalError = true; byPassPublishPatch = true; skipPlayPause = 3; if ((await isLoadedW()) === false) { console.log(`[yt-audio-only] video.play07.1 {${lzt}}`, "isLoadedW = false"); await clearVideoAndQueue(); await cancelPlayback(); } else { console.log(`[yt-audio-only] video.play07.1 {${lzt}}`, "isLoadedW = true"); await cancelPlayback(); } await delayPn(80); // wait some time for byPassNonFatalError and byPassPublishPatch skipPlayPause = 0; byPassNonFatalError = false; byPassPublishPatch = false; // } dirtyMark = 1 | 2 | 4 | 8; console.log(`[yt-audio-only] video.play08 {${lzt}}`, getPublishStatus17()); // await delayPn(40); // await audio.pause(); const promiseSeek_ = promiseSeek = new PromiseExternal(); // listAllPublish = true; if (isAtLiveHead) { await trySeekToLiveHead(); } const qX = getPlayerWrappedStateObject(); if (qX.isBuffering || qX.isSeeking || qX.isUnstarted) { await playVideo(); } if (isAtLiveHead === true && (await isAtLiveHeadW()) === false) { await trySeekToLiveHead(); } await delayPn(80); // byPassSync = false; playBusy--; if (lzt !== audio[qzk]) return; // abnormal if (promiseSeek_ !== promiseSeek) return; // abnormal console.log(`[yt-audio-only] video.play10 {${lzt}}`, getPublishStatus17()); const r = await Promise.race([promiseSeek_, delayPn(400).then(() => 123)]); promiseSeek = null; if (getPlayerWrappedStateObject().isDomPaused) { console.log('manual playing is required') // found in Firefox return; } if (lzt !== audio[qzk]) return; // normal console.log(`[yt-audio-only] video.play11 {${lzt}}`, getPublishStatus17(), r, isAtLiveHead, await isAtLiveHeadW()); if (r === 123 && isAtLiveHead === true && (await isAtLiveHeadW()) === false) { console.log(`[yt-audio-only] video.play11.1 {${lzt}}`, getPublishStatus17()); await trySeekToLiveHead(); dirtyMark = 1 | 2 | 4 | 8; console.log(`[yt-audio-only] video.play11.2 {${lzt}}`, getPublishStatus17()); } await delayPn(80); // wait sometime for next checking if (lzt !== audio[qzk]) return; // normal console.log(`[yt-audio-only] video.play12 {${lzt}}`, getPublishStatus17(), r, isAtLiveHead, await isAtLiveHeadW()); // ----- play safe ---- let stateObject = getPlayerWrappedStateObject(); if (stateObject.isPlaying && stateObject.isOrWillBePlaying && !stateObject.isPaused) return; // normal checking if (stateObject.isError || stateObject.isEnded) return; // error checking // retry console.log(`[yt-audio-only] video.play13 {${lzt}}`, getPublishStatus17(), r, { ...stateObject }); if (stateObject && !stateObject.isSeeking) { if (stateObject.isError || stateObject.isEnded) { } else if (stateObject.isOrWillBePlaying && stateObject.isPlaying && !stateObject.isPaused) { } else { console.log(`[yt-audio-only] video.play13.1 {${lzt}}`, getPublishStatus17(), r, { ...stateObject }); try { // listAllPublish = false; dirtyMark = 1 | 2 | 4 | 8; await playVideo(); } catch (e) { } } } // ----- play safe ---- } else if (!stateObject.isDomPaused && stateObject.isBuffering && stateObject.isOrWillBePlaying && !stateObject.isSeeking && !stateObject.isUnstarted) { console.log(3883) playBusy++; await delayPn(80); playVideo(); await delayPn(80); if (isAtLiveHead === true && (await isAtLiveHeadW()) === false) { console.log(`[yt-audio-only] video.play21.1 {${lzt}}`, getPublishStatus17()); await trySeekToLiveHead(); dirtyMark = 1 | 2 | 4 | 8; console.log(`[yt-audio-only] video.play21.2 {${lzt}}`, getPublishStatus17()); await delayPn(80); // wait sometime for playBusy } playBusy--; } else if (!stateObject.isDomPaused && !stateObject.isBuffering && stateObject.isOrWillBePlaying && !stateObject.isSeeking && !stateObject.isUnstarted) { console.log(3884) playBusy++; await delayPn(80); playVideo(); await delayPn(80); if (isAtLiveHead === true && (await isAtLiveHeadW()) === false) { console.log(`[yt-audio-only] video.play23.1 {${lzt}}`, getPublishStatus17()); await trySeekToLiveHead(); dirtyMark = 1 | 2 | 4 | 8; console.log(`[yt-audio-only] video.play23.2 {${lzt}}`, getPublishStatus17()); await delayPn(80); // wait sometime for playBusy } playBusy--; } else { console.log(3889, stateObject) } }).catch(console.warn); try { dirtyMark = 1 | 2 | 4 | 8; playBusy++; return await this.play3828(); } catch (e) { } finally { playBusy--; dirtyMark = 1 | 2 | 4 | 8; } } } console.log('[yt-audio-only] DONE') } catch (e) { console.warn(e); } } const setupAudioPlaying = (player00_) => { // console.log(5939,player00_); try { const player_ = player00_; if (!player_) return; if (player_.__audio544__) return; player_.__audio544__ = 1; updatePlayerAppFn(player_); } catch (e) { console.warn(e); } } if (!window.__ugAtg3747__) { window.__ugAtg3747__ = true; const updateLastActiveTimeGeneral = () => { // player_ -> yuu const player_ = playerDapXM() || playerAppXM(); if (player_) player_.updateLastActiveTime(); }; document.addEventListener('timeupdate', updateLastActiveTimeGeneral, true); } return { setupAudioPlaying, internalAppPTFn, standardAppPTFn, playerDapPTFn }; })(); if (location.origin === 'https://www.youtube.com') { if (location.pathname.startsWith('/embed/')) { // youtube embed const ytEmbedReady = observablePromise(() => document.querySelector('#player > .ytp-embed')).obtain(); const embedConfigFix = (async () => { while (true) { const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0; if (config_) { ytConfigFix(config_); break; } await delayPn(60); } }); ytEmbedReady.then(async (embedPlayer) => { embedConfigFix(); const player_ = embedPlayer; console.log(5919, player_) setupAudioPlaying(player_); // dekstop embed if (SHOW_VIDEO_STATIC_IMAGE) { let displayImage = ''; let html5Container = null; const moviePlayer = document.querySelector('#movie_player .html5-video-container .video-stream.html5-main-video, #masthead-player .html5-video-container .video-stream.html5-main-video'); if (moviePlayer) { html5Container = moviePlayer.closest('.html5-video-container'); } if (html5Container) { const overlayImage = document.querySelector('#movie_player .ytp-cued-thumbnail-overlay-image[style], #masthead-player .ytp-cued-thumbnail-overlay-image[style]'); if (overlayImage) { const cStyle = window.getComputedStyle(overlayImage); const cssImageValue = cStyle.backgroundImage; if (cssImageValue && typeof cssImageValue === 'string' && cssImageValue.startsWith('url(')) { displayImage = cssImageValue; } } if (!displayImage) { const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0; let embedded_player_response = null; if (config_) { embedded_player_response = ((config_.PLAYER_VARS || 0).embedded_player_response || 0) } if (embedded_player_response && typeof embedded_player_response === 'string') { let idx1 = embedded_player_response.indexOf('"defaultThumbnail"'); let idx2 = idx1 >= 0 ? embedded_player_response.lastIndexOf('"defaultThumbnail"') : -1; if (idx1 === idx2 && idx1 > 0) { let bk = 0; let j = -1; for (let i = idx1; i < embedded_player_response.length; i++) { if (i > idx1 + 40 && bk === 0) { j = i; break; } let t = embedded_player_response.charAt(i); if (t === '{') bk++; else if (t === '}') bk--; } if (j > idx1) { let defaultThumbnailString = embedded_player_response.substring(idx1, j); let defaultThumbnailObject = null; try { defaultThumbnailObject = JSON.parse(`{${defaultThumbnailString}}`); } catch (e) { } const thumbnails = ((defaultThumbnailObject.defaultThumbnail || 0).thumbnails || 0); if (thumbnails && thumbnails.length >= 1) { let thumbnailUrl = getThumbnailUrlFromThumbnails(thumbnails); if (thumbnailUrl && thumbnailUrl.length > 3) { displayImage = `url(${thumbnailUrl})`; } } } } } } if (displayImage) { html5Container.style.setProperty('--audio-only-thumbnail-image', `${displayImage}`); } else { html5Container.style.removeProperty('--audio-only-thumbnail-image') } } } }); } else { // youtube normal attachOneTimeEvent('yt-action', () => { const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0; ytConfigFix(config_); }); let r3 = new PromiseExternal(); document.addEventListener('yt-action', () => { let u = document.querySelector('ytd-watch-flexy'); if (u && typeof insp(u).calculateCurrentPlayerSize_ === 'function') { r3.resolve(u); } }, true); r3.then((watchFlexy) => { // for offline video, without audio -> so no size if (!watchFlexy) return; const cnt = insp(watchFlexy); if (typeof cnt.calculateCurrentPlayerSize_ === 'function' && !cnt.calculateCurrentPlayerSize3991_) { cnt.calculateCurrentPlayerSize3991_ = cnt.calculateCurrentPlayerSize_; cnt.calculateCurrentPlayerSize_ = function () { const r = this.calculateCurrentPlayerSize3991_(...arguments); if (r && r.width > 10 && !Number.isFinite(r.height)) { r.height = Math.round(r.width / 16 * 9); } return r; } } }); customElements.whenDefined('ytd-player').then(() => { const dummy = document.querySelector('ytd-player') || document.createElement('ytd-player'); const cnt = insp(dummy); const cProto = cnt.constructor.prototype; cProto.createMainAppPlayer932_ = cProto.createMainAppPlayer_; cProto.initPlayer932_ = cProto.initPlayer_; const configFixBeforeCreate = () => { try { const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0; if (config_) { ytConfigFix(config_); } } catch (e) { } } cProto.createMainAppPlayer_ = function (a, b, c) { configFixBeforeCreate(); let r = this.createMainAppPlayer932_(a, b, c); try { (async () => { const e = await this.mainAppPlayer_.api; setupAudioPlaying(e); // desktop normal })(); } finally { return r; } } cProto.initPlayer_ = function (a) { configFixBeforeCreate(); let r = this.initPlayer932_(a); try { (async () => { const e = await r; setupAudioPlaying(this.player_); // desktop normal })(); } finally { return r; } } }); } } else if (location.origin === 'https://m.youtube.com') { removeBottomOverlayForMobile = async (delay) => { let closeBtnRenderer = document.querySelector('.ytm-bottom-sheet-overlay-renderer-close.icon-close'); if (closeBtnRenderer) { const btn = closeBtnRenderer.querySelector('button'); const container = closeBtnRenderer.closest('#global-loader ~ .ytm-bottom-sheet-overlay-container'); if (container) { container.style.visibility = 'collapse'; container.style.zIndex = '-1'; } if (btn) { if (delay) { await delayPn(delay); } btn.click(); } } } const getAppJSON = () => { let t; t = document.querySelector('player-microformat-renderer.PlayerMicroformatRendererHost script[type="application/ld+json"]'); if (t) return t; t = document.querySelector('player-microformat-renderer.playerMicroformatRendererHost script[type="application/ld+json"]'); if (t) return t; return null; } let lastPlayerInfoText = ''; let mz = 0; onVideoChangeForMobile = async () => { let html5Container = null; const moviePlayer = document.querySelector('#player .html5-video-container .video-stream.html5-main-video'); if (moviePlayer) { html5Container = moviePlayer.closest('.html5-video-container'); } console.log('STx00', html5Container) if (!html5Container) return; let thumbnailUrl = ''; if (mz > 1e9) mz = 9; let mt = ++mz; const scriptText = await observablePromise(() => { if (mt !== mz) return 1; const t = getAppJSON(); const tt = (t ? t.textContent : '') || ''; if (tt === lastPlayerInfoText) return; return tt; }).obtain(); if (typeof scriptText !== 'string') return; // 1 lastPlayerInfoText = scriptText; if (!scriptText) return; if (SHOW_VIDEO_STATIC_IMAGE) { console.log('STx01') let idx1 = scriptText.indexOf('"thumbnailUrl"'); let idx2 = idx1 >= 0 ? scriptText.lastIndexOf('"thumbnailUrl"') : -1; if (idx1 === idx2 && idx1 > 0) { let bk = 0; let j = -1; for (let i = idx1; i < scriptText.length; i++) { if (i > idx1 + 20 && bk === 0) { j = i; break; } let t = scriptText.charAt(i); if (t === '[') bk++; else if (t === ']') bk--; else if (t === '{') bk++; else if (t === '}') bk--; } if (j > idx1) { let thumbnailUrlString = scriptText.substring(idx1, j); let thumbnailUrlObject = null; try { thumbnailUrlObject = JSON.parse(`{${thumbnailUrlString}}`); } catch (e) { } const thumbnails = thumbnailUrlObject.thumbnailUrl; if (thumbnails && thumbnails.length >= 1 && typeof thumbnails[0] === 'string') { if (thumbnails[0] && thumbnails[0].length > 3) { thumbnailUrl = thumbnails[0]; } } } } console.log('STx02', thumbnailUrl); if (thumbnailUrl && typeof thumbnailUrl === 'string') { html5Container.style.setProperty('--audio-only-thumbnail-image', `url(${thumbnailUrl})`); } else { html5Container.style.removeProperty('--audio-only-thumbnail-image') } } if (removeBottomOverlayForMobile) await removeBottomOverlayForMobile(40); await delayPn(80); const audio = moviePlayer; if (audio && audio.muted === true && audio.isConnected === true && audio.readyState >= 0 && audio.networkState >= 2 && audio.paused === false) { await audio.click(); } } let player0 = null; const mff = function (e) { const target = (e || 0).target || 0; if (target !== player0 && target && typeof target.getPlayerState === 'function') { player0 = target; setupAudioPlaying(target); // mobile } } document.addEventListener('player-initialized', mff, true); document.addEventListener('player-state-change', mff, true); document.addEventListener('player-ad-state-change', mff, true); document.addEventListener('player-detailed-error', mff, true); document.addEventListener('player-error', mff, true); document.addEventListener('on-play-autonav-video', mff, true); document.addEventListener('on-play-previous-autonav-video', mff, true); document.addEventListener('player-fullscreen-change', mff, true); document.addEventListener('player-fullscreen-toggled', mff, true); document.addEventListener('player-dom-paused', mff, true); document.addEventListener('yt-show-toast', mff, true); document.addEventListener('yt-innertube-command', mff, true); document.addEventListener('yt-update-c3-companion', mff, true); document.addEventListener('video-data-change', mff, true); document.addEventListener('video-progress', mff, true); document.addEventListener('local-media-change', mff, true); document.addEventListener('video-progress', updateLastActiveTimeAsync, true); // mobile // document.addEventListener('DOMContentLoaded', (evt) => { // const mo = new MutationObserver((mutations)=>{ // console.log(5899, mutations) // }); // mo.observe(document, {subtree: true, childList: true}) // }) // window.addEventListener('onReady', (evt) => { // console.log(6811) // }, true); // window.addEventListener('localmediachange', (evt) => { // console.log(6812) // }, true); // window.addEventListener('onVideoDataChange', (evt) => { // console.log(6813) // }, true); window.addEventListener('state-navigateend', async (evt) => { delayPn(200).then(() => { if (!getAppJSON()) { console.log('[mobile youtube audio only] getAppJSON fails.', document.querySelectorAll('script[type="application/ld+json"]').length); } }); const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0; ytConfigFix(config_); try { if (clickLockFn && clickTarget) { let a = HTMLElement.prototype.querySelector.call(clickTarget, '.video-stream.html5-main-video'); if (!a) return; if (a.muted === true && a.__spfgs__ !== true && a.paused === true && a.networkState === 0 && a.readyState === 0) { const pr = new Promise(resolve => { document.addEventListener('player-state-change', resolve, { once: true, passive: true, capture: false }); }).then(); clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 })); await delayPn(1); if (a.muted === false && a.__spfgs__ !== true && a.paused === true && a.networkState === 0 && a.readyState === 0) { clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 })); await delayPn(1); } delayRun(pr); } } } catch (e) { console.log('error_F12', e) } }, false); // document.addEventListener('volumechange', (evt) => { // console.log('volumechange') // }, true) // document.addEventListener('play', (evt) => { // console.log('play') // }, true) // document.addEventListener('player-initialized', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('renderer-module-load-start', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('video-data-change', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-state-change', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('updateui', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('renderer-module-load-end', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-autonav-pause', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-ad-state-change', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-detailed-error', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-error', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('on-play-autonav-video', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('on-play-previous-autonav-video', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-fullscreen-change', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-fullscreen-toggled', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-dom-paused', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('yt-show-toast', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('yt-innertube-command', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('yt-update-c3-companion', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('video-progress', (evt) => { // // console.log(evt.type) // }, true) // document.addEventListener('localmediachange', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-initialized', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('renderer-module-load-start', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('video-data-change', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-state-change', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('updateui', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('renderer-module-load-end', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-autonav-pause', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-ad-state-change', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-detailed-error', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-error', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('on-play-autonav-video', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('on-play-previous-autonav-video', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-fullscreen-change', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-fullscreen-toggled', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('player-dom-paused', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('yt-show-toast', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('yt-innertube-command', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('yt-update-c3-companion', (evt) => { // console.log(evt.type) // }, true) // window.addEventListener('video-progress', (evt) => { // // console.log(evt.type) // }, true) // window.addEventListener('localmediachange', (evt) => { // console.log(evt.type) // }, true) // document.addEventListener('player-error', (evt) => { // console.log(3001, evt.type, evt) // }, true) // document.addEventListener('player-detailed-error', (evt) => { // console.log(3002, evt.type, evt) // }, true) async function delayRun(pr) { let q = document.querySelector('#movie_player') || document.querySelector('#masthead-player'); if (!q) return; let a = document.querySelector('.video-stream.html5-main-video'); if (!a) return; await pr.then(); if (fa !== 1) { return; } else if (a.muted === true) { return; } else if (a.muted === false && a.readyState === 0 && a.networkState === 2) { if (a.paused === false) return; } else { return; } if (document.querySelector('.player-controls-content')) return; if (a.paused === true && a.muted === false && a.readyState === 0 && a.networkState === 2) { clickLockFn.call(clickTarget, mockEvent({ type: 'click', target: clickTarget, detail: 1 })); } if (a.paused === true && a.muted === false && a.networkState === 2 && a.readyState === 0) { if (typeof clickTarget.seekToLiveHead === 'function') await clickTarget.seekToLiveHead(); if (typeof clickTarget.isAtLiveHead === 'function' && (await clickTarget.isAtLiveHead()) === true) { if (typeof clickTarget.seekToStreamTime === 'function') await clickTarget.seekToStreamTime(); } } } durationchangeForMobile = true; } attachOneTimeEvent('yt-action', function () { const config_ = typeof yt !== 'undefined' ? (yt || 0).config_ : 0; ytConfigFix(config_); }); let prepared = false; function prepare() { if (prepared) return; prepared = true; if (typeof _yt_player !== 'undefined' && _yt_player && typeof _yt_player === 'object') { for (const [k, v] of Object.entries(_yt_player)) { const p = typeof v === 'function' ? v.prototype : 0; if (p && typeof p.clone === 'function' && typeof p.get === 'function' && typeof p.set === 'function' && typeof p.isEmpty === 'undefined' && typeof p.forEach === 'undefined' && typeof p.clear === 'undefined' ) { key = k; } } } if (key) { const ClassX = _yt_player[key]; _yt_player[key] = class extends ClassX { constructor(...args) { if (typeof args[0] === 'string' && args[0].startsWith('http://')) args[0] = ''; super(...args); } } _yt_player[key].luX1Y = 1; prototypeInherit(_yt_player[key].prototype, ClassX.prototype); } } let s3 = Symbol(); generalRegister('deviceIsAudioOnly', s3, (p) => { return typeof p.getPlayerType === 'function' && typeof p.getVideoEmbedCode === 'function' && typeof p.getVideoUrl === 'function' && !p.onCueRangeEnter && !p.getVideoData && !('ATTRIBUTE_NODE' in p) }, { get() { return this[s3]; }, set(nv) { if (typeof nv === 'boolean') this[s3] = true; else this[s3] = undefined; prepare(); return true; }, enumerable: false, configurable: true }); let s1 = Symbol(); let s2 = Symbol(); Object.defineProperty(Object.prototype, 'defraggedFromSubfragments', { get() { // console.log(501, this.constructor.prototype) return undefined; }, set(nv) { return true; }, enumerable: false, configurable: true }); Object.defineProperty(Object.prototype, 'hasSubfragmentedFmp4', { get() { // console.log(502, this.constructor.prototype) return this[s1]; }, set(nv) { if (typeof nv === 'boolean') this[s1] = false; else this[s1] = undefined; return true; }, enumerable: false, configurable: true }); Object.defineProperty(Object.prototype, 'hasSubfragmentedWebm', { get() { // console.log(503, this.constructor.prototype) return this[s2]; }, set(nv) { if (typeof nv === 'boolean') this[s2] = false; else this[s2] = undefined; return true; }, enumerable: false, configurable: true }); const supportedFormatsConfig = () => { function typeTest(type) { if (typeof type === 'string' && type.startsWith('video/')) { return false; } } // return a custom MIME type checker that can defer to the original function function makeModifiedTypeChecker(origChecker) { // Check if a video type is allowed return function (type) { let res = undefined; if (type === undefined) res = false; else { res = typeTest.call(this, type); } if (res === undefined) res = origChecker.apply(this, arguments); return res; }; } // Override video element canPlayType() function const proto = (HTMLVideoElement || 0).prototype; if (proto && typeof proto.canPlayType == 'function') { proto.canPlayType = makeModifiedTypeChecker(proto.canPlayType); } // Override media source extension isTypeSupported() function const mse = window.MediaSource; // Check for MSE support before use if (mse && typeof mse.isTypeSupported == 'function') { mse.isTypeSupported = makeModifiedTypeChecker(mse.isTypeSupported); } }; supportedFormatsConfig(); ; (async () => { const _yt_player_observable = observablePromise(() => { return (((window || 0)._yt_player || 0) || 0); }); const addProtoToArr = (parent, key, arr) => { let isChildProto = false; for (const sr of arr) { if (parent[key].prototype instanceof parent[sr]) { isChildProto = true; break; } } if (isChildProto) return; arr = arr.filter(sr => { if (parent[sr].prototype instanceof parent[key]) { return false; } return true; }); arr.push(key); return arr; }; const getEntriesForPlayerInterfaces = (_yt_player) => { const entries = Object.entries(_yt_player); const arr = new Array(entries.length); let arrI = 0; for (const entry of entries) { const [k, v] = entry; const p = typeof v === 'function' ? v.prototype : 0; if (p) { const b = ( typeof p.cancelPlayback === 'function' || typeof p.stopVideo === 'function' || typeof p.pauseVideo === 'function' || typeof p.playVideo === 'function' || typeof p.getPlayerStateObject === 'function' ); if (b) arr[arrI++] = entry; } } arr.length = arrI; return arr; } const getKeyPlayerDap = (_yt_player, filteredEntries) => { // one is quu (this.app.getPlayerStateObject(p)) // one is standardApp (return this.getPresentingPlayerType()===3?R$(this.C7).g7:g.O5(this,p).getPlayerState()) const w = 'keyPlayerDap'; let arr = []; let brr = new Map(); for (const [k, v] of filteredEntries) { const p = typeof v === 'function' ? v.prototype : 0; if (p) { let q = 0; if (typeof p.cancelPlayback === 'function') q += 50; if (typeof p.stopVideo === 'function') q += 50; if (typeof p.pauseVideo === 'function') q += 50; if (typeof p.playVideo === 'function') q += 50; if (typeof p.getPlayerStateObject === 'function') q += 50; if (q < 250) continue; if (typeof p.cancelPlayback === 'function' && p.cancelPlayback.length === 0) q += 20; if (typeof p.stopVideo === 'function' && p.stopVideo.length === 1) q += 20; if (typeof p.pauseVideo === 'function' && p.pauseVideo.length === 1) q += 20; if (typeof p.playVideo === 'function' && p.playVideo.length === 2) q += 20; if (typeof p.getPlayerStateObject === 'function' && p.getPlayerStateObject.length === 1) q += 20; if (typeof p.isBackground === 'function') q -= 5; if (typeof p.isBackground === 'function' && p.isBackground.length === 0) q -= 2; if (typeof p.getPlaybackRate === 'function') q += 25; if (typeof p.getPlaybackRate === 'function' && p.getPlaybackRate.length === 0) q += 15; if (typeof p.publish === 'function') q += 25; if (typeof p.publish === 'function' && p.publish.length === 1) q += 15; if (typeof p.addEventListener === 'function') q += 40; if (typeof p.addEventListener === 'function' && p.addEventListener.length === 2) q += 25; if (typeof p.removeEventListener === 'function') q += 40; if (typeof p.removeEventListener === 'function' && p.removeEventListener.length === 2) q += 25; if (q > 0) arr = addProtoToArr(_yt_player, k, arr) || arr; if (q > 0) brr.set(k, q); } } if (arr.length === 0) { console.warn(`[yt-audio-only] (key-extraction) Key does not exist (1). [${w}]`); } else { arr = arr.map(key => [key, (brr.get(key) || 0)]); if (arr.length > 1) arr.sort((a, b) => b[1] - a[1]); let match = null; for (const [key, _] of arr) { const p = _yt_player[key].prototype const f = (p ? p.getPlayerStateObject : null) || 0; if (f) { const o = {}; const w = new Proxy({}, { get(target, p) { o[p] = 1; return w; }, set(target, p, v) { return true; } }); try { f.call(w) } catch (e) { } if (o.app) { match = key; } } } if (!match) { console.warn(`[yt-audio-only] (key-extraction) Key does not exist (2). [${w}]`); } else { return match; } } } const getKeyStandardApp = (_yt_player, filteredEntries) => { // one is quu (this.app.getPlayerStateObject(p)) // one is standardApp (return this.getPresentingPlayerType()===3?R$(this.C7).g7:g.O5(this,p).getPlayerState()) const w = 'keyStandardApp'; let arr = []; let brr = new Map(); for (const [k, v] of filteredEntries) { const p = typeof v === 'function' ? v.prototype : 0; if (p) { let q = 0; if (typeof p.cancelPlayback === 'function') q += 50; if (typeof p.stopVideo === 'function') q += 50; if (typeof p.pauseVideo === 'function') q += 50; if (typeof p.playVideo === 'function') q += 50; if (typeof p.getPlayerStateObject === 'function') q += 50; if (q < 250) continue; if (typeof p.cancelPlayback === 'function' && p.cancelPlayback.length === 2) q += 20; if (typeof p.stopVideo === 'function' && p.stopVideo.length === 1) q += 20; if (typeof p.pauseVideo === 'function' && p.pauseVideo.length === 2) q += 20; if (typeof p.playVideo === 'function' && p.playVideo.length === 2) q += 20; if (typeof p.getPlayerStateObject === 'function' && p.getPlayerStateObject.length === 1) q += 20; if (typeof p.isBackground === 'function') q -= 5; if (typeof p.isBackground === 'function' && p.isBackground.length === 0) q -= 2; if (typeof p.getPlaybackRate === 'function') q -= 5; if (typeof p.getPlaybackRate === 'function' && p.getPlaybackRate.length === 0) q -= 2; if (typeof p.publish === 'function') q -= 5; if (typeof p.publish === 'function' && p.publish.length === 2) q -= 2; if (typeof p.addEventListener === 'function') q -= 5; if (typeof p.addEventListener === 'function' && p.addEventListener.length === 2) q -= 2; if (typeof p.removeEventListener === 'function') q -= 5; if (typeof p.removeEventListener === 'function' && p.removeEventListener.length === 2) q -= 2; if (q > 0) arr = addProtoToArr(_yt_player, k, arr) || arr; if (q > 0) brr.set(k, q); } } if (arr.length === 0) { console.warn(`[yt-audio-only] (key-extraction) Key does not exist (1). [${w}]`); } else { arr = arr.map(key => [key, (brr.get(key) || 0)]); if (arr.length > 1) arr.sort((a, b) => b[1] - a[1]); let match = null; for (const [key, _] of arr) { const p = _yt_player[key].prototype const f = (p ? p.getPlayerStateObject : null) || 0; if (f) { const o = {}; const w = new Proxy({}, { get(target, p) { o[p] = 1; return w; }, set(target, p, v) { return true; } }); try { f.call(w) } catch (e) { } if (!o.app) { match = key; } } } if (!match) { console.warn(`[yt-audio-only] (key-extraction) Key does not exist (2). [${w}]`); } else { return match; } } } const getKeyInternalApp = (_yt_player, filteredEntries) => { // internalApp const w = 'keyInternalApp'; let arr = []; let brr = new Map(); for (const [k, v] of filteredEntries) { const p = typeof v === 'function' ? v.prototype : 0; if (p) { let q = 0; if (typeof p.stopVideo === 'function') q += 1; if (typeof p.playVideo === 'function') q += 1; if (typeof p.pauseVideo === 'function') q += 1; if (q < 2) continue; if (typeof p.isBackground === 'function') q += 120; if (typeof p.getPlaybackRate === 'function') q += 50; // if (typeof p.publish === 'function') q += 50; if (typeof p.isAtLiveHead === 'function') q += 50; if (typeof p.getVideoData === 'function') q += 10; if (typeof p.getVolume === 'function') q += 10; if (typeof p.getStreamTimeOffset === 'function') q += 10; if (typeof p.getPlayerType === 'function') q += 10; if (typeof p.getPlayerState === 'function') q += 10; if (typeof p.getPlayerSize === 'function') q += 10; if (typeof p.cancelPlayback === 'function') q -= 4; if (q < 10) continue; if ('mediaElement' in p) q += 50; if ('videoData' in p) q += 50; if ('visibility' in p) q += 50; if (typeof p.isBackground === 'function' && p.isBackground.length === 0) q += 20; if (typeof p.getPlaybackRate === 'function' && p.getPlaybackRate.length === 0) q += 20; if (typeof p.publish === 'function' && p.publish.length === 2) q += 18; if (typeof p.isAtLiveHead === 'function' && p.isAtLiveHead.length === 2) q += 18; if (q > 0) arr = addProtoToArr(_yt_player, k, arr) || arr; if (q > 0) brr.set(k, q); } } if (arr.length === 0) { console.warn(`[yt-audio-only] (key-extraction) Key does not exist. [${w}]`); } else { arr = arr.map(key => [key, (brr.get(key) || 0)]); if (arr.length > 1) arr.sort((a, b) => b[1] - a[1]); if (arr.length > 2) console.log(`[yt-audio-only] (key-extraction) [${w}]`, arr); return arr[0][0]; } }; (async () => { // rAf scheduling const _yt_player = await _yt_player_observable.obtain(); if (!_yt_player || typeof _yt_player !== 'object') return; window.ktg = _yt_player; // console.log(keys0) const entriesForPlayerInterfaces = getEntriesForPlayerInterfaces(_yt_player); const keyPlayerDap = getKeyPlayerDap(_yt_player, entriesForPlayerInterfaces) const keyStandardApp = getKeyStandardApp(_yt_player, entriesForPlayerInterfaces) const keyInternalApp = getKeyInternalApp(_yt_player, entriesForPlayerInterfaces); console.log('[yt-audio-only] key obtained', [keyPlayerDap, keyStandardApp, keyInternalApp]); if (!keyPlayerDap || !keyStandardApp || !keyInternalApp) { console.warn('[yt-audio-only] key failure', [keyPlayerDap, keyStandardApp, keyInternalApp]); } if (keyPlayerDap) { const playerDapCT = _yt_player[keyPlayerDap]; if (typeof playerDapCT === 'function') { const playerDapPT = playerDapCT.prototype; playerDapPTFn(playerDapPT); } } if (keyStandardApp) { const standardAppCT = _yt_player[keyStandardApp]; if (typeof standardAppCT === 'function') { const standardAppPT = standardAppCT.prototype; standardAppPTFn(standardAppPT); } } if (keyInternalApp) { const internalAppCT = _yt_player[keyInternalApp]; if (typeof internalAppCT === 'function') { const internalAppPT = internalAppCT.prototype; internalAppPTFn(internalAppPT); } } })(); })(); //# sourceURL=debug://userscript/yt-audio-only.js } const getVideoIdByURL = () => { // It's almost certainly going to stay at 11 characters. The individual characters come from a set of 64 possibilities (A-Za-z0-9_-). // base64 form; 26+26+10+2; 64^len // Math.pow(64,11) = 73786976294838210000 const url = new URL(location.href); let m; if (m = /^\/watch\?v=([A-Za-z0-9_-]+)/.exec(`${url.pathname}?v=${url.searchParams.get('v')}`)) return `${m[1]}`; if (m = /^\/live\/([A-Za-z0-9_-]+)/.exec(url.pathname)) return `${m[1]}`; if (m = /^\/embed\/live_stream\?channel=([A-Za-z0-9_-]+)/.exec(`${url.pathname}?channel=${url.searchParams.get('channel')}`)) return `L:${m[1]}`; if (m = /^\/embed\/([A-Za-z0-9_-]+)/.exec(url.pathname)) return `${m[1]}`; if (m = /^\/channel\/([A-Za-z0-9_-]+)\/live\b/.exec(url.pathname)) return `L:${m[1]}`; if (url.hostname === 'youtu.be' && (m = /\/([A-Za-z0-9_-]+)/.exec(url.pathname))) return `${m[1]}`; return ''; }; const getVideoIdByElement = () => { const videoIdElements = [...document.querySelectorAll('[video-id]')].filter(v => !v.closest('[hidden]')); const videoId = videoIdElements.length > 0 ? videoIdElements[0].getAttribute('video-id') : null; return videoId || ''; }; const getEnableValue = async () => { const videoId = getVideoIdByURL() || getVideoIdByElement(); const siteVal = videoId ? await GM.getValue(`isEnable_aWsjF_${videoId}`, null) : null; return (siteVal !== null) ? siteVal : await GM.getValue("isEnable_aWsjF", true); }; const setEnableVal = async (val) => { const videoId = getVideoIdByURL() || getVideoIdByElement(); if (videoId) { try { const cv = await GM.getValue(`isEnable_aWsjF_${videoId}`, null); if (typeof cv === typeof val) await GM.setValue(`isEnable_aWsjF_${videoId}`, val); } catch (e) { } } await GM.setValue("isEnable_aWsjF", val); } const isEnable = (typeof GM !== 'undefined' && typeof GM.getValue === 'function') ? await getEnableValue() : null; if (typeof isEnable !== 'boolean') throw new DOMException("Please Update your browser", "NotSupportedError"); if (isEnable) { const element = document.createElement('button'); element.setAttribute('onclick', createHTML(`(${pageInjectionCode})()`)); element.click(); } GM_registerMenuCommand(`Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`, async function () { await setEnableVal(!isEnable); await GM.setValue('lastCheck_bWsm5', Date.now()); document.documentElement.setAttribute('forceRefresh032', ''); location.reload(); }); let messageCount = 0; let busy = false; window.addEventListener('message', (evt) => { const v = ((evt || 0).data || 0).ZECxh; if (typeof v === 'boolean') { if (messageCount > 1e9) messageCount = 9; const t = ++messageCount; if (v && isEnable) { requestAnimationFrame(async () => { if (t !== messageCount) return; if (busy) return; busy = true; if (await confirm("Livestream is detected. Press OK to disable YouTube Audio Mode.")) { await setEnableVal(!isEnable); await GM.setValue('lastCheck_bWsm5', Date.now()); document.documentElement.setAttribute('forceRefresh032', ''); location.reload(); } busy = false; }); } } }); const pLoad = new Promise(resolve => { if (document.readyState !== 'loading') { resolve(); } else { window.addEventListener("DOMContentLoaded", resolve, false); } }); function contextmenuInfoItemAppearedFn(target) { const btn = target.closest('.ytp-menuitem[role="menuitem"]'); if (!btn) return; if (btn.parentNode.querySelector('.ytp-menuitem[role="menuitem"].audio-only-toggle-btn')) return; document.documentElement.classList.add('with-audio-only-toggle-btn'); const newBtn = btn.cloneNode(true) newBtn.querySelector('.ytp-menuitem-label').textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`; newBtn.classList.add('audio-only-toggle-btn'); btn.parentNode.insertBefore(newBtn, btn.nextSibling); newBtn.addEventListener('click', async (evt) => { try { evt.stopPropagation(); evt.stopImmediatePropagation(); } catch (e) { } await setEnableVal(!isEnable); await GM.setValue('lastCheck_bWsm5', Date.now()); document.documentElement.setAttribute('forceRefresh032', ''); location.reload(); }); let t; let h = 0; t = btn.closest('.ytp-panel-menu[style*="height"]'); if (t) t.style.height = t.scrollHeight + 'px'; t = btn.closest('.ytp-panel[style*="height"]'); if (t) t.style.height = (h = t.scrollHeight) + 'px'; t = btn.closest('.ytp-popup.ytp-contextmenu[style*="height"]'); if (t && h > 0) t.style.height = h + 'px'; } function mobileMenuItemAppearedFn(target) { const btn = target.closest('ytm-menu-item'); if (!btn) return; if (btn.parentNode.querySelector('ytm-menu-item.audio-only-toggle-btn')) return; document.documentElement.classList.add('with-audio-only-toggle-btn'); const newBtn = btn.cloneNode(true); newBtn.querySelector('.menu-item-button').textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`; newBtn.classList.add('audio-only-toggle-btn'); btn.parentNode.insertBefore(newBtn, btn.nextSibling); newBtn.addEventListener('click', async (evt) => { try { evt.stopPropagation(); evt.stopImmediatePropagation(); } catch (e) { } await setEnableVal(!isEnable); await GM.setValue('lastCheck_bWsm5', Date.now()); document.documentElement.setAttribute('forceRefresh032', ''); location.reload(); }); } const lastEntry = (arr) => { return arr.length > 0 ? arr[arr.length - 1] : null; } function mobileMenuItemAppearedV2Fn(target) { const btn = target.closest('yt-list-item-view-model'); if (!(btn instanceof HTMLElement)) return; if (btn.parentNode.querySelector('yt-list-item-view-model.audio-only-toggle-btn')) return; const parentNode = btn.closest('player-settings-menu'); if (!parentNode) return; let qt = 1E9; let targetBtnO = lastEntry([...parentNode.getElementsByTagName(btn.nodeName)].filter(e => e.parentElement === btn.parentElement).map((elm) => { const count = elm.getElementsByTagName('*').length; if (count < qt) qt = count; return { elm: elm, count: count } }).filter((o) => o.count === qt)); const targetBtn = targetBtnO && targetBtnO.elm instanceof HTMLElement ? targetBtnO.elm : btn; const newBtn = targetBtn.cloneNode(true); if (newBtn instanceof HTMLElement) { document.documentElement.classList.add('with-audio-only-toggle-btn'); let newBtnContentElm = newBtn; let layerCN = 8; while (newBtnContentElm.childElementCount === 1 && layerCN--) { newBtnContentElm = newBtnContentElm.firstElementChild; } if (!(newBtnContentElm instanceof HTMLElement)) newBtnContentElm = newBtn; let t; if (t = lastEntry(newBtnContentElm.querySelectorAll('span[role="text"]'))) { newBtnContentElm = t; newBtnContentElm.classList.add('audio-only-toggle-btn-content2'); } else if (t = lastEntry(newBtnContentElm.querySelectorAll('[role="text"]'))) { newBtnContentElm = t; newBtnContentElm.classList.add('audio-only-toggle-btn-content2'); } else if (t = lastEntry(newBtnContentElm.querySelectorAll('span'))) { newBtnContentElm = t; newBtnContentElm.classList.add('audio-only-toggle-btn-content2'); } else if (t = lastEntry(newBtnContentElm.querySelector('.yt-core-attributed-string'))) { newBtnContentElm = t; newBtnContentElm.classList.add('audio-only-toggle-btn-content2'); } newBtnContentElm.textContent = `Turn ${isEnable ? 'OFF' : 'ON'} YouTube Audio Mode`; newBtn.classList.add('audio-only-toggle-btn'); newBtnContentElm.classList.add('audio-only-toggle-btn-content'); btn.parentNode.insertBefore(newBtn, btn.nextSibling); newBtn.addEventListener('click', async (evt) => { try { evt.stopPropagation(); evt.stopImmediatePropagation(); } catch (e) { } await setEnableVal(!isEnable); await GM.setValue('lastCheck_bWsm5', Date.now()); document.documentElement.setAttribute('forceRefresh032', ''); location.reload(); }); const contentWrapper = newBtn.closest('#content-wrapper'); if (contentWrapper) { contentWrapper.style.height = 'unset'; contentWrapper.style.maxHeight = 'unset'; } } } pLoad.then(() => { document.addEventListener('animationstart', (evt) => { const animationName = evt.animationName; if (!animationName) return; if (animationName === 'contextmenuInfoItemAppeared') contextmenuInfoItemAppearedFn(evt.target); if (animationName === 'mobileMenuItemAppeared') mobileMenuItemAppearedFn(evt.target); if (animationName === 'mobileMenuItemAppearedV2') mobileMenuItemAppearedV2Fn(evt.target); }, true); const cssForEnabled = isEnable ? ` .html5-video-player { background-color: black; } [style*="--audio-only-thumbnail-image"]{ background-image: var(--audio-only-thumbnail-image); object-fit: contain; background-position: center; background-size: contain; background-repeat: no-repeat; } .html5-video-player.ended-mode [style*="--audio-only-thumbnail-image"]{ background-image: none; } .html5-video-player.ytp-ce-shown .html5-video-container { opacity: 0.5; transition: opacity 0.5s; } ytd-video-preview #media-container div#player-container, ytd-video-preview #media-container div#thumbnail-container{ transition: initial !important; transition-duration:0ms !important; transition-delay:0ms !important; } ytd-video-preview #media-container div#thumbnail-container{ /* pointer-events:none !important; */ opacity:0; /* z-index:-1; */ } ytd-video-preview #media-container div#player-container, ytd-video-preview #media-container div#inline-preview-player{ background-color:transparent !important; background-image:none !important; } #movie_player > .html5-video-container:not(:empty), #masthead-player > .html5-video-container:not(:empty) { box-sizing: border-box; height: 100%; } #movie_player [style*="--audio-only-thumbnail-image"] ~ .ytp-cued-thumbnail-overlay > .ytp-cued-thumbnail-overlay-image[style*="background-image"], #masthead-player [style*="--audio-only-thumbnail-image"] ~ .ytp-cued-thumbnail-overlay > .ytp-cued-thumbnail-overlay-image[style*="background-image"] { opacity: 0; } #movie_player [style*="--audio-only-thumbnail-image"]::before, #masthead-player [style*="--audio-only-thumbnail-image"]::before { content: ''; display: block; position: absolute; left: 0; top: 0; bottom: 0; right: 0; /* background: transparent; */ /* We use multiple backgrounds: one gradient per side */ background: /* Left border gradient */ linear-gradient(to right, rgba(0,0,0,0.4), transparent) left center, /* Right border gradient */ linear-gradient(to left, rgba(0,0,0,0.4), transparent) right center, /* Top border gradient */ linear-gradient(to bottom, rgba(0,0,0,0.4), transparent) center top, /* Bottom border gradient */ linear-gradient(to top, rgba(0,0,0,0.4), transparent) center bottom; /* Prevents repetition of gradients */ background-repeat: no-repeat; /* Set the size of each gradient "border" */ background-size: 12% 100%, /* left border width and full height */ 12% 100%, /* right border width and full height */ 100% 12%, /* top border full width and small height */ 100% 12%; /* bottom border full width and small height */ /* Optional: a base background color inside the element */ /* background-color: #fff; */ /* background-color: var(--blinker-fmw83-bgc, transparent); */ opacity: var(--fmw83-opacity, 1); pointer-events: none !important; z-index:-1; } /* @keyframes blinker-fmw83 { 0%, 60%, 100% { opacity: 1; } 30% { opacity: 0.96; } } */ #movie_player.playing-mode [style*="--audio-only-thumbnail-image"], #masthead-player.playing-mode [style*="--audio-only-thumbnail-image"] { /* animation: blinker-fmw83 1.74s linear infinite; */ --fmw83-opacity: 0.6; } #global-loader ytw-scrim { display: none; } `: ""; const style = document.createElement('style'); style.id = 'fm9v0'; style.textContent = ` ${cssForEnabled} @keyframes mobileMenuItemAppeared { 0% { background-position-x: 3px; } 100% { background-position-x: 4px; } } @keyframes mobileMenuItemAppearedV2 { 0% { background-position-x: 3px; } 100% { background-position-x: 4px; } } ytm-select.player-speed-settings ~ ytm-menu-item:last-of-type { animation: mobileMenuItemAppeared 1ms linear 0s 1 normal forwards; } player-settings-menu > yt-list-item-view-model:last-of-type { animation: mobileMenuItemAppearedV2 1ms linear 0s 1 normal forwards; } player-settings-menu .audio-only-toggle-btn-content { padding: 14px 24px; box-sizing: border-box; font-size: 130%; } player-settings-menu .audio-only-toggle-btn-content2 { padding: 0; box-sizing: border-box; font-size: inherit; } @keyframes contextmenuInfoItemAppeared { 0% { background-position-x: 3px; } 100% { background-position-x: 4px; } } .ytp-contextmenu .ytp-menuitem[role="menuitem"] path[d^="M22 34h4V22h-4v12zm2-30C12.95"]{ animation: contextmenuInfoItemAppeared 1ms linear 0s 1 normal forwards; } #confirmDialog794 { z-index:999999 !important; display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ } #confirmDialog794 .confirm-box { position:relative; color: black; z-index:999999 !important; background-color: #fefefe; margin: 15% auto; /* 15% from the top and centered */ padding: 20px; border: 1px solid #888; width: 30%; /* Could be more or less, depending on screen size */ box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); } #confirmDialog794 .confirm-buttons { text-align: right; } #confirmDialog794 button { margin-left: 10px; } ` document.head.appendChild(style); }); const pNavigateFinished = new Promise(resolve => { document.addEventListener('yt-navigate-finish', resolve, true); }); pNavigateFinished.then(() => { const inputs = document.querySelectorAll('#masthead input[type="text"][name]'); let lastInputTextValue = null; let busy = false; let disableMonitoring = false; const setGV = async (val) => { const videoId = getVideoIdByURL() || getVideoIdByElement(); if (videoId) { const cgv = await GM.getValue(`isEnable_aWsjF_${videoId}`, null); if (cgv !== val || isEnable !== val) { disableMonitoring = true; await GM.setValue(`isEnable_aWsjF_${videoId}`, val); await GM.setValue('lastCheck_bWsm5', Date.now()); document.documentElement.setAttribute('forceRefresh032', ''); location.reload(); } } } const checkTextChangeF = async (evt) => { busy = false; const inputElem = (evt || 0).target; if (inputElem instanceof HTMLInputElement && !disableMonitoring) { const cv = inputElem.value; if (cv === lastInputTextValue) return; lastInputTextValue = cv; if (cv === 'vvv') { await setGV(false); } else if (cv === 'aaa') { await setGV(true); } } } const checkTextChange = (evt) => { if (busy) return; busy = true; Promise.resolve(evt).then(checkTextChangeF) }; for (const input of inputs) { input.addEventListener('input', checkTextChange, false); input.addEventListener('keydown', checkTextChange, false); input.addEventListener('keyup', checkTextChange, false); input.addEventListener('keypress', checkTextChange, false); input.addEventListener('change', checkTextChange, false); } }); const autoCleanUpKey = async () => { const lastCheck = await GM.getValue('lastCheck_bWsm5', null) || 0; if (Date.now() - lastCheck < 16000) return; // 16s GM.setValue('lastCheck_bWsm5', Date.now()); pLoad.then(async () => { const rArr = []; const arr = await GM.listValues(); const cv = await GM.getValue("isEnable_aWsjF", null); const fn = async (entry) => { try { if (typeof entry === 'string' && entry.length > 15 && entry.startsWith('isEnable_aWsjF_')) { const res = await GM.getValue(entry, null); if (typeof res === 'boolean' && res === cv) { await GM.deleteValue(entry); rArr.push(entry); } } } catch (e) { console.warn(e); } } arr.length > 1 && (await Promise.all(arr.map(fn))); rArr.length > 0 && console.log('[YouTube Audio Only] autoCleanUpKey', rArr); }); }; autoCleanUpKey(); })();