0.13.0-1 Series Flow
This commit is contained in:
@@ -739,6 +739,21 @@ function resolveSeriesDiscNumber(job) {
|
||||
);
|
||||
}
|
||||
|
||||
function compareSeriesChildJobsByDisc(leftJob, rightJob) {
|
||||
const leftDisc = resolveSeriesDiscNumber(leftJob);
|
||||
const rightDisc = resolveSeriesDiscNumber(rightJob);
|
||||
if (leftDisc !== null && rightDisc !== null && leftDisc !== rightDisc) {
|
||||
return leftDisc - rightDisc;
|
||||
}
|
||||
if (leftDisc !== null && rightDisc === null) {
|
||||
return -1;
|
||||
}
|
||||
if (leftDisc === null && rightDisc !== null) {
|
||||
return 1;
|
||||
}
|
||||
return Number(leftJob?.id || 0) - Number(rightJob?.id || 0);
|
||||
}
|
||||
|
||||
function BoolState({ value }) {
|
||||
const isTrue = Boolean(value);
|
||||
return isTrue ? (
|
||||
@@ -1113,7 +1128,9 @@ export default function JobDetailDialog({
|
||||
const metadataDetails = resolveMetadataDetailsForDisplay(job, omdbInfo);
|
||||
const seriesDiscNumber = isDvdSeries ? resolveSeriesDiscNumber(job) : null;
|
||||
const seriesDiscLabel = seriesDiscNumber ? `Disk ${seriesDiscNumber}` : 'Disk unbekannt';
|
||||
const childJobs = Array.isArray(job?.children) ? job.children : [];
|
||||
const childJobs = Array.isArray(job?.children)
|
||||
? [...job.children].sort(compareSeriesChildJobsByDisc)
|
||||
: [];
|
||||
const isSeriesContainer = isDvdSeries && String(job?.job_kind || '').trim().toLowerCase() === 'dvd_series_container';
|
||||
const seriesChildSummary = job?.seriesChildSummary || null;
|
||||
const seriesBackupSummary = isSeriesContainer ? seriesChildSummary?.backup : null;
|
||||
|
||||
@@ -13,6 +13,17 @@ export default function MetadataSelectionDialog({
|
||||
onSearch,
|
||||
busy
|
||||
}) {
|
||||
const parseDiscNumber = (rawValue) => {
|
||||
const text = String(rawValue ?? '').trim();
|
||||
if (!/^\d+$/.test(text)) {
|
||||
return null;
|
||||
}
|
||||
const parsed = Number(text);
|
||||
if (!Number.isFinite(parsed) || parsed <= 0) {
|
||||
return null;
|
||||
}
|
||||
return Math.trunc(parsed);
|
||||
};
|
||||
const [selected, setSelected] = useState(null);
|
||||
const [query, setQuery] = useState('');
|
||||
const [manualTitle, setManualTitle] = useState('');
|
||||
@@ -23,9 +34,18 @@ export default function MetadataSelectionDialog({
|
||||
const [searchBusy, setSearchBusy] = useState(false);
|
||||
const [searchError, setSearchError] = useState('');
|
||||
const [seasonFilter, setSeasonFilter] = useState('');
|
||||
const [discValidationError, setDiscValidationError] = useState('');
|
||||
const metadataProvider = String(context?.metadataProvider || 'omdb').trim().toLowerCase() || 'omdb';
|
||||
const mediaProfile = String(
|
||||
context?.mediaProfile
|
||||
|| context?.selectedMetadata?.mediaProfile
|
||||
|| ''
|
||||
).trim().toLowerCase();
|
||||
const providerLabel = metadataProvider === 'tmdb' ? 'TMDb' : 'OMDb';
|
||||
const supportsExternalIdInput = metadataProvider === 'omdb';
|
||||
const requiresDiscNumber = metadataProvider === 'tmdb' && (mediaProfile === 'dvd' || !mediaProfile);
|
||||
const effectiveDiscNumber = parseDiscNumber(manualDiscNumber);
|
||||
const hasValidDiscNumber = effectiveDiscNumber !== null;
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible) {
|
||||
@@ -51,8 +71,18 @@ export default function MetadataSelectionDialog({
|
||||
setSearchBusy(false);
|
||||
setSearchError('');
|
||||
setSeasonFilter('');
|
||||
setDiscValidationError('');
|
||||
}, [visible, context]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!discValidationError) {
|
||||
return;
|
||||
}
|
||||
if (!requiresDiscNumber || hasValidDiscNumber) {
|
||||
setDiscValidationError('');
|
||||
}
|
||||
}, [discValidationError, requiresDiscNumber, hasValidDiscNumber]);
|
||||
|
||||
const rows = useMemo(() => {
|
||||
const base = Array.isArray(context?.metadataCandidates)
|
||||
? context.metadataCandidates
|
||||
@@ -136,10 +166,10 @@ export default function MetadataSelectionDialog({
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const parsedDiscNumber = Number(manualDiscNumber);
|
||||
const effectiveDiscNumber = Number.isFinite(parsedDiscNumber) && parsedDiscNumber > 0
|
||||
? Math.trunc(parsedDiscNumber)
|
||||
: null;
|
||||
if (requiresDiscNumber && !hasValidDiscNumber) {
|
||||
setDiscValidationError('Disk-Nummer ist Pflicht und muss eine ganze Zahl >= 1 sein.');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = selected
|
||||
? {
|
||||
@@ -174,11 +204,19 @@ export default function MetadataSelectionDialog({
|
||||
await onSubmit(payload);
|
||||
};
|
||||
|
||||
const handleHideRequest = () => {
|
||||
if (requiresDiscNumber && !hasValidDiscNumber) {
|
||||
setDiscValidationError('Disk-Nummer ist Pflicht und muss eine ganze Zahl >= 1 sein.');
|
||||
return;
|
||||
}
|
||||
onHide?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
header="Metadaten auswählen"
|
||||
visible={visible}
|
||||
onHide={onHide}
|
||||
onHide={handleHideRequest}
|
||||
style={{ width: '52rem', maxWidth: '95vw' }}
|
||||
className="metadata-selection-dialog"
|
||||
breakpoints={{ '1200px': '92vw', '768px': '96vw', '560px': '98vw' }}
|
||||
@@ -211,16 +249,19 @@ export default function MetadataSelectionDialog({
|
||||
<InputText
|
||||
value={manualDiscNumber}
|
||||
onChange={(event) => setManualDiscNumber(event.target.value)}
|
||||
placeholder="Disc-Nr (optional)"
|
||||
placeholder={requiresDiscNumber ? 'Disc-Nr (Pflicht)' : 'Disc-Nr (optional)'}
|
||||
inputMode="numeric"
|
||||
disabled={searchBusy || busy}
|
||||
/>
|
||||
<small className="metadata-filter-subtitle">
|
||||
Optionale Disc-Nummer fuer internes Mapping und Output-Templates. Nur Werte groesser 0 werden gespeichert.
|
||||
{requiresDiscNumber
|
||||
? 'Pflichtfeld fuer Serien-DVDs. Ohne Disk-Nummer koennen die Metadaten nicht verlassen werden.'
|
||||
: 'Optionale Disc-Nummer fuer internes Mapping und Output-Templates. Nur Werte groesser 0 werden gespeichert.'}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{searchError ? <small className="error-text">{searchError}</small> : null}
|
||||
{discValidationError ? <small className="error-text">{discValidationError}</small> : null}
|
||||
|
||||
<div className="table-scroll-wrap table-scroll-medium">
|
||||
<DataTable
|
||||
@@ -271,13 +312,22 @@ export default function MetadataSelectionDialog({
|
||||
</div>
|
||||
|
||||
<div className="dialog-actions">
|
||||
<Button label="Abbrechen" severity="secondary" text onClick={onHide} />
|
||||
<Button
|
||||
label="Abbrechen"
|
||||
severity="secondary"
|
||||
text
|
||||
onClick={handleHideRequest}
|
||||
disabled={requiresDiscNumber && !hasValidDiscNumber}
|
||||
/>
|
||||
<Button
|
||||
label="Auswahl übernehmen"
|
||||
icon="pi pi-play"
|
||||
onClick={handleSubmit}
|
||||
loading={busy}
|
||||
disabled={!selected && !manualTitle.trim() && !manualImdb.trim()}
|
||||
disabled={
|
||||
(!selected && !manualTitle.trim() && !manualImdb.trim())
|
||||
|| (requiresDiscNumber && !hasValidDiscNumber)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
Reference in New Issue
Block a user