diff --git a/backend/package-lock.json b/backend/package-lock.json
index faaaebf..415a963 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ripster-backend",
- "version": "0.10.2-23",
+ "version": "0.10.2-24",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-backend",
- "version": "0.10.2-23",
+ "version": "0.10.2-24",
"dependencies": {
"archiver": "^7.0.1",
"cors": "^2.8.5",
diff --git a/backend/package.json b/backend/package.json
index ecb9926..a01519e 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "ripster-backend",
- "version": "0.10.2-23",
+ "version": "0.10.2-24",
"private": true,
"type": "commonjs",
"scripts": {
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 8751001..e673bde 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ripster-frontend",
- "version": "0.10.2-23",
+ "version": "0.10.2-24",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-frontend",
- "version": "0.10.2-23",
+ "version": "0.10.2-24",
"dependencies": {
"primeicons": "^7.0.0",
"primereact": "^10.9.2",
diff --git a/frontend/package.json b/frontend/package.json
index e14d713..97abdb9 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "ripster-frontend",
- "version": "0.10.2-23",
+ "version": "0.10.2-24",
"private": true,
"type": "module",
"scripts": {
diff --git a/frontend/src/components/JobDetailDialog.jsx b/frontend/src/components/JobDetailDialog.jsx
index 804d5ce..44eb040 100644
--- a/frontend/src/components/JobDetailDialog.jsx
+++ b/frontend/src/components/JobDetailDialog.jsx
@@ -2,7 +2,6 @@ import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { Dialog } from 'primereact/dialog';
import { Button } from 'primereact/button';
-import MediaInfoReviewPanel from './MediaInfoReviewPanel';
import blurayIndicatorIcon from '../assets/media-bluray.svg';
import discIndicatorIcon from '../assets/media-disc.svg';
import otherIndicatorIcon from '../assets/media-other.svg';
@@ -118,6 +117,55 @@ function shellQuote(value) {
return `'${raw.replace(/'/g, `'"'"'`)}'`;
}
+function trackLang(value) {
+ const raw = String(value || '').trim().toLowerCase();
+ if (!raw) return 'und';
+ const map = { en: 'en', eng: 'en', de: 'de', deu: 'de', ger: 'de', tr: 'tr', tur: 'tr', fr: 'fr', fra: 'fr', fre: 'fr', es: 'es', spa: 'es', it: 'it', ita: 'it' };
+ if (map[raw]) return map[raw];
+ return raw.length >= 2 ? raw.slice(0, 2) : raw;
+}
+
+function trackCodec(type, value, hint = null) {
+ const raw = String(value || '').trim();
+ const merged = `${raw} ${String(hint || '')}`.toLowerCase();
+ if (!raw) return '-';
+ if (type === 'subtitle') return merged.includes('pgs') ? 'PGS' : raw.toUpperCase();
+ if (merged.includes('dts-hd ma') || merged.includes('dts hd ma')) return 'DTS-HD MA';
+ if (merged.includes('dts-hd')) return 'DTS-HD';
+ if (merged.includes('dts') || merged.includes('dca')) return 'DTS';
+ if (merged.includes('truehd')) return 'TRUEHD';
+ if (merged.includes('e-ac-3') || merged.includes('eac3') || merged.includes('dd+')) return 'E-AC-3';
+ if (merged.includes('ac-3') || merged.includes('ac3') || merged.includes('dolby digital')) return 'AC-3';
+ return raw.toUpperCase();
+}
+
+function trackChLayout(rawValue) {
+ const raw = String(rawValue || '').trim().toLowerCase();
+ if (!raw) return null;
+ if (raw.includes('7.1')) return '8ch | Surround 7.1';
+ if (raw.includes('5.1')) return '6ch | Surround 5.1';
+ if (raw.includes('stereo') || raw.includes('2.0') || raw.includes('downmix')) return '2ch | Stereo';
+ if (raw.includes('mono') || raw.includes('1.0')) return '1ch | Mono';
+ const nMatch = raw.match(/^([\d.]+)$/);
+ if (nMatch) {
+ const n = Number(nMatch[1]);
+ if (Number.isFinite(n) && n > 0) return `${Math.trunc(n)}ch`;
+ }
+ const chMatch = raw.match(/(\d+)\s*ch/);
+ if (chMatch) return `${chMatch[1]}ch`;
+ return null;
+}
+
+function trackSizeFormat(bytes) {
+ const value = Number(bytes || 0);
+ if (!Number.isFinite(value) || value <= 0) return '-';
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
+ let size = value;
+ let i = 0;
+ while (size >= 1024 && i < units.length - 1) { size /= 1024; i++; }
+ return `${size.toFixed(2)} ${units[i]}`;
+}
+
function buildExecutedHandBrakeCommand(handbrakeInfo) {
const cmd = String(handbrakeInfo?.cmd || '').trim();
const args = Array.isArray(handbrakeInfo?.args) ? handbrakeInfo.args : [];
@@ -546,35 +594,9 @@ export default function JobDetailDialog({
|| configuredSelection.postScriptIds.length > 0
|| configuredSelection.preChainIds.length > 0
|| configuredSelection.postChainIds.length > 0;
- const reviewPreEncodeItems = [
- ...configuredSelection.preScriptIds.map((id) => ({ type: 'script', id })),
- ...configuredSelection.preChainIds.map((id) => ({ type: 'chain', id }))
- ];
- const reviewPostEncodeItems = [
- ...configuredSelection.postScriptIds.map((id) => ({ type: 'script', id })),
- ...configuredSelection.postChainIds.map((id) => ({ type: 'chain', id }))
- ];
const encodePlanUserPreset = job?.encodePlan?.userPreset && typeof job.encodePlan.userPreset === 'object'
? job.encodePlan.userPreset
: null;
- const encodePlanUserPresetId = Number(encodePlanUserPreset?.id);
- const reviewUserPresets = encodePlanUserPreset ? [encodePlanUserPreset] : [];
- const encodePlanManualTrackSelection = job?.encodePlan?.manualTrackSelection
- && typeof job.encodePlan.manualTrackSelection === 'object'
- ? job.encodePlan.manualTrackSelection
- : null;
- const reviewTrackSelectionByTitle = encodePlanManualTrackSelection?.titleId != null
- ? {
- [encodePlanManualTrackSelection.titleId]: {
- audioTrackIds: Array.isArray(encodePlanManualTrackSelection.audioTrackIds)
- ? encodePlanManualTrackSelection.audioTrackIds
- : [],
- subtitleTrackIds: Array.isArray(encodePlanManualTrackSelection.subtitleTrackIds)
- ? encodePlanManualTrackSelection.subtitleTrackIds
- : []
- }
- }
- : {};
const reviewSelectedEncodeTitleId = job?.encodePlan?.encodeInputTitleId ?? null;
const executedHandBrakeCommand = buildExecutedHandBrakeCommand(job?.handbrakeInfo);
const canDownloadRaw = Boolean(job?.raw_path && job?.rawStatus?.exists && typeof onDownloadArchive === 'function');
@@ -851,25 +873,67 @@ export default function JobDetailDialog({
) : null}
- {/* Titel-Liste */}
- {!isCd && !isAudiobook && job.encodePlan ? (
- Spurauswahl
-