Files
suaveplan/packages/media/video/video-thumbnails/tests/setup/fixtures.ts
2026-05-27 23:47:53 +01:00

89 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { spawn } from "node:child_process";
import { mkdir, mkdtemp, rm, stat } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import ffmpegInstaller from "@ffmpeg-installer/ffmpeg";
/** Path of the on-the-fly fixture video. Cached per Vitest worker. */
let fixturePath: string | undefined;
let fixtureDir: string | undefined;
/**
* Synthesise a 5-second 320×240 colour-gradient MP4 once per worker and return
* its absolute path. Subsequent calls return the cached path. Uses ffmpeg's
* `lavfi` virtual source so no checked-in binary is required.
*/
export async function getFixtureVideo(): Promise<string> {
if (fixturePath !== undefined) {
return fixturePath;
}
const dir = await mkdtemp(join(tmpdir(), "vt-fixture-"));
const out = join(dir, "fixture.mp4");
await new Promise<void>((resolve, reject) => {
const child = spawn(
ffmpegInstaller.path,
[
"-y",
"-f",
"lavfi",
"-i",
"testsrc=duration=5:size=320x240:rate=10",
"-pix_fmt",
"yuv420p",
"-c:v",
"libx264",
"-preset",
"ultrafast",
"-tune",
"zerolatency",
out,
],
{ stdio: "pipe" }
);
let stderr = "";
child.stderr.on("data", (chunk) => {
stderr += String(chunk);
});
child.once("error", reject);
child.once("exit", (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`ffmpeg fixture build failed: ${stderr}`));
}
});
});
const fileStat = await stat(out);
if (fileStat.size === 0) {
throw new Error("fixture video has zero bytes");
}
fixtureDir = dir;
fixturePath = out;
return out;
}
/** Create a unique tmp output directory for one test. */
export async function makeOutputDir(label: string): Promise<string> {
const dir = await mkdtemp(join(tmpdir(), `vt-${label}-`));
await mkdir(dir, { recursive: true });
return dir;
}
/** Best-effort cleanup; safe to ignore failures (Windows / locked files). */
export async function safeRm(path: string): Promise<void> {
try {
await rm(path, { recursive: true, force: true });
} catch {
// ignored
}
}
/** Clear the cached fixture (used by setup teardown). */
export async function clearFixtureCache(): Promise<void> {
if (fixtureDir !== undefined) {
await safeRm(fixtureDir);
}
fixturePath = undefined;
fixtureDir = undefined;
}