Files
2026-05-26 22:46:00 +02:00

56 lines
1.7 KiB
TypeScript

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,
});
}