import { AUDIO_EXTS, VIDEO_CONTAINER_EXTS, } from "yt-dlp-transcript-common/lib/mediaFiles"; export type VideoFile = { name: string; // NULL for a tiered file (a link into `channels//media/`, release 17) // whose media drive is unmounted or not answering: the file exists, its size // is not knowable now. Rendered "—", never 0. size: number | null; mtime: number; }; export const WHISPER_FILENAME = "transcript.json"; export const CANONICAL_VTT = "transcript.en.vtt"; // lib/videoStatus.ts TRANSCRIPT_PIN_FILENAME (this module is client-side). export const TRANSCRIPT_PIN_FILENAME = "transcript-pin.json"; export function isTranscriptVttName(name: string): boolean { return /^transcript\.[^.]+\.vtt$/.test(name); } // One list, shared with the detection predicates in lib/mediaFiles.ts — these // were duplicated here and drifting. isAudioFile deliberately stays on // AUDIO_EXTS alone: audio.mp4 is a wrong-format cleanup target, not something // this panel offers a transcribe button for (editor/e2e/video-page.spec.ts:426). const AUDIO_EXT_SET = new Set(AUDIO_EXTS); const VIDEO_EXT_SET = new Set(VIDEO_CONTAINER_EXTS); const TEXT_EXTS = new Set(["vtt", "json", "txt", "srt", "log"]); export function fileExt(name: string): string { const dot = name.lastIndexOf("."); return dot >= 0 ? name.slice(dot + 1).toLowerCase() : ""; } export function isAudioFile(name: string): boolean { return AUDIO_EXT_SET.has(fileExt(name)); } // Files we can transcode FROM: any media file ffmpeg can demux to audio. // Includes video containers so a kept source (e.g. audio.mp4 when // keepSourceVideo=true) can be re-extracted to audio. to // overwrite a truncated or corrupt prior extraction. export function isTranscodeSource(name: string): boolean { if (!name.startsWith("audio.")) return false; if (name.startsWith("audio.tmp-")) return false; const ext = fileExt(name); return AUDIO_EXT_SET.has(ext) || VIDEO_EXT_SET.has(ext); } export function audioExt(name: string): string { const dot = name.lastIndexOf("."); return dot >= 0 ? name.slice(dot + 1) : ""; } export function mediaKind(name: string): "audio" | "video" | "text" | null { const ext = fileExt(name); if (AUDIO_EXT_SET.has(ext)) return "audio"; if (VIDEO_EXT_SET.has(ext)) return "video"; if (TEXT_EXTS.has(ext)) return "text"; return null; } export function mediaUrl(slug: string, videoId: string, filename: string): string { return `/api/channels/${encodeURIComponent(slug)}/videos/${encodeURIComponent(videoId)}/files/${encodeURIComponent(filename)}`; }