0.12.0-5 Pre-Plugin
This commit is contained in:
@@ -8933,6 +8933,15 @@ class PipelineService extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// An Incomplete_ raw folder means the rip never finished — skip it and re-rip.
|
||||
if (existingRawInput && resolveRawFolderStateFromPath(job.raw_path) === RAW_FOLDER_STATES.INCOMPLETE) {
|
||||
logger.info('startPreparedJob:raw-incomplete-skip', {
|
||||
jobId,
|
||||
rawPath: job.raw_path
|
||||
});
|
||||
existingRawInput = null;
|
||||
}
|
||||
|
||||
if (existingRawInput) {
|
||||
await historyService.updateJob(jobId, {
|
||||
status: 'MEDIAINFO_CHECK',
|
||||
@@ -9258,6 +9267,17 @@ class PipelineService extends EventEmitter {
|
||||
}
|
||||
|
||||
const mkInfo = this.safeParseJson(sourceJob.makemkv_info_json);
|
||||
|
||||
// Importierte Jobs (RAW-Ordner-Import) müssen zuerst vollständig analysiert und
|
||||
// encodiert werden, bevor ein Re-Encode möglich ist. Nur "Neu einlesen" ist erlaubt.
|
||||
if (mkInfo?.source === 'orphan_raw_import' && !sourceJob.handbrake_info_json) {
|
||||
const error = new Error(
|
||||
'Re-Encode nicht möglich: Job wurde via RAW-Import erstellt und wurde noch nicht vollständig encodiert. Bitte zuerst "Neu einlesen" ausführen.'
|
||||
);
|
||||
error.statusCode = 409;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const sourceEncodePlan = this.safeParseJson(sourceJob.encode_plan_json);
|
||||
const reencodeMediaProfile = this.resolveMediaProfileForJob(sourceJob, {
|
||||
makemkvInfo: mkInfo,
|
||||
@@ -11824,7 +11844,8 @@ class PipelineService extends EventEmitter {
|
||||
await historyService.updateJob(jobId, {
|
||||
makemkv_info_json: JSON.stringify(this.withAnalyzeContextMediaProfile({
|
||||
...error.runInfo,
|
||||
analyzeContext: mkInfoBeforeRip?.analyzeContext || null
|
||||
analyzeContext: mkInfoBeforeRip?.analyzeContext || null,
|
||||
pluginExecution: mkInfoBeforeRip?.pluginExecution || null
|
||||
}, mediaProfile))
|
||||
});
|
||||
}
|
||||
@@ -11887,10 +11908,17 @@ class PipelineService extends EventEmitter {
|
||||
const isCdRetry = mediaProfile === 'cd';
|
||||
const isAudiobookRetry = mediaProfile === 'audiobook';
|
||||
|
||||
// CD-Jobs dürfen auch im FINISHED-Status neu gerippt werden (z.B. importierte Jobs)
|
||||
// CD-Jobs dürfen auch im FINISHED-Status neu gerippt werden (z.B. importierte Jobs).
|
||||
// Importierte Audiobooks (orphan_raw_import ohne bisherigen Encode) dürfen ebenfalls
|
||||
// neu gestartet werden, da erst der vollständige Flow durchlaufen werden muss.
|
||||
const isImportedAudiobookWithoutEncode = isAudiobookRetry
|
||||
&& sourceStatus === 'FINISHED'
|
||||
&& sourceMakemkvInfo?.source === 'orphan_raw_import'
|
||||
&& !sourceJob.handbrake_info_json;
|
||||
const retryable = ['ERROR', 'CANCELLED'].includes(sourceStatus)
|
||||
|| ['ERROR', 'CANCELLED'].includes(sourceLastState)
|
||||
|| (isCdRetry && ['FINISHED', 'ERROR', 'CANCELLED'].includes(sourceStatus));
|
||||
|| (isCdRetry && ['FINISHED', 'ERROR', 'CANCELLED'].includes(sourceStatus))
|
||||
|| isImportedAudiobookWithoutEncode;
|
||||
if (!retryable) {
|
||||
const error = new Error(
|
||||
`Retry nicht möglich: Job ${jobId} ist nicht im Status ERROR/CANCELLED (aktuell ${sourceStatus || sourceLastState || '-'}).`
|
||||
@@ -12293,6 +12321,15 @@ class PipelineService extends EventEmitter {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const mkInfoForRestart = this.safeParseJson(job.makemkv_info_json);
|
||||
if (mkInfoForRestart?.source === 'orphan_raw_import' && !job.handbrake_info_json) {
|
||||
const error = new Error(
|
||||
'Encode-Neustart nicht möglich: Job wurde via RAW-Import erstellt und wurde noch nicht vollständig encodiert. Bitte zuerst "Neu einlesen" ausführen.'
|
||||
);
|
||||
error.statusCode = 409;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const encodePlan = this.safeParseJson(job.encode_plan_json);
|
||||
if (!encodePlan || !Array.isArray(encodePlan.titles) || encodePlan.titles.length === 0) {
|
||||
const error = new Error('Encode-Neustart nicht möglich: encode_plan fehlt.');
|
||||
@@ -14045,9 +14082,8 @@ class PipelineService extends EventEmitter {
|
||||
message: `${metadata.title || job.title || job.detected_title || `Job #${jobId}`} -> ${preferredFinalOutputPath}`
|
||||
});
|
||||
|
||||
let temporaryChapterMetadataPath = null;
|
||||
|
||||
// Activation Bytes für AAX-Dateien aus Cache lesen
|
||||
// Activation Bytes für AAX-Dateien aus Cache lesen (vor dem Background-Start,
|
||||
// damit ein Fehler hier den HTTP-Request direkt abbricht).
|
||||
let encodeActivationBytes = null;
|
||||
if (path.extname(inputPath).toLowerCase() === '.aax') {
|
||||
try {
|
||||
@@ -14063,7 +14099,11 @@ class PipelineService extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Den eigentlichen ffmpeg-Encode im Hintergrund ausführen, damit der HTTP-Request
|
||||
// sofort nach dem Setzen des ENCODING-Status zurückkehrt (kein Blockieren bis FINISHED).
|
||||
void (async () => {
|
||||
let temporaryChapterMetadataPath = null;
|
||||
try {
|
||||
let ffmpegRunInfo = null;
|
||||
if (isSplitOutput) {
|
||||
const outputFiles = Array.isArray(incompleteChapterPlan?.outputFiles)
|
||||
@@ -14346,8 +14386,6 @@ class PipelineService extends EventEmitter {
|
||||
}
|
||||
logger.error('audiobook:encode:failed', { jobId, error: errorToMeta(error) });
|
||||
await this.failJob(jobId, 'ENCODING', error);
|
||||
error.jobAlreadyFailed = true;
|
||||
throw error;
|
||||
} finally {
|
||||
if (temporaryChapterMetadataPath) {
|
||||
try {
|
||||
@@ -14357,6 +14395,9 @@ class PipelineService extends EventEmitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
return { started: true, stage: 'ENCODING', outputPath: incompleteOutputPath };
|
||||
}
|
||||
|
||||
// ── CD Pipeline ─────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user