// fetch-via-editor.mjs's --max-height: checked before any request, sent with a // window and with --full, and a reported height comes back on `done`. // // The editor is a scripted HTTP server on a loopback port: no corpus, no // yt-dlp, nothing fetched. // // Run with: pnpm test:scripts import assert from "node:assert/strict"; import { execFile } from "node:child_process"; import { mkdtemp, rm, writeFile } from "node:fs/promises"; import http from "node:http"; import os from "node:os"; import path from "node:path"; import test from "node:test"; import { fileURLToPath } from "node:url"; const SCRIPT = path.join(path.dirname(fileURLToPath(import.meta.url)), "fetch-via-editor.mjs"); const MANIFEST = { provenance: { channelSlug: "demo-channel", manifestId: "demo" }, timeline: [{ id: "c01", type: "clip", video: "abc123", start: 10, end: 20, note: "why" }], }; /** An editor that answers every POST with `answer` and records the bodies. */ async function stubEditor(answer) { const posts = []; const server = http.createServer((req, res) => { let raw = ""; req.on("data", (c) => (raw += c)); req.on("end", () => { posts.push(JSON.parse(raw || "{}")); res.writeHead(answer.status, { "content-type": "application/json" }); res.end(JSON.stringify(answer.body)); }); }); await new Promise((r) => server.listen(0, "127.0.0.1", r)); const { port } = /** @type {import("node:net").AddressInfo} */ (server.address()); return { posts, url: `http://127.0.0.1:${port}`, close: () => new Promise((r) => server.close(r)) }; } /** Run the script; resolves with its exit code and NDJSON events. */ async function run(editorUrl, args) { const dir = await mkdtemp(path.join(os.tmpdir(), "fetch-via-editor-")); try { const manifest = path.join(dir, "video.manifest.json"); await writeFile(manifest, JSON.stringify(MANIFEST)); return await new Promise((resolve) => { execFile( process.execPath, [SCRIPT, manifest, "--fetch-only", "c01", "--progress", "ndjson", ...args], { env: { ...process.env, ARCHILYZER_EDITOR_URL: editorUrl, WORKER_TOKEN: "tok" } }, (err, stdout) => { const events = stdout .split("\n") .filter(Boolean) .map((l) => JSON.parse(l)); resolve({ code: err ? err.code : 0, events }); }, ); }); } finally { await rm(dir, { recursive: true, force: true }); } } const CACHED = (height) => ({ status: 200, body: { cached: true, file: "/corpus/clips/7.00-23.00.mp4", from: 7, to: 23, bytes: 1, height }, }); test("--max-height rides on a window request; a taller cached file is noted and its height carried", async () => { const ed = await stubEditor(CACHED(1080)); try { const { code, events } = await run(ed.url, ["--max-height", "480"]); assert.equal(code, 0); assert.equal(ed.posts.length, 1); assert.equal(ed.posts[0].maxHeight, 480); assert.equal(ed.posts[0].from, 7); const done = events.find((e) => e.ev === "done"); assert.equal(done.height, 1080); assert.ok( events.some((e) => e.ev === "note" && /is 1080p, taller than --max-height 480/.test(e.message)), JSON.stringify(events), ); } finally { await ed.close(); } }); test("--max-height rides on --full, which sends no span", async () => { const ed = await stubEditor(CACHED(720)); try { const { code, events } = await run(ed.url, ["--full", "--max-height", "720"]); assert.equal(code, 0); assert.equal(ed.posts[0].full, true); assert.equal(ed.posts[0].maxHeight, 720); assert.equal("from" in ed.posts[0], false); assert.ok(!events.some((e) => e.ev === "note" && /taller/.test(e.message))); } finally { await ed.close(); } }); test("no --max-height sends none; a bad one is refused before any request", async () => { const ed = await stubEditor(CACHED(720)); try { assert.equal((await run(ed.url, [])).code, 0); assert.equal("maxHeight" in ed.posts[0], false); for (const bad of ["4320", "720.5", "tall"]) { const { code, events } = await run(ed.url, ["--max-height", bad]); assert.equal(code, 1, bad); assert.ok(events.some((e) => e.ev === "note" && /must be a whole number of pixels from 144 to 2160/.test(e.message))); } assert.equal(ed.posts.length, 1); } finally { await ed.close(); } });