From 78d569189f2f5663f83fbebe32791c296e3753eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Tue, 21 Apr 2026 10:18:57 +0200 Subject: [PATCH] fix stop buttons: centralize processInbox launch through abort-aware startProcessInbox All three processInbox callers (manual button, auto-processing toggle, post-scan auto-process) now go through startProcessInbox() which manages the shared abort controller. Previously only the manual button set the abort controller, so Stop Sorting had no effect when processing was triggered from the settings toggle or after scan completion. Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 2 +- server/api/review.ts | 35 +++++++++++++++++++++++++---------- server/api/scan.ts | 10 ++-------- server/api/settings.ts | 10 ++-------- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 0679928..9a6d434 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "netfelix-audio-fix", - "version": "2026.04.21.6", + "version": "2026.04.21.7", "scripts": { "dev:server": "NODE_ENV=development bun --hot server/index.tsx", "dev:client": "vite", diff --git a/server/api/review.ts b/server/api/review.ts index eaf46f4..0208ea2 100644 --- a/server/api/review.ts +++ b/server/api/review.ts @@ -1090,14 +1090,17 @@ app.post("/approve-batch", async (c) => { // update progressively via SSE events. let processInboxAbort: AbortController | null = null; -app.post("/process-inbox", async (c) => { - if (processInboxAbort) { - return c.json({ ok: false, error: "processing already running" }, 409); - } +/** + * Single entry point for launching processInbox. Manages the abort controller + * so every caller (manual button, auto-process toggle, post-scan auto-process) + * can be stopped via the /process-inbox/stop endpoint. + * Returns false if a run is already in progress. + */ +export function startProcessInbox(): boolean { + if (processInboxAbort) return false; processInboxAbort = new AbortController(); const { signal } = processInboxAbort; - // Fire and forget — the frontend tracks progress via SSE events. const db = getDb(); processInbox(db, getAudioLanguages(), undefined, { onStart: emitInboxSortStart, @@ -1110,15 +1113,27 @@ app.post("/process-inbox", async (c) => { processInboxAbort = null; }); + return true; +} + +export function stopProcessInbox(): boolean { + if (processInboxAbort) { + processInboxAbort.abort(); + return true; + } + return false; +} + +app.post("/process-inbox", async (c) => { + if (!startProcessInbox()) { + return c.json({ ok: false, error: "processing already running" }, 409); + } return c.json({ ok: true }); }); app.post("/process-inbox/stop", (c) => { - if (processInboxAbort) { - processInboxAbort.abort(); - return c.json({ ok: true }); - } - return c.json({ ok: true, message: "not running" }); + const stopped = stopProcessInbox(); + return c.json({ ok: true, stopped }); }); // ─── Process single item ──────────────────────────────────────────────────── diff --git a/server/api/scan.ts b/server/api/scan.ts index 010b094..d8999d3 100644 --- a/server/api/scan.ts +++ b/server/api/scan.ts @@ -235,14 +235,8 @@ async function runScan(limit: number | null = null): Promise { emitSse("complete", { scanned: processed, total, errors }); if (getConfig("auto_processing") === "1") { - const { processInbox, getAudioLanguages } = await import("./review"); - const { emitInboxSorted, emitInboxSortStart, emitInboxSortProgress } = await import("./execute"); - processInbox(db, getAudioLanguages(), undefined, { - onStart: emitInboxSortStart, - onProgress: emitInboxSortProgress, - }) - .then((result) => emitInboxSorted(result)) - .catch(() => emitInboxSorted({ moved_to_queue: 0, moved_to_review: 0 })); + const { startProcessInbox } = await import("./review"); + startProcessInbox(); } } diff --git a/server/api/settings.ts b/server/api/settings.ts index d7e0e4b..f08ed24 100644 --- a/server/api/settings.ts +++ b/server/api/settings.ts @@ -90,14 +90,8 @@ app.post("/auto-processing", async (c) => { setConfig("auto_processing", body.enabled ? "1" : "0"); if (body.enabled) { - const { processInbox, getAudioLanguages } = await import("./review"); - const { emitInboxSorted, emitInboxSortStart, emitInboxSortProgress } = await import("./execute"); - processInbox(getDb(), getAudioLanguages(), undefined, { - onStart: emitInboxSortStart, - onProgress: emitInboxSortProgress, - }) - .then((result) => emitInboxSorted(result)) - .catch(() => emitInboxSorted({ moved_to_queue: 0, moved_to_review: 0 })); + const { startProcessInbox } = await import("./review"); + startProcessInbox(); } return c.json({ ok: true, enabled: body.enabled }); });