import "server-only"; export type JobStatus = | "queued" | "running" | "completed" | "warning" | "failed" | "cancelled"; export interface JobRow { id: string; code: string; videoAbs: string; jobDir: string; /** Final destination of the moved .srt, populated on success/warning. */ targetSubtitlePath: string | null; status: JobStatus; enqueuedAt: number; startedAt: number | null; endedAt: number | null; exitCode: number | null; error: string | null; /** Latest "Step X/Y: " parsed from stderr. */ stage: string | null; stageIndex: number | null; stageTotal: number | null; cueCount: number | null; /** JSON-stringified args array passed to whisperjav. */ cliArgs: string; logPath: string; statsPath: string | null; /** Source video duration (sec) at enqueue time — used for ETA. Null * when the video hasn't been probed yet. */ videoDurationSec: number | null; /** WhisperJAV --mode at enqueue time. Persisted so historical ETA * multipliers can be grouped per mode. */ mode: string | null; } /** Snapshot returned by the detail endpoint — JobRow plus a tail of log lines. */ export interface JobDetail extends JobRow { logTail: string[]; } export interface EnqueueRequest { code: string; partIdx: number; /** When true, allow overwriting an existing target subtitle file. */ overwrite?: boolean; }