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 @@
+