Give yt-dlp a JavaScript runtime to avoid YouTube's bot checks
Downloads failed with "Sign in to confirm you're not a bot" even with cookies and a working proxy. yt-dlp was also warning that no JavaScript runtime was available: YouTube's player challenges now require one, and without it extraction degrades into exactly those bot checks. The image already ships Node, so yt-dlp is pointed at it via --js-runtimes, but only after confirming the installed build understands the flag — an older binary would otherwise fail on an unknown option. Startup logs which runtime was picked and warns when there is none. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
71dc3f2da8
commit
2ee907626e
+30
-3
@@ -31,8 +31,28 @@ interface YtDlpEntry {
|
||||
entries?: YtDlpEntry[] | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modern yt-dlp needs a JavaScript runtime for YouTube's player challenges;
|
||||
* without one, extraction is degraded and YouTube starts answering with "Sign in
|
||||
* to confirm you're not a bot". Our image already ships Node, so we point yt-dlp
|
||||
* at it — but only once we have confirmed this build understands the flag.
|
||||
*/
|
||||
let jsRuntimeArgs: string[] = [];
|
||||
|
||||
async function detectJsRuntime(): Promise<string | null> {
|
||||
if (!config.YTDLP_JS_RUNTIME) return null;
|
||||
try {
|
||||
const { stdout } = await runYtDlp(["--help"], 15_000);
|
||||
if (!stdout.includes("--js-runtimes")) return null;
|
||||
jsRuntimeArgs = ["--js-runtimes", config.YTDLP_JS_RUNTIME];
|
||||
return config.YTDLP_JS_RUNTIME;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function baseArgs(): string[] {
|
||||
const args = ["--no-warnings", "--no-playlist-reverse", "--ignore-config", "--no-color"];
|
||||
const args = ["--no-warnings", "--no-playlist-reverse", "--ignore-config", "--no-color", ...jsRuntimeArgs];
|
||||
if (config.YTDLP_COOKIES) args.push("--cookies", config.YTDLP_COOKIES);
|
||||
if (config.YTDLP_PROXY) args.push("--proxy", config.YTDLP_PROXY);
|
||||
for (const value of config.YTDLP_EXTRACTOR_ARGS?.split(";") ?? []) {
|
||||
@@ -351,10 +371,17 @@ export function openAudioStream(pageUrl: string): AudioProcess {
|
||||
};
|
||||
}
|
||||
|
||||
export async function checkAvailable(): Promise<string | null> {
|
||||
export interface YtDlpStatus {
|
||||
version: string;
|
||||
jsRuntime: string | null;
|
||||
}
|
||||
|
||||
export async function checkAvailable(): Promise<YtDlpStatus | null> {
|
||||
try {
|
||||
const { stdout } = await runYtDlp(["--version"], 15_000);
|
||||
return stdout.trim() || null;
|
||||
const version = stdout.trim();
|
||||
if (!version) return null;
|
||||
return { version, jsRuntime: await detectJsRuntime() };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user