import path from "node:path"; import { readFile } from "node:fs/promises"; import { writeJsonAtomic } from "../lib/jsonFile-server"; import type { Paths } from "../lib/paths"; // Leaf module for the maybe-missing record: the set of videos we have on disk // that no longer appear in the channel's fresh listing (deleted, made private, // or unlisted). Deliberately dependency-free apart from the Paths type so BOTH // producers can import it — the quick availability check (controller/) and the // sync full sweep (ytdlp/runYtdlp.ts). quickAvailabilityCheck imports runYtdlp, // so runYtdlp cannot import back from it; this module breaks that cycle. export const MAYBE_MISSING_FILENAME = "maybe-missing.json"; export type MaybeMissingRecord = { checkedAt: string; freshPlaylistCount: number; ids: string[]; }; function maybeMissingPath(paths: Paths, slug: string): string { return path.join(paths.channelsDir, slug, MAYBE_MISSING_FILENAME); } export async function loadMaybeMissing( paths: Paths, slug: string, ): Promise { try { const raw = await readFile(maybeMissingPath(paths, slug), "utf8"); const parsed = JSON.parse(raw) as Partial; if ( typeof parsed?.checkedAt === "string" && Array.isArray(parsed.ids) && typeof parsed.freshPlaylistCount === "number" ) { return { checkedAt: parsed.checkedAt, freshPlaylistCount: parsed.freshPlaylistCount, ids: parsed.ids.filter((id): id is string => typeof id === "string"), }; } return null; } catch { return null; } } export async function writeMaybeMissing( paths: Paths, slug: string, record: MaybeMissingRecord, ): Promise { // No mkdir: the channel dir exists. Chained with the roster/scan writes of // every other actor in this process (lib/jsonFile-server.ts). await writeJsonAtomic(maybeMissingPath(paths, slug), record); } // Diff a fresh listing's canonical ids against the videos we already have on // disk. Anything known but absent from the listing is "maybe missing". Shared // by the quick availability check and the sync full sweep so both flag the same // set by the same rule. export function diffMaybeMissing( knownIds: ReadonlyArray, freshIds: ReadonlySet, ): string[] { return knownIds.filter((id) => !freshIds.has(id)).sort(); }