0.13.1-7 Fix Series

This commit is contained in:
2026-04-14 13:28:03 +00:00
parent 9297a84eea
commit c89a93ed05
17 changed files with 174 additions and 63 deletions
+60 -25
View File
@@ -64,6 +64,20 @@ function normalizeDrivePath(value) {
return String(value || '').trim();
}
function getPathBaseName(value) {
const normalized = String(value || '').trim().replace(/[\\]+/g, '/');
if (!normalized) {
return '';
}
const segments = normalized.split('/').filter(Boolean);
return segments[segments.length - 1] || '';
}
function isIncompleteRawPath(rawPath) {
const baseName = getPathBaseName(rawPath);
return /^incomplete_/i.test(baseName);
}
function formatPercent(value, digits = 1) {
const parsed = Number(value);
if (!Number.isFinite(parsed)) {
@@ -1643,27 +1657,7 @@ export default function RipperPage({
latestCancelledJob = await fetchLatestCancelledJob();
}
}
const latestStatus = String(
latestCancelledJob?.status
|| latestCancelledJob?.last_state
|| ''
).trim().toUpperCase();
const autoPreparedForRestart = cancelledState === 'ENCODING' && latestStatus === 'READY_TO_ENCODE';
if (cancelledState === 'ENCODING' && cancelledJobId && !autoPreparedForRestart) {
setCancelCleanupDialog({
visible: true,
jobId: cancelledJobId,
target: 'movie',
path: latestCancelledJob?.output_path || cancelledJob?.output_path || null
});
} else if (cancelledState === 'RIPPING' && cancelledJobId) {
setCancelCleanupDialog({
visible: true,
jobId: cancelledJobId,
target: 'raw',
path: latestCancelledJob?.raw_path || cancelledJob?.raw_path || null
});
}
// No post-cancel cleanup dialog here; encode/rip cleanup is handled by settings or retry flows.
} catch (error) {
showError(error);
} finally {
@@ -1939,13 +1933,20 @@ export default function RipperPage({
return;
}
const job = ripperJobs.find((item) => normalizeJobId(item?.id) === normalizedJobId) || null;
const ripSuccessful = Number(job?.rip_successful || 0) === 1;
const deleteIncompleteRaw = !ripSuccessful && isIncompleteRawPath(job?.raw_path);
const deleteTarget = deleteIncompleteRaw ? 'raw' : 'none';
const title = String(job?.title || job?.detected_title || `Job #${normalizedJobId}`).trim();
const confirmed = await confirmModal({
header: 'Job löschen',
message:
`Job #${normalizedJobId} wirklich löschen?\n` +
`${title}\n\n` +
'Hinweis: Dateien bleiben erhalten. Das zugeordnete Laufwerk wird freigegeben und auf Leerzustand zurückgesetzt.',
(deleteIncompleteRaw
? 'Hinweis: Unvollständiges RAW wird gelöscht. Für einen neuen Versuch bitte das Laufwerk erneut analysieren.'
: 'Hinweis: Dateien bleiben erhalten. Vollständiges RAW ist anschließend über /database wiederherstellbar.') +
'\nZugehörige Einträge (z.B. Serien-Container oder Folgejobs) werden ebenfalls entfernt.' +
'\nDas zugeordnete Laufwerk wird freigegeben und auf Leerzustand zurückgesetzt.',
acceptLabel: 'Löschen',
rejectLabel: 'Abbrechen',
danger: true
@@ -1969,8 +1970,8 @@ export default function RipperPage({
await wait(250);
}
}
await api.deleteJobEntry(normalizedJobId, 'none', {
includeRelated: false,
await api.deleteJobEntry(normalizedJobId, deleteTarget, {
includeRelated: true,
resetDriveState: true,
keepDetectedDevice: false
});
@@ -2207,7 +2208,40 @@ export default function RipperPage({
setBusy(true);
try {
if (metadataDialogReassignMode) {
await api.assignJobOmdb(payload.jobId, payload);
const providerRaw = String(payload?.metadataProvider || '').trim().toLowerCase();
const nextWorkflowKind = String(
payload?.workflowKind
|| (providerRaw === 'tmdb' ? 'series' : (providerRaw === 'omdb' ? 'film' : ''))
|| ''
).trim().toLowerCase();
const reassignJob = ripperJobs.find((item) => normalizeJobId(item?.id) === normalizeJobId(payload?.jobId)) || null;
const currentWorkflowKind = String(
reassignJob?.makemkvInfo?.analyzeContext?.selectedMetadata?.workflowKind
|| reassignJob?.makemkvInfo?.analyzeContext?.workflowKind
|| reassignJob?.makemkvInfo?.selectedMetadata?.workflowKind
|| effectiveMetadataDialogContext?.selectedMetadata?.workflowKind
|| ''
).trim().toLowerCase();
const currentProvider = String(
reassignJob?.makemkvInfo?.analyzeContext?.metadataProvider
|| reassignJob?.makemkvInfo?.selectedMetadata?.metadataProvider
|| effectiveMetadataDialogContext?.metadataProvider
|| ''
).trim().toLowerCase();
const shouldRestartReview = Boolean(
nextWorkflowKind
&& currentWorkflowKind
&& nextWorkflowKind !== currentWorkflowKind
) || Boolean(
currentProvider
&& providerRaw
&& currentProvider !== providerRaw
);
if (shouldRestartReview) {
await api.selectMetadata(payload);
} else {
await api.assignJobOmdb(payload.jobId, payload);
}
} else {
await api.selectMetadata(payload);
}
@@ -3051,6 +3085,7 @@ export default function RipperPage({
{!isCdJob && !isAudiobookJob ? (
<PipelineStatusCard
jobId={jobId}
jobRow={job}
pipeline={pipelineForJob}
onAnalyze={handleAnalyze}
onReanalyze={handleReanalyze}