// missingEvidenceWindows over a temp site: which cited spans are on disk, which // are windows to fetch, and which no window fetch can fill — through the real // report checker and the real tier lookup (ffprobe over a few frames of lavfi). // // Run with: pnpm --filter yt-dlp-transcript-common exec tsx --test publish/missingEvidenceWindows.test.ts import { after, test } from "node:test"; import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; const ROOT = mkdtempSync(path.join(tmpdir(), "missing-evidence-")); Object.assign(process.env, { TRANSCRIPTS_DIR: path.join(ROOT, "transcripts"), SAVED_VIDEOS_DIR: path.join(ROOT, "saved-videos"), SITES_DIR: path.join(ROOT, "transcripts", "sites"), SETTINGS_FILE: path.join(ROOT, "settings.json"), EXPORT_PUBLIC_DIR: path.join(ROOT, "public"), EXPORT_INDEX_DIR: path.join(ROOT, ".export-index"), EXPORT_BUILDS_DIR: path.join(ROOT, ".export-builds"), ARCHILYZER_CONFIG_DIR: path.join(ROOT, "config"), }); after(() => rmSync(ROOT, { recursive: true, force: true })); const { getPaths } = await import("../lib/paths"); const { missingEvidenceWindows } = await import("./reportMedia"); const paths = getPaths(); const SITE = "demo-site"; const CH = "demo-channel"; const OFF = "off-site"; const writeJson = (file: string, value: unknown) => { mkdirSync(path.dirname(file), { recursive: true }); writeFileSync(file, JSON.stringify(value, null, 2)); }; const videoDir = (slug: string, id: string) => path.join(paths.channelsDir, slug, "data", id); for (const [slug, extra] of [ [CH, {}], [OFF, {}], ] as const) { writeJson(path.join(paths.channelsDir, slug, "config.json"), { handling: "transcribe", name: slug, url: "https://www.youtube.com/@demo", ...extra, }); } // A fetched window holding 0–6 s of abc123. mkdirSync(path.join(videoDir(CH, "abc123"), "clips"), { recursive: true }); execFileSync("ffmpeg", [ "-nostdin", "-v", "error", "-y", "-f", "lavfi", "-i", "testsrc=size=160x90:rate=10:duration=6", "-f", "lavfi", "-i", "sine=frequency=440:duration=6", "-c:v", "libx264", "-preset", "ultrafast", "-pix_fmt", "yuv420p", "-c:a", "aac", "-shortest", path.join(videoDir(CH, "abc123"), "clips", "0.00-6.00.mp4"), ]); // A video the source says is gone. writeJson(path.join(videoDir(CH, "gone1"), "availability.json"), { checkedAt: "2026-10-01T00:00:00.000Z", availability: "deleted", }); writeJson(path.join(paths.sitesDir, SITE, "site.json"), { title: "Demo", channels: [{ slug: CH }], search: false, reports: ["r1", "r2"], }); const report = (id: string, citations: Record) => ({ format: "archilyzer-report", version: 1, id, kind: "sweep", title: `Report ${id}`, citations, sections: [ { id: "s1", title: "One", body: Object.keys(citations).map((c) => `[${c}](cite:${c})`).join(" ") }, ], }); writeJson( path.join(paths.sitesDir, SITE, "reports", "r1", "report.json"), report("r1", { c01: { kind: "video", channel: CH, id: "abc123", start: 1, end: 2, quote: "on disk" }, c02: { kind: "video", channel: CH, id: "missing1", start: 10.004, end: 12.001, pad: { before: 1, after: 1 }, quote: "the one to fetch" }, c03: { kind: "video", channel: CH, id: "gone1", start: 5, end: 6, quote: "removed" }, c04: { kind: "video", channel: OFF, id: "elsewhere", start: 5, end: 6, quote: "not this site's" }, }), ); writeJson( path.join(paths.sitesDir, SITE, "reports", "r2", "report.json"), report("r2", { d01: { kind: "video", channel: CH, id: "missing1", start: 10.004, end: 12.001, pad: { after: 3 }, quote: "again" }, }), ); test("on disk, to fetch, and what no window can fill", async () => { const r = await missingEvidenceWindows(paths, SITE); assert.equal(r.siteId, SITE); assert.equal(r.onDisk, 1); assert.deepEqual(r.problems, []); // One window for the moment two reports cite, with the wider pad on each // side (from the moment's rounded start and end), and the two decimals a // window is named by. assert.deepEqual(r.missing, [ { slug: CH, id: "missing1", from: 9, to: 15, clipId: "r1#c02", citations: ["r1#c02", "r2#d01"], reason: "the one to fetch", }, ]); const why = Object.fromEntries(r.unfetchable.map((u) => [u.id, u.why])); assert.deepEqual(why, { gone1: "gone", elsewhere: "not-in-site", }); assert.match(r.unfetchable.find((u) => u.id === "gone1")!.message, /deleted/); }); test("a site that does not exist is an error", async () => { await assert.rejects(missingEvidenceWindows(paths, "no-such-site"), /no site "no-such-site"/); });