// A second on a rendered cut -> the entry, title, quote and source second. // // Run with: pnpm test:scripts import assert from "node:assert/strict"; import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import test from "node:test"; import { momentFileInfo, resolveMoment, resolveMomentOnFile } from "./moments.mjs"; const manifest = { provenance: { siteOrigin: "https://arch.test", channelSlug: "chan" }, timeline: [ { type: "teaser", id: "tz", lines: ["X"] }, { type: "clip", id: "c1", video: "v1", start: 100, end: 110, cutStart: 102, cutEnd: 108, quote: "the words", onscreen: { title: "Own title" } }, { type: "clip", id: "c2", video: "v2", channel: "other", start: 50, end: 60 }, ], }; const schedule = { transition: 0.5, total: 20.5, segments: [ { id: "tz", start: 0, end: 4.5, title: "Teaser" }, { id: "c1", start: 4, end: 10.5 }, { id: "c2", start: 10, end: 20.5, title: "Schedule title" }, ], }; test("momentFileInfo reads the take and the variant from the path", () => { assert.deepEqual(momentFileInfo("takes/deck/preview.mp4"), { take: "deck", variant: null }); assert.deepEqual(momentFileInfo("takes/deck/out/full/x.mp4"), { take: "deck", variant: "full" }); assert.deepEqual(momentFileInfo("out/sourced/slug.mp4"), { take: null, variant: "sourced" }); assert.deepEqual(momentFileInfo("video.mp4"), { take: null, variant: null }); }); test("resolveMoment: the entry on screen, the incoming one past half a crossfade", () => { assert.equal(resolveMoment({ schedule, manifest, t: 1 }).entry, "tz"); assert.equal(resolveMoment({ schedule, manifest, t: 4.1 }).entry, "tz", "still the outgoing one"); const c1 = resolveMoment({ schedule, manifest, t: 6, duration: 20.5 }); assert.deepEqual(c1, { entry: "c1", title: "Own title", quote: "the words", sourceT: 104, channel: "chan", video: "v1", url: "https://arch.test/?v=chan%2Fv1&t=104", }); const c2 = resolveMoment({ schedule, manifest, t: 12 }); assert.equal(c2.title, "Schedule title"); assert.equal(c2.channel, "other"); assert.equal(c2.sourceT, 52); }); test("approx: a file of another length, an estimated schedule, a held frame", () => { assert.equal(resolveMoment({ schedule, manifest, t: 6, duration: 30 }).approx, true); assert.equal(resolveMoment({ schedule: { ...schedule, estimated: true }, manifest, t: 6 }).approx, true); // c1's cut is 6 s; 7.5 s in is a held frame const held = resolveMoment({ schedule, manifest, t: 4 + 7.5 - 0.01 + 0, duration: 20.5 }); assert.equal(held.entry, "c2"); const c1held = resolveMoment({ schedule: { ...schedule, segments: [schedule.segments[0], { id: "c1", start: 4 }] }, manifest, t: 12, duration: 20.5 }); assert.equal(c1held.sourceT, 108); assert.equal(c1held.approx, true); }); test("resolveMomentOnFile finds a take's schedule, preferring the default variant", async () => { const dir = await mkdtemp(path.join(tmpdir(), "umtool-moments-")); try { await writeFile(path.join(dir, "video.manifest.json"), JSON.stringify(manifest)); await mkdir(path.join(dir, "takes", "t1", "out", "full"), { recursive: true }); await mkdir(path.join(dir, "takes", "t1", "out", "sourced"), { recursive: true }); await writeFile(path.join(dir, "takes", "t1", "out", "sourced", "schedule.json"), JSON.stringify(schedule)); await writeFile(path.join(dir, "takes", "t1", "out", "full", "schedule.json"), JSON.stringify({ ...schedule, segments: [{ id: "c2", start: 0 }] })); const r = await resolveMomentOnFile(dir, "takes/t1/preview.mp4", 6, 20.5); assert.equal(r.entry, "c1"); assert.equal(r.schedule, "takes/t1/out/sourced/schedule.json"); assert.deepEqual(await resolveMomentOnFile(dir, "takes/none/preview.mp4", 6), { entry: null, schedule: null }); } finally { await rm(dir, { recursive: true }); } });