69 lines
2.8 KiB
TypeScript
69 lines
2.8 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { assertLocalRequest } from "@/lib/api/localOnly";
|
|
import { enqueueJob, cancelAllQueued } from "@/lib/whisperjav/queue";
|
|
import { rawDb } from "@/lib/db/client";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
/** Enqueue WhisperJAV for many codes at once. Each code becomes a
|
|
* separate row in whisperjav_jobs; the single-worker loop processes
|
|
* them sequentially. Codes that already have a generated subtitle
|
|
* are skipped (alreadyExists), not failed. */
|
|
export async function POST(req: NextRequest) {
|
|
const blocked = assertLocalRequest(req);
|
|
if (blocked) return blocked;
|
|
|
|
const body = await req.json().catch(() => ({}));
|
|
const rawCodes = Array.isArray(body.codes) ? body.codes : [];
|
|
const codes = rawCodes
|
|
.filter((c: unknown): c is string => typeof c === "string" && c.trim().length > 0)
|
|
.map((c: string) => c.trim());
|
|
if (codes.length === 0) {
|
|
return NextResponse.json({ enqueued: 0, skipped: 0, errors: [] });
|
|
}
|
|
|
|
let enqueued = 0;
|
|
let skipped = 0;
|
|
const errors: Array<{ code: string; error: string }> = [];
|
|
|
|
for (const code of codes) {
|
|
try {
|
|
// Always part 0 for batch — multi-part videos are uncommon and
|
|
// the user can hit individual codes via the player picker for
|
|
// those edge cases.
|
|
const result = await enqueueJob({ code, partIdx: 0, overwrite: false });
|
|
if ("alreadyExists" in result) skipped++;
|
|
else enqueued++;
|
|
} catch (e) {
|
|
errors.push({ code, error: (e as Error).message });
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({ enqueued, skipped, errors });
|
|
}
|
|
|
|
/** Cancel every queued (not-yet-running) job. Useful when the user
|
|
* wants to stop a batch mid-flight. The currently-running job is
|
|
* left alone — kill it via the per-job cancel endpoint. */
|
|
export async function DELETE(req: NextRequest) {
|
|
const blocked = assertLocalRequest(req);
|
|
if (blocked) return blocked;
|
|
const cancelled = cancelAllQueued();
|
|
return NextResponse.json({ cancelled });
|
|
}
|
|
|
|
/** Lightweight queue-state probe used by the batch UI: how many jobs
|
|
* are queued/running right now, plus the active row's id. */
|
|
export async function GET(req: NextRequest) {
|
|
const blocked = assertLocalRequest(req);
|
|
if (blocked) return blocked;
|
|
const queued = (rawDb
|
|
.prepare(`SELECT COUNT(*) AS n FROM whisperjav_jobs WHERE status = 'queued'`)
|
|
.get() as { n: number }).n;
|
|
const running = rawDb
|
|
.prepare(`SELECT id, code, started_at, stage, stage_index, stage_total FROM whisperjav_jobs WHERE status = 'running' ORDER BY started_at DESC LIMIT 1`)
|
|
.get() as { id: string; code: string; started_at: number | null; stage: string | null; stage_index: number | null; stage_total: number | null } | undefined;
|
|
return NextResponse.json({ queued, running: running ?? null });
|
|
}
|