import { FaceError, faceQueue, isFaceBody, judgeFace, readFaceVerdicts, rejectedVideos, } from "@/lib/faces"; export const dynamic = "force-dynamic"; // The face judger's queue and its judgements. // // GET the 22 corners on record, deduped, accepted-cover ones first, plus // every judgement made so far and the videos a rebuild will now skip // POST one judgement // // The queue is READ FROM THE MANIFESTS on every request, like every other pile // in this tool. A cached copy would go stale the moment make-thumb.mjs ran, // which is the one command most likely to be running while this page is open. // // Nothing here writes thumb-manifest.json. lib/thumbs.ts sets out why at // length; the short version is that accept-thumb.mjs is its sole writer and a // second writer with different atomicity guarantees on the authority file is // not acceptable. The judgements go in a file this app owns outright, and // make-thumb.mjs reads it. const noStore = { "cache-control": "no-store" }; export async function GET() { const [queue, verdicts, rejected] = await Promise.all([ faceQueue(), readFaceVerdicts(), rejectedVideos(), ]); return Response.json({ queue, faces: verdicts.faces, rejected }, { headers: noStore }); } export async function POST(request: Request) { let body: unknown; try { body = await request.json(); } catch { return Response.json({ error: "bad json" }, { status: 400 }); } if (!isFaceBody(body)) { return Response.json({ error: "not a face judgement" }, { status: 400 }); } try { const judgement = await judgeFace(body); return Response.json( { ok: true, judgement, rejected: await rejectedVideos() }, { headers: noStore }, ); } catch (e) { if (e instanceof FaceError) return Response.json({ error: e.message }, { status: e.status }); return Response.json({ error: "could not write the judgement" }, { status: 500 }); } }