diff --git a/frontend/src/Settings/Indexers/Options/IndexerOptions.js b/frontend/src/Settings/Indexers/Options/IndexerOptions.js index 0a39ec7b7..d47a3ca3c 100644 --- a/frontend/src/Settings/Indexers/Options/IndexerOptions.js +++ b/frontend/src/Settings/Indexers/Options/IndexerOptions.js @@ -47,6 +47,18 @@ function IndexerOptions(props) { /> + + Maximum Size + + + + Retention diff --git a/src/Lidarr.Api.V1/Config/IndexerConfigModule.cs b/src/Lidarr.Api.V1/Config/IndexerConfigModule.cs index a58e5546d..5b21994fb 100644 --- a/src/Lidarr.Api.V1/Config/IndexerConfigModule.cs +++ b/src/Lidarr.Api.V1/Config/IndexerConfigModule.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Core.Configuration; using Lidarr.Http.Validation; @@ -13,6 +13,9 @@ namespace Lidarr.Api.V1.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 Lidarr.Api.V1.Config return IndexerConfigResourceMapper.ToResource(model); } } -} \ No newline at end of file +} diff --git a/src/Lidarr.Api.V1/Config/IndexerConfigResource.cs b/src/Lidarr.Api.V1/Config/IndexerConfigResource.cs index a5f1f92fb..f354dac64 100644 --- a/src/Lidarr.Api.V1/Config/IndexerConfigResource.cs +++ b/src/Lidarr.Api.V1/Config/IndexerConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Core.Configuration; +using NzbDrone.Core.Configuration; using Lidarr.Http.REST; namespace Lidarr.Api.V1.Config @@ -6,6 +6,7 @@ namespace Lidarr.Api.V1.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; } } @@ -17,6 +18,7 @@ namespace Lidarr.Api.V1.Config return new IndexerConfigResource { MinimumAge = model.MinimumAge, + MaximumSize = model.MaximumSize, Retention = model.Retention, RssSyncInterval = model.RssSyncInterval, }; diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/MaximumSizeSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/MaximumSizeSpecificationFixture.cs new file mode 100644 index 000000000..d3a1ef88e --- /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 RemoteAlbum _remoteAlbum; + + [SetUp] + public void Setup() + { + _remoteAlbum = new RemoteAlbum() { Release = new ReleaseInfo() }; + } + + private void WithMaximumSize(int size) + { + Mocker.GetMock().SetupGet(c => c.MaximumSize).Returns(size); + } + + private void WithSize(int size) + { + _remoteAlbum.Release.Size = size * 1024 * 1024; + } + + [Test] + public void should_return_true_when_maximum_size_is_set_to_zero() + { + WithMaximumSize(0); + WithSize(1000); + + Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_when_size_is_smaller_than_maximum_size() + { + WithMaximumSize(2000); + WithSize(1999); + + Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_when_size_is_equals_to_maximum_size() + { + WithMaximumSize(2000); + WithSize(2000); + + Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_false_when_size_is_bigger_than_maximum_size() + { + WithMaximumSize(2000); + WithSize(2001); + + Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_return_true_when_size_is_zero() + { + WithMaximumSize(2000); + WithSize(0); + + Subject.IsSatisfiedBy(_remoteAlbum, 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 23c3cb702..2e9e550cb 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -118,6 +118,7 @@ + diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 83817a5d2..c18898c38 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -99,6 +99,13 @@ namespace NzbDrone.Core.Configuration set { SetValue("RssSyncInterval", value); } } + public int MaximumSize + { + get { return GetValueInt("MaximumSize", 0);} + + set { SetValue("MaximumSize", value);} + } + public int MinimumAge { get { return GetValueInt("MinimumAge", 0); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index ff39ae96f..2f3d03594 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -43,6 +43,7 @@ namespace NzbDrone.Core.Configuration //Indexers int Retention { get; set; } int RssSyncInterval { get; set; } + int MaximumSize { get; set; } int MinimumAge { get; set; } //UI diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/MaximumSizeSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/MaximumSizeSpecification.cs new file mode 100644 index 000000000..04f12ece0 --- /dev/null +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/MaximumSizeSpecification.cs @@ -0,0 +1,53 @@ +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 SpecificationPriority Priority => SpecificationPriority.Default; + public RejectionType Type => RejectionType.Permanent; + + public Decision IsSatisfiedBy(RemoteAlbum 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 (subject.Release.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 cf5ea55f5..92f3f7471 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -212,6 +212,7 @@ +