import fs from "node:fs"; import path from "node:path"; import type { HomepageSummary, HomepageSummarySite, } from "yt-dlp-transcript-common/lib/homepageSummary"; import { wordmarkLeadFor } from "yt-dlp-transcript-common/lib/brand"; // The build-time cross-site summary, or null when this build shipped without // corpus data (`build:nodata`, or a source-only checkout that has never run // compose โ€” see next.config.ts). // // NULL, NOT AN EMPTY SUMMARY. The previous loader synthesized a zero-filled // summary so the page always had something to render, which turned "we have no // data" into "0 transcripts ยท 0 sites" โ€” a claim that the product does nothing, // printed in the same typeface as the real numbers. Callers must branch: render // the live numbers only when this returns non-null, and say plainly why they're // absent otherwise. // // Read with `readFileSync` at module scope of a server component, mirroring // export/app/changelog/page.tsx. `output: "export"` means this runs at build, // never at request time. export function loadSummary(): HomepageSummary | null { try { const file = summaryFile( process.env, path.join(/* turbopackIgnore: true */ process.cwd(), "public", "homepage-summary.json"), ); const parsed = JSON.parse( fs.readFileSync(/* turbopackIgnore: true */ file, "utf8"), ) as HomepageSummary; // A file that exists but carries no sites/totals is as uninformative as no // file at all; treat it the same rather than rendering an empty dashboard. if (!parsed || typeof parsed.totals?.transcripts !== "number") return null; return { ...parsed, sites: (parsed.sites ?? []).map(withCheckedLead) }; } catch { return null; } } // The file loadSummary reads: `public/homepage-summary.json`, or the file // E2E_HOMEPAGE_SUMMARY_FILE names โ€” but ONLY outside a production build. The e2e's // `next dev` points it at a synthetic summary (e2e/fixture-summary.ts, written // by playwright.config.ts); // `next build` runs with NODE_ENV=production and ignores it, so a variable left // in a build shell can never ship a fixture as the homepage's numbers. export function summaryFile( env: Readonly>, publicFile: string, ): string { const override = env.NODE_ENV !== "production" ? env.E2E_HOMEPAGE_SUMMARY_FILE : undefined; return override || publicFile; } // A site's `wordmarkLead` (release 14) is used only when it is what compose // would have written: a proper prefix of its title (lib/brand.ts // wordmarkLeadFor). A summary from before release 14 has none, and one edited // by hand may hold anything; either way the card then shows the plain title. export function withCheckedLead(site: HomepageSummarySite): HomepageSummarySite { const { wordmarkLead, ...rest } = site; const lead = wordmarkLeadFor(site.siteTitle, wordmarkLead); return lead ? { ...rest, wordmarkLead: lead } : rest; }