1.0.0-rc3 rc3

This commit is contained in:
2026-05-27 09:49:12 +02:00
parent eeef1fdb73
commit 2359c03bc8
13 changed files with 411 additions and 76 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "ripster-backend",
"version": "1.0.0-rc2",
"version": "1.0.0-rc3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-backend",
"version": "1.0.0-rc2",
"version": "1.0.0-rc3",
"dependencies": {
"archiver": "^7.0.1",
"cors": "^2.8.5",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ripster-backend",
"version": "1.0.0-rc2",
"version": "1.0.0-rc3",
"private": true,
"type": "commonjs",
"scripts": {
+59 -28
View File
@@ -107,6 +107,16 @@ function nowIso() {
return new Date().toISOString();
}
function appendLinesInPlace(target, lines) {
if (!Array.isArray(target) || !Array.isArray(lines) || lines.length === 0) {
return target;
}
for (const line of lines) {
target.push(line);
}
return target;
}
function normalizeLifecycleJobState(value) {
return String(value || '').trim().toUpperCase();
}
@@ -9637,8 +9647,6 @@ function applyPreviousSelectionDefaultsToReviewPlan(reviewPlan, previousPlan = n
const postEncodeScriptIds = normalizeScriptIdList(previousPlan?.postEncodeScriptIds || []);
const preEncodeChainIds = normalizeChainIdList(previousPlan?.preEncodeChainIds || []);
const postEncodeChainIds = normalizeChainIdList(previousPlan?.postEncodeChainIds || []);
const userPreset = normalizeUserPresetForPlan(previousPlan?.userPreset || null);
nextPlan = {
...nextPlan,
preEncodeScriptIds,
@@ -9647,7 +9655,7 @@ function applyPreviousSelectionDefaultsToReviewPlan(reviewPlan, previousPlan = n
postEncodeScripts: buildScriptDescriptorList(postEncodeScriptIds, previousPlan?.postEncodeScripts || []),
preEncodeChainIds,
postEncodeChainIds,
userPreset,
userPreset: null,
reviewConfirmed: false,
reviewConfirmedAt: null,
prefilledFromPreviousRun: true,
@@ -9659,8 +9667,7 @@ function applyPreviousSelectionDefaultsToReviewPlan(reviewPlan, previousPlan = n
|| preEncodeScriptIds.length > 0
|| postEncodeScriptIds.length > 0
|| preEncodeChainIds.length > 0
|| postEncodeChainIds.length > 0
|| Boolean(userPreset);
|| postEncodeChainIds.length > 0;
return {
plan: nextPlan,
@@ -9670,7 +9677,7 @@ function applyPreviousSelectionDefaultsToReviewPlan(reviewPlan, previousPlan = n
postEncodeScriptCount: postEncodeScriptIds.length,
preEncodeChainCount: preEncodeChainIds.length,
postEncodeChainCount: postEncodeChainIds.length,
userPresetApplied: Boolean(userPreset)
userPresetApplied: false
};
}
@@ -18149,7 +18156,7 @@ class PipelineService extends EventEmitter {
source: 'HANDBRAKE_SCAN',
silent: !this.isPrimaryJob(jobId)
});
lines.push(...pluginScan.scanLines);
appendLinesInPlace(lines, pluginScan.scanLines);
runInfo = pluginScan.runInfo || null;
sourceArg = pluginScan.sourceArg || null;
reviewPluginExecution = this.mergePluginExecutionState(
@@ -18514,7 +18521,7 @@ class PipelineService extends EventEmitter {
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
silent: !this.isPrimaryJob(jobId)
});
resolveScanLines.push(...pluginScan.scanLines);
appendLinesInPlace(resolveScanLines, pluginScan.scanLines);
reviewPluginExecution = this.mergePluginExecutionState(
reviewPluginExecution,
pluginScan.pluginExecution
@@ -18656,7 +18663,7 @@ class PipelineService extends EventEmitter {
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
silent: !this.isPrimaryJob(jobId)
});
scanLines.push(...pluginScan.scanLines);
appendLinesInPlace(scanLines, pluginScan.scanLines);
reviewPluginExecution = this.mergePluginExecutionState(
reviewPluginExecution,
pluginScan.pluginExecution
@@ -19315,8 +19322,15 @@ class PipelineService extends EventEmitter {
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
silent: !this.isPrimaryJob(jobId)
});
resolveScanLines.push(...pluginScan.scanLines);
appendLinesInPlace(resolveScanLines, pluginScan.scanLines);
handBrakeResolveRunInfo = pluginScan.runInfo || null;
const resolveScanStatus = String(handBrakeResolveRunInfo?.status || '').trim().toUpperCase();
if (resolveScanStatus === 'CANCELLED') {
const error = new Error('HandBrake Playlist-Mapping wurde abgebrochen.');
error.statusCode = 409;
error.runInfo = handBrakeResolveRunInfo;
throw error;
}
reviewPluginExecution = this.mergePluginExecutionState(
reviewPluginExecution,
pluginScan.pluginExecution
@@ -19328,6 +19342,16 @@ class PipelineService extends EventEmitter {
error.runInfo = handBrakeResolveRunInfo;
throw error;
}
const knownPlaylists = listAvailableHandBrakePlaylists(resolveScanJson);
if (knownPlaylists.length === 0 && resolveScanStatus && resolveScanStatus !== 'SUCCESS') {
const error = new Error(
`HandBrake Playlist-Mapping unvollständig (${resolveScanStatus}). `
+ 'Scan enthält keine erkennbaren Playlist-IDs.'
);
error.statusCode = resolveScanStatus === 'CANCELLED' ? 409 : 502;
error.runInfo = handBrakeResolveRunInfo;
throw error;
}
resolvedHandBrakeTitleId = resolveHandBrakeTitleIdForPlaylist(resolveScanJson, resolvedPlaylistId, {
expectedMakemkvTitleId: selectedTitleForReview,
@@ -19336,7 +19360,6 @@ class PipelineService extends EventEmitter {
playlistAliases: playlistAliasesForResolve
});
if (!resolvedHandBrakeTitleId) {
const knownPlaylists = listAvailableHandBrakePlaylists(resolveScanJson);
const error = new Error(
`Kein HandBrake-Titel für ${toPlaylistFile(resolvedPlaylistId)} gefunden.`
+ ` ${knownPlaylists.length > 0 ? `Scan-Playlists: ${knownPlaylists.map((id) => `${id}.mpls`).join(', ')}` : 'Scan enthält keine erkennbaren Playlist-IDs.'}`
@@ -22781,6 +22804,10 @@ class PipelineService extends EventEmitter {
: '';
const hasExplicitUserPresetSelection = !multipartSettingsLocked && explicitUserPresetId !== null;
const hasExplicitHandBrakePresetSelection = !multipartSettingsLocked && Boolean(rawHandBrakePreset);
const explicitPresetClearRequested = !multipartSettingsLocked
&& (hasUserPresetIdField || hasHandBrakePresetField)
&& explicitUserPresetId === null
&& !rawHandBrakePreset;
let resolvedUserPreset = null;
if (hasExplicitUserPresetSelection) {
resolvedUserPreset = await userPresetService.getPresetById(explicitUserPresetId);
@@ -22799,7 +22826,7 @@ class PipelineService extends EventEmitter {
}
: null;
}
if (!resolvedUserPreset) {
if (!resolvedUserPreset && !explicitPresetClearRequested) {
resolvedUserPreset = normalizeUserPresetForPlan(
planForConfirm?.userPreset || encodePlan?.userPreset || null
);
@@ -22833,20 +22860,24 @@ class PipelineService extends EventEmitter {
const requiresExplicitPreset = readyMediaProfile === 'dvd'
|| readyMediaProfile === 'bluray'
|| (readyMediaProfile === 'converter' && confirmedConverterMediaType !== 'audio');
const planPresetName = String(
planForConfirm?.userPreset?.handbrakePreset
|| encodePlan?.userPreset?.handbrakePreset
|| planForConfirm?.selectors?.preset
|| encodePlan?.selectors?.preset
|| ''
).trim();
const planExtraArgs = String(
planForConfirm?.userPreset?.extraArgs
|| encodePlan?.userPreset?.extraArgs
|| planForConfirm?.selectors?.extraArgs
|| encodePlan?.selectors?.extraArgs
|| ''
).trim();
const planPresetName = explicitPresetClearRequested
? ''
: String(
planForConfirm?.userPreset?.handbrakePreset
|| encodePlan?.userPreset?.handbrakePreset
|| planForConfirm?.selectors?.preset
|| encodePlan?.selectors?.preset
|| ''
).trim();
const planExtraArgs = explicitPresetClearRequested
? ''
: String(
planForConfirm?.userPreset?.extraArgs
|| encodePlan?.userPreset?.extraArgs
|| planForConfirm?.selectors?.extraArgs
|| encodePlan?.selectors?.extraArgs
|| ''
).trim();
const effectivePresetName = String(
resolvedUserPreset?.handbrakePreset
|| rawHandBrakePreset
@@ -23800,7 +23831,7 @@ class PipelineService extends EventEmitter {
source: 'HANDBRAKE_SCAN_DVD',
silent: !this.isPrimaryJob(jobId)
});
dvdScanLines.push(...pluginScan.scanLines);
appendLinesInPlace(dvdScanLines, pluginScan.scanLines);
dvdScanRunInfo = pluginScan.runInfo || null;
reviewPluginExecution = this.mergePluginExecutionState(
reviewPluginExecution,
@@ -24548,7 +24579,7 @@ class PipelineService extends EventEmitter {
source: 'HANDBRAKE_SCAN_DVD_TITLES',
silent: !this.isPrimaryJob(jobId)
});
dvdTitleScanLines.push(...pluginScan.scanLines);
appendLinesInPlace(dvdTitleScanLines, pluginScan.scanLines);
dvdTitleScanRunInfo = pluginScan.runInfo || null;
reviewPluginExecution = this.mergePluginExecutionState(
reviewPluginExecution,
+28 -2
View File
@@ -308,12 +308,38 @@ function removeSelectionArgs(extraArgs) {
const isAudioWithValue = AUDIO_SELECTION_KEYS_WITH_VALUE.has(key);
const isAudioFlagOnly = AUDIO_SELECTION_KEYS_FLAG_ONLY.has(key);
const isSubtitleWithValue = SUBTITLE_SELECTION_KEYS_WITH_VALUE.has(key)
|| SUBTITLE_FLAG_KEYS_WITH_VALUE.has(key);
const isSubtitleSelectionWithValue = SUBTITLE_SELECTION_KEYS_WITH_VALUE.has(key);
const isSubtitleFlagWithValue = SUBTITLE_FLAG_KEYS_WITH_VALUE.has(key);
const isSubtitleWithValue = isSubtitleSelectionWithValue || isSubtitleFlagWithValue;
const isSubtitleFlagOnly = SUBTITLE_SELECTION_KEYS_FLAG_ONLY.has(key);
const isTitleWithValue = TITLE_SELECTION_KEYS_WITH_VALUE.has(key);
const skip = isAudioWithValue || isAudioFlagOnly || isSubtitleWithValue || isSubtitleFlagOnly || isTitleWithValue;
if (isSubtitleFlagWithValue) {
const inlineValue = token.includes('=')
? token.slice(token.indexOf('=') + 1)
: '';
const hasAttachedValue = token.includes('=');
const nextToken = String(args[i + 1] || '');
const hasSeparateValue = !hasAttachedValue && nextToken && !nextToken.startsWith('-');
const candidateValue = String(
hasAttachedValue
? inlineValue
: (hasSeparateValue ? nextToken : '')
).trim().toLowerCase();
// Keep explicit "none" subtitle flags from extra args.
// This allows users to intentionally clear subtitle burn/default/forced behavior.
if (candidateValue === 'none') {
filtered.push(token);
if (hasSeparateValue) {
filtered.push(nextToken);
i += 1;
}
continue;
}
}
if (!skip) {
filtered.push(token);
continue;