import { NextResponse } from "next/server"; import { getPaths } from "yt-dlp-transcript-common/lib/paths"; import { listChannelConfigs } from "yt-dlp-transcript-common/controller/channels"; import { isSocialChannel } from "yt-dlp-transcript-common/lib/channelConfig"; import { siteChannelIndex } from "yt-dlp-transcript-common/lib/site"; import { opsAuth } from "../_lib"; export const dynamic = "force-dynamic"; // GET /api/ops/channels // // Every channel, one line each: what a caller needs to pick a slug for the // other channel routes, and to see which sites carry it — a channel on no site // is private to this editor. Config reads only (no report, no media probe, no // directory walk); `get channel ` is the deep read of one. export async function GET(request: Request) { const denied = opsAuth(request); if (denied) return denied; const paths = getPaths(); const [rows, index] = await Promise.all([ listChannelConfigs(paths), Promise.resolve(siteChannelIndex(paths)), ]); const sitesOf = new Map(); for (const [siteId, slugs] of Object.entries(index)) { for (const slug of slugs) { sitesOf.set(slug, [...(sitesOf.get(slug) ?? []), siteId]); } } return NextResponse.json({ ok: true, channels: rows.map(({ slug, config }) => ({ slug, name: config.name ?? slug, kind: isSocialChannel(config) ? "social" : "video", platform: config.platform ?? null, handling: config.handling, url: config.url ?? null, sites: sitesOf.get(slug) ?? [], ...(config.excludeFromBuild ? { excludeFromBuild: true } : {}), ...(config.excludeFromCleanup ? { excludeFromCleanup: true } : {}), })), }); }