#!/usr/bin/env node // Cut ONE clip out of the window already on disk. // // node bin/cut-from-cache.mjs --project --clip [--reencode|--no-reencode] // // A CLI so the Deliver panel's "cut the confirmed clips" can be ONE job with // one step per clip: lib/jobs.ts then owns the sequencing, the `k of n` the UI // reads off stepIndex, the timeout, and a Stop that kills the process group // rather than a promise nobody can interrupt. A loop inside a request handler // would have had to reinvent all four. // // Never fetches. A clip with no containing window exits 3 and says so, which // is a fact about the cache and not a failure of the cut. import process from "node:process"; import { resolveProject } from "../lib/projects/core.mjs"; import { cutClipFromCache } from "../lib/report/cut.mjs"; const argv = process.argv.slice(2); const val = (flag) => { const i = argv.indexOf(flag); return i < 0 ? null : argv[i + 1]; }; const projectArg = val("--project"); const clipId = val("--clip"); if (!projectArg || !clipId) { console.error("usage: cut-from-cache.mjs --project --clip [--reencode|--no-reencode]"); process.exit(2); } const r = await resolveProject(projectArg); if (!r.project) { console.error(`no project matches "${projectArg}"`); process.exit(2); } const reencode = argv.includes("--reencode") ? "always" : argv.includes("--no-reencode") ? "never" : "auto"; // TEST-ONLY PACING, and the only reason it exists: a cut of a cached window is // about a second of ffmpeg, which is too fast for a spec to press Stop in the // middle of -- and "Stop abandons the REST, and the next run resumes rather // than re-cutting" is the whole argument for one step per clip. The e2e // fixture's server sets this; nothing else ever should. const delay = Number(process.env.E2E_UMTOOL_CUT_DELAY_MS ?? 0); if (delay > 0) await new Promise((r) => setTimeout(r, delay)); const res = await cutClipFromCache(r.project, clipId, { reencode }); if (!res.ok) { console.error(`${clipId}: ${res.error}`); // 3 is "nothing on disk holds this clip", which the panel already lists // under its own heading with a fetch link. Every other failure is a 1. process.exit(res.reason === "not-fetched" ? 3 : 1); } console.log( `CUT-OK ${res.id} ${res.seconds?.toFixed(2)}s (wanted ${res.want.toFixed(2)}s) ` + `${res.mode} from ${res.window.name}`, );