done column: 'verify N' header button to backfill ✓ → ✓✓
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m5s
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m5s
new POST /api/execute/verify-unverified that picks every plan with status=done + verified=0 and runs handOffToJellyfin sequentially in the background. each handoff fires the existing plan_update sse so the done column promotes cards as jellyfin's verdict lands. exported handOffToJellyfin so the route can reuse the same flow as a fresh job. done column header shows a 'Verify N' action whenever there are unverified done plans, alongside the existing 'Clear'. one click and the user can backfill ✓✓ across every legacy done item without re-transcoding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,7 @@ import type { Job, MediaItem, MediaStream } from "../types";
|
||||
* match the plan, so the check always passed immediately. Jellyfin is the
|
||||
* independent observer that matters.
|
||||
*/
|
||||
async function handOffToJellyfin(itemId: number): Promise<void> {
|
||||
export async function handOffToJellyfin(itemId: number): Promise<void> {
|
||||
const db = getDb();
|
||||
const row = db.prepare("SELECT jellyfin_id FROM media_items WHERE id = ?").get(itemId) as
|
||||
| { jellyfin_id: string }
|
||||
@@ -354,6 +354,40 @@ app.post("/clear-completed", (c) => {
|
||||
return c.json({ ok: true, cleared: result.changes });
|
||||
});
|
||||
|
||||
// ─── Verify all unverified done plans ────────────────────────────────────────
|
||||
// Backfill: kicks off the post-job jellyfin handoff for every plan that's
|
||||
// status=done + verified=0. Sequential with a small inter-call delay to
|
||||
// avoid hammering jellyfin's metadata refresher (each one waits up to 15s
|
||||
// for DateLastRefreshed to advance). Returns immediately with the count;
|
||||
// each individual handoff emits a plan_update SSE so the UI promotes ✓ → ✓✓
|
||||
// (or flips back to Review on disagreement) as it lands.
|
||||
app.post("/verify-unverified", (c) => {
|
||||
const db = getDb();
|
||||
const rows = db
|
||||
.prepare(`
|
||||
SELECT mi.id as item_id FROM review_plans rp
|
||||
JOIN media_items mi ON mi.id = rp.item_id
|
||||
WHERE rp.status = 'done' AND rp.verified = 0
|
||||
ORDER BY rp.reviewed_at DESC NULLS LAST
|
||||
`)
|
||||
.all() as { item_id: number }[];
|
||||
|
||||
if (rows.length === 0) return c.json({ ok: true, count: 0 });
|
||||
|
||||
(async () => {
|
||||
for (const row of rows) {
|
||||
try {
|
||||
await handOffToJellyfin(row.item_id);
|
||||
} catch (err) {
|
||||
warn(`verify-unverified: handoff for item ${row.item_id} threw: ${String(err)}`);
|
||||
}
|
||||
}
|
||||
log(`verify-unverified: processed ${rows.length} unverified done plan(s)`);
|
||||
})();
|
||||
|
||||
return c.json({ ok: true, count: rows.length });
|
||||
});
|
||||
|
||||
// ─── Stop running job ─────────────────────────────────────────────────────────
|
||||
|
||||
app.post("/stop", (c) => {
|
||||
|
||||
Reference in New Issue
Block a user