"use client"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { X, ExternalLink, Loader2, AlertTriangle, Cpu, PlayCircle } from "lucide-react"; function formatJobElapsed(sec: number): string { const s = Math.max(0, Math.floor(sec)); const m = Math.floor(s / 60); const r = s % 60; return `${String(m).padStart(2, "0")}:${String(r).padStart(2, "0")}`; } import { useSettings } from "@/components/settings/SettingsProvider"; import { VariantPicker } from "./VariantPicker"; import { SubtitlePicker, type SubtitleSources, type EmbeddedEntry, type SidecarEntry, type LangIso, } from "./SubtitlePicker"; import { dispatchVideoStatusRefresh } from "./videoStatusEvents"; import { cn } from "@/lib/utils"; /** One alternate encode of a single part. partIdx is the absolute index * into the on-disk findVideosForCode list — used as the stream URL's * `?part=` value. */ interface VariantOut { partIdx: number; abs: string; rel: string; filename: string; size: number; label: string; metadata?: VideoMetadata | null; } interface PartOut { partIndex: number; defaultIdx: number; variants: VariantOut[]; } interface VideoMetadata { sizeBytes: number; durationSec: number | null; videoCodec: string | null; videoBFrames: number | null; width: number | null; height: number | null; videoBitrate: number | null; playbackMode: string | null; probeError: string | null; } /** * Snapshot dropped/total decoded video frames from a live