0.13.1-8 Fix Analysis

This commit is contained in:
2026-04-14 19:25:07 +00:00
parent c89a93ed05
commit 717bb305c0
11 changed files with 184 additions and 20 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "ripster-backend",
"version": "0.13.1-7",
"version": "0.13.1-8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-backend",
"version": "0.13.1-7",
"version": "0.13.1-8",
"dependencies": {
"archiver": "^7.0.1",
"cors": "^2.8.5",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ripster-backend",
"version": "0.13.1-7",
"version": "0.13.1-8",
"private": true,
"type": "commonjs",
"scripts": {
+11
View File
@@ -425,6 +425,17 @@ router.post(
})
);
router.post(
'/jobs/:jobId/raw-decision',
asyncHandler(async (req, res) => {
const jobId = Number(req.params.jobId);
const { decision } = req.body;
logger.info('post:raw-decision', { reqId: req.reqId, jobId, decision });
const result = await pipelineService.submitRawDecision(jobId, decision);
res.json({ result });
})
);
router.post(
'/start/:jobId',
asyncHandler(async (req, res) => {
+102 -10
View File
@@ -13692,6 +13692,83 @@ class PipelineService extends EventEmitter {
return this.runMediainfoReviewForJob(jobId, rawPath, options);
}
async submitRawDecision(jobId, decision) {
const historyService = require('./historyService'); // already required at top? wait, pipelineService requires historyService. We can just use historyService directly.
const job = await historyService.getJobById(jobId);
if (!job) throw new Error('Job nicht gefunden.');
const isWaiting = (
String(job.status || '').trim().toUpperCase() === 'WAITING_FOR_USER_DECISION' ||
String(job.last_state || '').trim().toUpperCase() === 'WAITING_FOR_USER_DECISION'
);
if (!isWaiting) {
throw new Error(`Job ist nicht im Status WAITING_FOR_USER_DECISION (${job.status})`);
}
if (decision === 'delete') {
const fsOptions = { recursive: true, force: true };
if (job.raw_path && require('fs').existsSync(job.raw_path)) {
await require('fs').promises.rm(job.raw_path, fsOptions);
await historyService.appendLog(jobId, 'SYSTEM', `RAW-Verzeichnis wurde auf Benutzerwunsch gelöscht: ${job.raw_path}`);
}
} else if (decision === 'continue') {
await historyService.appendLog(jobId, 'SYSTEM', `Benutzer hat "Mit vorhandenem RAW weiter machen" gewählt.`);
} else if (decision === 'cancel') {
await historyService.appendLog(jobId, 'SYSTEM', `Benutzer hat auf Grund vorhandenem RAW abgebrochen.`);
await this.cancelJob(jobId);
return historyService.getJobById(jobId);
} else {
throw new Error(`Unbekannte Entscheidung: ${decision}`);
}
const mkInfo = this.safeParseJson(job.makemkv_info_json);
const currentAnalyzeContext = mkInfo?.analyzeContext || {};
const playlistDecisionRequired = Boolean(currentAnalyzeContext.playlistDecisionRequired);
const selectedTitleId = currentAnalyzeContext.selectedTitleId ?? null;
const requiresManualPlaylistSelection = Boolean(playlistDecisionRequired && selectedTitleId === null);
const nextStatus = requiresManualPlaylistSelection ? 'WAITING_FOR_USER_DECISION' : 'READY_TO_START';
await this.setState(nextStatus, {
activeJobId: jobId,
progress: 0,
eta: null,
statusText: requiresManualPlaylistSelection
? 'waiting_for_manual_playlist_selection'
: (decision === 'continue'
? 'Metadaten übernommen - vorhandenes RAW erkannt'
: 'Metadaten übernommen - bereit zum Start'),
context: {
...(this.snapshot.context || {}),
waitingForRawDecision: false,
manualDecisionState: requiresManualPlaylistSelection
? 'waiting_for_manual_playlist_selection'
: null
}
});
if (requiresManualPlaylistSelection) {
await historyService.appendLog(
jobId,
'SYSTEM',
'Bitte selected_playlist setzen (z.B. 00800 oder 00800.mpls), bevor Backup/Encoding gestartet wird.'
);
return historyService.getJobById(jobId);
}
if (decision === 'continue') {
await historyService.appendLog(jobId, 'SYSTEM', `Starte automatische Spur-Ermittlung (Mediainfo) mit vorhandenem RAW: ${job.raw_path}`);
await this.startPreparedJob(jobId);
return historyService.getJobById(jobId);
}
await historyService.appendLog(jobId, 'SYSTEM', 'RAW gelöscht oder ignoriert. Starte Backup/Rip automatisch.');
await this.startPreparedJob(jobId);
return historyService.getJobById(jobId);
}
async selectMetadata({
jobId,
title,
@@ -14515,11 +14592,12 @@ class PipelineService extends EventEmitter {
recommendation: null
}
: basePlaylistDecision;
const isRawImportMetadataJob = String(mkInfo?.source || '').trim().toLowerCase() === 'orphan_raw_import';
const requiresManualPlaylistSelection = Boolean(
playlistDecision.playlistDecisionRequired && playlistDecision.selectedTitleId === null
);
const nextStatus = requiresManualPlaylistSelection ? 'WAITING_FOR_USER_DECISION' : 'READY_TO_START';
const isRawImportMetadataJob = String(mkInfo?.source || '').trim().toLowerCase() === 'orphan_raw_import';
const requiresRawDecision = shouldAutoReviewFromRaw && !isRawImportMetadataJob;
const nextStatus = (requiresManualPlaylistSelection || requiresRawDecision) ? 'WAITING_FOR_USER_DECISION' : 'READY_TO_START';
const updatedMakemkvInfo = this.withAnalyzeContextMediaProfile({
...mkInfo,
@@ -14605,11 +14683,13 @@ class PipelineService extends EventEmitter {
activeJobId: jobId,
progress: 0,
eta: null,
statusText: requiresManualPlaylistSelection
? 'waiting_for_manual_playlist_selection'
: (shouldAutoReviewFromRaw
? 'Metadaten übernommen - vorhandenes RAW erkannt'
: 'Metadaten übernommen - bereit zum Start'),
statusText: requiresRawDecision
? 'waiting_for_raw_decision'
: (requiresManualPlaylistSelection
? 'waiting_for_manual_playlist_selection'
: (shouldAutoReviewFromRaw
? 'Metadaten übernommen - vorhandenes RAW erkannt'
: 'Metadaten übernommen - bereit zum Start')),
context: {
...(this.snapshot.context || {}),
jobId,
@@ -14622,9 +14702,12 @@ class PipelineService extends EventEmitter {
selectedPlaylist: playlistDecision.selectedPlaylist || null,
selectedTitleId: playlistDecision.selectedTitleId ?? null,
waitingForManualPlaylistSelection: requiresManualPlaylistSelection,
manualDecisionState: requiresManualPlaylistSelection
? 'waiting_for_manual_playlist_selection'
: null
waitingForRawDecision: requiresRawDecision,
manualDecisionState: requiresRawDecision
? 'waiting_for_raw_decision'
: (requiresManualPlaylistSelection
? 'waiting_for_manual_playlist_selection'
: null)
}
});
} else {
@@ -14636,6 +14719,15 @@ class PipelineService extends EventEmitter {
);
}
if (requiresRawDecision) {
await historyService.appendLog(
jobId,
'SYSTEM',
`Vorhandenes RAW zur Disk gefunden: ${updatedRawPath}. Warte auf Entscheidung.`
);
return historyService.getJobById(jobId);
}
if (requiresManualPlaylistSelection) {
const playlistFiles = playlistDecision.candidatePlaylists
.map((item) => item.playlistFile)