New: Bulk manage Maximum Single Episode Age for indexers

This commit is contained in:
Bogdan 2025-03-20 19:47:52 +02:00
parent 76a747a051
commit 0af9e295a5
7 changed files with 47 additions and 1 deletions

View file

@ -17,6 +17,7 @@ interface SavePayload {
enableAutomaticSearch?: boolean;
enableInteractiveSearch?: boolean;
priority?: number;
seasonSearchMaximumSingleEpisodeAge?: number;
}
interface ManageIndexersEditModalContentProps {
@ -59,6 +60,10 @@ function ManageIndexersEditModalContent(
const [enableInteractiveSearch, setEnableInteractiveSearch] =
useState(NO_CHANGE);
const [priority, setPriority] = useState<null | number>(null);
const [
seasonSearchMaximumSingleEpisodeAge,
setSeasonSearchMaximumSingleEpisodeAge,
] = useState<null | number>(null);
const save = useCallback(() => {
let hasChanges = false;
@ -84,6 +89,12 @@ function ManageIndexersEditModalContent(
payload.priority = priority as number;
}
if (seasonSearchMaximumSingleEpisodeAge !== null) {
hasChanges = true;
payload.seasonSearchMaximumSingleEpisodeAge =
seasonSearchMaximumSingleEpisodeAge as number;
}
if (hasChanges) {
onSavePress(payload);
}
@ -94,6 +105,7 @@ function ManageIndexersEditModalContent(
enableAutomaticSearch,
enableInteractiveSearch,
priority,
seasonSearchMaximumSingleEpisodeAge,
onSavePress,
onModalClose,
]);
@ -112,6 +124,9 @@ function ManageIndexersEditModalContent(
case 'priority':
setPriority(value as number);
break;
case 'seasonSearchMaximumSingleEpisodeAge':
setSeasonSearchMaximumSingleEpisodeAge(value as number);
break;
default:
console.warn(`EditIndexersModalContent Unknown Input: '${name}'`);
}
@ -172,6 +187,20 @@ function ManageIndexersEditModalContent(
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('MaximumSingleEpisodeAge')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="seasonSearchMaximumSingleEpisodeAge"
helpText={translate('MaximumSingleEpisodeAgeHelpText')}
value={seasonSearchMaximumSingleEpisodeAge}
min={0}
unit="days"
onChange={onInputChange}
/>
</FormGroup>
</ModalBody>
<ModalFooter className={styles.modalFooter}>

View file

@ -72,6 +72,12 @@ const COLUMNS = [
isSortable: true,
isVisible: true,
},
{
name: 'seasonSearchMaximumSingleEpisodeAge',
label: () => translate('MaximumSingleEpisodeAge'),
isSortable: true,
isVisible: true,
},
{
name: 'tags',
label: () => translate('Tags'),

View file

@ -4,8 +4,9 @@
.enableAutomaticSearch,
.enableInteractiveSearch,
.priority,
.seasonSearchMaximumSingleEpisodeAge,
.implementation {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
word-break: break-all;
}
}

View file

@ -7,6 +7,7 @@ interface CssExports {
'implementation': string;
'name': string;
'priority': string;
'seasonSearchMaximumSingleEpisodeAge': string;
'tags': string;
}
export const cssExports: CssExports;

View file

@ -17,6 +17,7 @@ interface ManageIndexersModalRowProps {
enableAutomaticSearch: boolean;
enableInteractiveSearch: boolean;
priority: number;
seasonSearchMaximumSingleEpisodeAge: number;
implementation: string;
tags: number[];
columns: Column[];
@ -33,6 +34,7 @@ function ManageIndexersModalRow(props: ManageIndexersModalRowProps) {
enableAutomaticSearch,
enableInteractiveSearch,
priority,
seasonSearchMaximumSingleEpisodeAge,
implementation,
tags,
onSelectedChange,
@ -90,6 +92,10 @@ function ManageIndexersModalRow(props: ManageIndexersModalRowProps) {
<TableRowCell className={styles.priority}>{priority}</TableRowCell>
<TableRowCell className={styles.seasonSearchMaximumSingleEpisodeAge}>
{seasonSearchMaximumSingleEpisodeAge}
</TableRowCell>
<TableRowCell className={styles.tags}>
<SeriesTagList tags={tags} />
</TableRowCell>

View file

@ -9,6 +9,7 @@ namespace Sonarr.Api.V3.Indexers
public bool? EnableAutomaticSearch { get; set; }
public bool? EnableInteractiveSearch { get; set; }
public int? Priority { get; set; }
public int? SeasonSearchMaximumSingleEpisodeAge { get; set; }
}
public class IndexerBulkResourceMapper : ProviderBulkResourceMapper<IndexerBulkResource, IndexerDefinition>
@ -26,6 +27,7 @@ namespace Sonarr.Api.V3.Indexers
existing.EnableAutomaticSearch = resource.EnableAutomaticSearch ?? existing.EnableAutomaticSearch;
existing.EnableInteractiveSearch = resource.EnableInteractiveSearch ?? existing.EnableInteractiveSearch;
existing.Priority = resource.Priority ?? existing.Priority;
existing.SeasonSearchMaximumSingleEpisodeAge = resource.SeasonSearchMaximumSingleEpisodeAge ?? existing.SeasonSearchMaximumSingleEpisodeAge;
});
return existingDefinitions;

View file

@ -18,6 +18,7 @@ namespace Sonarr.Api.V3.Indexers
: base(signalRBroadcaster, indexerFactory, "indexer", ResourceMapper, BulkResourceMapper)
{
SharedValidator.RuleFor(c => c.Priority).InclusiveBetween(1, 50);
SharedValidator.RuleFor(c => c.SeasonSearchMaximumSingleEpisodeAge).GreaterThanOrEqualTo(0);
SharedValidator.RuleFor(c => c.DownloadClientId).SetValidator(downloadClientExistsValidator);
}
}