push verified=1 to the UI via a plan_update SSE event
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
the ✓✓ write was landing in the db but never reaching the browser. job_update fires once at job completion (card renders ✓, verified=0), then handOffToJellyfin takes ~15s to refresh jellyfin + re-analyze + UPDATE review_plans SET verified=1. no further sse, so the pipeline page never re-polled and the card stayed at ✓ until the user navigated away and back. new plan_update event emitted at the end of handOffToJellyfin. the pipeline page listens and triggers the same 1s-coalesced reload as job_update, so the done column promotes ✓ → ✓✓ within a second of jellyfin's verdict landing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -88,6 +88,10 @@ async function handOffToJellyfin(itemId: number): Promise<void> {
|
||||
|
||||
const result = await upsertJellyfinItem(db, fresh, rescanCfg, { source: "webhook" });
|
||||
log(`Post-job verify for item ${itemId}: is_noop=${result.isNoop}`);
|
||||
// Nudge connected clients so the Done column re-polls and promotes
|
||||
// the card from ✓ to ✓✓ (or flips it back to Review if jellyfin
|
||||
// disagreed).
|
||||
emitPlanUpdate(itemId);
|
||||
} catch (err) {
|
||||
warn(`Post-job verification for item ${itemId} failed: ${String(err)}`);
|
||||
}
|
||||
@@ -169,6 +173,18 @@ function emitJobProgress(jobId: number, seconds: number, total: number): void {
|
||||
for (const l of jobListeners) l(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit when a review_plan mutates asynchronously (after the job already
|
||||
* finished). Right now the only producer is handOffToJellyfin — the
|
||||
* verified=1 write that lands ~15s after a job completes. Without this
|
||||
* the UI would keep showing ✓ indefinitely until the user navigates
|
||||
* away and back, since we'd never fire job_update again for that item.
|
||||
*/
|
||||
function emitPlanUpdate(itemId: number): void {
|
||||
const line = `event: plan_update\ndata: ${JSON.stringify({ itemId })}\n\n`;
|
||||
for (const l of jobListeners) l(line);
|
||||
}
|
||||
|
||||
/** Parse "Duration: HH:MM:SS.MS" from ffmpeg startup output. */
|
||||
function parseFFmpegDuration(line: string): number | null {
|
||||
const match = line.match(/Duration:\s*(\d+):(\d+):(\d+)\.(\d+)/);
|
||||
|
||||
Reference in New Issue
Block a user