diff --git a/backend/package-lock.json b/backend/package-lock.json index af79d08..5a3ff9d 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "ripster-backend", - "version": "0.12.0-9", + "version": "0.12.0-10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ripster-backend", - "version": "0.12.0-9", + "version": "0.12.0-10", "dependencies": { "archiver": "^7.0.1", "cors": "^2.8.5", diff --git a/backend/package.json b/backend/package.json index 9bab9bb..d7c5b63 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "ripster-backend", - "version": "0.12.0-9", + "version": "0.12.0-10", "private": true, "type": "commonjs", "scripts": { diff --git a/backend/src/services/pipelineService.js b/backend/src/services/pipelineService.js index 9403f58..7ac1029 100644 --- a/backend/src/services/pipelineService.js +++ b/backend/src/services/pipelineService.js @@ -7133,7 +7133,15 @@ class PipelineService extends EventEmitter { const runningJobs = await historyService.getRunningJobs(); const foreignRunningJobs = runningJobs.filter((item) => Number(item?.id) !== Number(job.id)); - const keepCurrentPipelineSession = foreignRunningJobs.length > 0; + // Only block metadata selection if a foreign job requires active user interaction + // in the pipeline UI. Autonomous jobs (ENCODING, RIPPING, READY_TO_ENCODE) run + // independently via activeProcesses and must not prevent new disc metadata selection. + const PIPELINE_INTERACTIVE_STATES = new Set([ + 'ANALYZING', 'METADATA_SELECTION', 'WAITING_FOR_USER_DECISION', 'MEDIAINFO_CHECK' + ]); + const keepCurrentPipelineSession = foreignRunningJobs.some( + (item) => PIPELINE_INTERACTIVE_STATES.has(String(item?.status || '').toUpperCase()) + ); if (!keepCurrentPipelineSession) { await this.setState('METADATA_SELECTION', { activeJobId: job.id, @@ -7161,7 +7169,7 @@ class PipelineService extends EventEmitter { await historyService.appendLog( job.id, 'SYSTEM', - `Metadaten-Auswahl im Hintergrund vorbereitet. Aktive Session bleibt bei laufendem Job #${foreignRunningJobs.map((item) => item.id).join(',')}.` + `Metadaten-Auswahl im Hintergrund vorbereitet. Aktive Session bleibt bei interaktivem Job #${foreignRunningJobs.map((item) => item.id).join(',')}.` ); } @@ -8478,7 +8486,15 @@ class PipelineService extends EventEmitter { const runningJobs = await historyService.getRunningJobs(); const foreignRunningJobs = runningJobs.filter((item) => Number(item?.id) !== Number(jobId)); - const keepCurrentPipelineSession = foreignRunningJobs.length > 0; + // Only block the state transition if a foreign job requires active user interaction. + // Autonomous jobs (ENCODING, RIPPING, READY_TO_ENCODE) must not prevent this job + // from advancing through its own pipeline steps. + const PIPELINE_INTERACTIVE_STATES = new Set([ + 'ANALYZING', 'METADATA_SELECTION', 'WAITING_FOR_USER_DECISION', 'MEDIAINFO_CHECK' + ]); + const keepCurrentPipelineSession = foreignRunningJobs.some( + (item) => PIPELINE_INTERACTIVE_STATES.has(String(item?.status || '').toUpperCase()) + ); if (existingRawPath) { await historyService.appendLog( @@ -11201,17 +11217,26 @@ class PipelineService extends EventEmitter { ? `${finishedStatusTextBase} (${postEncodeScriptsSummary.failed} Skript(e) fehlgeschlagen)` : finishedStatusTextBase; - await this.setState('FINISHED', { - activeJobId: jobId, - progress: 100, - eta: null, - statusText: finishedStatusText, - context: { - jobId, - mode, - outputPath: finalizedOutputPath - } - }); + // Only switch the pipeline UI to FINISHED if this job is still the active one. + // If the pipeline has moved to another job (e.g. metadata selection for a new disc + // that was inserted while this one was encoding), complete silently so the other + // job's UI state is not disrupted. The DB status is already FINISHED (above). + if (Number(this.snapshot.activeJobId) === Number(jobId)) { + await this.setState('FINISHED', { + activeJobId: jobId, + progress: 100, + eta: null, + statusText: finishedStatusText, + context: { + jobId, + mode, + outputPath: finalizedOutputPath + } + }); + } else { + logger.info('encoding:finished:background', { jobId, mode, activeJobId: this.snapshot.activeJobId }); + void this.pumpQueue(); + } if (mode === 'reencode') { void this.notifyPushover('reencode_finished', { @@ -14046,18 +14071,24 @@ class PipelineService extends EventEmitter { error_message: null }); - await this.setState('FINISHED', { - activeJobId: jobId, - progress: 100, - eta: null, - statusText: 'Audiobook abgeschlossen', - context: { - jobId, - mode: 'audiobook', - mediaProfile: 'audiobook', - outputPath: finalizedOutputPath - } - }); + // Only switch the pipeline UI to FINISHED if this job is still the active one. + if (Number(this.snapshot.activeJobId) === Number(jobId)) { + await this.setState('FINISHED', { + activeJobId: jobId, + progress: 100, + eta: null, + statusText: 'Audiobook abgeschlossen', + context: { + jobId, + mode: 'audiobook', + mediaProfile: 'audiobook', + outputPath: finalizedOutputPath + } + }); + } else { + logger.info('audiobook:finished:background', { jobId, activeJobId: this.snapshot.activeJobId }); + void this.pumpQueue(); + } void this.notifyPushover('job_finished', { title: 'Ripster - Audiobook abgeschlossen', diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d48cd64..5dc8ed8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "ripster-frontend", - "version": "0.12.0-9", + "version": "0.12.0-10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ripster-frontend", - "version": "0.12.0-9", + "version": "0.12.0-10", "dependencies": { "primeicons": "^7.0.0", "primereact": "^10.9.2", diff --git a/frontend/package.json b/frontend/package.json index 330becd..e8e9e65 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "ripster-frontend", - "version": "0.12.0-9", + "version": "0.12.0-10", "private": true, "type": "module", "scripts": { diff --git a/package-lock.json b/package-lock.json index 67a2f5c..376f61e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ripster", - "version": "0.12.0-9", + "version": "0.12.0-10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ripster", - "version": "0.12.0-9", + "version": "0.12.0-10", "devDependencies": { "concurrently": "^9.1.2" } diff --git a/package.json b/package.json index b6f0bb6..7f95767 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ripster", "private": true, - "version": "0.12.0-9", + "version": "0.12.0-10", "scripts": { "dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"", "dev:backend": "npm run dev --prefix backend",