import { NextRequest, NextResponse } from "next/server"; import { assertLocalRequest } from "@/lib/api/localOnly"; import { rawDb } from "@/lib/db/client"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; interface CandidateRow { id: number; code: string; title: string | null; thumb_path: string; } /** * Codes with a playable video but no discoverable subtitle. The user * picks from this list when running batch WhisperJAV generation. * * has_subtitle is the cheap signal — populated by the video index * scan (sidecar files / generated subs / library roots). */ export async function GET(req: NextRequest) { const blocked = assertLocalRequest(req); if (blocked) return blocked; const limit = Math.min(500, Math.max(1, Number(req.nextUrl.searchParams.get("limit") ?? "200"))); const offset = Math.max(0, Number(req.nextUrl.searchParams.get("offset") ?? "0")); const includeAlreadyHasSubs = req.nextUrl.searchParams.get("all") === "1"; const where = includeAlreadyHasSubs ? `i.has_video = 1 AND i.code IS NOT NULL AND i.deleted_at IS NULL AND i.parent_image_id IS NULL` : `i.has_video = 1 AND i.has_subtitle = 0 AND i.code IS NOT NULL AND i.deleted_at IS NULL AND i.parent_image_id IS NULL`; const rows = rawDb.prepare(` SELECT i.id, i.code, i.title, i.thumb_path FROM images i WHERE ${where} ORDER BY UPPER(i.code) ASC LIMIT ? OFFSET ? `).all(limit, offset) as CandidateRow[]; const totalRow = rawDb.prepare(` SELECT COUNT(*) AS n FROM images i WHERE ${where} `).get() as { n: number }; return NextResponse.json({ candidates: rows.map((r) => ({ id: r.id, code: r.code, title: r.title, thumbPath: r.thumb_path, })), total: totalRow.n, }); }