New: Minimum Age setting to deal with propagation issues (Usenet only)
This commit is contained in:
parent
eeafa2cb64
commit
580f03a5bc
|
@ -9,6 +9,12 @@ namespace NzbDrone.Api.Config
|
|||
public IndexerConfigModule(IConfigService configService)
|
||||
: base(configService)
|
||||
{
|
||||
SharedValidator.RuleFor(c => c.MinimumAge)
|
||||
.GreaterThan(0);
|
||||
|
||||
SharedValidator.RuleFor(c => c.Retention)
|
||||
.GreaterThanOrEqualTo(0);
|
||||
|
||||
SharedValidator.RuleFor(c => c.RssSyncInterval)
|
||||
.InclusiveBetween(10, 120)
|
||||
.When(c => c.RssSyncInterval > 0);
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace NzbDrone.Api.Config
|
|||
{
|
||||
public class IndexerConfigResource : RestResource
|
||||
{
|
||||
public Int32 MinimumAge { get; set; }
|
||||
public Int32 Retention { get; set; }
|
||||
public Int32 RssSyncInterval { get; set; }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class MinimumAgeSpecificationFixture : CoreTest<MinimumAgeSpecification>
|
||||
{
|
||||
private RemoteEpisode _remoteEpisode;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_remoteEpisode = new RemoteEpisode
|
||||
{
|
||||
Release = new ReleaseInfo() { DownloadProtocol = DownloadProtocol.Usenet }
|
||||
};
|
||||
}
|
||||
|
||||
private void WithMinimumAge(int minutes)
|
||||
{
|
||||
Mocker.GetMock<IConfigService>().SetupGet(c => c.MinimumAge).Returns(minutes);
|
||||
}
|
||||
|
||||
private void WithAge(int minutes)
|
||||
{
|
||||
_remoteEpisode.Release.PublishDate = DateTime.UtcNow.AddMinutes(-minutes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_minimum_age_is_set_to_zero()
|
||||
{
|
||||
WithMinimumAge(0);
|
||||
WithAge(100);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_age_is_greater_than_minimum_age()
|
||||
{
|
||||
WithMinimumAge(30);
|
||||
WithAge(100);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_when_age_is_less_than_minimum_age()
|
||||
{
|
||||
WithMinimumAge(30);
|
||||
WithAge(10);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
public class RetentionSpecificationFixture : CoreTest<RetentionSpecification>
|
||||
{
|
||||
|
||||
private RemoteEpisode _remoteEpisode;
|
||||
|
||||
[SetUp]
|
||||
|
@ -32,7 +31,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
private void WithAge(int days)
|
||||
{
|
||||
_remoteEpisode.Release.PublishDate = DateTime.Now.AddDays(-days);
|
||||
_remoteEpisode.Release.PublishDate = DateTime.UtcNow.AddDays(-days);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -136,6 +136,7 @@
|
|||
<Compile Include="DecisionEngineTests\PrioritizeDownloadDecisionFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\QualityAllowedByProfileSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\QualityUpgradeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\MinimumAgeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RetentionSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RssSync\DelaySpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
|
||||
|
|
|
@ -108,6 +108,13 @@ namespace NzbDrone.Core.Configuration
|
|||
set { SetValue("RssSyncInterval", value); }
|
||||
}
|
||||
|
||||
public int MinimumAge
|
||||
{
|
||||
get { return GetValueInt("MinimumAge", 0); }
|
||||
|
||||
set { SetValue("MinimumAge", value); }
|
||||
}
|
||||
|
||||
public Boolean AutoDownloadPropers
|
||||
{
|
||||
get { return GetValueBoolean("AutoDownloadPropers", true); }
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace NzbDrone.Core.Configuration
|
|||
//Indexers
|
||||
Int32 Retention { get; set; }
|
||||
Int32 RssSyncInterval { get; set; }
|
||||
Int32 MinimumAge { get; set; }
|
||||
|
||||
//UI
|
||||
Int32 FirstDayOfWeek { get; set; }
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
using NLog;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class MinimumAgeSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MinimumAgeSpecification(IConfigService configService, Logger logger)
|
||||
{
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public RejectionType Type { get { return RejectionType.Temporary; } }
|
||||
|
||||
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
if (subject.Release.DownloadProtocol != Indexers.DownloadProtocol.Usenet)
|
||||
{
|
||||
_logger.Debug("Not checking minimum age requirement for non-usenet report");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var age = subject.Release.AgeMinutes;
|
||||
var minimumAge = _configService.MinimumAge;
|
||||
|
||||
_logger.Debug("Checking if report meets minimum age requirements. {0}", age);
|
||||
|
||||
if (minimumAge > 0 && age < minimumAge)
|
||||
{
|
||||
_logger.Debug("Only {0} minutes old, minimum age is {1} minutes", age, minimumAge);
|
||||
return Decision.Reject("Only {0} minutes old, minimum age is {1} minutes", age, minimumAge);
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
@ -36,6 +37,7 @@ namespace NzbDrone.Core.Download.Pending
|
|||
private readonly ISeriesService _seriesService;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IDelayProfileService _delayProfileService;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
|
@ -43,6 +45,7 @@ namespace NzbDrone.Core.Download.Pending
|
|||
ISeriesService seriesService,
|
||||
IParsingService parsingService,
|
||||
IDelayProfileService delayProfileService,
|
||||
IConfigService configService,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
{
|
||||
|
@ -50,6 +53,7 @@ namespace NzbDrone.Core.Download.Pending
|
|||
_seriesService = seriesService;
|
||||
_parsingService = parsingService;
|
||||
_delayProfileService = delayProfileService;
|
||||
_configService = configService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
@ -202,8 +206,10 @@ namespace NzbDrone.Core.Download.Pending
|
|||
private int GetDelay(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
var delayProfile = _delayProfileService.AllForTags(remoteEpisode.Series.Tags).OrderBy(d => d.Order).First();
|
||||
var delay = delayProfile.GetProtocolDelay(remoteEpisode.Release.DownloadProtocol);
|
||||
var minimumAge = _configService.MinimumAge;
|
||||
|
||||
return delayProfile.GetProtocolDelay(remoteEpisode.Release.DownloadProtocol);
|
||||
return new [] { delay, minimumAge }.Max();
|
||||
}
|
||||
|
||||
private void RemoveGrabbed(RemoteEpisode remoteEpisode)
|
||||
|
|
|
@ -268,6 +268,7 @@
|
|||
<Compile Include="DecisionEngine\Specifications\ReleaseRestrictionsSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\NotSampleSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\QualityAllowedByProfileSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\MinimumAgeSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RetentionSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RetrySpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RssSync\DelaySpecification.cs" />
|
||||
|
|
|
@ -18,7 +18,7 @@ define(
|
|||
//If the release is pending we want to use the timeleft as the time it will be processed at
|
||||
if (this.cellValue.get('status').toLowerCase() === 'pending') {
|
||||
this.$el.html('-');
|
||||
this.$el.attr('title', 'Will be processed {0}'.format(moment(this.cellValue.get('estimatedCompletionTime')).calendar()));
|
||||
this.$el.attr('title', 'Will be processed during the first RSS Sync after {0}'.format(moment(this.cellValue.get('estimatedCompletionTime')).calendar()));
|
||||
this.$el.attr('data-container', 'body');
|
||||
|
||||
return this;
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
<fieldset>
|
||||
<legend>Options</legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Minimum Age</label>
|
||||
|
||||
<div class="col-sm-1 col-sm-push-2 help-inline">
|
||||
<i class="icon-nd-form-info" title="Usenet only: Reports that do not meet minimum age will not be grabbed, until they do"/>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2 col-sm-pull-1">
|
||||
<input type="number" min="0" name="minimumAge" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Retention</label>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="col-sm-1 col-sm-push-2 help-inline">
|
||||
<i class="icon-nd-form-info" title="Usenet only: Set to zero to set to unlimited"/>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2 col-sm-pull-1">
|
||||
<input type="number" min="0" name="retention" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue