From f96d67b8d82f4aa00dfa70813bdda5ce5b39bd9d Mon Sep 17 00:00:00 2001 From: Giancarmine Salucci Date: Thu, 9 Jul 2026 06:47:05 +0200 Subject: [PATCH] D5: explicit VTT fallback branch when tryGetCaptions returns null for empty/unusable segments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tryGetCaptions now returns null when transcriptEntriesToSegments produces empty array (all entries whitespace/filtered out), not a CaptionResult with zero segments - downloadYouTube simplifies null check — null from tryGetCaptions always means 'no usable captions', triggers explicit VTT fallback to downloadAudio - Add JSDoc explaining VTT fallback contract --- src/lib/server/downloader.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/lib/server/downloader.ts b/src/lib/server/downloader.ts index 00eb893..9f0c7b3 100644 --- a/src/lib/server/downloader.ts +++ b/src/lib/server/downloader.ts @@ -48,11 +48,13 @@ export interface AudioResult { export type DownloadResult = CaptionResult | AudioResult; -/** Try to get auto-generated captions from YouTube. Returns null if unavailable. */ +/** Try to get auto-generated captions from YouTube. Returns null if unavailable + * (fetch error OR parsed segments are empty/unusable). */ async function tryGetCaptions(url: string, _outDir: string): Promise { try { const transcript = await fetchTranscript(url, { lang: 'en' }); const segments = transcriptEntriesToSegments(transcript); + if (segments.length === 0) return null; const title = await getYouTubeTitle(url); return { type: 'captions', segments, title }; } catch { @@ -100,15 +102,20 @@ async function downloadAudio(url: string, outDir: string): Promise<{ audioPath: return { audioPath: join(outDir, audioFile), title }; } -/** Download a YouTube URL: try captions first, fall back to audio. */ +/** Download a YouTube URL: try captions first, fall back to audio. + * + * VTT fallback: when tryGetCaptions returns null (parse failure or + * empty/unusable segments) we fall through to downloadAudio instead + * of returning an empty CaptionResult. */ export async function downloadYouTube(url: string, jobId: string): Promise { await ensureTmpDir(); const outDir = join(TMP_DIR, jobId); await mkdir(outDir, { recursive: true }); const captions = await tryGetCaptions(url, outDir); - if (captions && captions.segments.length > 0) return captions; + if (captions) return captions; + /* VTT fallback: captions unavailable — download full audio for whisper transcription */ const { audioPath, title } = await downloadAudio(url, outDir); return { type: 'audio', audioPath, title }; }