import type { Metadata } from "next"; import { getPaths } from "yt-dlp-transcript-common/lib/paths"; import { readChannelConfig } from "yt-dlp-transcript-common/controller/channels"; import { getSettings } from "yt-dlp-transcript-common/lib/settings"; import { postsVisibleTo } from "yt-dlp-transcript-common/lib/postsVisibility"; import { currentSite } from "../lib/site"; import { OfflineManager, type OfflineChannel } from "../components/OfflineManager"; import { isCitedSite } from "yt-dlp-transcript-common/lib/siteSchema"; import { NotOnCitedSite } from "../components/reports/parts"; export const metadata: Metadata = { title: "Offline", description: "Download channels for offline search.", }; // Static list of this site's channels (slug + display name), resolved at build // time. The client OfflineManager uses the slugs to fetch/cache each channel's // transcript shards through the service worker. export default async function OfflinePage() { const site = currentSite(); if (isCitedSite(site)) return ; const paths = getPaths(); const settings = getSettings(); // The members this build publishes: an X channel is left out of a public // site while X posts are private (lib/postsVisibility.ts, the rule the // index build and compose narrow the site's data by). const members = await Promise.all( site.channels.map(async ({ slug }) => ({ slug, config: await readChannelConfig(paths, slug).catch(() => null), })), ); const channels: OfflineChannel[] = members .filter(({ config }) => postsVisibleTo(site, config, settings)) .map(({ slug, config }) => ({ slug, name: config?.name ?? slug })); channels.sort((a, b) => a.name.localeCompare(b.name)); return (

Offline

Install this archive and download channels to search them without a connection. Downloads can be large — each channel is fetched on demand.

); }