"use client"; import type { DownloadOutcomeRecord } from "yt-dlp-transcript-common/lib/downloadOutcome"; export function DownloadOutcomeBadge({ outcome, }: { outcome: DownloadOutcomeRecord; }) { if (outcome.status === "ok") return null; const tone = outcome.status === "failed" ? "border-destructive/30 bg-destructive-soft text-destructive" : "border-warning/30 bg-warning-soft text-warning"; const label = ((): string => { switch (outcome.status) { case "ok-with-cookies": return "Retried with cookies"; case "ok-auto-transcribed": return "Auto-transcribed (no subs available)"; case "failed": { const lastAttempt = outcome.attempts[outcome.attempts.length - 1]; const cls = lastAttempt?.availabilityClass; return cls ? `Download failed: ${cls}` : "Download failed"; } case "failed-corrupt-source": return "Corrupt source — download couldn't finish"; case "corrupt-full-source": return "Corrupt full source — download completed but audio is malformed (file kept)"; case "failed-short-audio": return "Truncated download — audio far shorter than the video (file kept)"; case "skipped-filtered": { const f = outcome.filter; const why = f?.reason ? `: ${f.reason}` : ""; // The outcome records what happened, not a verdict — whether this video // is SETTLED is derived from the channel's metadata scan and its current // patterns, and the Diagnostics bucket is where that answer lives. return f?.name === "titleFilter" ? `Filtered out by the download filter${why}` : `Skipped by filter${why}`; } // NOT a download, and the badge has to say so plainly: this video's media // was never fetched and never will be while the filter stands. What is // here is its live chat, which is why the video is in the corpus at all. case "chat-only": return "Chat only (filtered livestream) — live chat kept, no media and no transcript"; default: return outcome.status; } })(); const lastErr = outcome.status === "failed" ? outcome.attempts[outcome.attempts.length - 1]?.error : undefined; return (
{label} {outcome.attempts.length} attempt {outcome.attempts.length === 1 ? "" : "s"} ·{" "} {new Date(outcome.finishedAt).toLocaleString()}
{lastErr && (
error tail
            {lastErr}
          
)}
); }