diff --git a/src/NzbDrone.Api/Config/IndexerConfigModule.cs b/src/NzbDrone.Api/Config/IndexerConfigModule.cs index 73c2442b8..db5299944 100644 --- a/src/NzbDrone.Api/Config/IndexerConfigModule.cs +++ b/src/NzbDrone.Api/Config/IndexerConfigModule.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Api.Validation; using NzbDrone.Core.Configuration; @@ -13,6 +13,9 @@ namespace NzbDrone.Api.Config SharedValidator.RuleFor(c => c.MinimumAge) .GreaterThanOrEqualTo(0); + SharedValidator.RuleFor(c => c.MaximumSize) + .GreaterThanOrEqualTo(0); + SharedValidator.RuleFor(c => c.Retention) .GreaterThanOrEqualTo(0); @@ -25,4 +28,4 @@ namespace NzbDrone.Api.Config return IndexerConfigResourceMapper.ToResource(model); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Config/IndexerConfigResource.cs b/src/NzbDrone.Api/Config/IndexerConfigResource.cs index 884e2e839..bdcfbfd9c 100644 --- a/src/NzbDrone.Api/Config/IndexerConfigResource.cs +++ b/src/NzbDrone.Api/Config/IndexerConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using NzbDrone.Api.REST; using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; @@ -7,6 +7,7 @@ namespace NzbDrone.Api.Config public class IndexerConfigResource : RestResource { public int MinimumAge { get; set; } + public int MaximumSize { get; set; } public int Retention { get; set; } public int RssSyncInterval { get; set; } public bool PreferIndexerFlags { get; set; } @@ -23,6 +24,7 @@ namespace NzbDrone.Api.Config return new IndexerConfigResource { MinimumAge = model.MinimumAge, + MaximumSize = model.MaximumSize, Retention = model.Retention, RssSyncInterval = model.RssSyncInterval, PreferIndexerFlags = model.PreferIndexerFlags, diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/MaximumSizeSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/MaximumSizeSpecificationFixture.cs new file mode 100644 index 000000000..85dc33f92 --- /dev/null +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/MaximumSizeSpecificationFixture.cs @@ -0,0 +1,75 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.DecisionEngine.Specifications; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.DecisionEngineTests +{ + public class MaximumSizeSpecificationFixture : CoreTest + { + private RemoteMovie _remoteMovie; + + [SetUp] + public void Setup() + { + _remoteMovie = new RemoteMovie { Release = new ReleaseInfo() }; + } + + private void WithMaximumSize(int size) + { + Mocker.GetMock().SetupGet(c => c.MaximumSize).Returns(size); + } + + private void WithSize(int size) + { + _remoteMovie.Release.Size = size * 1024 * 1024; + } + + [Test] + public void should_return_true_when_maximum_size_is_set_to_zero() + { + WithMaximumSize(0); + WithSize(1000); + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_when_size_is_smaller_than_maximum_size() + { + WithMaximumSize(2000); + WithSize(1999); + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_when_size_is_equals_to_maximum_size() + { + WithMaximumSize(2000); + WithSize(2000); + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_false_when_size_is_bigger_than_maximum_size() + { + WithMaximumSize(2000); + WithSize(2001); + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_return_true_when_size_is_zero() + { + WithMaximumSize(2000); + WithSize(0); + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); + } + } +} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index fdf73fc16..7f815a3d9 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -138,6 +138,7 @@ + diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 06344c73f..9b1ca4820 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -106,11 +106,11 @@ namespace NzbDrone.Core.Configuration set { SetValue("RssSyncInterval", value); } } - public int AvailabilityDelay - { - get { return GetValueInt("AvailabilityDelay",0); } - set { SetValue("AvailabilityDelay", value); } - } + public int AvailabilityDelay + { + get { return GetValueInt("AvailabilityDelay", 0); } + set { SetValue("AvailabilityDelay", value); } + } public int NetImportSyncInterval { @@ -118,57 +118,64 @@ namespace NzbDrone.Core.Configuration set { SetValue("NetImportSyncInterval", value); } } - + public string TraktAuthToken - { + { get { return GetValue("TraktAuthToken", string.Empty); } set { SetValue("TraktAuthToken", value); } - } - - public string TraktRefreshToken - { - get { return GetValue("TraktRefreshToken", string.Empty); } - - set {SetValue("TraktRefreshToken", value); } - } - - public int TraktTokenExpiry - { - get { return GetValueInt("TraktTokenExpiry", 0); } - - set { SetValue("TraktTokenExpiry", value); } - } - - public string NewTraktAuthToken - { - get {return GetValue("NewTraktAuthToken", string.Empty); } - set { SetValue("NewTraktAuthToken", value); } - } - - public string NewTraktRefreshToken - { - get {return GetValue("NewTraktRefreshToken", string.Empty); } - set { SetValue("NewTraktRefreshToken", value); } - } - - public int NewTraktTokenExpiry - { - get {return GetValueInt("NewTraktTokenExpiry", 0); } - set { SetValue("NewTraktTokenExpiry", value); } - } - - public string ListSyncLevel - { - get { return GetValue("ListSyncLevel", "disabled"); } - set { SetValue("ListSyncLevel", value); } - } - - public string ImportExclusions - { - get { return GetValue("ImportExclusions", string.Empty); } - set { SetValue("ImportExclusions", value); } - } + } + + public string TraktRefreshToken + { + get { return GetValue("TraktRefreshToken", string.Empty); } + + set { SetValue("TraktRefreshToken", value); } + } + + public int TraktTokenExpiry + { + get { return GetValueInt("TraktTokenExpiry", 0); } + + set { SetValue("TraktTokenExpiry", value); } + } + + public string NewTraktAuthToken + { + get { return GetValue("NewTraktAuthToken", string.Empty); } + set { SetValue("NewTraktAuthToken", value); } + } + + public string NewTraktRefreshToken + { + get { return GetValue("NewTraktRefreshToken", string.Empty); } + set { SetValue("NewTraktRefreshToken", value); } + } + + public int NewTraktTokenExpiry + { + get { return GetValueInt("NewTraktTokenExpiry", 0); } + set { SetValue("NewTraktTokenExpiry", value); } + } + + public string ListSyncLevel + { + get { return GetValue("ListSyncLevel", "disabled"); } + set { SetValue("ListSyncLevel", value); } + } + + public string ImportExclusions + { + get { return GetValue("ImportExclusions", string.Empty); } + set { SetValue("ImportExclusions", value); } + } + + public int MaximumSize + { + get { return GetValueInt("MaximumSize", 0); } + + set { SetValue("MaximumSize", value); } + } public int MinimumAge { @@ -195,22 +202,22 @@ namespace NzbDrone.Core.Configuration { get { return GetValueBoolean("PreferIndexerFlags", false); } - set {SetValue("PreferIndexerFlags", value);} + set { SetValue("PreferIndexerFlags", value); } } - public bool AllowHardcodedSubs - { - get { return GetValueBoolean("AllowHardcodedSubs", false); } + public bool AllowHardcodedSubs + { + get { return GetValueBoolean("AllowHardcodedSubs", false); } - set { SetValue("AllowHardcodedSubs", value); } - } + set { SetValue("AllowHardcodedSubs", value); } + } - public string WhitelistedHardcodedSubs - { - get { return GetValue("WhitelistedHardcodedSubs", ""); } + public string WhitelistedHardcodedSubs + { + get { return GetValue("WhitelistedHardcodedSubs", ""); } - set { SetValue("WhitelistedHardcodedSubs", value); } - } + set { SetValue("WhitelistedHardcodedSubs", value); } + } public ParsingLeniencyType ParsingLeniency { diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 3e0b67e56..790a1a56a 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -48,6 +48,7 @@ namespace NzbDrone.Core.Configuration //Indexers int Retention { get; set; } int RssSyncInterval { get; set; } + int MaximumSize { get; set; } int MinimumAge { get; set; } bool PreferIndexerFlags { get; set; } diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/MaximumSizeSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/MaximumSizeSpecification.cs new file mode 100644 index 000000000..602bece64 --- /dev/null +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/MaximumSizeSpecification.cs @@ -0,0 +1,52 @@ +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.DecisionEngine.Specifications +{ + public class MaximumSizeSpecification : IDecisionEngineSpecification + { + private readonly IConfigService _configService; + private readonly Logger _logger; + + public MaximumSizeSpecification(IConfigService configService, Logger logger) + { + _configService = configService; + _logger = logger; + } + + public RejectionType Type => RejectionType.Permanent; + + public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria) + { + var size = subject.Release.Size; + var maximumSize = _configService.MaximumSize.Megabytes(); + + if (maximumSize == 0) + { + _logger.Debug("Maximum size is not set."); + return Decision.Accept(); + } + + if (size == 0) + { + _logger.Debug("Release has unknown size, skipping size check."); + return Decision.Accept(); + } + + _logger.Debug("Checking if release meets maximum size requirements. {0}", size.SizeSuffix()); + + if (size > maximumSize) + { + var message = $"{size.SizeSuffix()} is too big, maximum size is {maximumSize.SizeSuffix()}"; + + _logger.Debug(message); + return Decision.Reject(message); + } + + return Decision.Accept(); + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 6ae70e38b..9a851d1a2 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -128,6 +128,7 @@ + diff --git a/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs b/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs index b43975d1a..0bfbd4a0b 100644 --- a/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs +++ b/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs @@ -25,6 +25,18 @@ +
+ + +
+ +
+ +
+ +
+
+