diff --git a/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js b/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js index ce05e49b..c00b5252 100644 --- a/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js +++ b/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js @@ -17,6 +17,51 @@ import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; import styles from './EditMetadataProfileModalContent.css'; +// Each option is a combination of the existing skipMissingIsbn/skipMissingAsin flags. The backend +// keeps an edition when: neither flag -> always; isbn only -> ISBN or ASIN; asin only -> ASIN; +// both -> ISBN and ASIN. Requiring ISBN alone has no flag combination, so it isn't offered. +const identifierRequirementFlags = { + none: { skipMissingIsbn: false, skipMissingAsin: false }, + missingBoth: { skipMissingIsbn: true, skipMissingAsin: false }, + missingEither: { skipMissingIsbn: true, skipMissingAsin: true }, + missingAsin: { skipMissingIsbn: false, skipMissingAsin: true } +}; + +const identifierRequirementOptions = [ + { + key: 'none', + get value() { + return translate('SkipMissingIdentifierNone'); + } + }, + { + key: 'missingBoth', + get value() { + return translate('SkipMissingIdentifierMissingBoth'); + } + }, + { + key: 'missingEither', + get value() { + return translate('SkipMissingIdentifierMissingEither'); + } + }, + { + key: 'missingAsin', + get value() { + return translate('SkipMissingIdentifierMissingAsin'); + } + } +]; + +function getIdentifierRequirement(skipMissingIsbn, skipMissingAsin) { + if (skipMissingIsbn) { + return skipMissingAsin ? 'missingEither' : 'missingBoth'; + } + + return skipMissingAsin ? 'missingAsin' : 'none'; +} + function fieldWithDefault(field, value) { return field ?? { value, @@ -76,6 +121,17 @@ function EditMetadataProfileModalContent(props) { const labelSuffix = isAudiobook ? 'Audiobook' : 'Book'; const deleteDisabledTooltip = translate('IsInUseCantDeleteAMetadataProfileThatIsAttachedToAnAuthorImportListOrRootFolder'); + const identifierRequirement = getIdentifierRequirement(skipMissingIsbnField.value, skipMissingAsinField.value); + const identifierRequirementErrors = [...skipMissingIsbnField.errors, ...skipMissingAsinField.errors]; + const identifierRequirementWarnings = [...skipMissingIsbnField.warnings, ...skipMissingAsinField.warnings]; + + const onIdentifierRequirementChange = ({ value }) => { + const flags = identifierRequirementFlags[value] ?? identifierRequirementFlags.none; + + onInputChange({ name: 'skipMissingIsbn', value: flags.skipMissingIsbn }); + onInputChange({ name: 'skipMissingAsin', value: flags.skipMissingAsin }); + }; + return ( @@ -162,25 +218,14 @@ function EditMetadataProfileModalContent(props) { - - - - - {translate(`SkipMissingAsin${labelSuffix}`)} - - - diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 12c5600a..b2c84db3 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -1902,18 +1902,18 @@ "Skip": "Skip", "SkipFreeSpaceCheck": "Skip Free Space Check", "SkipFreeSpaceCheckWhenImportingHelpText": "Use when Chaptarr is unable to detect free space from your author root folder", - "SkipMissingAsinAudiobook": "Skip audiobooks missing ASIN", - "SkipMissingAsinAudiobookHelpText": "Requires ASIN. Best for well-known, well-published authors where complete metadata is expected.", - "SkipMissingAsinBook": "Skip books missing ASIN", - "SkipMissingAsinBookHelpText": "Requires ASIN. Best for well-known, well-published authors where complete metadata is expected.", "SkipMissingDateAudiobook": "Skip audiobooks with missing release date", "SkipMissingDateAudiobookHelpText": "Hides audiobooks with no release date in metadata. They will appear once providers add a date on the next author refresh.", "SkipMissingDateBook": "Skip books with missing release date", "SkipMissingDateBookHelpText": "Hides books with no release date in metadata. They will appear once providers add a date on the next author refresh.", "SkipMissingIdentifierAudiobook": "Skip audiobooks missing identifier", - "SkipMissingIdentifierAudiobookHelpText": "Filters out audiobooks without any identifier (ISBN or ASIN). Quick way to remove low-quality metadata entries.", + "SkipMissingIdentifierAudiobookHelpText": "Which identifiers an audiobook edition needs to be kept. Editions you have files for or added manually are never skipped.", "SkipMissingIdentifierBook": "Skip books missing identifier", - "SkipMissingIdentifierBookHelpText": "Filters out books without any identifier (ISBN or ASIN). Quick way to remove low-quality metadata entries.", + "SkipMissingIdentifierBookHelpText": "Which identifiers a book edition needs to be kept. Editions you have files for or added manually are never skipped.", + "SkipMissingIdentifierMissingAsin": "Skip if missing ASIN", + "SkipMissingIdentifierMissingBoth": "Skip if missing both ISBN and ASIN (Require either)", + "SkipMissingIdentifierMissingEither": "Skip if missing either ISBN or ASIN (Require both)", + "SkipMissingIdentifierNone": "Don't skip", "SkipMissingIdentifierOmnibusAudiobook": "Skip omnibus/collection audiobooks without identifiers", "SkipMissingIdentifierOmnibusAudiobookHelpText": "Removes omnibus/collection audiobooks only when no edition has an ASIN or ISBN.", "SkipMissingIdentifierOmnibusBook": "Skip omnibus/collection books without identifiers",