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:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "netfelix-audio-fix",
|
||||
"version": "2026.04.14.22",
|
||||
"version": "2026.04.14.23",
|
||||
"scripts": {
|
||||
"dev:server": "NODE_ENV=development bun --hot server/index.tsx",
|
||||
"dev:client": "vite",
|
||||
|
||||
@@ -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+)/);
|
||||
|
||||
@@ -64,6 +64,12 @@ export function PipelinePage() {
|
||||
}
|
||||
scheduleReload();
|
||||
});
|
||||
// plan_update lands ~15s after a job finishes — the post-job jellyfin
|
||||
// verification writes verified=1 (or flips the plan back to pending).
|
||||
// Without refreshing here the Done column would never promote ✓ to ✓✓.
|
||||
es.addEventListener("plan_update", () => {
|
||||
scheduleReload();
|
||||
});
|
||||
es.addEventListener("job_progress", (e) => {
|
||||
setProgress(JSON.parse((e as MessageEvent).data));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user