import type { HomepageRecentItem } from "yt-dlp-transcript-common/lib/homepageSummary"; import type { VideoState } from "yt-dlp-transcript-common/lib/availability"; // THE RAIL — the product in one object. // // Real recordings, most recently acquired first: the date, the channel, the // title, and where the recording stands on the platform it came from. Most read // KEPT. The ones re-checked and found gone read GONE, and that chip is the only // hot colour above the fold. // // HARD RULE: nothing here may be invented. No placeholder titles, no sample // quotes, no assumed states. Inventing content on the marketing site for an // archiving tool would undercut the entire product, so absent data renders an // empty state and absent state renders no chip at all — never a cheerful // default. That is why `status` is optional all the way down: a summary written // before the field existed must show nothing rather than guess. // Open the transcript on its destination site: the export apps open the modal // from the `v` slug param (see common/components/PlayerProvider). siteUrl carries // no trailing slash, so `${siteUrl}/?v=` targets the site root. function transcriptHref(item: HomepageRecentItem): string | null { if (!item.siteUrl) return null; return `${item.siteUrl}/?v=${encodeURIComponent(item.slug)}`; } // "20260701" -> "2026-07-01". The rail is a log, so it wants the sortable form, // not a friendly one. function isoDay(yyyymmdd: string): string { if (!/^\d{8}$/.test(yyyymmdd)) return yyyymmdd; return `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`; } // The chip is a claim about a recording, so each state gets its own words. // "available" deliberately reads KEPT rather than anything stronger: it means we // have a copy and nothing has told us the original is gone — not that the // original is confirmed to still be there. const STATE_CHIP: Record = { available: { label: "Kept", gone: false }, maybe_missing: { label: "Missing?", gone: false }, unlisted: { label: "Unlisted", gone: false }, private: { label: "Private", gone: true }, members_only: { label: "Members", gone: true }, deleted: { label: "Gone", gone: true }, }; function StateChip({ status }: { status?: VideoState }) { if (!status) return null; const chip = STATE_CHIP[status]; if (!chip) return null; return ( {chip.label} ); } export function RecentAdditions({ items, limit = 8, }: { items: HomepageRecentItem[]; limit?: number; }) { const rows = items.slice(0, limit); if (rows.length === 0) { return (

No acquisitions to show — this build shipped without corpus data.

); } return (
Recent acquisitions State at source
    {rows.map((item, i) => { const href = transcriptHref(item); // Two shapes, one row. Wide: a single log line — date, channel, // title, state. Narrow: the metadata and the state chip share the // top line and the title gets the full width beneath, because // squeezing four columns into 375px truncates the title to nothing // and orphans the chip on its own line. const inner = ( <>
    {item.channel}
    {item.title} ); const rowClass = "rail-row group flex flex-wrap items-center gap-x-4 gap-y-1.5 px-4 py-3 sm:flex-nowrap sm:py-2.5"; return (
  • {href ? ( {inner} ) : (
    {inner}
    )}
  • ); })}
); }