Fix YouTube test yt-dlp fakes for non-Windows CI

This commit is contained in:
2026-04-03 12:28:50 -07:00
parent a7a50358e9
commit 3203713fd5
4 changed files with 127 additions and 8 deletions

View File

@@ -16,8 +16,14 @@ async function withTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {
function makeFakeYtDlpScript(dir: string, payload: string): void { function makeFakeYtDlpScript(dir: string, payload: string): void {
const scriptPath = path.join(dir, 'yt-dlp'); const scriptPath = path.join(dir, 'yt-dlp');
const script = `#!/usr/bin/env node const script = process.platform === 'win32'
? `#!/usr/bin/env node
process.stdout.write(${JSON.stringify(payload)}); process.stdout.write(${JSON.stringify(payload)});
`
: `#!/usr/bin/env sh
cat <<'EOF' | base64 -d
${Buffer.from(payload).toString('base64')}
EOF
`; `;
fs.writeFileSync(scriptPath, script, 'utf8'); fs.writeFileSync(scriptPath, script, 'utf8');
if (process.platform !== 'win32') { if (process.platform !== 'win32') {
@@ -28,8 +34,10 @@ process.stdout.write(${JSON.stringify(payload)});
function makeHangingFakeYtDlpScript(dir: string): void { function makeHangingFakeYtDlpScript(dir: string): void {
const scriptPath = path.join(dir, 'yt-dlp'); const scriptPath = path.join(dir, 'yt-dlp');
const script = `#!/usr/bin/env node const script = `#!/usr/bin/env sh
setInterval(() => {}, 1000); while :; do
sleep 1;
done
`; `;
fs.writeFileSync(scriptPath, script, 'utf8'); fs.writeFileSync(scriptPath, script, 'utf8');
if (process.platform !== 'win32') { if (process.platform !== 'win32') {

View File

@@ -16,8 +16,14 @@ async function withTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {
function makeFakeYtDlpScript(dir: string, payload: string): void { function makeFakeYtDlpScript(dir: string, payload: string): void {
const scriptPath = path.join(dir, 'yt-dlp'); const scriptPath = path.join(dir, 'yt-dlp');
const script = `#!/usr/bin/env node const script = process.platform === 'win32'
? `#!/usr/bin/env node
process.stdout.write(${JSON.stringify(payload)}); process.stdout.write(${JSON.stringify(payload)});
`
: `#!/usr/bin/env sh
cat <<'EOF' | base64 -d
${Buffer.from(payload).toString('base64')}
EOF
`; `;
fs.writeFileSync(scriptPath, script, 'utf8'); fs.writeFileSync(scriptPath, script, 'utf8');
if (process.platform !== 'win32') { if (process.platform !== 'win32') {

View File

@@ -93,6 +93,95 @@ process.exit(0);
return scriptPath; return scriptPath;
} }
function makeFakeYtDlpShellScript(dir: string): string {
const scriptPath = path.join(dir, 'yt-dlp');
const script = `#!/usr/bin/env sh
has_auto_subs=0
wants_auto_subs=0
wants_manual_subs=0
sub_lang=''
output_template=''
while [ "$#" -gt 0 ]; do
case "$1" in
--write-auto-subs)
wants_auto_subs=1
;;
--write-subs)
wants_manual_subs=1
;;
--sub-langs)
sub_lang="$2"
shift
;;
-o)
output_template="$2"
shift
;;
esac
shift
done
if [ "$YTDLP_EXPECT_AUTO_SUBS" = "1" ] && [ "$wants_auto_subs" != "1" ]; then
exit 2
fi
if [ "$YTDLP_EXPECT_MANUAL_SUBS" = "1" ] && [ "$wants_manual_subs" != "1" ]; then
exit 3
fi
if [ -n "$YTDLP_EXPECT_SUB_LANG" ] && [ "$sub_lang" != "$YTDLP_EXPECT_SUB_LANG" ]; then
exit 4
fi
prefix="$(printf '%s' "$output_template" | sed 's/%\.%(ext)s$//')"
if [ -z "$prefix" ]; then
exit 1
fi
mkdir -p "$(dirname \"$prefix\")"
if [ "$YTDLP_FAKE_MODE" = "multi" ]; then
OLD_IFS="$IFS"
IFS=","
for lang in $sub_lang; do
if [ -n "$lang" ]; then
printf 'WEBVTT\\n' > "${prefix}.${lang}.vtt"
fi
done
IFS="$OLD_IFS"
elif [ "$YTDLP_FAKE_MODE" = "rolling-auto" ]; then
cat <<'EOF' > "${prefix}.vtt"
WEBVTT
00:00:01.000 --> 00:00:02.000
今日は
00:00:02.000 --> 00:00:03.000
今日はいい天気ですね
00:00:03.000 --> 00:00:04.000
今日はいい天気ですね本当に
EOF
elif [ "$YTDLP_FAKE_MODE" = "multi-primary-only-fail" ]; then
primary_lang="${sub_lang%%,*}"
if [ -n "$primary_lang" ]; then
printf 'WEBVTT\\n' > "${prefix}.${primary_lang}.vtt"
fi
printf "ERROR: Unable to download video subtitles for 'en': HTTP Error 429: Too Many Requests\\n" 1>&2
exit 1
elif [ "$YTDLP_FAKE_MODE" = "both" ]; then
printf 'WEBVTT\\n' > "${prefix}.vtt"
printf 'webp' > "${prefix}.orig.webp"
elif [ "$YTDLP_FAKE_MODE" = "webp-only" ]; then
printf 'webp' > "${prefix}.orig.webp"
else
printf 'WEBVTT\\n' > "${prefix}.vtt"
fi
`;
fs.writeFileSync(scriptPath, script, 'utf8');
fs.chmodSync(scriptPath, 0o755);
return scriptPath;
}
async function withFakeYtDlp<T>( async function withFakeYtDlp<T>(
mode: 'both' | 'webp-only' | 'multi' | 'multi-primary-only-fail' | 'rolling-auto', mode: 'both' | 'webp-only' | 'multi' | 'multi-primary-only-fail' | 'rolling-auto',
fn: (dir: string, binDir: string) => Promise<T>, fn: (dir: string, binDir: string) => Promise<T>,
@@ -100,7 +189,11 @@ async function withFakeYtDlp<T>(
return await withTempDir(async (root) => { return await withTempDir(async (root) => {
const binDir = path.join(root, 'bin'); const binDir = path.join(root, 'bin');
fs.mkdirSync(binDir, { recursive: true }); fs.mkdirSync(binDir, { recursive: true });
if (process.platform === 'win32') {
makeFakeYtDlpScript(binDir); makeFakeYtDlpScript(binDir);
} else {
makeFakeYtDlpShellScript(binDir);
}
const originalPath = process.env.PATH ?? ''; const originalPath = process.env.PATH ?? '';
process.env.PATH = `${binDir}${path.delimiter}${originalPath}`; process.env.PATH = `${binDir}${path.delimiter}${originalPath}`;
@@ -129,6 +222,11 @@ async function withFakeYtDlpCommand<T>(
process.env.YTDLP_FAKE_MODE = mode; process.env.YTDLP_FAKE_MODE = mode;
process.env.SUBMINER_YTDLP_BIN = process.env.SUBMINER_YTDLP_BIN =
process.platform === 'win32' ? path.join(binDir, 'yt-dlp.cmd') : path.join(binDir, 'yt-dlp'); process.platform === 'win32' ? path.join(binDir, 'yt-dlp.cmd') : path.join(binDir, 'yt-dlp');
if (process.platform === 'win32') {
makeFakeYtDlpScript(binDir);
} else {
makeFakeYtDlpShellScript(binDir);
}
try { try {
return await fn(root, binDir); return await fn(root, binDir);
} finally { } finally {

View File

@@ -17,10 +17,17 @@ async function withTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {
function makeFakeYtDlpScript(dir: string, payload: unknown, rawScript = false): void { function makeFakeYtDlpScript(dir: string, payload: unknown, rawScript = false): void {
const scriptPath = path.join(dir, 'yt-dlp'); const scriptPath = path.join(dir, 'yt-dlp');
const stdoutBody = typeof payload === 'string' ? payload : JSON.stringify(payload); const stdoutBody = typeof payload === 'string' ? payload : JSON.stringify(payload);
const script = rawScript const script =
process.platform === 'win32'
? rawScript
? stdoutBody ? stdoutBody
: `#!/usr/bin/env node : `#!/usr/bin/env node
process.stdout.write(${JSON.stringify(stdoutBody)}); process.stdout.write(${JSON.stringify(stdoutBody)});
`
: `#!/usr/bin/env sh
cat <<'EOF' | base64 -d
${Buffer.from(rawScript ? stdoutBody : `${JSON.stringify(stdoutBody)}`).toString('base64')}
EOF
`; `;
fs.writeFileSync(scriptPath, script, 'utf8'); fs.writeFileSync(scriptPath, script, 'utf8');
if (process.platform !== 'win32') { if (process.platform !== 'win32') {