diff --git a/packages/cli/src/commands/init.test.ts b/packages/cli/src/commands/init.test.ts index ded2b14ca5..259d2837be 100644 --- a/packages/cli/src/commands/init.test.ts +++ b/packages/cli/src/commands/init.test.ts @@ -1,6 +1,7 @@ -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import { spawnSync } from "node:child_process"; import { + chmodSync, copyFileSync, existsSync, mkdirSync, @@ -17,6 +18,7 @@ import { injectTailwindBrowserScript, nameTooLongMessage, resolveVideoDurationSeconds, + transcodeToMp4, } from "./init.js"; const cliEntry = resolve(fileURLToPath(import.meta.url), "..", "..", "cli.ts"); @@ -698,3 +700,30 @@ describe("applyResolutionPreset", () => { } }); }); + +describe("transcodeToMp4", () => { + it.skipIf(process.platform === "win32")( + "finishes when ffmpeg logs far more than a pipe buffer holds", + async () => { + const dir = mkdtempSync(join(tmpdir(), "hf-init-ffmpeg-log-")); + const ffmpeg = join(dir, "ffmpeg"); + const output = join(dir, "out.mp4"); + // Blocking writes, like ffmpeg's own log: 1 MB stalls on a pipe nobody reads. + const script = `const fs = require("node:fs"); +const line = Buffer.alloc(1024, "x"); +for (let i = 0; i < 1024; i++) fs.writeSync(2, line); +fs.writeFileSync(process.argv.at(-1), "");`; + writeFileSync(ffmpeg, `#!${process.execPath}\n${script}\n`); + chmodSync(ffmpeg, 0o755); + vi.stubEnv("HYPERFRAMES_FFMPEG_PATH", ffmpeg); + try { + await expect(transcodeToMp4(join(dir, "in.mov"), output)).resolves.toBe(true); + expect(existsSync(output)).toBe(true); + } finally { + vi.unstubAllEnvs(); + rmSync(dir, { recursive: true, force: true }); + } + }, + 5_000, + ); +}); diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 80f082d4cf..b3bf347f1b 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -211,7 +211,7 @@ export function transcodeToMp4(inputPath: string, outputPath: string): Promise resolvePromise(code === 0)); diff --git a/packages/cli/src/commands/render.ts b/packages/cli/src/commands/render.ts index 36d508644d..fba7f97037 100644 --- a/packages/cli/src/commands/render.ts +++ b/packages/cli/src/commands/render.ts @@ -847,7 +847,7 @@ async function renderDocker( const stderrTail = createStderrTail(); // stderr is piped so the failure can name its cause; it is still echoed live. const child = spawn("docker", dockerArgs, { - stdio: options.quiet ? ["pipe", "pipe", "pipe"] : ["inherit", "inherit", "pipe"], + stdio: options.quiet ? ["pipe", "ignore", "pipe"] : ["inherit", "inherit", "pipe"], }); child.stderr?.on("data", (chunk: Buffer) => { process.stderr.write(chunk);