0.10.2-13 DVD Media Info Fix

This commit is contained in:
2026-03-16 13:40:01 +00:00
parent affabd3720
commit 2cbbbd9a86
7 changed files with 206 additions and 94 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "ripster-backend",
"version": "0.10.2-12",
"version": "0.10.2-13",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-backend",
"version": "0.10.2-12",
"version": "0.10.2-13",
"dependencies": {
"archiver": "^7.0.1",
"cors": "^2.8.5",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ripster-backend",
"version": "0.10.2-12",
"version": "0.10.2-13",
"private": true,
"type": "commonjs",
"scripts": {
+120 -8
View File
@@ -8154,8 +8154,10 @@ class PipelineService extends EventEmitter {
const mediaInfoByPath = {};
const mediaInfoRuns = [];
let effectiveMediaFiles = mediaFiles;
const buildReviewSnapshot = (processedCount) => {
const processedFiles = mediaFiles
const processedFiles = effectiveMediaFiles
.slice(0, processedCount)
.filter((item) => Boolean(mediaInfoByPath[item.path]));
@@ -8178,12 +8180,113 @@ class PipelineService extends EventEmitter {
mediaProfile,
sourceJobId: options.sourceJobId || null,
reviewConfirmed: false,
partial: processedFiles.length < mediaFiles.length,
partial: processedFiles.length < effectiveMediaFiles.length,
processedFiles: processedFiles.length,
totalFiles: mediaFiles.length
totalFiles: effectiveMediaFiles.length
};
};
// For DVD sources, use HandBrake scan directly instead of mediainfo (mediainfo
// is unreliable on VOB files and often returns incomplete track information).
const isDvdSource = rawMedia.source === 'dvd'
|| rawMedia.source === 'dvd_image'
|| rawMedia.source === 'single_extensionless';
let dvdHandBrakeScanJson = null;
let dvdHandBrakeScanInputPath = null;
if (isDvdSource && mediaFiles.length > 0) {
// For 'dvd': scan the folder that contains VIDEO_TS (parent of the VIDEO_TS dir).
// For image/extensionless: scan the file directly.
dvdHandBrakeScanInputPath = rawMedia.source === 'dvd'
? path.dirname(path.dirname(mediaFiles[0].path))
: mediaFiles[0].path;
await historyService.appendLog(
jobId,
'SYSTEM',
`DVD-Analyse via HandBrake Scan: ${path.basename(dvdHandBrakeScanInputPath)}`
);
await this.updateProgress('MEDIAINFO_CHECK', 10, null, 'HandBrake DVD-Scan läuft', jobId);
const dvdScanLines = [];
const dvdScanConfig = await settingsService.buildHandBrakeScanConfigForInput(dvdHandBrakeScanInputPath, {
mediaProfile,
settingsMap: settings
});
logger.info('mediainfo:review:dvd-handbrake-scan:command', {
jobId,
dvdHandBrakeScanInputPath,
cmd: dvdScanConfig.cmd,
args: dvdScanConfig.args
});
const dvdScanRunInfo = await this.runCommand({
jobId,
stage: 'MEDIAINFO_CHECK',
source: 'HANDBRAKE_SCAN_DVD',
cmd: dvdScanConfig.cmd,
args: dvdScanConfig.args,
collectLines: dvdScanLines,
collectStderrLines: false
});
dvdHandBrakeScanJson = parseMediainfoJsonOutput(dvdScanLines.join('\n'));
if (dvdHandBrakeScanJson) {
const titleInfo = parseHandBrakeSelectedTitleInfo(dvdHandBrakeScanJson);
if (titleInfo) {
const syntheticMediaInfo = buildSyntheticMediaInfoFromMakeMkvTitle(titleInfo);
mediaInfoByPath[dvdHandBrakeScanInputPath] = syntheticMediaInfo;
effectiveMediaFiles = [{ path: dvdHandBrakeScanInputPath, size: 0 }];
const audioCount = Array.isArray(titleInfo.audioTracks) ? titleInfo.audioTracks.length : 0;
const subtitleCount = Array.isArray(titleInfo.subtitleTracks) ? titleInfo.subtitleTracks.length : 0;
await historyService.appendLog(
jobId,
'SYSTEM',
`HandBrake DVD-Scan: Audio=${audioCount}, Subtitle=${subtitleCount}, Dauer=${formatDurationClock(titleInfo.durationSeconds)}`
);
} else {
await historyService.appendLog(
jobId,
'SYSTEM',
'HandBrake DVD-Scan: Kein Titel erkannt, falle auf MediaInfo zurück.'
);
dvdHandBrakeScanJson = null;
}
} else {
await historyService.appendLog(
jobId,
'SYSTEM',
'HandBrake DVD-Scan: Ausgabe nicht lesbar, falle auf MediaInfo zurück.'
);
}
mediaInfoRuns.push({ filePath: dvdHandBrakeScanInputPath, runInfo: dvdScanRunInfo, fallbackRunInfo: null });
const partialReview = buildReviewSnapshot(1);
if (this.isPrimaryJob(jobId)) {
await this.setState('MEDIAINFO_CHECK', {
activeJobId: jobId,
progress: 50,
eta: null,
statusText: `HandBrake DVD-Scan abgeschlossen: ${path.basename(dvdHandBrakeScanInputPath)}`,
context: {
jobId,
rawPath,
inputPath: partialReview?.encodeInputPath || null,
hasEncodableTitle: Boolean(partialReview?.encodeInputPath),
reviewConfirmed: false,
mode: options.mode || 'rip',
mediaProfile,
sourceJobId: options.sourceJobId || null,
mediaInfoReview: partialReview,
selectedMetadata
}
});
}
}
// For non-DVD sources (or when HandBrake scan failed), run mediainfo on each file.
if (!isDvdSource || !dvdHandBrakeScanJson) {
for (let i = 0; i < mediaFiles.length; i += 1) {
const file = mediaFiles[i];
const percent = Number((((i + 1) / mediaFiles.length) * 100).toFixed(2));
@@ -8260,9 +8363,10 @@ class PipelineService extends EventEmitter {
});
}
}
}
const review = buildMediainfoReview({
mediaFiles,
mediaFiles: effectiveMediaFiles,
mediaInfoByPath,
settings,
presetProfile,
@@ -8279,8 +8383,8 @@ class PipelineService extends EventEmitter {
sourceJobId: options.sourceJobId || null,
reviewConfirmed: false,
partial: false,
processedFiles: mediaFiles.length,
totalFiles: mediaFiles.length
processedFiles: effectiveMediaFiles.length,
totalFiles: effectiveMediaFiles.length
};
const reviewPrefillResult = applyPreviousSelectionDefaultsToReviewPlan(
enrichedReview,
@@ -8295,7 +8399,10 @@ class PipelineService extends EventEmitter {
|| rawMedia.source === 'dvd_image'
|| rawMedia.source === 'single_extensionless';
if (needsHandBrakeTitleScan) {
const dvdScanInputPath = rawMedia.source === 'dvd' ? rawPath : mediaFiles[0].path;
// Use the same path that was used for the DVD HandBrake scan above, or fall back
// to the existing logic for cases where the scan was not yet performed.
const dvdScanInputPath = dvdHandBrakeScanInputPath
|| (rawMedia.source === 'dvd' ? rawPath : mediaFiles[0].path);
const preSelectedHandBrakeTitleId = normalizeReviewTitleId(options?.selectedHandBrakeTitleId);
if (preSelectedHandBrakeTitleId) {
enrichedReview = {
@@ -8309,6 +8416,10 @@ class PipelineService extends EventEmitter {
`HandBrake Titel-Auswahl (manuell) übernommen: -t ${preSelectedHandBrakeTitleId}`
);
} else {
// Reuse the HandBrake scan result from the DVD analysis step when available,
// otherwise run a fresh scan for title selection.
let dvdTitleScanJson = dvdHandBrakeScanJson || null;
if (!dvdTitleScanJson) {
await historyService.appendLog(
jobId,
'SYSTEM',
@@ -8335,7 +8446,8 @@ class PipelineService extends EventEmitter {
collectLines: dvdTitleScanLines,
collectStderrLines: false
});
const dvdTitleScanJson = parseMediainfoJsonOutput(dvdTitleScanLines.join('\n'));
dvdTitleScanJson = parseMediainfoJsonOutput(dvdTitleScanLines.join('\n'));
}
if (dvdTitleScanJson) {
const allTitles = parseHandBrakeTitleList(dvdTitleScanJson);
const minLengthMinutes = Number(settings?.makemkv_min_length_minutes || 0);
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "ripster-frontend",
"version": "0.10.2-12",
"version": "0.10.2-13",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-frontend",
"version": "0.10.2-12",
"version": "0.10.2-13",
"dependencies": {
"primeicons": "^7.0.0",
"primereact": "^10.9.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ripster-frontend",
"version": "0.10.2-12",
"version": "0.10.2-13",
"private": true,
"type": "module",
"scripts": {
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "ripster",
"version": "0.10.2-12",
"version": "0.10.2-13",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster",
"version": "0.10.2-12",
"version": "0.10.2-13",
"devDependencies": {
"concurrently": "^9.1.2"
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "ripster",
"private": true,
"version": "0.10.2-12",
"version": "0.10.2-13",
"scripts": {
"dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"",
"dev:backend": "npm run dev --prefix backend",