From e32e7998227e63af8db0c3ab4d01479ea5d5cac7 Mon Sep 17 00:00:00 2001 From: pc035860 Date: Sat, 27 Jul 2024 17:39:45 +0800 Subject: [PATCH 1/3] Make API key reading compatible with changed ytcfg structure --- web-resources/wresources.js | 134 +++++++----------------------------- 1 file changed, 23 insertions(+), 111 deletions(-) diff --git a/web-resources/wresources.js b/web-resources/wresources.js index 9805996..fc9dffe 100644 --- a/web-resources/wresources.js +++ b/web-resources/wresources.js @@ -7010,117 +7010,29 @@ } function nn() { try { - var e, - t, - n, - o, - r, - i, - a, - s, - c, - l, - d, - u, - h, - m, - p, - f, - v, - y, - g, - w, - b, - x, - _, - C, - E, - T, - I, - k, - R, - M; - return ( - (null === - (t = - null === (e = window) || void 0 === e ? void 0 : e.ytcfg.data_) || - void 0 === t - ? void 0 - : t.INNERTUBE_API_KEY) || - (null === (n = window) || - void 0 === n || - null === (o = n.ytcfg) || - void 0 === o || - null === (r = o.data_) || - void 0 === r || - null === (i = r.WEB_PLAYER_CONTEXT_CONFIGS) || - void 0 === i || - null === (a = i.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_WATCH) || - void 0 === a - ? void 0 - : a.innertubeApiKey) || - (null === (s = window) || - void 0 === s || - null === (c = s.ytcfg) || - void 0 === c || - null === (l = c.data_) || - void 0 === l || - null === (d = l.WEB_PLAYER_CONTEXT_CONFIGS) || - void 0 === d || - null === (u = d.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_CHANNEL_TRAILER) || - void 0 === u - ? void 0 - : u.innertubeApiKey) || - (null === (h = window) || - void 0 === h || - null === (m = h.ytcfg) || - void 0 === m || - null === (p = m.data_) || - void 0 === p || - null === (f = p.WEB_PLAYER_CONTEXT_CONFIGS) || - void 0 === f || - null === - (v = f.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_PLAYLIST_OVERVIEW) || - void 0 === v - ? void 0 - : v.innertubeApiKey) || - (null === (y = window) || - void 0 === y || - null === (g = y.ytcfg) || - void 0 === g || - null === (w = g.data_) || - void 0 === w || - null === (b = w.WEB_PLAYER_CONTEXT_CONFIGS) || - void 0 === b || - null === - (x = - b.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_VERTICAL_LANDING_PAGE_PROMO) || - void 0 === x - ? void 0 - : x.innertubeApiKey) || - (null === (_ = window) || - void 0 === _ || - null === (C = _.ytcfg) || - void 0 === C || - null === (E = C.data_) || - void 0 === E || - null === (T = E.WEB_PLAYER_CONTEXT_CONFIGS) || - void 0 === T || - null === - (I = T.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_SPONSORSHIPS_OFFER) || - void 0 === I - ? void 0 - : I.innertubeApiKey) || - (null === (k = window) || - void 0 === k || - null === (R = k.ytplayer) || - void 0 === R || - null === (M = R.web_player_context_config) || - void 0 === M - ? void 0 - : M.innertubeApiKey) - ); - } catch (e) { + const ytcfgData = window?.ytcfg?.data_; + const innertubeApiKey = + ytcfgData?.INNERTUBE_API_KEY || + ytcfgData?.WEB_PLAYER_CONTEXT_CONFIGS + ?.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_WATCH?.innertubeApiKey || + ytcfgData?.WEB_PLAYER_CONTEXT_CONFIGS + ?.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_CHANNEL_TRAILER + ?.innertubeApiKey || + ytcfgData?.WEB_PLAYER_CONTEXT_CONFIGS + ?.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_PLAYLIST_OVERVIEW + ?.innertubeApiKey || + ytcfgData?.WEB_PLAYER_CONTEXT_CONFIGS + ?.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_VERTICAL_LANDING_PAGE_PROMO + ?.innertubeApiKey || + ytcfgData?.WEB_PLAYER_CONTEXT_CONFIGS + ?.WEB_PLAYER_CONTEXT_CONFIG_ID_KEVLAR_SPONSORSHIPS_OFFER + ?.innertubeApiKey || + window?.ytplayer?.web_player_context_config?.innertubeApiKey || + // Compatible with PocketTube modifying ytcfg structure + window?.ytcfg?.INNERTUBE_API_KEY; + + return innertubeApiKey; + } catch (error) { return; } } From 7036de317ec75c28ff04c9a75faeed58c08f0a3b Mon Sep 17 00:00:00 2001 From: pc035860 Date: Sat, 27 Jul 2024 18:52:35 +0800 Subject: [PATCH 2/3] Add fallback for retrieving `window.ytcfg.data_` All innertube api parameters generation functions are now async --- web-resources/wresources.js | 488 ++++++++++++++---------------------- 1 file changed, 183 insertions(+), 305 deletions(-) diff --git a/web-resources/wresources.js b/web-resources/wresources.js index fc9dffe..3c030c6 100644 --- a/web-resources/wresources.js +++ b/web-resources/wresources.js @@ -6716,8 +6716,10 @@ async function Qt(e, t) { try { if (!e) return; - const _ = ((n = window), - JSON.parse( + + const ytcfgData = await getPageCfgData(window, null); + + const defaultParams = JSON.parse( JSON.stringify({ ctoken: null, continuation: null, @@ -6727,150 +6729,80 @@ headers: { accept: '*/*', 'accept-language': - (null === (o = n.ytcfg) || - void 0 === o || - null === (r = o.data_) || - void 0 === r || - null === (i = r.GOOGLE_FEEDBACK_PRODUCT_DATA) || - void 0 === i - ? void 0 - : i.accept_language) || 'en-US,en;q=0.9', + ytcfgData?.GOOGLE_FEEDBACK_PRODUCT_DATA?.accept_language || + 'en-US,en;q=0.9', 'cache-control': 'no-cache', 'content-type': 'application/x-www-form-urlencoded', pragma: 'no-cache', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', - 'x-spf-previous': Xt(n.location.href), - 'x-spf-referer': Xt(n.location.href), - 'x-youtube-identity-token': - null === (a = n.ytcfg) || - void 0 === a || - null === (s = a.data_) || - void 0 === s - ? void 0 - : s.ID_TOKEN, + 'x-spf-previous': Xt(window.location.href), + 'x-spf-referer': Xt(window.location.href), + 'x-youtube-identity-token': ytcfgData?.ID_TOKEN, 'x-youtube-client-name': - (null === (c = n.ytcfg) || - void 0 === c || - null === (l = c.data_) || - void 0 === l - ? void 0 - : l.INNERTUBE_CONTEXT_CLIENT_NAME) || '1', + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', 'x-youtube-client-version': - null === (d = n.ytcfg) || - void 0 === d || - null === (u = d.data_) || - void 0 === u - ? void 0 - : u.INNERTUBE_CONTEXT_CLIENT_VERSION, + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, 'x-youtube-device': - (null === (h = n.ytcfg) || - void 0 === h || - null === (m = h.data_) || - void 0 === m - ? void 0 - : m.DEVICE) || 'cbr=Chrome&cplatform=DESKTOP', - 'x-youtube-page-cl': - null === (p = n.ytcfg) || - void 0 === p || - null === (f = p.data_) || - void 0 === f - ? void 0 - : f.PAGE_CL, - 'x-youtube-page-label': - null === (v = n.ytcfg) || - void 0 === v || - null === (y = v.data_) || - void 0 === y - ? void 0 - : y.PAGE_BUILD_LABEL, + ytcfgData?.DEVICE || 'cbr=Chrome&cplatform=DESKTOP', + 'x-youtube-page-cl': ytcfgData?.PAGE_CL, + 'x-youtube-page-label': ytcfgData?.PAGE_BUILD_LABEL, 'x-youtube-time-zone': Intl.DateTimeFormat().resolvedOptions().timeZone, 'x-youtube-utc-offset': Math.abs(new Date().getTimezoneOffset()), - 'x-youtube-variants-checksum': - null === (g = n.ytcfg) || - void 0 === g || - null === (w = g.data_) || - void 0 === w - ? void 0 - : w.VARIANTS_CHECKSUM, + 'x-youtube-variants-checksum': ytcfgData?.VARIANTS_CHECKSUM, }, - referrer: Xt(n.location.href), + referrer: Xt(window.location.href), referrerPolicy: 'origin-when-cross-origin', - body: `session_token=${ - null === (b = n.ytcfg) || - void 0 === b || - null === (x = b.data_) || - void 0 === x - ? void 0 - : x.XSRF_TOKEN - }`, + body: `session_token=${ytcfgData?.XSRF_TOKEN}`, method: 'POST', mode: 'cors', }, }) - )).params; - (_.method = 'GET'), delete _.headers['content-type'], delete _.body; - const C = await fetch(`${Xt(e)}&pbj=1`, { - ..._, - signal: t, - cache: 'no-store', - }), - E = await C.json(); - return (ycsOptions.getInitYtData = E), E; - } catch (e) { + ); + + const requestParams = defaultParams.params; + requestParams.method = 'GET'; + delete requestParams.headers['content-type']; + delete requestParams.body; + + const response = await fetch(`${Xt(e)}&pbj=1`, { + ...requestParams, + signal: t, + cache: 'no-store', + }); + + const data = await response.json(); + ycsOptions.getInitYtData = data; + return data; + } catch (error) { return; } - var n, o, r, i, a, s, c, l, d, u, h, m, p, f, v, y, g, w, b, x; } - function Zt(e, t, n) { + async function Zt(global, t, n) { if (t) try { - var o, r, i, a, s, c, l, d, u, h; + const ytcfgData = await getPageCfgData(global, null); return JSON.parse( JSON.stringify({ headers: { accept: '*/*', 'accept-language': - (null === (o = e.ytcfg) || - void 0 === o || - null === (r = o.data_) || - void 0 === r || - null === (i = r.GOOGLE_FEEDBACK_PRODUCT_DATA) || - void 0 === i - ? void 0 - : i.accept_language) || 'en-US,en;q=0.9', + ytcfgData?.GOOGLE_FEEDBACK_PRODUCT_DATA?.accept_language || + 'en-US,en;q=0.9', 'content-type': 'application/json', pragma: 'no-cache', 'cache-control': 'no-store', 'x-youtube-client-name': - (null === (a = e.ytcfg) || - void 0 === a || - null === (s = a.data_) || - void 0 === s - ? void 0 - : s.INNERTUBE_CONTEXT_CLIENT_NAME) || '1', + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', 'x-youtube-client-version': - null === (c = e.ytcfg) || - void 0 === c || - null === (l = c.data_) || - void 0 === l - ? void 0 - : l.INNERTUBE_CONTEXT_CLIENT_VERSION, + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, }, referrerPolicy: 'strict-origin-when-cross-origin', body: JSON.stringify({ context: { - client: - null === (d = e.ytcfg) || - void 0 === d || - null === (u = d.data_) || - void 0 === u || - null === (h = u.INNERTUBE_CONTEXT) || - void 0 === h - ? void 0 - : h.client, + client: ytcfgData?.INNERTUBE_CONTEXT?.client, }, continuation: t.continuation, currentPlayerState: { @@ -6886,57 +6818,33 @@ return; } } - function en(e, t) { + async function en(global, params) { try { - var n, o, r, i, a, s, c, l, d, u; + const ytcfgData = await getPageCfgData(global, null); return JSON.parse( JSON.stringify({ headers: { accept: '*/*', 'accept-language': - (null === (n = e.ytcfg) || - void 0 === n || - null === (o = n.data_) || - void 0 === o || - null === (r = o.GOOGLE_FEEDBACK_PRODUCT_DATA) || - void 0 === r - ? void 0 - : r.accept_language) || 'en-US,en;q=0.9', + ytcfgData?.GOOGLE_FEEDBACK_PRODUCT_DATA?.accept_language || + 'en-US,en;q=0.9', 'content-type': 'application/json', pragma: 'no-cache', 'cache-control': 'no-store', 'x-youtube-client-name': - (null === (i = e.ytcfg) || - void 0 === i || - null === (a = i.data_) || - void 0 === a - ? void 0 - : a.INNERTUBE_CONTEXT_CLIENT_NAME) || '1', + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', 'x-youtube-client-version': - null === (s = e.ytcfg) || - void 0 === s || - null === (c = s.data_) || - void 0 === c - ? void 0 - : c.INNERTUBE_CONTEXT_CLIENT_VERSION, + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, }, referrerPolicy: 'strict-origin-when-cross-origin', body: JSON.stringify({ context: { - client: - null === (l = e.ytcfg) || - void 0 === l || - null === (d = l.data_) || - void 0 === d || - null === (u = d.INNERTUBE_CONTEXT) || - void 0 === u - ? void 0 - : u.client, + client: ytcfgData?.INNERTUBE_CONTEXT?.client, }, clickTracking: { - clickTrackingParams: t.clickTrackingParams, + clickTrackingParams: params.clickTrackingParams, }, - continuation: t.continue, + continuation: params.continue, }), method: 'POST', mode: 'cors', @@ -6947,57 +6855,34 @@ return; } } - function tn(e, t) { + async function tn(global, signal, params) { try { - var n, o, r, i, a, s, c, l, d, u; + const ytcfgData = await getPageCfgData(global, signal); + return JSON.parse( JSON.stringify({ headers: { accept: '*/*', 'accept-language': - (null === (n = e.ytcfg) || - void 0 === n || - null === (o = n.data_) || - void 0 === o || - null === (r = o.GOOGLE_FEEDBACK_PRODUCT_DATA) || - void 0 === r - ? void 0 - : r.accept_language) || 'en-US,en;q=0.9', + ytcfgData?.GOOGLE_FEEDBACK_PRODUCT_DATA?.accept_language || + 'en-US,en;q=0.9', 'content-type': 'application/json', pragma: 'no-cache', 'cache-control': 'no-store', 'x-youtube-client-name': - (null === (i = e.ytcfg) || - void 0 === i || - null === (a = i.data_) || - void 0 === a - ? void 0 - : a.INNERTUBE_CONTEXT_CLIENT_NAME) || '1', + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', 'x-youtube-client-version': - null === (s = e.ytcfg) || - void 0 === s || - null === (c = s.data_) || - void 0 === c - ? void 0 - : c.INNERTUBE_CONTEXT_CLIENT_VERSION, + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, }, referrerPolicy: 'strict-origin-when-cross-origin', body: JSON.stringify({ context: { - client: - null === (l = e.ytcfg) || - void 0 === l || - null === (d = l.data_) || - void 0 === d || - null === (u = d.INNERTUBE_CONTEXT) || - void 0 === u - ? void 0 - : u.client, + client: ytcfgData?.INNERTUBE_CONTEXT?.client, }, clickTracking: { - clickTrackingParams: t.clickTracking, + clickTrackingParams: params.clickTracking, }, - continuation: t.continue, + continuation: params.continue, }), method: 'POST', mode: 'cors', @@ -7008,7 +6893,7 @@ return; } } - function nn() { + function getInnertubeApiKey() { try { const ytcfgData = window?.ytcfg?.data_; const innertubeApiKey = @@ -7067,53 +6952,29 @@ async function loadChatReplay(signal) { try { const n = await on(signal), - o = (function (e, t) { - if (t) + o = await (async function (e, t) { + if (t) { try { - var n, o, r, i, a, s, c, l, d, u; + const pageCfgData = await getPageCfgData(e, null); return JSON.parse( JSON.stringify({ headers: { accept: '*/*', 'accept-language': - (null === (n = e.ytcfg) || - void 0 === n || - null === (o = n.data_) || - void 0 === o || - null === (r = o.GOOGLE_FEEDBACK_PRODUCT_DATA) || - void 0 === r - ? void 0 - : r.accept_language) || 'en-US,en;q=0.9', + pageCfgData?.GOOGLE_FEEDBACK_PRODUCT_DATA + ?.accept_language || 'en-US,en;q=0.9', 'content-type': 'application/json', pragma: 'no-cache', 'cache-control': 'no-store', 'x-youtube-client-name': - (null === (i = e.ytcfg) || - void 0 === i || - null === (a = i.data_) || - void 0 === a - ? void 0 - : a.INNERTUBE_CONTEXT_CLIENT_NAME) || '1', + pageCfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', 'x-youtube-client-version': - null === (s = e.ytcfg) || - void 0 === s || - null === (c = s.data_) || - void 0 === c - ? void 0 - : c.INNERTUBE_CONTEXT_CLIENT_VERSION, + pageCfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, }, referrerPolicy: 'strict-origin-when-cross-origin', body: JSON.stringify({ context: { - client: - null === (l = e.ytcfg) || - void 0 === l || - null === (d = l.data_) || - void 0 === d || - null === (u = d.INNERTUBE_CONTEXT) || - void 0 === u - ? void 0 - : u.client, + client: pageCfgData?.INNERTUBE_CONTEXT?.client, }, continuation: t.continuation, }), @@ -7125,11 +6986,12 @@ } catch (e) { return; } + } })(window, n); if (o) { var t; const n = await fetch( - `https://www.youtube.com/youtubei/v1/live_chat/get_live_chat?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/live_chat/get_live_chat?key=${getInnertubeApiKey()}`, { ...o, signal, @@ -7285,6 +7147,53 @@ return; } } + async function _getPageCfgData(videoId, signal) { + let data; + const response = await fetch(`https://www.youtube.com/watch?v=${videoId}`, { + method: 'GET', + mode: 'no-cors', + credentials: 'include', + signal, + cache: 'default', + }); + const html = await response.text(); + const splittedHtml = html.split('window.ytplayer={};\nytcfg.set('); + if (splittedHtml.length <= 1) { + throw new Error('Fail to load video html'); + } + + try { + data = JSON.parse( + splittedHtml[1] + .split('); window.ytcfg.obfuscatedData_')[0] + .replace('\n', '') + ); + } catch (e) { + // do nothing + } + return data; + } + const pageCfgDataPool = {}; + async function getPageCfgData(global, signal, optUrl) { + let data = global.ytcfg?.data_ ?? null; + + if (data) { + return Promise.resolve(data); + } + + const url = optUrl ?? window.location.href; + + const videoId = getVideoId(url); + + if (pageCfgDataPool[videoId]) { + return pageCfgDataPool[videoId]; + } + + data = await _getPageCfgData(videoId, signal); + pageCfgDataPool[videoId] = data; + + return data; + } function sn(e) { if ('string' != typeof e) return; const t = document.querySelectorAll(e); @@ -7293,64 +7202,55 @@ async function cn(t, n, o) { const r = async () => { try { + const getFetchOptions = async ( + global, + url, + signal, + bodyTransformFn = (body) => body + ) => { + const ytcfgData = await getPageCfgData(global, signal, url); + return JSON.parse( + JSON.stringify({ + headers: { + accept: '*/*', + 'accept-language': + ytcfgData?.GOOGLE_FEEDBACK_PRODUCT_DATA?.accept_language || + 'en-US,en;q=0.9', + 'content-type': 'application/json', + pragma: 'no-cache', + 'cache-control': 'no-store', + 'x-youtube-client-name': + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', + 'x-youtube-client-version': + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, + }, + referrer: url, + referrerPolicy: 'strict-origin-when-cross-origin', + body: JSON.stringify( + bodyTransformFn({ + context: { + client: ytcfgData?.INNERTUBE_CONTEXT?.client, + }, + }) + ), + method: 'POST', + mode: 'cors', + credentials: 'include', + }) + ); + }; const e = await (async function (e, t, n) { try { var o, r, i, a, s, c, l, d, u, h; if ('string' != typeof t) return; - const m = JSON.parse( - JSON.stringify({ - headers: { - accept: '*/*', - 'accept-language': - (null === (o = e.ytcfg) || - void 0 === o || - null === (r = o.data_) || - void 0 === r || - null === (i = r.GOOGLE_FEEDBACK_PRODUCT_DATA) || - void 0 === i - ? void 0 - : i.accept_language) || 'en-US,en;q=0.9', - 'content-type': 'application/json', - pragma: 'no-cache', - 'cache-control': 'no-store', - 'x-youtube-client-name': - (null === (a = e.ytcfg) || - void 0 === a || - null === (s = a.data_) || - void 0 === s - ? void 0 - : s.INNERTUBE_CONTEXT_CLIENT_NAME) || '1', - 'x-youtube-client-version': - null === (c = e.ytcfg) || - void 0 === c || - null === (l = c.data_) || - void 0 === l - ? void 0 - : l.INNERTUBE_CONTEXT_CLIENT_VERSION, - }, - referrer: t, - referrerPolicy: 'strict-origin-when-cross-origin', - body: JSON.stringify({ - context: { - client: - null === (d = e.ytcfg) || - void 0 === d || - null === (u = d.data_) || - void 0 === u || - null === (h = u.INNERTUBE_CONTEXT) || - void 0 === h - ? void 0 - : h.client, - }, - videoId: getVideoId(t), - }), - method: 'POST', - mode: 'cors', - credentials: 'include', - }) - ), + const m = await getFetchOptions(e, t, n, (body) => { + return { + ...body, + videoId: getVideoId(t), + }; + }), p = await fetch( - `https://www.youtube.com/youtubei/v1/next?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { ...m, signal: n, @@ -7374,52 +7274,30 @@ )(e), o = await (async function (e, t, n) { try { - var o, r, i, a, s, c, l, d, u, h; - if ('object' != typeof t) return; + if (typeof t !== 'object') return; + + const ytcfgData = await getPageCfgData(e, n, t.url); + const m = JSON.parse( JSON.stringify({ headers: { accept: '*/*', 'accept-language': - (null === (o = e.ytcfg) || - void 0 === o || - null === (r = o.data_) || - void 0 === r || - null === (i = r.GOOGLE_FEEDBACK_PRODUCT_DATA) || - void 0 === i - ? void 0 - : i.accept_language) || 'en-US,en;q=0.9', + ytcfgData?.GOOGLE_FEEDBACK_PRODUCT_DATA + ?.accept_language || 'en-US,en;q=0.9', 'content-type': 'application/json', pragma: 'no-cache', 'cache-control': 'no-store', 'x-youtube-client-name': - (null === (a = e.ytcfg) || - void 0 === a || - null === (s = a.data_) || - void 0 === s - ? void 0 - : s.INNERTUBE_CONTEXT_CLIENT_NAME) || '1', + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', 'x-youtube-client-version': - null === (c = e.ytcfg) || - void 0 === c || - null === (l = c.data_) || - void 0 === l - ? void 0 - : l.INNERTUBE_CONTEXT_CLIENT_VERSION, + ytcfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, }, referrer: t.url, referrerPolicy: 'strict-origin-when-cross-origin', body: JSON.stringify({ context: { - client: - null === (d = e.ytcfg) || - void 0 === d || - null === (u = d.data_) || - void 0 === u || - null === (h = u.INNERTUBE_CONTEXT) || - void 0 === h - ? void 0 - : h.client, + client: ytcfgData?.INNERTUBE_CONTEXT?.client, }, clickTracking: { clickTrackingParams: '', @@ -7432,7 +7310,7 @@ }) ), p = await fetch( - `https://www.youtube.com/youtubei/v1/next?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { ...m, signal: n, @@ -7728,9 +7606,9 @@ continue: token, clickTracking: cTrParams, }; - const requestOptions = tn(window, data); + const requestOptions = await tn(window, n, data); const response = await Ft( - `https://www.youtube.com/youtubei/v1/next?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { ...requestOptions, signal: n, @@ -7858,9 +7736,9 @@ continue: token, clickTracking: clickTrackingParams, }; - const requestOptions = tn(window, data); + const requestOptions = await tn(window, n, data); const response = await Ft( - `https://www.youtube.com/youtubei/v1/next?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { ...requestOptions, signal: n, @@ -8369,11 +8247,11 @@ let i; if ( ((i = t.clickTrackingParams - ? en(window, { + ? await en(window, { continue: t.continue, clickTrackingParams: t.clickTrackingParams, }) - : en(window, { + : await en(window, { continue: qt(() => objectScan( [ @@ -8401,7 +8279,7 @@ })), i && (e = await fetch( - `https://www.youtube.com/youtubei/v1/next?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { ...i, signal: n, @@ -8455,9 +8333,9 @@ ? void 0 : p.token, }, - o = en(window, t), + o = await en(window, t), r = await Ft( - `https://www.youtube.com/youtubei/v1/next?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { ...o, signal: n, @@ -10663,12 +10541,12 @@ let n = 0, o = !0; for (; o; ) { - const r = Zt(window, $, n); + const r = await Zt(window, $, n); if (!r) return (o = !1), P; { var w, b; const i = await Ft( - `https://www.youtube.com/youtubei/v1/live_chat/get_live_chat_replay?key=${nn()}`, + `https://www.youtube.com/youtubei/v1/live_chat/get_live_chat_replay?key=${getInnertubeApiKey()}`, { ...r, signal, From 38f38a9fcba84adbcff71ebc5e91fc44498a31ba Mon Sep 17 00:00:00 2001 From: pc035860 Date: Wed, 31 Jul 2024 00:15:49 +0800 Subject: [PATCH 3/3] Rename functions and parameters for better readability --- web-resources/wresources.js | 249 +++++++++++++++++++++--------------- 1 file changed, 146 insertions(+), 103 deletions(-) diff --git a/web-resources/wresources.js b/web-resources/wresources.js index 3c030c6..07f5e2b 100644 --- a/web-resources/wresources.js +++ b/web-resources/wresources.js @@ -6665,7 +6665,22 @@ return; } } - function Wt(e, t) { + /** + * Recursively searches for a specific property in an object and returns an array of paths to that property + * @param {Object} e - The object to search + * @param {string} t - The name of the property to find + * @returns {Array} An array containing the paths to the found properties + * + * @example + * const obj = { + * a: { b: { c: 1 } }, + * d: { c: 2 }, + * e: { f: { c: 3 } } + * }; + * findPropertyPaths(obj, 'c'); + * // Returns: [{ 'a.b.c': 1 }, { 'd.c': 2 }, { 'e.f.c': 3 }] + */ + function findPropertyPaths(e, t) { const n = []; try { (function e(o, r) { @@ -6699,7 +6714,7 @@ function Kt(e, t) { t && (t.textContent = e.toString()); } - function Xt(e) { + function normalizeVideoUrl(e) { try { if ('string' != typeof e) return; const t = new URL(e), @@ -6713,9 +6728,9 @@ return; } } - async function Qt(e, t) { + async function fetchInitialYouTubeData(url, signal) { try { - if (!e) return; + if (!url) return; const ytcfgData = await getPageCfgData(window, null); @@ -6737,8 +6752,8 @@ 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', - 'x-spf-previous': Xt(window.location.href), - 'x-spf-referer': Xt(window.location.href), + 'x-spf-previous': normalizeVideoUrl(window.location.href), + 'x-spf-referer': normalizeVideoUrl(window.location.href), 'x-youtube-identity-token': ytcfgData?.ID_TOKEN, 'x-youtube-client-name': ytcfgData?.INNERTUBE_CONTEXT_CLIENT_NAME || '1', @@ -6753,7 +6768,7 @@ 'x-youtube-utc-offset': Math.abs(new Date().getTimezoneOffset()), 'x-youtube-variants-checksum': ytcfgData?.VARIANTS_CHECKSUM, }, - referrer: Xt(window.location.href), + referrer: normalizeVideoUrl(window.location.href), referrerPolicy: 'origin-when-cross-origin', body: `session_token=${ytcfgData?.XSRF_TOKEN}`, method: 'POST', @@ -6767,9 +6782,9 @@ delete requestParams.headers['content-type']; delete requestParams.body; - const response = await fetch(`${Xt(e)}&pbj=1`, { + const response = await fetch(`${normalizeVideoUrl(url)}&pbj=1`, { ...requestParams, - signal: t, + signal, cache: 'no-store', }); @@ -6780,10 +6795,14 @@ return; } } - async function Zt(global, t, n) { - if (t) + async function getChatReplayContinuationRequestOptions( + globalContext, + continuationData, + playerOffsetMs + ) { + if (continuationData) try { - const ytcfgData = await getPageCfgData(global, null); + const ytcfgData = await getPageCfgData(globalContext, null); return JSON.parse( JSON.stringify({ headers: { @@ -6804,9 +6823,9 @@ context: { client: ytcfgData?.INNERTUBE_CONTEXT?.client, }, - continuation: t.continuation, + continuation: continuationData.continuation, currentPlayerState: { - playerOffsetMs: n.toString(), + playerOffsetMs: playerOffsetMs.toString(), }, }), method: 'POST', @@ -6818,9 +6837,12 @@ return; } } - async function en(global, params) { + async function getCommentsContinuationRequestOptionsSub( + globalContext, + continuationData + ) { try { - const ytcfgData = await getPageCfgData(global, null); + const ytcfgData = await getPageCfgData(globalContext, null); return JSON.parse( JSON.stringify({ headers: { @@ -6842,9 +6864,9 @@ client: ytcfgData?.INNERTUBE_CONTEXT?.client, }, clickTracking: { - clickTrackingParams: params.clickTrackingParams, + clickTrackingParams: continuationData.clickTrackingParams, }, - continuation: params.continue, + continuation: continuationData.continue, }), method: 'POST', mode: 'cors', @@ -6855,10 +6877,13 @@ return; } } - async function tn(global, signal, params) { + async function getCommentsContinuationRequestOptions( + globalContext, + signal, + continuationData + ) { try { - const ytcfgData = await getPageCfgData(global, signal); - + const ytcfgData = await getPageCfgData(globalContext, signal); return JSON.parse( JSON.stringify({ headers: { @@ -6880,9 +6905,9 @@ client: ytcfgData?.INNERTUBE_CONTEXT?.client, }, clickTracking: { - clickTrackingParams: params.clickTracking, + clickTrackingParams: continuationData.clickTracking, }, - continuation: params.continue, + continuation: continuationData.continue, }), method: 'POST', mode: 'cors', @@ -6921,28 +6946,31 @@ return; } } - async function on(e) { + async function getReloadContinuationData(signal) { try { - const t = await Qt(window.location.href, e); - if (t) { + const initialData = await fetchInitialYouTubeData( + window.location.href, + signal + ); + if (initialData) { if ( qt( () => - t[3].response.contents.twoColumnWatchNextResults.conversationBar - .liveChatRenderer.header.liveChatHeaderRenderer.viewSelector - .sortFilterSubMenuRenderer.subMenuItems[1].continuation - .reloadContinuationData + initialData[3].response.contents.twoColumnWatchNextResults + .conversationBar.liveChatRenderer.header.liveChatHeaderRenderer + .viewSelector.sortFilterSubMenuRenderer.subMenuItems[1] + .continuation.reloadContinuationData ) ) return qt( () => - t[3].response.contents.twoColumnWatchNextResults.conversationBar - .liveChatRenderer.header.liveChatHeaderRenderer.viewSelector - .sortFilterSubMenuRenderer.subMenuItems[1].continuation - .reloadContinuationData + initialData[3].response.contents.twoColumnWatchNextResults + .conversationBar.liveChatRenderer.header.liveChatHeaderRenderer + .viewSelector.sortFilterSubMenuRenderer.subMenuItems[1] + .continuation.reloadContinuationData ); - const e = Wt(t, 'reloadContinuationData'); - if (e.length > 0) return Object.values(e[e.length - 1])[0]; + const paths = findPropertyPaths(initialData, 'reloadContinuationData'); + if (paths.length > 0) return Object.values(paths[paths.length - 1])[0]; } return; } catch (e) { @@ -6951,11 +6979,11 @@ } async function loadChatReplay(signal) { try { - const n = await on(signal), - o = await (async function (e, t) { - if (t) { + const n = await getReloadContinuationData(signal), + o = await (async function (globalContext, continuationData) { + if (continuationData) { try { - const pageCfgData = await getPageCfgData(e, null); + const pageCfgData = await getPageCfgData(globalContext, null); return JSON.parse( JSON.stringify({ headers: { @@ -6976,7 +7004,7 @@ context: { client: pageCfgData?.INNERTUBE_CONTEXT?.client, }, - continuation: t.continuation, + continuation: continuationData.continuation, }), method: 'POST', mode: 'cors', @@ -7174,8 +7202,8 @@ return data; } const pageCfgDataPool = {}; - async function getPageCfgData(global, signal, optUrl) { - let data = global.ytcfg?.data_ ?? null; + async function getPageCfgData(globalContext, signal, optUrl) { + let data = globalContext.ytcfg?.data_ ?? null; if (data) { return Promise.resolve(data); @@ -7203,12 +7231,12 @@ const r = async () => { try { const getFetchOptions = async ( - global, + globalContext, url, signal, bodyTransformFn = (body) => body ) => { - const ytcfgData = await getPageCfgData(global, signal, url); + const ytcfgData = await getPageCfgData(globalContext, signal, url); return JSON.parse( JSON.stringify({ headers: { @@ -7261,7 +7289,7 @@ } catch (e) { return; } - })(window, Xt(window.location.href), n), + })(window, normalizeVideoUrl(window.location.href), n), t = objectScan( [ '**.contents.twoColumnWatchNextResults.results.results.contents[?].itemSectionRenderer.contents[?].continuationItemRenderer.continuationEndpoint.continuationCommand.token', @@ -7272,13 +7300,21 @@ abort: !0, } )(e), - o = await (async function (e, t, n) { + o = await (async function ( + globalContext, + continuationData, + signal + ) { try { - if (typeof t !== 'object') return; + if (typeof continuationData !== 'object') return; - const ytcfgData = await getPageCfgData(e, n, t.url); + const ytcfgData = await getPageCfgData( + globalContext, + signal, + continuationData.url + ); - const m = JSON.parse( + const requestOptions = JSON.parse( JSON.stringify({ headers: { accept: '*/*', @@ -7293,7 +7329,7 @@ 'x-youtube-client-version': ytcfgData?.INNERTUBE_CONTEXT_CLIENT_VERSION, }, - referrer: t.url, + referrer: continuationData.url, referrerPolicy: 'strict-origin-when-cross-origin', body: JSON.stringify({ context: { @@ -7302,29 +7338,29 @@ clickTracking: { clickTrackingParams: '', }, - continuation: t.continue, + continuation: continuationData.continue, }), method: 'POST', mode: 'cors', credentials: 'include', }) ), - p = await fetch( + response = await fetch( `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { - ...m, - signal: n, + ...requestOptions, + signal, cache: 'no-store', } ); - return await p.json(); - } catch (e) { + return await response.json(); + } catch (error) { return; } })( window, { - url: Xt(window.location.href), + url: normalizeVideoUrl(window.location.href), continue: t, }, n @@ -7606,7 +7642,8 @@ continue: token, clickTracking: cTrParams, }; - const requestOptions = await tn(window, n, data); + const requestOptions = + await getCommentsContinuationRequestOptions(window, n, data); const response = await Ft( `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { @@ -7736,7 +7773,12 @@ continue: token, clickTracking: clickTrackingParams, }; - const requestOptions = await tn(window, n, data); + const requestOptions = + await getCommentsContinuationRequestOptions( + window, + n, + data + ); const response = await Ft( `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { @@ -8247,11 +8289,11 @@ let i; if ( ((i = t.clickTrackingParams - ? await en(window, { + ? await getCommentsContinuationRequestOptionsSub(window, { continue: t.continue, clickTrackingParams: t.clickTrackingParams, }) - : await en(window, { + : await getCommentsContinuationRequestOptionsSub(window, { continue: qt(() => objectScan( [ @@ -8304,36 +8346,24 @@ // temporarily store last response let contData; for (; (null == i ? void 0 : i.length) > 0; ) { - var l, d, u; const updatesById = getFrameworkUpdatesById(contData || o); i = migrateContinuationItems(i, updatesById); await processComments(i, t); - const e = i[i.length - 1]; + const item = i[i.length - 1]; if ( - null == e || - null === (l = e.continuationItemRenderer) || - void 0 === l || - null === (d = l.continuationEndpoint) || - void 0 === d || - null === (u = d.continuationCommand) || - void 0 === u - ? void 0 - : u.token + item?.continuationItemRenderer?.continuationEndpoint + ?.continuationCommand?.token ) { - var h, m, p; - const t = { - continue: - null == e || - null === (h = e.continuationItemRenderer) || - void 0 === h || - null === (m = h.continuationEndpoint) || - void 0 === m || - null === (p = m.continuationCommand) || - void 0 === p - ? void 0 - : p.token, - }, - o = await en(window, t), + const continuationToken = + item?.continuationItemRenderer?.continuationEndpoint + ?.continuationCommand?.token; + const continuationData = { + continue: continuationToken, + }; + const o = await getCommentsContinuationRequestOptionsSub( + window, + continuationData + ), r = await Ft( `https://www.youtube.com/youtubei/v1/next?key=${getInnertubeApiKey()}`, { @@ -8823,7 +8853,7 @@ type: 'YCS_CACHE_STORAGE_SET', body: { url: t, - videoId: getVideoId(Xt(t)), + videoId: getVideoId(normalizeVideoUrl(t)), date: new Date().getTime(), titleVideo: n, comments: e.comments, @@ -10377,7 +10407,7 @@ return e; } }, - $ = await on(signal); + $ = await getReloadContinuationData(signal); if (!$) return; const P = n || new Map(), j = await loadChatReplay(signal); @@ -10461,7 +10491,9 @@ o.replayChatItemAction.actions[0].addLiveChatTickerItemAction.item.liveChatTickerPaidMessageItemRenderer.showItemEndpoint.showLiveChatItemEndpoint.renderer.liveChatPaidMessageRenderer); else { const e = qt(() => - Object.keys(Wt(o, 'timestampUsec')[0])[0] + Object.keys( + findPropertyPaths(o, 'timestampUsec')[0] + )[0] .split('.') .slice(0, -1) .join('.') @@ -10541,7 +10573,12 @@ let n = 0, o = !0; for (; o; ) { - const r = await Zt(window, $, n); + const r = + await getChatReplayContinuationRequestOptions( + window, + $, + n + ); if (!r) return (o = !1), P; { var w, b; @@ -10566,7 +10603,10 @@ a && a.length > 0) ) { const [, e] = Object.entries( - Wt(a[a.length - 1], 'videoOffsetTimeMsec')[0] + findPropertyPaths( + a[a.length - 1], + 'videoOffsetTimeMsec' + )[0] )[0]; if (n === e) { o = !1; @@ -10633,7 +10673,10 @@ else { const t = qt(() => Object.keys( - Wt(e, 'timestampUsec')[0] + findPropertyPaths( + e, + 'timestampUsec' + )[0] )[0] .split('.') .slice(0, -1) @@ -10906,7 +10949,7 @@ 'word-wrap: break-word; white-space: pre-wrap;'), n.insertAdjacentText( 'afterbegin', - `\nYCS - YouTube Comment Search\n\nComments\nFile created by ${new Date().toString()}\nVideo URL: ${Xt( + `\nYCS - YouTube Comment Search\n\nComments\nFile created by ${new Date().toString()}\nVideo URL: ${normalizeVideoUrl( window.location.href )}\nTitle: ${document.title}\nTotal: ${ e.count @@ -10932,7 +10975,7 @@ try { const e = mn(commentsDataBuf); hn( - `\nYCS - YouTube Comment Search\n\nComments\nFile created by ${new Date().toString()}\nVideo URL: ${Xt( + `\nYCS - YouTube Comment Search\n\nComments\nFile created by ${new Date().toString()}\nVideo URL: ${normalizeVideoUrl( window.location.href )}\nTitle: ${document.title}\nTotal: ${e.count}\n${ e.html @@ -10967,7 +11010,7 @@ 'word-wrap: break-word; white-space: pre-wrap;'), n.insertAdjacentText( 'afterbegin', - `\nYCS - YouTube Comment Search\n\nComments chat\nFile created by ${new Date().toString()}\nVideo URL: ${Xt( + `\nYCS - YouTube Comment Search\n\nComments chat\nFile created by ${new Date().toString()}\nVideo URL: ${normalizeVideoUrl( window.location.href )}\nTitle: ${document.title}\nTotal: ${ e.count @@ -10993,7 +11036,7 @@ try { const e = pn([...chatDataBuf.values()]); hn( - `\nYCS - YouTube Comment Search\n\nComments chat\nFile created by ${new Date().toString()}\nVideo URL: ${Xt( + `\nYCS - YouTube Comment Search\n\nComments chat\nFile created by ${new Date().toString()}\nVideo URL: ${normalizeVideoUrl( window.location.href )}\nTitle: ${document.title}\nTotal: ${e.count}\n${ e.html @@ -11055,7 +11098,7 @@ 'word-wrap: break-word; white-space: pre-wrap;'), n.insertAdjacentText( 'afterbegin', - `\nYCS - YouTube Comment Search\n\nTranscript video\nFile created by ${new Date().toString()}\nVideo URL: ${Xt( + `\nYCS - YouTube Comment Search\n\nTranscript video\nFile created by ${new Date().toString()}\nVideo URL: ${normalizeVideoUrl( window.location.href )}\nTitle: ${document.title}\nTotal: ${ e.count @@ -11116,7 +11159,7 @@ .cueGroups ); hn( - `\nYCS - YouTube Comment Search\n\nTranscript video\nFile created by ${new Date().toString()}\nVideo URL: ${Xt( + `\nYCS - YouTube Comment Search\n\nTranscript video\nFile created by ${new Date().toString()}\nVideo URL: ${normalizeVideoUrl( window.location.href )}\nTitle: ${document.title}\nTotal: ${e.count}\n${ e.html @@ -12724,7 +12767,7 @@ { type: 'YCS_CACHE_STORAGE_GET', body: { - videoId: getVideoId(Xt(e)), + videoId: getVideoId(normalizeVideoUrl(e)), }, }, window.location.origin @@ -13008,12 +13051,12 @@ } } function r() { - let e = Xt(window.location.href); + let e = normalizeVideoUrl(window.location.href); setInterval(() => { Yt() && document.querySelector('#meta.style-scope.ytd-watch-flexy') && - e !== Xt(window.location.href) && - ((e = Xt(window.location.href)), t.abort(), o()); + e !== normalizeVideoUrl(window.location.href) && + ((e = normalizeVideoUrl(window.location.href)), t.abort(), o()); }, 1e3); } r();