import path from "node:path"; import { createReadStream, type ReadStream } from "node:fs"; import { lstat, stat } from "node:fs/promises"; import { NextResponse } from "next/server"; import { getPaths } from "yt-dlp-transcript-common/lib/paths"; import { makeSafeController } from "yt-dlp-transcript-common/lib/safeStreamController"; import { readChannelConfig } from "yt-dlp-transcript-common/controller/channels"; import { channelMediaStall, channelTextStall, } from "yt-dlp-transcript-common/lib/channelMedia"; import { isTierable } from "yt-dlp-transcript-common/lib/mediaTier"; import { NOT_ANSWERING, isDriveNotAnswering, onDrive, } from "yt-dlp-transcript-common/lib/storageHealth"; export const dynamic = "force-dynamic"; const SAFE_SEGMENT = /^[A-Za-z0-9._-]+$/; const MIME_BY_EXT: Record = { mp3: "audio/mpeg", m4a: "audio/mp4", aac: "audio/aac", ogg: "audio/ogg", opus: "audio/ogg", wav: "audio/wav", flac: "audio/flac", mp4: "video/mp4", webm: "video/webm", mkv: "video/x-matroska", mov: "video/quicktime", vtt: "text/vtt; charset=utf-8", json: "application/json; charset=utf-8", }; function contentTypeFor(name: string): string { const dot = name.lastIndexOf("."); const ext = dot >= 0 ? name.slice(dot + 1).toLowerCase() : ""; return MIME_BY_EXT[ext] ?? "application/octet-stream"; } // Wrap a Node ReadStream as a WHATWG ReadableStream that survives the browser // aborting the response mid-flight. The browser does this constantly while // scrubbing an