New: Setting for absolute maximum size for a release

Closes #2367 #1996
This commit is contained in:
Marcelo Castagna 2018-01-12 16:50:21 -03:00 committed by Taloth
parent d0e8aef949
commit d25e5fe329
9 changed files with 155 additions and 1 deletions

View File

@ -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);
}
}
}
}

View File

@ -6,6 +6,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; }
}
@ -17,6 +18,7 @@ namespace NzbDrone.Api.Config
return new IndexerConfigResource
{
MinimumAge = model.MinimumAge,
MaximumSize = model.MaximumSize,
Retention = model.Retention,
RssSyncInterval = model.RssSyncInterval,
};

View File

@ -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<MaximumSizeSpecification>
{
private RemoteEpisode _remoteEpisode;
[SetUp]
public void Setup()
{
_remoteEpisode = new RemoteEpisode() { Release = new ReleaseInfo() };
}
private void WithMaximumSize(int size)
{
Mocker.GetMock<IConfigService>().SetupGet(c => c.MaximumSize).Returns(size);
}
private void WithSize(int size)
{
_remoteEpisode.Release.Size = size * 1024 * 1024;
}
[Test]
public void should_return_true_when_maximum_size_is_set_to_zero()
{
WithMaximumSize(0);
WithSize(1000);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_when_size_is_smaller_than_maximum_size()
{
WithMaximumSize(2000);
WithSize(1999);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_when_size_is_equals_to_maximum_size()
{
WithMaximumSize(2000);
WithSize(2000);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_false_when_size_is_bigger_than_maximum_size()
{
WithMaximumSize(2000);
WithSize(2001);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_when_size_is_zero()
{
WithMaximumSize(2000);
WithSize(0);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
}
}

View File

@ -146,6 +146,7 @@
<Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\AnimeVersionUpgradeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\FullSeasonSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\MaximumSizeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\ProtocolSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\CutoffSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\DownloadDecisionMakerFixture.cs" />

View File

@ -106,6 +106,12 @@ 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); }

View File

@ -45,6 +45,7 @@ namespace NzbDrone.Core.Configuration
//Indexers
int Retention { get; set; }
int RssSyncInterval { get; set; }
int MaximumSize { get; set; }
int MinimumAge { get; set; }
//UI

View File

@ -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(RemoteEpisode 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();
}
}
}

View File

@ -332,6 +332,7 @@
<Compile Include="DecisionEngine\Specifications\AnimeVersionUpgradeSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\FullSeasonSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\CutoffSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\MaximumSizeSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\ProtocolSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\LanguageSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\QueueSpecification.cs" />

View File

@ -12,6 +12,18 @@
<input type="number" min="0" name="minimumAge" class="form-control"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Maximum Size</label>
<div class="col-sm-1 col-sm-push-2 help-inline">
<i class="icon-sonarr-form-info" title="Maximum size for a release to be grabbed in MB. Set to zero to set to unlimited"/>
</div>
<div class="col-sm-2 col-sm-pull-1">
<input type="number" min="0" name="maximumSize" class="form-control"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Retention</label>