// The clip bench's view of what is cached: out/clips-raw plus the corpus's // windows, listed by clipWindowDirs through the render's own sources.mjs -- // so a window the bench calls fetched is one the build cuts from. // // Run with: pnpm test:scripts import assert from "node:assert/strict"; import test from "node:test"; import path from "node:path"; import os from "node:os"; import { mkdir, mkdtemp, rm, symlink, writeFile } from "node:fs/promises"; import { rawCacheOf } from "./raw-cache.mjs"; import { clipWindowDirs } from "../projects/report.mjs"; import { resolveLocalSource } from "umtool-report-to-video/sources"; const SLUG = "demo-channel"; async function fixture() { const root = await mkdtemp(path.join(os.tmpdir(), "raw-cache-")); const projectDir = path.join(root, "project"); const channelsDir = path.join(root, "channels"); const rawDir = path.join(projectDir, "out", "clips-raw"); await mkdir(rawDir, { recursive: true }); const video = async (id) => { const dir = path.join(channelsDir, SLUG, "data", id); await mkdir(path.join(dir, "clips"), { recursive: true }); return dir; }; return { root, projectDir, channelsDir, rawDir, video }; } const touch = (p) => writeFile(p, Buffer.alloc(16, 1)); test("rawCacheOf with no corpus windows reads clips-raw alone", async () => { const f = await fixture(); try { await touch(path.join(f.rawDir, "abc123_0.00-30.00.mp4")); const c = await rawCacheOf(f.projectDir); assert.equal(c.containing("abc123", 5, 10).name, "abc123_0.00-30.00.mp4"); assert.equal(c.isFetched({ video: "abc123", start: 25, end: 31 }), false); } finally { await rm(f.root, { recursive: true, force: true }); } }); test("clipWindowDirs: corpus windows and a saved source, and the render resolves the same files", async () => { const f = await fixture(); try { const a = await f.video("abc123"); await touch(path.join(a, "clips", "100.00-160.00.mp4")); await touch(path.join(a, "clips", "100.00-160.00.json")); // A window on a drive that is not there is no window. await symlink(path.join(f.root, "gone.mp4"), path.join(a, "clips", "300.00-400.00.mp4")); // A second video with its whole source in the store; its span is the cue // doc's duration. const b = await f.video("def456"); const store = path.join(f.root, "store", SLUG, "def456"); await mkdir(store, { recursive: true }); await touch(path.join(store, "source-media.mp4")); await writeFile(path.join(b, "saved-video.json"), JSON.stringify({ dir: store, file: "source-media.mp4", bytes: 16 })); await writeFile(path.join(b, "transcript.cues.json"), JSON.stringify({ duration: 1800, cues: [] })); const m = { provenance: { channelSlug: SLUG }, timeline: [ { id: "c1", type: "clip", video: "abc123", start: 110, end: 120 }, { id: "c2", type: "clip", video: "abc123", start: 320, end: 330 }, { id: "c3", type: "clip", video: "def456", start: 1000, end: 1010 }, { id: "c4", type: "clip", video: "nope99", start: 1, end: 2 }, ], }; const extra = await clipWindowDirs(m, f.channelsDir); assert.deepEqual( extra.map((e) => [e.video, e.windows.map((w) => [w.kind, w.name, w.from, w.to])]), [ ["abc123", [["corpus-window", "100.00-160.00.mp4", 100, 160]]], ["def456", [["saved-video", "source-media.mp4", 0, 1800]]], ], ); const c = await rawCacheOf(f.projectDir, { extraWindows: extra }); assert.equal(c.isFetched(m.timeline[0]), true); assert.equal(c.isFetched(m.timeline[1]), false, "the dangling window is not fetched"); assert.equal(c.isFetched(m.timeline[2]), true); assert.equal(c.isFetched(m.timeline[3]), false); // The render, asked the same question, finds the same files. const probe = async () => ({ duration: 1800 }); for (const e of m.timeline.slice(0, 3)) { const hit = await resolveLocalSource( { video: e.video, slug: SLUG, from: e.start, to: e.end }, { channelsDir: f.channelsDir, probe }, ); const bench = c.containing(e.video, e.start, e.end); assert.equal(hit?.path ?? null, bench?.path ?? null, e.id); } } finally { await rm(f.root, { recursive: true, force: true }); } });