0.9.1-5 Minor fixes

This commit is contained in:
2026-03-14 10:06:59 +00:00
parent c3875803ff
commit 6378a9a4cb
9 changed files with 155 additions and 40 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "ripster-frontend",
"version": "0.9.1-4",
"version": "0.9.1-5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-frontend",
"version": "0.9.1-4",
"version": "0.9.1-5",
"dependencies": {
"primeicons": "^7.0.0",
"primereact": "^10.9.2",

View File

@@ -1,6 +1,6 @@
{
"name": "ripster-frontend",
"version": "0.9.1-4",
"version": "0.9.1-5",
"private": true,
"type": "module",
"scripts": {

View File

@@ -532,6 +532,84 @@ function resolveAudioEncoderPreviewLabel(track, encoderToken, copyMask, fallback
return `Transcode (${normalizedToken})`;
}
function parseAudioSelectorFromArgs(extraArgsString, baseSelector) {
const base = baseSelector && typeof baseSelector === 'object' ? baseSelector : {};
const args = String(extraArgsString || '').trim();
if (!args) {
return base;
}
// Tokenize: split on whitespace but respect quoted strings
const tokens = [];
let current = '';
let inQuote = null;
for (let i = 0; i < args.length; i++) {
const ch = args[i];
if (inQuote) {
if (ch === inQuote) {
inQuote = null;
} else {
current += ch;
}
} else if (ch === '"' || ch === "'") {
inQuote = ch;
} else if (ch === ' ' || ch === '\t') {
if (current) {
tokens.push(current);
current = '';
}
} else {
current += ch;
}
}
if (current) {
tokens.push(current);
}
const result = { ...base };
const getNext = (i) => (i + 1 < tokens.length ? tokens[i + 1] : null);
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
// Support both --flag=value and --flag value
const eqIdx = token.indexOf('=');
const flag = eqIdx !== -1 ? token.slice(0, eqIdx) : token;
const inlineVal = eqIdx !== -1 ? token.slice(eqIdx + 1) : null;
const getValue = () => {
if (inlineVal !== null) return inlineVal;
const next = getNext(i);
if (next && !next.startsWith('-')) {
i++;
return next;
}
return null;
};
if (flag === '--aencoder') {
const val = getValue();
if (val) {
result.encoders = val.split(',').map((s) => s.trim()).filter(Boolean);
result.encoderSource = 'args';
}
} else if (flag === '--audio-copy-mask') {
const val = getValue();
if (val) {
result.copyMask = val.split(',').map((s) => s.trim()).filter(Boolean);
}
} else if (flag === '--audio-fallback') {
const val = getValue();
if (val) {
result.fallbackEncoder = val.trim();
}
}
}
return result;
}
function buildAudioActionPreviewSummary(track, selectedIndex, audioSelector) {
const selector = audioSelector && typeof audioSelector === 'object' ? audioSelector : {};
const availableEncoders = Array.isArray(selector.encoders) ? selector.encoders : [];
@@ -759,6 +837,9 @@ export default function MediaInfoReviewPanel({
const effectivePresetOverride = selectedUserPreset
? { handbrakePreset: selectedUserPreset.handbrakePreset || '', extraArgs: selectedUserPreset.extraArgs || '' }
: null;
const effectiveAudioSelector = effectivePresetOverride?.extraArgs
? parseAudioSelectorFromArgs(effectivePresetOverride.extraArgs, review?.selectors?.audio)
: (review?.selectors?.audio || null);
const hasUserPresets = normalizedUserPresets.length > 0;
const allowUserPresetSelection = hasUserPresets && typeof onUserPresetChange === 'function' && allowEncodeItemSelection;
@@ -843,10 +924,10 @@ export default function MediaInfoReviewPanel({
<div><strong>Preset-Profil:</strong> {effectivePresetOverride ? 'user-preset' : (review.selectors?.presetProfileSource || '-')}</div>
<div><strong>MIN_LENGTH_MINUTES:</strong> {review.minLengthMinutes}</div>
<div><strong>Encode Input:</strong> {encodeInputTitle?.fileName || '-'}</div>
<div><strong>Audio Auswahl:</strong> {review.selectors?.audio?.mode || '-'}</div>
<div><strong>Audio Encoder:</strong> {(review.selectors?.audio?.encoders || []).join(', ') || 'Preset-Default'}</div>
<div><strong>Audio Copy-Mask:</strong> {(review.selectors?.audio?.copyMask || []).join(', ') || '-'}</div>
<div><strong>Audio Fallback:</strong> {review.selectors?.audio?.fallbackEncoder || '-'}</div>
<div><strong>Audio Auswahl:</strong> {effectiveAudioSelector?.mode || '-'}</div>
<div><strong>Audio Encoder:</strong> {(effectiveAudioSelector?.encoders || []).join(', ') || 'Preset-Default'}</div>
<div><strong>Audio Copy-Mask:</strong> {(effectiveAudioSelector?.copyMask || []).join(', ') || '-'}</div>
<div><strong>Audio Fallback:</strong> {effectiveAudioSelector?.fallbackEncoder || '-'}</div>
<div><strong>Subtitle Auswahl:</strong> {review.selectors?.subtitle?.mode || '-'}</div>
<div><strong>Subtitle Flags:</strong> {review.selectors?.subtitle?.forcedOnly ? 'forced-only' : '-'}{review.selectors?.subtitle?.burnBehavior === 'first' ? ' + burned(first)' : ''}</div>
</div>
@@ -1206,7 +1287,7 @@ export default function MediaInfoReviewPanel({
type="audio"
allowSelection={allowTrackSelectionForTitle}
selectedTrackIds={selectedAudioTrackIds}
audioSelector={review?.selectors?.audio || null}
audioSelector={effectiveAudioSelector}
onToggleTrack={(trackId, checked) => {
if (!allowTrackSelectionForTitle || typeof onTrackSelectionChange !== 'function') {
return;

View File

@@ -667,7 +667,7 @@ export default function HistoryPage() {
const confirmDeleteEntry = async (target) => {
const normalizedTarget = String(target || '').trim().toLowerCase();
if (!['raw', 'movie', 'both'].includes(normalizedTarget)) {
if (!['raw', 'movie', 'both', 'none'].includes(normalizedTarget)) {
return;
}
const jobId = Number(deleteEntryDialogRow?.id || 0);
@@ -686,10 +686,13 @@ export default function HistoryPage() {
const rawDirs = Number(fileSummary?.raw?.dirsRemoved || 0);
const movieDirs = Number(fileSummary?.movie?.dirsRemoved || 0);
const detail = normalizedTarget === 'none'
? `${deletedJobIds.length || 1} Eintrag/Einträge entfernt (Dateien bleiben erhalten)`
: `${deletedJobIds.length || 1} Eintrag/Einträge entfernt | RAW: ${rawFiles} Dateien, ${rawDirs} Ordner | ${deleteEntryOutputShortLabel}: ${movieFiles} Dateien, ${movieDirs} Ordner`;
toastRef.current?.show({
severity: 'success',
summary: 'Historie gelöscht',
detail: `${deletedJobIds.length || 1} Eintrag/Einträge entfernt | RAW: ${rawFiles} Dateien, ${rawDirs} Ordner | ${deleteEntryOutputShortLabel}: ${movieFiles} Dateien, ${movieDirs} Ordner`,
detail,
life: 5000
});
@@ -1124,36 +1127,46 @@ export default function HistoryPage() {
<div>
<h4>{`RAW (${previewRawExisting.length}/${previewRawPaths.length})`}</h4>
{previewRawPaths.length > 0 ? (
<ul className="history-delete-preview-list">
{previewRawPaths.map((item) => (
<li key={`delete-raw-${item.path}`}>
<span className={item.exists ? 'exists-yes' : 'exists-no'}>
{item.exists ? 'vorhanden' : 'nicht gefunden'}
</span>
{' '}| {item.path}
</li>
))}
</ul>
) : (
{previewRawPaths.length > 0 ? (() => {
const display = previewRawPaths.filter(p => p.exists).length > 0
? previewRawPaths.filter(p => p.exists)
: previewRawPaths.slice(0, 1);
return (
<ul className="history-delete-preview-list">
{display.map((item) => (
<li key={`delete-raw-${item.path}`}>
<span className={item.exists ? 'exists-yes' : 'exists-no'}>
{item.exists ? 'vorhanden' : 'nicht gefunden'}
</span>
{' '}| {item.path}
</li>
))}
</ul>
);
})() : (
<small className="history-dv-subtle">Keine RAW-Pfade.</small>
)}
</div>
<div>
<h4>{`${deleteEntryOutputShortLabel} (${previewMovieExisting.length}/${previewMoviePaths.length})`}</h4>
{previewMoviePaths.length > 0 ? (
<ul className="history-delete-preview-list">
{previewMoviePaths.map((item) => (
<li key={`delete-movie-${item.path}`}>
<span className={item.exists ? 'exists-yes' : 'exists-no'}>
{item.exists ? 'vorhanden' : 'nicht gefunden'}
</span>
{' '}| {item.path}
</li>
))}
</ul>
) : (
{previewMoviePaths.length > 0 ? (() => {
const display = previewMoviePaths.filter(p => p.exists).length > 0
? previewMoviePaths.filter(p => p.exists)
: previewMoviePaths.slice(0, 1);
return (
<ul className="history-delete-preview-list">
{display.map((item) => (
<li key={`delete-movie-${item.path}`}>
<span className={item.exists ? 'exists-yes' : 'exists-no'}>
{item.exists ? 'vorhanden' : 'nicht gefunden'}
</span>
{' '}| {item.path}
</li>
))}
</ul>
);
})() : (
<small className="history-dv-subtle">Keine Movie-Pfade.</small>
)}
</div>
@@ -1187,6 +1200,15 @@ export default function HistoryPage() {
loading={deleteEntryTargetBusy === 'both'}
disabled={deleteTargetActionsDisabled}
/>
<Button
label="Nur Eintrag löschen"
icon="pi pi-database"
severity="secondary"
outlined
onClick={() => confirmDeleteEntry('none')}
loading={deleteEntryTargetBusy === 'none'}
disabled={deleteTargetActionsDisabled}
/>
<Button
label="Abbrechen"
severity="secondary"