0.12.0-10 Fix Multi Job

This commit is contained in:
2026-03-23 07:30:44 +00:00
parent a87ba330b1
commit 6911892b89
7 changed files with 66 additions and 35 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "ripster-backend", "name": "ripster-backend",
"version": "0.12.0-9", "version": "0.12.0-10",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ripster-backend", "name": "ripster-backend",
"version": "0.12.0-9", "version": "0.12.0-10",
"dependencies": { "dependencies": {
"archiver": "^7.0.1", "archiver": "^7.0.1",
"cors": "^2.8.5", "cors": "^2.8.5",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ripster-backend", "name": "ripster-backend",
"version": "0.12.0-9", "version": "0.12.0-10",
"private": true, "private": true,
"type": "commonjs", "type": "commonjs",
"scripts": { "scripts": {
+57 -26
View File
@@ -7133,7 +7133,15 @@ class PipelineService extends EventEmitter {
const runningJobs = await historyService.getRunningJobs(); const runningJobs = await historyService.getRunningJobs();
const foreignRunningJobs = runningJobs.filter((item) => Number(item?.id) !== Number(job.id)); 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) { if (!keepCurrentPipelineSession) {
await this.setState('METADATA_SELECTION', { await this.setState('METADATA_SELECTION', {
activeJobId: job.id, activeJobId: job.id,
@@ -7161,7 +7169,7 @@ class PipelineService extends EventEmitter {
await historyService.appendLog( await historyService.appendLog(
job.id, job.id,
'SYSTEM', '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 runningJobs = await historyService.getRunningJobs();
const foreignRunningJobs = runningJobs.filter((item) => Number(item?.id) !== Number(jobId)); 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) { if (existingRawPath) {
await historyService.appendLog( await historyService.appendLog(
@@ -11201,17 +11217,26 @@ class PipelineService extends EventEmitter {
? `${finishedStatusTextBase} (${postEncodeScriptsSummary.failed} Skript(e) fehlgeschlagen)` ? `${finishedStatusTextBase} (${postEncodeScriptsSummary.failed} Skript(e) fehlgeschlagen)`
: finishedStatusTextBase; : finishedStatusTextBase;
await this.setState('FINISHED', { // Only switch the pipeline UI to FINISHED if this job is still the active one.
activeJobId: jobId, // If the pipeline has moved to another job (e.g. metadata selection for a new disc
progress: 100, // that was inserted while this one was encoding), complete silently so the other
eta: null, // job's UI state is not disrupted. The DB status is already FINISHED (above).
statusText: finishedStatusText, if (Number(this.snapshot.activeJobId) === Number(jobId)) {
context: { await this.setState('FINISHED', {
jobId, activeJobId: jobId,
mode, progress: 100,
outputPath: finalizedOutputPath 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') { if (mode === 'reencode') {
void this.notifyPushover('reencode_finished', { void this.notifyPushover('reencode_finished', {
@@ -14046,18 +14071,24 @@ class PipelineService extends EventEmitter {
error_message: null error_message: null
}); });
await this.setState('FINISHED', { // Only switch the pipeline UI to FINISHED if this job is still the active one.
activeJobId: jobId, if (Number(this.snapshot.activeJobId) === Number(jobId)) {
progress: 100, await this.setState('FINISHED', {
eta: null, activeJobId: jobId,
statusText: 'Audiobook abgeschlossen', progress: 100,
context: { eta: null,
jobId, statusText: 'Audiobook abgeschlossen',
mode: 'audiobook', context: {
mediaProfile: 'audiobook', jobId,
outputPath: finalizedOutputPath 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', { void this.notifyPushover('job_finished', {
title: 'Ripster - Audiobook abgeschlossen', title: 'Ripster - Audiobook abgeschlossen',
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "ripster-frontend", "name": "ripster-frontend",
"version": "0.12.0-9", "version": "0.12.0-10",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ripster-frontend", "name": "ripster-frontend",
"version": "0.12.0-9", "version": "0.12.0-10",
"dependencies": { "dependencies": {
"primeicons": "^7.0.0", "primeicons": "^7.0.0",
"primereact": "^10.9.2", "primereact": "^10.9.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ripster-frontend", "name": "ripster-frontend",
"version": "0.12.0-9", "version": "0.12.0-10",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "ripster", "name": "ripster",
"version": "0.12.0-9", "version": "0.12.0-10",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ripster", "name": "ripster",
"version": "0.12.0-9", "version": "0.12.0-10",
"devDependencies": { "devDependencies": {
"concurrently": "^9.1.2" "concurrently": "^9.1.2"
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "ripster", "name": "ripster",
"private": true, "private": true,
"version": "0.12.0-9", "version": "0.12.0-10",
"scripts": { "scripts": {
"dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"", "dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"",
"dev:backend": "npm run dev --prefix backend", "dev:backend": "npm run dev --prefix backend",