import { test } from "node:test"; import assert from "node:assert/strict"; import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs"; import os from "node:os"; import path from "node:path"; import type { ChannelConfig } from "../lib/channelConfig"; // Run with: // pnpm --filter yt-dlp-transcript-common exec tsx --test controller/remoteListing.test.ts // // The diff of a listing against the held ids, and one run with the listing // injected. Every id here is invented. const ROOT = mkdtempSync(path.join(os.tmpdir(), "remote-listing-")); process.env.TRANSCRIPTS_DIR = ROOT; process.env.SETTINGS_FILE = path.join(ROOT, "settings.json"); writeFileSync(process.env.SETTINGS_FILE, "{}\n"); const { diffRemoteListing, heldVideoIds, isRemoteListingPlatform, runRemoteListing } = await import( "./remoteListing" ); const { getPaths } = await import("../lib/paths"); test("only Odysee and BitChute are listed this way", () => { assert.equal(isRemoteListingPlatform("odysee"), true); assert.equal(isRemoteListingPlatform("bitchute"), true); assert.equal(isRemoteListingPlatform("youtube"), false); assert.equal(isRemoteListingPlatform(null), false); }); test("the diff keeps listing order, collapses duplicates, and counts entries with no id", () => { const d = diffRemoteListing( [ "https://www.bitchute.com/video/AbC123/", "https://www.bitchute.com/video/held01/", "https://www.bitchute.com/channel/somebody/", "https://www.bitchute.com/embed/AbC123/", "https://odysee.com/@demo:0/a-video:7", ], new Set(["held01", "gone99"]), ); assert.equal(d.listed, 5); assert.equal(d.unparsed, 1); assert.equal(d.held, 1); assert.deepEqual(d.notHeld, [ { id: "AbC123", url: "https://www.bitchute.com/video/AbC123/" }, { id: "7", url: "https://odysee.com/@demo:0/a-video:7" }, ]); assert.deepEqual(d.heldNotListed, ["gone99"]); }); test("held ids are data/ directories; an absent data/ holds nothing", async () => { assert.deepEqual([...(await heldVideoIds(path.join(ROOT, "nowhere")))], []); const dir = path.join(ROOT, "h", "data"); mkdirSync(path.join(dir, "v1"), { recursive: true }); mkdirSync(path.join(dir, ".hidden"), { recursive: true }); writeFileSync(path.join(dir, "stray.txt"), ""); assert.deepEqual([...(await heldVideoIds(dir))], ["v1"]); }); test("a run lists through the injected reader and answers the diff", async () => { const slug = "demo-bitchute"; mkdirSync(path.join(ROOT, "channels", slug, "data", "held01"), { recursive: true }); const config = { handling: "transcribe", platform: "bitchute", url: "https://www.bitchute.com/channel/demo/" } as ChannelConfig; writeFileSync(path.join(ROOT, "channels", slug, "config.json"), JSON.stringify(config)); const lines: string[] = []; let asked = 0; const r = await runRemoteListing({ paths: getPaths(), slug, channelConfig: config, platform: "bitchute", onLog: (l) => lines.push(l), signal: new AbortController().signal, deps: { list: async () => { asked++; return ["https://www.bitchute.com/video/held01/", "https://www.bitchute.com/video/new001/"]; }, now: () => new Date("2026-10-10T00:00:00Z"), }, }); assert.equal(asked, 1); assert.equal(r.listedAt, "2026-10-10T00:00:00.000Z"); assert.deepEqual(r.notHeld, [{ id: "new001", url: "https://www.bitchute.com/video/new001/" }]); assert.match(lines.join(""), /2 listed, 1 held, 1 not held, 0 held but not listed/); });