5 Commits

Author SHA1 Message Date
jj
91989b8de1 youtube: await decipher()s
Some checks failed
CodeQL / Analyze (javascript-typescript) (pull_request) Failing after 13s
Run service tests / test service functionality (pull_request) Successful in 23s
Run tests / check lockfile correctness (pull_request) Successful in 20s
Run tests / web sanity check (pull_request) Successful in 1m25s
Run tests / api sanity check (pull_request) Failing after 27s
Run service tests / test service: ${{ matrix.service }} (pull_request) Failing after 20s
they are async as of https://github.com/LuanRT/YouTube.js/pull/1047
2025-10-13 23:30:58 +00:00
jj
1dc0aa89df youtube: provide own JS interpreter
since the data should be side-effect free, this should
be fine for now, but maybe it might be a good idea to look
into a proper sandboxed environment in the future.
2025-10-13 23:30:58 +00:00
jj
c86ab40acd youtube: fix custom fetch breakage
https://github.com/LuanRT/YouTube.js/issues/962#issuecomment-2864091135
2025-10-13 23:30:58 +00:00
jj
dad8bf8baa api/youtube: try new session server 2025-10-13 22:52:42 +00:00
jj
3e25b91b67 api/package: bump youtubei.js to 16.0.0 2025-10-13 22:19:46 +00:00
4 changed files with 59 additions and 27 deletions

View File

@@ -39,7 +39,7 @@
"set-cookie-parser": "2.6.0", "set-cookie-parser": "2.6.0",
"undici": "^6.21.3", "undici": "^6.21.3",
"url-pattern": "1.0.3", "url-pattern": "1.0.3",
"youtubei.js": "15.1.1", "youtubei.js": "16.0.0",
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"optionalDependencies": { "optionalDependencies": {

View File

@@ -9,6 +9,10 @@ const defaultAgent = new Agent();
let session; let session;
const validateSession = (sessionResponse) => { const validateSession = (sessionResponse) => {
sessionResponse.visitor_data ??= sessionResponse.contentBinding;
sessionResponse.potoken ??= sessionResponse.poToken;
sessionResponse.updated ??= new Date().getTime();
if (!sessionResponse.potoken) { if (!sessionResponse.potoken) {
throw "no poToken in session response"; throw "no poToken in session response";
} }
@@ -33,11 +37,11 @@ const updateSession = (newSession) => {
const loadSession = async () => { const loadSession = async () => {
const sessionServerUrl = new URL(env.ytSessionServer); const sessionServerUrl = new URL(env.ytSessionServer);
sessionServerUrl.pathname = "/token"; sessionServerUrl.pathname = "/get_pot";
const newSession = await fetch( const newSession = await fetch(
sessionServerUrl, sessionServerUrl,
{ dispatcher: defaultAgent } { method: 'POST', dispatcher: defaultAgent }
).then(a => a.json()); ).then(a => a.json());
validateSession(newSession); validateSession(newSession);

View File

@@ -1,12 +1,29 @@
import HLS from "hls-parser"; import HLS from "hls-parser";
import { fetch } from "undici"; import { fetch, Request } from "undici";
import { Innertube, Session } from "youtubei.js"; import { Innertube, Platform, Session } from "youtubei.js";
import { env } from "../../config.js"; import { env } from "../../config.js";
import { getCookie } from "../cookie/manager.js"; import { getCookie } from "../cookie/manager.js";
import { getYouTubeSession } from "../helpers/youtube-session.js"; import { getYouTubeSession } from "../helpers/youtube-session.js";
// https://github.com/LuanRT/YouTube.js/pull/1052
Platform.shim.eval = async (data, env) => {
const properties = [];
if (env.n) {
properties.push(`n: exportedVars.nFunction("${env.n}")`)
}
if (env.sig) {
properties.push(`sig: exportedVars.sigFunction("${env.sig}")`)
}
const code = `${data.output}\nreturn { ${properties.join(', ')} }`;
return new Function(code)();
}
const PLAYER_REFRESH_PERIOD = 1000 * 60 * 15; // ms const PLAYER_REFRESH_PERIOD = 1000 * 60 * 15; // ms
let innertube, lastRefreshedAt; let innertube, lastRefreshedAt;
@@ -66,7 +83,6 @@ const cloneInnertube = async (customFetch, useSession) => {
cookie, cookie,
po_token: useSession ? sessionTokens?.potoken : undefined, po_token: useSession ? sessionTokens?.potoken : undefined,
visitor_data: useSession ? sessionTokens?.visitor_data : undefined, visitor_data: useSession ? sessionTokens?.visitor_data : undefined,
player_id : "0004de42",
}); });
lastRefreshedAt = +new Date(); lastRefreshedAt = +new Date();
} }
@@ -207,10 +223,24 @@ export default async function (o) {
let yt; let yt;
try { try {
yt = await cloneInnertube( yt = await cloneInnertube(
(input, init) => fetch(input, { (input, init) => {
const url = typeof input === 'string'
? new URL(input)
: input instanceof URL
? input
: new URL(input.url);
const request = new Request(
url,
input instanceof Platform.shim.Request
? input : undefined
);
return fetch(request, {
...init, ...init,
dispatcher: o.dispatcher dispatcher: o.dispatcher
}), });
},
useSession useSession
); );
} catch (e) { } catch (e) {
@@ -530,7 +560,7 @@ export default async function (o) {
} }
if (!clientsWithNoCipher.includes(innertubeClient) && innertube) { if (!clientsWithNoCipher.includes(innertubeClient) && innertube) {
urls = audio.decipher(innertube.session.player); urls = await audio.decipher(innertube.session.player);
} }
let cover = `https://i.ytimg.com/vi/${o.id}/maxresdefault.jpg`; let cover = `https://i.ytimg.com/vi/${o.id}/maxresdefault.jpg`;
@@ -577,8 +607,8 @@ export default async function (o) {
filenameAttributes.extension = o.container === "auto" ? codecList[codec].container : o.container; filenameAttributes.extension = o.container === "auto" ? codecList[codec].container : o.container;
if (!clientsWithNoCipher.includes(innertubeClient) && innertube) { if (!clientsWithNoCipher.includes(innertubeClient) && innertube) {
video = video.decipher(innertube.session.player); video = await video.decipher(innertube.session.player);
audio = audio.decipher(innertube.session.player); audio = await audio.decipher(innertube.session.player);
} else { } else {
video = video.url; video = video.url;
audio = audio.url; audio = audio.url;

26
pnpm-lock.yaml generated
View File

@@ -59,8 +59,8 @@ importers:
specifier: 1.0.3 specifier: 1.0.3
version: 1.0.3 version: 1.0.3
youtubei.js: youtubei.js:
specifier: 15.1.1 specifier: 16.0.0
version: 15.1.1 version: 16.0.0
zod: zod:
specifier: ^3.23.8 specifier: ^3.23.8
version: 3.23.8 version: 3.23.8
@@ -1447,9 +1447,6 @@ packages:
resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==}
engines: {node: 20 || >=22} engines: {node: 20 || >=22}
jintr@3.3.1:
resolution: {integrity: sha512-nnOzyhf0SLpbWuZ270Omwbj5LcXUkTcZkVnK8/veJXtSZOiATM5gMZMdmzN75FmTyj+NVgrGaPdH12zIJ24oIA==}
joycon@3.1.1: joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -1538,6 +1535,10 @@ packages:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
meriyah@6.1.4:
resolution: {integrity: sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==}
engines: {node: '>=18.0.0'}
methods@1.1.2: methods@1.1.2:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -2186,8 +2187,8 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
youtubei.js@15.1.1: youtubei.js@16.0.0:
resolution: {integrity: sha512-fuEDj9Ky6cAQg93BrRVCbr+GTYNZQAIFZrx/a3oDRuGc3Mf5bS0dQfoYwwgjtSV7sgAKQEEdGtzRdBzOc8g72Q==} resolution: {integrity: sha512-aMx+ulnrxzsgVsxTr7gbBVnIjti2NQUlMwCoo1/MzICCJS3iMLOPUFdo7bSpwskL6ljzQ/LxmmB4WQC3FtkBlA==}
zimmerframe@1.1.2: zimmerframe@1.1.2:
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
@@ -3388,10 +3389,6 @@ snapshots:
dependencies: dependencies:
'@isaacs/cliui': 8.0.2 '@isaacs/cliui': 8.0.2
jintr@3.3.1:
dependencies:
acorn: 8.14.0
joycon@3.1.1: {} joycon@3.1.1: {}
js-yaml@3.14.1: js-yaml@3.14.1:
@@ -3464,6 +3461,8 @@ snapshots:
merge2@1.4.1: {} merge2@1.4.1: {}
meriyah@6.1.4: {}
methods@1.1.2: {} methods@1.1.2: {}
micromatch@4.0.7: micromatch@4.0.7:
@@ -4044,11 +4043,10 @@ snapshots:
yocto-queue@0.1.0: {} yocto-queue@0.1.0: {}
youtubei.js@15.1.1: youtubei.js@16.0.0:
dependencies: dependencies:
'@bufbuild/protobuf': 2.2.5 '@bufbuild/protobuf': 2.2.5
jintr: 3.3.1 meriyah: 6.1.4
undici: 6.21.3
zimmerframe@1.1.2: {} zimmerframe@1.1.2: {}