mirror of
https://github.com/Readarr/Readarr
synced 2025-12-10 02:15:16 +01:00
New: Add min pages and ignored terms to metadata profiles
This commit is contained in:
parent
23142a59d7
commit
00e4555736
6 changed files with 91 additions and 4 deletions
|
|
@ -15,6 +15,9 @@ import { inputTypes, kinds } from 'Helpers/Props';
|
|||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditMetadataProfileModalContent.css';
|
||||
|
||||
// Tab, enter, and comma
|
||||
const tagInputDelimiters = [9, 13, 188];
|
||||
|
||||
function EditMetadataProfileModalContent(props) {
|
||||
const {
|
||||
isFetching,
|
||||
|
|
@ -38,7 +41,9 @@ function EditMetadataProfileModalContent(props) {
|
|||
skipMissingIsbn,
|
||||
skipPartsAndSets,
|
||||
skipSeriesSecondary,
|
||||
allowedLanguages
|
||||
allowedLanguages,
|
||||
ignored,
|
||||
minPages
|
||||
} = item;
|
||||
|
||||
return (
|
||||
|
|
@ -92,6 +97,21 @@ function EditMetadataProfileModalContent(props) {
|
|||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('MinimumPages')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="minPages"
|
||||
{...minPages}
|
||||
helpText={translate('MinPagesHelpText')}
|
||||
min={0}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('SkipBooksWithMissingReleaseDate')}
|
||||
|
|
@ -157,6 +177,23 @@ function EditMetadataProfileModalContent(props) {
|
|||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
{translate('MustNotContain')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT_TAG}
|
||||
name="ignored"
|
||||
helpText={translate('IgnoredHelpText')}
|
||||
kind={kinds.DANGER}
|
||||
placeholder={translate('IgnoredPlaceHolder')}
|
||||
delimiters={tagInputDelimiters}
|
||||
{...ignored}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
</Form>
|
||||
}
|
||||
</ModalBody>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(008)]
|
||||
public class extend_metadata_profiles : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("MetadataProfiles").AddColumn("MinPages").AsInt32().NotNullable().WithDefaultValue(0);
|
||||
Alter.Table("MetadataProfiles").AddColumn("Ignored").AsString().Nullable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -349,6 +349,8 @@
|
|||
"MinimumFreeSpace": "Minimum Free Space",
|
||||
"MinimumFreeSpaceWhenImportingHelpText": "Prevent import if it would leave less than this amount of disk space available",
|
||||
"MinimumLimits": "Minimum Limits",
|
||||
"MinimumPages": "Minimum Pages",
|
||||
"MinPagesHelpText": "Ignore books with fewer pages than this",
|
||||
"MinimumPopularity": "Minimum Popularity",
|
||||
"Missing": "Missing",
|
||||
"MissingBooks": "Missing Books",
|
||||
|
|
|
|||
|
|
@ -11,5 +11,7 @@ public class MetadataProfile : ModelBase
|
|||
public bool SkipPartsAndSets { get; set; }
|
||||
public bool SkipSeriesSecondary { get; set; }
|
||||
public string AllowedLanguages { get; set; }
|
||||
public int MinPages { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Metadata
|
||||
|
|
@ -36,6 +37,7 @@ public class MetadataProfileService : IMetadataProfileService, IHandle<Applicati
|
|||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IImportListFactory _importListFactory;
|
||||
private readonly IRootFolderService _rootFolderService;
|
||||
private readonly ITermMatcherService _termMatcherService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MetadataProfileService(IMetadataProfileRepository profileRepository,
|
||||
|
|
@ -44,6 +46,7 @@ public MetadataProfileService(IMetadataProfileRepository profileRepository,
|
|||
IMediaFileService mediaFileService,
|
||||
IImportListFactory importListFactory,
|
||||
IRootFolderService rootFolderService,
|
||||
ITermMatcherService termMatcherService,
|
||||
Logger logger)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
|
|
@ -52,6 +55,7 @@ public MetadataProfileService(IMetadataProfileRepository profileRepository,
|
|||
_mediaFileService = mediaFileService;
|
||||
_importListFactory = importListFactory;
|
||||
_rootFolderService = rootFolderService;
|
||||
_termMatcherService = termMatcherService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
|
@ -129,6 +133,8 @@ private List<Book> FilterBooks(IEnumerable<Book> remoteBooks, List<Book> localBo
|
|||
FilterByPredicate(hash, x => x.ForeignBookId, localHash, profile, (x, p) => !p.SkipMissingDate || x.ReleaseDate.HasValue, "release date is missing");
|
||||
FilterByPredicate(hash, x => x.ForeignBookId, localHash, profile, (x, p) => !p.SkipPartsAndSets || !IsPartOrSet(x, seriesLinks.GetValueOrDefault(x), titles), "book is part of set");
|
||||
FilterByPredicate(hash, x => x.ForeignBookId, localHash, profile, (x, p) => !p.SkipSeriesSecondary || !seriesLinks.ContainsKey(x) || seriesLinks[x].Any(y => y.IsPrimary), "book is a secondary series item");
|
||||
FilterByPredicate(hash, x => x.ForeignBookId, localHash, profile, (x, p) => x.Editions.Value.Any(e => e.PageCount > p.MinPages) || x.Editions.Value.All(e => e.PageCount == 0), "minimum page count not met");
|
||||
FilterByPredicate(hash, x => x.ForeignBookId, localHash, profile, (x, p) => !MatchesTerms(x.Title, p.Ignored), "contains ignored terms");
|
||||
|
||||
foreach (var book in hash)
|
||||
{
|
||||
|
|
@ -137,7 +143,7 @@ private List<Book> FilterBooks(IEnumerable<Book> remoteBooks, List<Book> localBo
|
|||
book.Editions = FilterEditions(book.Editions.Value, localEditions, localFiles, profile);
|
||||
}
|
||||
|
||||
FilterByPredicate(hash, x => x.ForeignBookId, localHash, profile, (x, p) => x.Editions.Value.Any(), "all editions filterd out");
|
||||
FilterByPredicate(hash, x => x.ForeignBookId, localHash, profile, (x, p) => x.Editions.Value.Any(), "all editions filtered out");
|
||||
|
||||
return hash.ToList();
|
||||
}
|
||||
|
|
@ -153,6 +159,7 @@ private List<Edition> FilterEditions(IEnumerable<Edition> editions, List<Edition
|
|||
|
||||
FilterByPredicate(hash, x => x.ForeignEditionId, localHash, profile, (x, p) => !allowedLanguages.Any() || allowedLanguages.Contains(x.Language?.ToLower() ?? "null"), "edition language not allowed");
|
||||
FilterByPredicate(hash, x => x.ForeignEditionId, localHash, profile, (x, p) => !p.SkipMissingIsbn || x.Isbn13.IsNotNullOrWhiteSpace() || x.Asin.IsNotNullOrWhiteSpace(), "isbn and asin is missing");
|
||||
FilterByPredicate(hash, x => x.ForeignEditionId, localHash, profile, (x, p) => !MatchesTerms(x.Title, p.Ignored), "contains ignored terms");
|
||||
|
||||
return hash.ToList();
|
||||
}
|
||||
|
|
@ -195,6 +202,24 @@ private bool IsPartOrSet(Book book, List<SeriesBookLink> seriesLinks, HashSet<st
|
|||
return false;
|
||||
}
|
||||
|
||||
private bool MatchesTerms(string value, string terms)
|
||||
{
|
||||
if (terms.IsNullOrWhiteSpace() || value.IsNullOrWhiteSpace())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var split = terms.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
var foundTerms = ContainsAny(split, value);
|
||||
|
||||
return foundTerms.Any();
|
||||
}
|
||||
|
||||
private List<string> ContainsAny(List<string> terms, string title)
|
||||
{
|
||||
return terms.Where(t => _termMatcherService.IsMatch(t, title)).ToList();
|
||||
}
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
var profiles = All();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ public class MetadataProfileResource : RestResource
|
|||
public bool SkipPartsAndSets { get; set; }
|
||||
public bool SkipSeriesSecondary { get; set; }
|
||||
public string AllowedLanguages { get; set; }
|
||||
public int MinPages { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
}
|
||||
|
||||
public static class MetadataProfileResourceMapper
|
||||
|
|
@ -34,7 +36,9 @@ public static MetadataProfileResource ToResource(this MetadataProfile model)
|
|||
SkipMissingIsbn = model.SkipMissingIsbn,
|
||||
SkipPartsAndSets = model.SkipPartsAndSets,
|
||||
SkipSeriesSecondary = model.SkipSeriesSecondary,
|
||||
AllowedLanguages = model.AllowedLanguages
|
||||
AllowedLanguages = model.AllowedLanguages,
|
||||
MinPages = model.MinPages,
|
||||
Ignored = model.Ignored
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +58,9 @@ public static MetadataProfile ToModel(this MetadataProfileResource resource)
|
|||
SkipMissingIsbn = resource.SkipMissingIsbn,
|
||||
SkipPartsAndSets = resource.SkipPartsAndSets,
|
||||
SkipSeriesSecondary = resource.SkipSeriesSecondary,
|
||||
AllowedLanguages = resource.AllowedLanguages
|
||||
AllowedLanguages = resource.AllowedLanguages,
|
||||
MinPages = resource.MinPages,
|
||||
Ignored = resource.Ignored
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue