"use server"; import { revalidatePath } from "next/cache"; import { getWorkerPool } from "yt-dlp-transcript-common/jobs/workerPool"; import { getPaths } from "yt-dlp-transcript-common/lib/paths"; import { saveSettings } from "../settings/saveSettings"; import { sanitizeWorkers, validateWorkers, } from "yt-dlp-transcript-common/lib/workers"; import { writeWorkerDefaults } from "yt-dlp-transcript-common/jobs/workerDefaults"; // Worker controls for the Workers page, of three kinds. // // Most are transient operator overrides on the LIVE POOL — they are NOT written // to settings.json (a restart returns workers to their configured enabled // state). // // setDefaultWorkersAction snapshots the currently enabled workers to a small // persisted file (workerDefaults.ts) that the pool re-applies on the next // launch — "Set as default" on this page. // // saveWorkersAction is the PERSISTED LIST itself, which used to be a fieldset // in the settings form. It lives here now, beside the workers it describes. export type WorkerActionResult = { ok: boolean; error?: string }; export type SaveWorkersResult = { ok: true } | { ok: false; error: string }; // THE ONE WRITER OF settings.workers. Reads the current file and replaces this // block only — every other block is preserved verbatim, the contract // cadence-ui.spec.ts holds every settings writer to. Then the live pool: a // saved Enabled change is an explicit intent and takes effect now // (applyEnabled), exactly as the whole-object settings form did before this // moved here. export async function saveWorkersAction( _prev: SaveWorkersResult | undefined, formData: FormData, ): Promise { // Workers are submitted as a JSON array by the WorkersField client component. // Sanitize + validate here for a friendly error; writeSettings re-validates on save. let workersInput: unknown; try { workersInput = JSON.parse(String(formData.get("workersJson") ?? "[]")); } catch { return { ok: false, error: "Workers payload is malformed" }; } const workers = sanitizeWorkers(workersInput); const workersErr = validateWorkers(workers); if (workersErr) return { ok: false, error: workersErr }; try { await saveSettings({ workers }); } catch (e) { return { ok: false, error: (e as Error).message }; } getWorkerPool().reconfigure(workers, { applyEnabled: true }); revalidatePath("/workers"); return { ok: true }; } function refresh() { revalidatePath("/workers"); } export async function enableWorkerAction(id: string): Promise { const ok = getWorkerPool().enableWorker(id); refresh(); return ok ? { ok: true } : { ok: false, error: `Unknown worker "${id}"` }; } export async function disableWorkerAction(id: string): Promise { const ok = getWorkerPool().disableWorker(id); refresh(); return ok ? { ok: true } : { ok: false, error: `Unknown worker "${id}"` }; } // Drain: stop giving the worker new transcriptions but let in-flight ones finish // (the "free up the GPU when done with the current video" path). export async function drainWorkerAction(id: string): Promise { const ok = getWorkerPool().drainWorker(id); refresh(); return ok ? { ok: true } : { ok: false, error: `Unknown worker "${id}"` }; } // THE TRANSCRIPTION PAUSE IS NOT HERE ANY MORE. It is one lane of one pair, // ../operations/actions.ts's pauseLaneAction / resumeLaneAction, which flips the // live pool and persists the flag in one place — see there for why the // revalidation list leaves "/" alone. // Gracefully stop the worker's in-flight transcription and keep the partial // result (parakeet finishes the current window, stitches, and writes a partial). export async function stopWorkerPartialAction( id: string, ): Promise { const ok = getWorkerPool().partialStopWorker(id); refresh(); return ok ? { ok: true } : { ok: false, error: `Worker "${id}" has nothing to stop` }; } // Persist the CURRENT enabled workers as the launch default. On the next server // start the pool enables exactly these workers and disables every other one // (including workers added later that aren't in this set). Overwrites any // previous default. export async function setDefaultWorkersAction(): Promise { const ids = getWorkerPool().enabledIds(); try { await writeWorkerDefaults(getPaths(), ids); } catch (e) { return { ok: false, error: (e as Error).message }; } refresh(); return { ok: true }; }