diff --git a/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js b/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js
index 65a36bd39..71fc7a7a0 100644
--- a/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js
+++ b/frontend/src/Settings/Profiles/Metadata/EditMetadataProfileModalContent.js
@@ -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) {
/>
+
+
+ {translate('MinimumPages')}
+
+
+
+
+
{translate('SkipBooksWithMissingReleaseDate')}
@@ -157,6 +177,23 @@ function EditMetadataProfileModalContent(props) {
/>
+
+
+ {translate('MustNotContain')}
+
+
+
+
+
}
diff --git a/src/NzbDrone.Core/Datastore/Migration/008_extend_metadata_profiles.cs b/src/NzbDrone.Core/Datastore/Migration/008_extend_metadata_profiles.cs
new file mode 100644
index 000000000..ab2bd3420
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/008_extend_metadata_profiles.cs
@@ -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();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json
index b36956e24..1f3029113 100644
--- a/src/NzbDrone.Core/Localization/Core/en.json
+++ b/src/NzbDrone.Core/Localization/Core/en.json
@@ -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",
diff --git a/src/NzbDrone.Core/Profiles/Metadata/MetadataProfile.cs b/src/NzbDrone.Core/Profiles/Metadata/MetadataProfile.cs
index de7689d67..2c5fb0537 100644
--- a/src/NzbDrone.Core/Profiles/Metadata/MetadataProfile.cs
+++ b/src/NzbDrone.Core/Profiles/Metadata/MetadataProfile.cs
@@ -11,5 +11,7 @@ namespace NzbDrone.Core.Profiles.Metadata
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; }
}
}
diff --git a/src/NzbDrone.Core/Profiles/Metadata/MetadataProfileService.cs b/src/NzbDrone.Core/Profiles/Metadata/MetadataProfileService.cs
index 4fa3b4997..c121ae16e 100644
--- a/src/NzbDrone.Core/Profiles/Metadata/MetadataProfileService.cs
+++ b/src/NzbDrone.Core/Profiles/Metadata/MetadataProfileService.cs
@@ -9,6 +9,7 @@ using NzbDrone.Core.ImportLists;
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 @@ namespace NzbDrone.Core.Profiles.Metadata
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 @@ namespace NzbDrone.Core.Profiles.Metadata
IMediaFileService mediaFileService,
IImportListFactory importListFactory,
IRootFolderService rootFolderService,
+ ITermMatcherService termMatcherService,
Logger logger)
{
_profileRepository = profileRepository;
@@ -52,6 +55,7 @@ namespace NzbDrone.Core.Profiles.Metadata
_mediaFileService = mediaFileService;
_importListFactory = importListFactory;
_rootFolderService = rootFolderService;
+ _termMatcherService = termMatcherService;
_logger = logger;
}
@@ -129,6 +133,8 @@ namespace NzbDrone.Core.Profiles.Metadata
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 @@ namespace NzbDrone.Core.Profiles.Metadata
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 @@ namespace NzbDrone.Core.Profiles.Metadata
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 @@ namespace NzbDrone.Core.Profiles.Metadata
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 ContainsAny(List terms, string title)
+ {
+ return terms.Where(t => _termMatcherService.IsMatch(t, title)).ToList();
+ }
+
public void Handle(ApplicationStartedEvent message)
{
var profiles = All();
diff --git a/src/Readarr.Api.V1/Profiles/Metadata/MetadataProfileResource.cs b/src/Readarr.Api.V1/Profiles/Metadata/MetadataProfileResource.cs
index 8a3c84249..a5864391e 100644
--- a/src/Readarr.Api.V1/Profiles/Metadata/MetadataProfileResource.cs
+++ b/src/Readarr.Api.V1/Profiles/Metadata/MetadataProfileResource.cs
@@ -14,6 +14,8 @@ namespace Readarr.Api.V1.Profiles.Metadata
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 @@ namespace Readarr.Api.V1.Profiles.Metadata
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 @@ namespace Readarr.Api.V1.Profiles.Metadata
SkipMissingIsbn = resource.SkipMissingIsbn,
SkipPartsAndSets = resource.SkipPartsAndSets,
SkipSeriesSecondary = resource.SkipSeriesSecondary,
- AllowedLanguages = resource.AllowedLanguages
+ AllowedLanguages = resource.AllowedLanguages,
+ MinPages = resource.MinPages,
+ Ignored = resource.Ignored
};
}