This commit is contained in:
Steel City Phantom 2026-05-05 17:03:34 +01:00 committed by GitHub
commit cb18445255
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 100 additions and 4 deletions

View file

@ -78,6 +78,7 @@ function EditImportListModalContent({
qualityProfileId, qualityProfileId,
searchOnAdd, searchOnAdd,
tags, tags,
tagExisting,
fields, fields,
} = item; } = item;
@ -256,6 +257,18 @@ function EditImportListModalContent({
/> />
</FormGroup> </FormGroup>
<FormGroup>
<FormLabel>{translate('TagExisting')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="tagExisting"
helpText={translate('TagExistingHelpText')}
{...tagExisting}
onChange={handleInputChange}
/>
</FormGroup>
{fields?.length ? ( {fields?.length ? (
<div> <div>
{fields.map((field) => { {fields.map((field) => {

View file

@ -18,6 +18,7 @@ interface SavePayload {
qualityProfileId?: number; qualityProfileId?: number;
minimumAvailability?: string; minimumAvailability?: string;
rootFolderPath?: string; rootFolderPath?: string;
tagExisting?: boolean;
} }
interface ManageImportListsEditModalContentProps { interface ManageImportListsEditModalContentProps {
@ -62,7 +63,7 @@ function ManageImportListsEditModalContent(
); );
const [minimumAvailability, setMinimumAvailability] = useState(NO_CHANGE); const [minimumAvailability, setMinimumAvailability] = useState(NO_CHANGE);
const [rootFolderPath, setRootFolderPath] = useState(NO_CHANGE); const [rootFolderPath, setRootFolderPath] = useState(NO_CHANGE);
const [tagExisting, setTagExisting] = useState(NO_CHANGE);
const save = useCallback(() => { const save = useCallback(() => {
let hasChanges = false; let hasChanges = false;
const payload: SavePayload = {}; const payload: SavePayload = {};
@ -91,6 +92,10 @@ function ManageImportListsEditModalContent(
hasChanges = true; hasChanges = true;
payload.rootFolderPath = rootFolderPath; payload.rootFolderPath = rootFolderPath;
} }
if (tagExisting !== NO_CHANGE) {
hasChanges = true;
payload.tagExisting = tagExisting === 'enabled';
}
if (hasChanges) { if (hasChanges) {
onSavePress(payload); onSavePress(payload);
@ -103,6 +108,7 @@ function ManageImportListsEditModalContent(
qualityProfileId, qualityProfileId,
minimumAvailability, minimumAvailability,
rootFolderPath, rootFolderPath,
tagExisting,
onSavePress, onSavePress,
onModalClose, onModalClose,
]); ]);
@ -124,6 +130,9 @@ function ManageImportListsEditModalContent(
case 'rootFolderPath': case 'rootFolderPath':
setRootFolderPath(value as string); setRootFolderPath(value as string);
break; break;
case 'tagExisting':
setTagExisting(value as string);
break;
default: default:
console.warn(`EditImportListModalContent Unknown Input: '${name}'`); console.warn(`EditImportListModalContent Unknown Input: '${name}'`);
} }
@ -199,6 +208,18 @@ function ManageImportListsEditModalContent(
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup>
<FormLabel>{translate('TagExisting')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="tagExisting"
value={tagExisting}
values={enableOptions}
onChange={onInputChange}
/>
</FormGroup>
</ModalBody> </ModalBody>
<ModalFooter className={styles.modalFooter}> <ModalFooter className={styles.modalFooter}>

View file

@ -82,6 +82,12 @@ const COLUMNS = [
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{
name: 'tagExisting',
label: () => translate('TagExisting'),
isSortable: true,
isVisible: true,
},
]; ];
interface ManageImportListsModalContentProps { interface ManageImportListsModalContentProps {

View file

@ -5,6 +5,7 @@
.minimumAvailability, .minimumAvailability,
.qualityProfileId, .qualityProfileId,
.rootFolderPath, .rootFolderPath,
.tagExisting,
.implementation { .implementation {
composes: cell from '~Components/Table/Cells/TableRowCell.css'; composes: cell from '~Components/Table/Cells/TableRowCell.css';

View file

@ -8,6 +8,7 @@ interface CssExports {
'name': string; 'name': string;
'qualityProfileId': string; 'qualityProfileId': string;
'rootFolderPath': string; 'rootFolderPath': string;
'tagExisting': string;
'tags': string; 'tags': string;
} }
export const cssExports: CssExports; export const cssExports: CssExports;

View file

@ -19,6 +19,7 @@ interface ManageImportListsModalRowProps {
minimumAvailability: string; minimumAvailability: string;
implementation: string; implementation: string;
tags: number[]; tags: number[];
tagExisting: boolean;
enabled: boolean; enabled: boolean;
enableAuto: boolean; enableAuto: boolean;
columns: Column[]; columns: Column[];
@ -38,6 +39,7 @@ function ManageImportListsModalRow(props: ManageImportListsModalRowProps) {
enabled, enabled,
enableAuto, enableAuto,
tags, tags,
tagExisting,
onSelectedChange, onSelectedChange,
} = props; } = props;
@ -91,6 +93,10 @@ function ManageImportListsModalRow(props: ManageImportListsModalRowProps) {
<TableRowCell className={styles.tags}> <TableRowCell className={styles.tags}>
<MovieTagList tags={tags} /> <MovieTagList tags={tags} />
</TableRowCell> </TableRowCell>
<TableRowCell className={styles.tagExisting}>
{tagExisting ? translate('Yes') : translate('No')}
</TableRowCell>
</TableRow> </TableRow>
); );
} }

View file

@ -15,6 +15,7 @@ interface ImportList extends Provider {
minRefreshInterval: string; minRefreshInterval: string;
name: string; name: string;
tags: number[]; tags: number[];
tagExisting: boolean;
} }
export default ImportList; export default ImportList;

View file

@ -0,0 +1,13 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration;
[Migration(243)]
public class add_tag_existing_to_importlists : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("ImportLists").AddColumn("TagExisting").AsBoolean().WithDefaultValue(false);
}
}

View file

@ -16,6 +16,7 @@ public class ImportListDefinition : ProviderDefinition, IEquatable<ImportListDef
public int QualityProfileId { get; set; } public int QualityProfileId { get; set; }
public string RootFolderPath { get; set; } public string RootFolderPath { get; set; }
public bool SearchOnAdd { get; set; } public bool SearchOnAdd { get; set; }
public bool TagExisting { get; set; }
[MemberwiseEqualityIgnore] [MemberwiseEqualityIgnore]
public override bool Enable => Enabled; public override bool Enable => Enabled;

View file

@ -76,18 +76,25 @@ private void SyncList(ImportListDefinition definition)
private void ProcessMovieReport(ImportListDefinition importList, ImportListMovie report, List<ImportListExclusion> listExclusions, List<int> dbMovies, List<Movie> moviesToAdd) private void ProcessMovieReport(ImportListDefinition importList, ImportListMovie report, List<ImportListExclusion> listExclusions, List<int> dbMovies, List<Movie> moviesToAdd)
{ {
if (report.TmdbId == 0 || !importList.EnableAuto) if (report.TmdbId == 0)
{ {
return; return;
} }
// Check to see if movie in DB // Check to see if movie in DB and maybe apply tags
if (dbMovies.Contains(report.TmdbId)) if (dbMovies.Contains(report.TmdbId))
{ {
TagExisting(importList, report);
_logger.Debug("{0} [{1}] Rejected, Movie Exists in DB", report.TmdbId, report.Title); _logger.Debug("{0} [{1}] Rejected, Movie Exists in DB", report.TmdbId, report.Title);
return; return;
} }
// Now that retro-tags are applied, end if auto import is disabled
if (!importList.EnableAuto)
{
return;
}
// Check to see if movie excluded // Check to see if movie excluded
var excludedMovie = listExclusions.SingleOrDefault(s => s.TmdbId == report.TmdbId); var excludedMovie = listExclusions.SingleOrDefault(s => s.TmdbId == report.TmdbId);
@ -123,6 +130,26 @@ private void ProcessMovieReport(ImportListDefinition importList, ImportListMovie
} }
} }
private void TagExisting(ImportListDefinition importList, ImportListMovie report)
{
if (importList.TagExisting)
{
var movie = _movieService.FindByTmdbId(report.TmdbId);
var preCount = movie.Tags.Count;
foreach (var tag in importList.Tags)
{
movie.Tags.Add(tag);
}
if (preCount != movie.Tags.Count)
{
_movieService.UpdateMovie(movie);
_logger.Debug("{0} [{1}] Tagged existing movie", report.TmdbId, report.Title);
}
}
}
private void ProcessListItems(ImportListFetchResult listFetchResult) private void ProcessListItems(ImportListFetchResult listFetchResult)
{ {
listFetchResult.Movies = listFetchResult.Movies.DistinctBy(x => listFetchResult.Movies = listFetchResult.Movies.DistinctBy(x =>

View file

@ -1697,6 +1697,8 @@
"Result": "Result", "Result": "Result",
"Retention": "Retention", "Retention": "Retention",
"RetentionHelpText": "Usenet only: Set to zero to set for unlimited retention", "RetentionHelpText": "Usenet only: Set to zero to set for unlimited retention",
"TagExistingHelpText": "Tag existing movies in {appName}",
"TagExisting": "Tag Existing",
"RetryingDownloadOn": "Retrying download on {date} at {time}", "RetryingDownloadOn": "Retrying download on {date} at {time}",
"RootFolder": "Root Folder", "RootFolder": "Root Folder",
"RootFolderCheckMultipleMessage": "Multiple root folders are missing: {rootFolderPaths}", "RootFolderCheckMultipleMessage": "Multiple root folders are missing: {rootFolderPaths}",

View file

@ -11,6 +11,7 @@ public class ImportListBulkResource : ProviderBulkResource<ImportListBulkResourc
public string RootFolderPath { get; set; } public string RootFolderPath { get; set; }
public int? QualityProfileId { get; set; } public int? QualityProfileId { get; set; }
public MovieStatusType? MinimumAvailability { get; set; } public MovieStatusType? MinimumAvailability { get; set; }
public bool? TagExisting { get; set; }
} }
public class ImportListBulkResourceMapper : ProviderBulkResourceMapper<ImportListBulkResource, ImportListDefinition> public class ImportListBulkResourceMapper : ProviderBulkResourceMapper<ImportListBulkResource, ImportListDefinition>
@ -29,6 +30,7 @@ public override List<ImportListDefinition> UpdateModel(ImportListBulkResource re
existing.RootFolderPath = resource.RootFolderPath ?? existing.RootFolderPath; existing.RootFolderPath = resource.RootFolderPath ?? existing.RootFolderPath;
existing.QualityProfileId = resource.QualityProfileId ?? existing.QualityProfileId; existing.QualityProfileId = resource.QualityProfileId ?? existing.QualityProfileId;
existing.MinimumAvailability = resource.MinimumAvailability ?? existing.MinimumAvailability; existing.MinimumAvailability = resource.MinimumAvailability ?? existing.MinimumAvailability;
existing.TagExisting = resource.TagExisting ?? existing.TagExisting;
}); });
return existingDefinitions; return existingDefinitions;

View file

@ -16,6 +16,7 @@ public class ImportListResource : ProviderResource<ImportListResource>
public ImportListType ListType { get; set; } public ImportListType ListType { get; set; }
public int ListOrder { get; set; } public int ListOrder { get; set; }
public TimeSpan MinRefreshInterval { get; set; } public TimeSpan MinRefreshInterval { get; set; }
public bool TagExisting { get; set; }
} }
public class ImportListResourceMapper : ProviderResourceMapper<ImportListResource, ImportListDefinition> public class ImportListResourceMapper : ProviderResourceMapper<ImportListResource, ImportListDefinition>
@ -39,6 +40,7 @@ public override ImportListResource ToResource(ImportListDefinition definition)
resource.ListType = definition.ListType; resource.ListType = definition.ListType;
resource.ListOrder = (int)definition.ListType; resource.ListOrder = (int)definition.ListType;
resource.MinRefreshInterval = definition.MinRefreshInterval; resource.MinRefreshInterval = definition.MinRefreshInterval;
resource.TagExisting = definition.TagExisting;
return resource; return resource;
} }
@ -61,6 +63,7 @@ public override ImportListDefinition ToModel(ImportListResource resource, Import
definition.MinimumAvailability = resource.MinimumAvailability; definition.MinimumAvailability = resource.MinimumAvailability;
definition.ListType = resource.ListType; definition.ListType = resource.ListType;
definition.MinRefreshInterval = resource.MinRefreshInterval; definition.MinRefreshInterval = resource.MinRefreshInterval;
definition.TagExisting = resource.TagExisting;
return definition; return definition;
} }

View file

@ -16,7 +16,6 @@ public class ProviderResource<T> : RestResource
public string InfoLink { get; set; } public string InfoLink { get; set; }
public ProviderMessage Message { get; set; } public ProviderMessage Message { get; set; }
public HashSet<int> Tags { get; set; } public HashSet<int> Tags { get; set; }
public List<T> Presets { get; set; } public List<T> Presets { get; set; }
} }