New: Option to not prefer repacks/propers (for use with Custom Formats)

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
pull/5003/head
Qstick 4 years ago
parent d31b1e1e9b
commit ecf6dccb35

@ -21,6 +21,12 @@ const rescanAfterRefreshOptions = [
{ key: 'never', value: 'Never' } { key: 'never', value: 'Never' }
]; ];
const downloadPropersAndRepacksOptions = [
{ key: 'preferAndUpgrade', value: 'Prefer and Upgrade' },
{ key: 'doNotUpgrade', value: 'Do not Upgrade Automatically' },
{ key: 'doNotPrefer', value: 'Do not Prefer' }
];
const fileDateOptions = [ const fileDateOptions = [
{ key: 'none', value: 'None' }, { key: 'none', value: 'None' },
{ key: 'cinemas', value: 'In Cinemas Date' }, { key: 'cinemas', value: 'In Cinemas Date' },
@ -230,14 +236,23 @@ class MediaManagement extends Component {
isAdvanced={true} isAdvanced={true}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >
<FormLabel>{translate('DownloadPropers')}</FormLabel> <FormLabel>{translate('DownloadPropersAndRepacks')}</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.SELECT}
name="autoDownloadPropers" name="downloadPropersAndRepacks"
helpText={translate('AutoDownloadPropersHelpText')} helpTexts={[
translate('DownloadPropersAndRepacksHelpText1'),
translate('DownloadPropersAndRepacksHelpText2')
]}
helpTextWarning={
settings.downloadPropersAndRepacks.value === 'doNotPrefer' ?
translate('DownloadPropersAndRepacksHelpTextWarning') :
undefined
}
values={downloadPropersAndRepacksOptions}
onChange={onInputChange} onChange={onInputChange}
{...settings.autoDownloadPropers} {...settings.downloadPropersAndRepacks}
/> />
</FormGroup> </FormGroup>

@ -1,5 +1,6 @@
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Qualities;
using Radarr.Http.REST; using Radarr.Http.REST;
namespace NzbDrone.Api.Config namespace NzbDrone.Api.Config
@ -8,7 +9,7 @@ namespace NzbDrone.Api.Config
{ {
public bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; } public bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; }
public string RecycleBin { get; set; } public string RecycleBin { get; set; }
public bool AutoDownloadPropers { get; set; } public ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
public bool CreateEmptySeriesFolders { get; set; } public bool CreateEmptySeriesFolders { get; set; }
public FileDateType FileDate { get; set; } public FileDateType FileDate { get; set; }
public bool AutoRenameFolders { get; set; } public bool AutoRenameFolders { get; set; }
@ -32,7 +33,7 @@ namespace NzbDrone.Api.Config
{ {
AutoUnmonitorPreviouslyDownloadedEpisodes = model.AutoUnmonitorPreviouslyDownloadedMovies, AutoUnmonitorPreviouslyDownloadedEpisodes = model.AutoUnmonitorPreviouslyDownloadedMovies,
RecycleBin = model.RecycleBin, RecycleBin = model.RecycleBin,
AutoDownloadPropers = model.AutoDownloadPropers, DownloadPropersAndRepacks = model.DownloadPropersAndRepacks,
CreateEmptySeriesFolders = model.CreateEmptyMovieFolders, CreateEmptySeriesFolders = model.CreateEmptyMovieFolders,
FileDate = model.FileDate, FileDate = model.FileDate,
AutoRenameFolders = model.AutoRenameFolders, AutoRenameFolders = model.AutoRenameFolders,

@ -13,7 +13,6 @@ namespace NzbDrone.Api.Profiles
{ {
public string Name { get; set; } public string Name { get; set; }
public Quality Cutoff { get; set; } public Quality Cutoff { get; set; }
public string PreferredTags { get; set; }
public List<ProfileQualityItemResource> Items { get; set; } public List<ProfileQualityItemResource> Items { get; set; }
public int MinFormatScore { get; set; } public int MinFormatScore { get; set; }
public int CutoffFormatScore { get; set; } public int CutoffFormatScore { get; set; }
@ -66,7 +65,6 @@ namespace NzbDrone.Api.Profiles
Id = model.Id, Id = model.Id,
Name = model.Name, Name = model.Name,
PreferredTags = model.PreferredTags != null ? string.Join(",", model.PreferredTags) : "",
Cutoff = cutoff, Cutoff = cutoff,
// Flatten groups so things don't explode // Flatten groups so things don't explode
@ -127,7 +125,6 @@ namespace NzbDrone.Api.Profiles
Name = resource.Name, Name = resource.Name,
Cutoff = resource.Cutoff.Id, Cutoff = resource.Cutoff.Id,
PreferredTags = resource.PreferredTags.Split(',').ToList(),
Items = resource.Items.ConvertAll(ToModel), Items = resource.Items.ConvertAll(ToModel),
MinFormatScore = resource.MinFormatScore, MinFormatScore = resource.MinFormatScore,
CutoffFormatScore = resource.CutoffFormatScore, CutoffFormatScore = resource.CutoffFormatScore,

@ -6,6 +6,7 @@ using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.CustomFormats; using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
@ -61,7 +62,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
remoteMovie.Movie = Builder<Movie>.CreateNew().With(m => m.Profile = new Profile remoteMovie.Movie = Builder<Movie>.CreateNew().With(m => m.Profile = new Profile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
PreferredTags = new List<string> { "DTS-HD", "SPARKS" },
FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name), FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
MinFormatScore = 0 MinFormatScore = 0
}) })
@ -90,6 +90,20 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
}); });
} }
[Test]
public void should_put_reals_before_non_reals()
{
var remoteMovie1 = GivenRemoteMovie(new QualityModel(Quality.HDTV720p, new Revision(version: 1, real: 0)));
var remoteMovie2 = GivenRemoteMovie(new QualityModel(Quality.HDTV720p, new Revision(version: 1, real: 1)));
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie1));
decisions.Add(new DownloadDecision(remoteMovie2));
var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Revision.Real.Should().Be(1);
}
[Test] [Test]
public void should_put_propers_before_non_propers() public void should_put_propers_before_non_propers()
{ {
@ -392,23 +406,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
qualifiedReports.First().RemoteMovie.Release.Should().Be(remoteMovie1.Release); qualifiedReports.First().RemoteMovie.Release.Should().Be(remoteMovie1.Release);
} }
[Test]
public void should_prefer_more_prioritized_words()
{
var remoteMovie1 = GivenRemoteMovie(new QualityModel(Quality.HDTV720p));
var remoteMovie2 = GivenRemoteMovie(new QualityModel(Quality.HDTV720p));
remoteMovie1.Release.Title += " DTS-HD";
remoteMovie2.Release.Title += " DTS-HD SPARKS";
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie1));
decisions.Add(new DownloadDecision(remoteMovie2));
var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions);
qualifiedReports.First().RemoteMovie.Release.Should().Be(remoteMovie2.Release);
}
[Test] [Test]
public void should_prefer_better_custom_format() public void should_prefer_better_custom_format()
{ {
@ -469,5 +466,94 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions); var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions);
qualifiedReports.First().RemoteMovie.Release.Should().Be(remoteMovie2.Release); qualifiedReports.First().RemoteMovie.Release.Should().Be(remoteMovie2.Release);
} }
[Test]
public void should_prefer_proper_over_score_when_download_propers_is_prefer_and_upgrade()
{
Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.PreferAndUpgrade);
var remoteMovie1 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(1)));
var remoteMovie2 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(2)));
remoteMovie1.CustomFormatScore = 10;
remoteMovie2.CustomFormatScore = 0;
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie1));
decisions.Add(new DownloadDecision(remoteMovie2));
var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Revision.Version.Should().Be(2);
}
[Test]
public void should_prefer_proper_over_score_when_download_propers_is_do_not_upgrade()
{
Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.DoNotUpgrade);
var remoteMovie1 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(1)));
var remoteMovie2 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(2)));
remoteMovie1.CustomFormatScore = 10;
remoteMovie2.CustomFormatScore = 0;
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie1));
decisions.Add(new DownloadDecision(remoteMovie2));
var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Revision.Version.Should().Be(2);
}
[Test]
public void should_prefer_score_over_proper_when_download_propers_is_do_not_prefer()
{
Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.DoNotPrefer);
var remoteMovie1 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(1)));
var remoteMovie2 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(2)));
remoteMovie1.CustomFormatScore = 10;
remoteMovie2.CustomFormatScore = 0;
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie1));
decisions.Add(new DownloadDecision(remoteMovie2));
var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Quality.Should().Be(Quality.WEBDL1080p);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Revision.Version.Should().Be(1);
qualifiedReports.First().RemoteMovie.CustomFormatScore.Should().Be(10);
}
[Test]
public void should_prefer_score_over_real_when_download_propers_is_do_not_prefer()
{
Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.DoNotPrefer);
var remoteMovie1 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(1, 0)));
var remoteMovie2 = GivenRemoteMovie(new QualityModel(Quality.WEBDL1080p, new Revision(1, 1)));
remoteMovie1.CustomFormatScore = 10;
remoteMovie2.CustomFormatScore = 0;
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie1));
decisions.Add(new DownloadDecision(remoteMovie2));
var qualifiedReports = Subject.PrioritizeDecisionsForMovies(decisions);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Quality.Should().Be(Quality.WEBDL1080p);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Revision.Version.Should().Be(1);
qualifiedReports.First().RemoteMovie.ParsedMovieInfo.Quality.Revision.Real.Should().Be(0);
qualifiedReports.First().RemoteMovie.CustomFormatScore.Should().Be(10);
}
} }
} }

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@ -51,11 +51,11 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2); CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2);
} }
private void GivenAutoDownloadPropers(bool autoDownloadPropers) private void GivenAutoDownloadPropers(ProperDownloadTypes type)
{ {
Mocker.GetMock<IConfigService>() Mocker.GetMock<IConfigService>()
.SetupGet(s => s.AutoDownloadPropers) .SetupGet(s => s.DownloadPropersAndRepacks)
.Returns(autoDownloadPropers); .Returns(type);
} }
[Test] [Test]
@ -68,7 +68,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
List<CustomFormat> newFormats, List<CustomFormat> newFormats,
bool expected) bool expected)
{ {
GivenAutoDownloadPropers(true); GivenAutoDownloadPropers(ProperDownloadTypes.PreferAndUpgrade);
var profile = new Profile var profile = new Profile
{ {
@ -86,9 +86,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
} }
[Test] [Test]
public void should_return_false_if_proper_and_autoDownloadPropers_is_false() public void should_return_true_if_proper_and_download_propers_is_do_not_download()
{ {
GivenAutoDownloadPropers(false); GivenAutoDownloadPropers(ProperDownloadTypes.DoNotUpgrade);
var profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }; var profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() };

@ -25,7 +25,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
{ {
private Profile _profile; private Profile _profile;
private DelayProfile _delayProfile; private DelayProfile _delayProfile;
private RemoteMovie _remoteEpisode; private RemoteMovie _remoteMovie;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
.With(s => s.Profile = _profile) .With(s => s.Profile = _profile)
.Build(); .Build();
_remoteEpisode = Builder<RemoteMovie>.CreateNew() _remoteMovie = Builder<RemoteMovie>.CreateNew()
.With(r => r.Movie = series) .With(r => r.Movie = series)
.Build(); .Build();
@ -52,12 +52,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_profile.Cutoff = Quality.WEBDL720p.Id; _profile.Cutoff = Quality.WEBDL720p.Id;
_remoteEpisode.ParsedMovieInfo = new ParsedMovieInfo(); _remoteMovie.ParsedMovieInfo = new ParsedMovieInfo();
_remoteEpisode.Release = new ReleaseInfo(); _remoteMovie.Release = new ReleaseInfo();
_remoteEpisode.Release.DownloadProtocol = DownloadProtocol.Usenet; _remoteMovie.Release.DownloadProtocol = DownloadProtocol.Usenet;
//_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1).Build().ToList();
//_remoteEpisode.Episodes.First().EpisodeFileId = 0;
Mocker.GetMock<IDelayProfileService>() Mocker.GetMock<IDelayProfileService>()
.Setup(s => s.BestForTags(It.IsAny<HashSet<int>>())) .Setup(s => s.BestForTags(It.IsAny<HashSet<int>>()))
.Returns(_delayProfile); .Returns(_delayProfile);
@ -70,7 +68,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
private void GivenExistingFile(QualityModel quality) private void GivenExistingFile(QualityModel quality)
{ {
//_remoteEpisode.Episodes.First().EpisodeFileId = 1; //_remoteEpisode.Episodes.First().EpisodeFileId = 1;
_remoteEpisode.Movie.MovieFile = new MovieFile { Quality = quality }; _remoteMovie.Movie.MovieFile = new MovieFile { Quality = quality };
} }
private void GivenUpgradeForExistingFile() private void GivenUpgradeForExistingFile()
@ -89,12 +87,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_be_false_when_system_invoked_search_and_release_is_younger_than_delay() public void should_be_false_when_system_invoked_search_and_release_is_younger_than_delay()
{ {
_remoteEpisode.ParsedMovieInfo.Quality = new QualityModel(Quality.SDTV); _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.SDTV);
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteMovie.Release.PublishDate = DateTime.UtcNow;
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, new MovieSearchCriteria()).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteMovie, new MovieSearchCriteria()).Accepted.Should().BeFalse();
} }
[Test] [Test]
@ -102,44 +100,44 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
{ {
_delayProfile.UsenetDelay = 0; _delayProfile.UsenetDelay = 0;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_true_when_quality_is_last_allowed_in_profile() public void should_be_true_when_quality_is_last_allowed_in_profile()
{ {
_remoteEpisode.ParsedMovieInfo.Quality = new QualityModel(Quality.Bluray720p); _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.Bluray720p);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_true_when_release_is_older_than_delay() public void should_be_true_when_release_is_older_than_delay()
{ {
_remoteEpisode.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p); _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p);
_remoteEpisode.Release.PublishDate = DateTime.UtcNow.AddHours(-10); _remoteMovie.Release.PublishDate = DateTime.UtcNow.AddHours(-10);
_delayProfile.UsenetDelay = 60; _delayProfile.UsenetDelay = 60;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_false_when_release_is_younger_than_delay() public void should_be_false_when_release_is_younger_than_delay()
{ {
_remoteEpisode.ParsedMovieInfo.Quality = new QualityModel(Quality.SDTV); _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.SDTV);
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteMovie.Release.PublishDate = DateTime.UtcNow;
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_true_when_release_is_a_proper_for_existing_episode() public void should_be_true_when_release_is_a_proper_for_existing_movie()
{ {
_remoteEpisode.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p, new Revision(version: 2)); _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p, new Revision(version: 2));
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteMovie.Release.PublishDate = DateTime.UtcNow;
GivenExistingFile(new QualityModel(Quality.HDTV720p)); GivenExistingFile(new QualityModel(Quality.HDTV720p));
GivenUpgradeForExistingFile(); GivenUpgradeForExistingFile();
@ -150,14 +148,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_true_when_release_is_a_real_for_existing_episode() public void should_be_true_when_release_is_a_real_for_existing_movie()
{ {
_remoteEpisode.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p, new Revision(real: 1)); _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p, new Revision(real: 1));
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteMovie.Release.PublishDate = DateTime.UtcNow;
GivenExistingFile(new QualityModel(Quality.HDTV720p)); GivenExistingFile(new QualityModel(Quality.HDTV720p));
GivenUpgradeForExistingFile(); GivenUpgradeForExistingFile();
@ -168,20 +166,20 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_false_when_release_is_proper_for_existing_episode_of_different_quality() public void should_be_false_when_release_is_proper_for_existing_movie_of_different_quality()
{ {
_remoteEpisode.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p, new Revision(version: 2)); _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p, new Revision(version: 2));
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteMovie.Release.PublishDate = DateTime.UtcNow;
GivenExistingFile(new QualityModel(Quality.SDTV)); GivenExistingFile(new QualityModel(Quality.SDTV));
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -48,13 +48,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_firstFile.Quality = new QualityModel(Quality.SDTV); _firstFile.Quality = new QualityModel(Quality.SDTV);
} }
private void GivenAutoDownloadPropers()
{
Mocker.GetMock<IConfigService>()
.Setup(s => s.AutoDownloadPropers)
.Returns(true);
}
[Test] [Test]
public void should_return_false_when_movieFile_was_added_more_than_7_days_ago() public void should_return_false_when_movieFile_was_added_more_than_7_days_ago()
{ {
@ -85,6 +78,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_return_false_when_proper_but_auto_download_propers_is_false() public void should_return_false_when_proper_but_auto_download_propers_is_false()
{ {
Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.DoNotUpgrade);
_firstFile.Quality.Quality = Quality.DVD; _firstFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today; _firstFile.DateAdded = DateTime.Today;
@ -94,7 +91,21 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_return_true_when_movieFile_was_added_today() public void should_return_true_when_movieFile_was_added_today()
{ {
GivenAutoDownloadPropers(); Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.PreferAndUpgrade);
_firstFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today;
Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
}
public void should_return_true_when_propers_are_not_preferred()
{
Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.DoNotPrefer);
_firstFile.Quality.Quality = Quality.DVD; _firstFile.Quality.Quality = Quality.DVD;

@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
movie = GetMovie(1); movie = GetMovie(1);
} }
movie.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities(), PreferredTags = new List<string>() }; movie.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() };
var remoteMovie = new RemoteMovie() var remoteMovie = new RemoteMovie()
{ {

@ -11,6 +11,7 @@ using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.MetadataSource.SkyHook.Resource; using NzbDrone.Core.MetadataSource.SkyHook.Resource;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Security; using NzbDrone.Core.Security;
namespace NzbDrone.Core.Configuration namespace NzbDrone.Core.Configuration
@ -156,11 +157,11 @@ namespace NzbDrone.Core.Configuration
set { SetValue("MinimumAge", value); } set { SetValue("MinimumAge", value); }
} }
public bool AutoDownloadPropers public ProperDownloadTypes DownloadPropersAndRepacks
{ {
get { return GetValueBoolean("AutoDownloadPropers", true); } get { return GetValueEnum("DownloadPropersAndRepacks", ProperDownloadTypes.PreferAndUpgrade); }
set { SetValue("AutoDownloadPropers", value); } set { SetValue("DownloadPropersAndRepacks", value); }
} }
public bool EnableCompletedDownloadHandling public bool EnableCompletedDownloadHandling

@ -3,6 +3,7 @@ using NzbDrone.Common.Http.Proxy;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MetadataSource.SkyHook.Resource; using NzbDrone.Core.MetadataSource.SkyHook.Resource;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Security; using NzbDrone.Core.Security;
namespace NzbDrone.Core.Configuration namespace NzbDrone.Core.Configuration
@ -29,7 +30,7 @@ namespace NzbDrone.Core.Configuration
bool AutoUnmonitorPreviouslyDownloadedMovies { get; set; } bool AutoUnmonitorPreviouslyDownloadedMovies { get; set; }
string RecycleBin { get; set; } string RecycleBin { get; set; }
int RecycleBinCleanupDays { get; set; } int RecycleBinCleanupDays { get; set; }
bool AutoDownloadPropers { get; set; } ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
bool CreateEmptyMovieFolders { get; set; } bool CreateEmptyMovieFolders { get; set; }
bool DeleteEmptyFolders { get; set; } bool DeleteEmptyFolders { get; set; }
FileDateType FileDate { get; set; } FileDateType FileDate { get; set; }

@ -0,0 +1,44 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(183)]
public class download_propers_config : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(SetMetadataFileExtension);
Execute.Sql("DELETE FROM Config WHERE Key = 'autodownloadpropers'");
Delete.Column("PreferredTags").FromTable("Profiles");
}
private void SetMetadataFileExtension(IDbConnection conn, IDbTransaction tran)
{
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandText = "SELECT Value FROM Config WHERE Key = 'autodownloadpropers'";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var value = reader.GetString(0);
var newValue = bool.Parse(value) ? "PreferAndUpgrade" : "DoNotUpgrade";
using (var updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "INSERT INTO Config (key, value) VALUES ('downloadpropersandrepacks', ?)";
updateCmd.AddParameter(newValue);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}

@ -30,7 +30,7 @@ namespace NzbDrone.Core.DecisionEngine
var comparers = new List<CompareDelegate> var comparers = new List<CompareDelegate>
{ {
CompareQuality, CompareQuality,
ComparePreferredWords, CompareCustomFormatScore,
CompareProtocol, CompareProtocol,
CompareIndexerFlags, CompareIndexerFlags,
ComparePeersIfTorrent, ComparePeersIfTorrent,
@ -57,28 +57,18 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareQuality(DownloadDecision x, DownloadDecision y) private int CompareQuality(DownloadDecision x, DownloadDecision y)
{ {
if (_configService.DownloadPropersAndRepacks == ProperDownloadTypes.DoNotPrefer)
{
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.Movie.Profile.GetIndex(remoteMovie.ParsedMovieInfo.Quality.Quality));
}
return CompareAll(CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.Movie.Profile.GetIndex(remoteMovie.ParsedMovieInfo.Quality.Quality)), return CompareAll(CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.Movie.Profile.GetIndex(remoteMovie.ParsedMovieInfo.Quality.Quality)),
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.CustomFormatScore), CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.ParsedMovieInfo.Quality.Revision));
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.ParsedMovieInfo.Quality.Revision.Real),
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.ParsedMovieInfo.Quality.Revision.Version));
} }
private int ComparePreferredWords(DownloadDecision x, DownloadDecision y) private int CompareCustomFormatScore(DownloadDecision x, DownloadDecision y)
{ {
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie => remoteMovie.CustomFormatScore);
{
var title = remoteMovie.Release.Title;
var preferredWords = remoteMovie.Movie.Profile.PreferredTags;
if (preferredWords == null)
{
return 0;
}
var num = preferredWords.AsEnumerable().Count(w => title.ToLower().Contains(w.ToLower()));
return num;
});
} }
private int CompareIndexerFlags(DownloadDecision x, DownloadDecision y) private int CompareIndexerFlags(DownloadDecision x, DownloadDecision y)

@ -46,21 +46,6 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol); var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol);
var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol; var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol;
// Preferred word count
var title = subject.Release.Title;
var preferredWords = subject.Movie.Profile?.PreferredTags;
var preferredCount = 0;
if (preferredWords == null)
{
preferredCount = 1;
_logger.Debug("Preferred words is null, setting preffered count to 1.");
}
else
{
preferredCount = preferredWords.AsEnumerable().Count(w => title.ToLower().Contains(w.ToLower()));
}
if (delay == 0) if (delay == 0)
{ {
_logger.Debug("Profile does not require a waiting period before download for {0}.", subject.Release.DownloadProtocol); _logger.Debug("Profile does not require a waiting period before download for {0}.", subject.Release.DownloadProtocol);
@ -71,7 +56,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
var file = subject.Movie.MovieFile; var file = subject.Movie.MovieFile;
if (isPreferredProtocol && (subject.Movie.MovieFileId != 0 && file != null) && (preferredCount > 0 || preferredWords == null)) if (isPreferredProtocol && (subject.Movie.MovieFileId != 0 && file != null))
{ {
var customFormats = _formatService.ParseCustomFormat(file); var customFormats = _formatService.ParseCustomFormat(file);
var upgradable = _qualityUpgradableSpecification.IsUpgradable(profile, var upgradable = _qualityUpgradableSpecification.IsUpgradable(profile,
@ -86,7 +71,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
if (revisionUpgrade) if (revisionUpgrade)
{ {
_logger.Debug("New quality is a better revision for existing quality and preferred word count is {0}, skipping delay", preferredCount); _logger.Debug("New quality is a better revision for existing quality, skipping delay");
return Decision.Accept(); return Decision.Accept();
} }
} }
@ -96,9 +81,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
var bestQualityInProfile = profile.LastAllowedQuality(); var bestQualityInProfile = profile.LastAllowedQuality();
var isBestInProfile = comparer.Compare(subject.ParsedMovieInfo.Quality.Quality, bestQualityInProfile) >= 0; var isBestInProfile = comparer.Compare(subject.ParsedMovieInfo.Quality.Quality, bestQualityInProfile) >= 0;
if (isBestInProfile && isPreferredProtocol && (preferredCount > 0 || preferredWords == null)) if (isBestInProfile && isPreferredProtocol)
{ {
_logger.Debug("Quality is highest in profile for preferred protocol and preferred word count is {0}, will not delay.", preferredCount); _logger.Debug("Quality is highest in profile for preferred protocol, will not delay.");
return Decision.Accept(); return Decision.Accept();
} }

@ -3,6 +3,7 @@ using NLog;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
{ {
@ -29,6 +30,14 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
return Decision.Accept(); return Decision.Accept();
} }
var downloadPropersAndRepacks = _configService.DownloadPropersAndRepacks;
if (downloadPropersAndRepacks == ProperDownloadTypes.DoNotPrefer)
{
_logger.Debug("Propers are not preferred, skipping check");
return Decision.Accept();
}
if (subject.Movie.MovieFile == null) if (subject.Movie.MovieFile == null)
{ {
return Decision.Accept(); return Decision.Accept();
@ -38,16 +47,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
if (_qualityUpgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedMovieInfo.Quality)) if (_qualityUpgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedMovieInfo.Quality))
{ {
if (file.DateAdded < DateTime.Today.AddDays(-7)) if (downloadPropersAndRepacks == ProperDownloadTypes.DoNotUpgrade)
{ {
_logger.Debug("Proper for old file, rejecting: {0}", subject); _logger.Debug("Auto downloading of propers is disabled");
return Decision.Reject("Proper for old file"); return Decision.Reject("Proper downloading is disabled");
} }
if (!_configService.AutoDownloadPropers) if (file.DateAdded < DateTime.Today.AddDays(-7))
{ {
_logger.Debug("Auto downloading of propers is disabled"); _logger.Debug("Proper for old file, rejecting: {0}", subject);
return Decision.Reject("Proper downloading is disabled"); return Decision.Reject("Proper for old file");
} }
} }

@ -47,10 +47,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
// Accept unless the user doesn't want to prefer propers, optionally they can // Accept unless the user doesn't want to prefer propers, optionally they can
// use preferred words to prefer propers/repacks over non-propers/repacks. // use preferred words to prefer propers/repacks over non-propers/repacks.
if (_configService.AutoDownloadPropers && if (_configService.DownloadPropersAndRepacks != ProperDownloadTypes.DoNotPrefer &&
newQuality?.Revision.CompareTo(currentQuality.Revision) > 0) newQuality?.Revision.CompareTo(currentQuality.Revision) > 0)
{ {
_logger.Debug("New item has a better quality revision");
return true; return true;
} }

@ -46,7 +46,6 @@
"AudioInfo": "Audio Info", "AudioInfo": "Audio Info",
"Authentication": "Authentication", "Authentication": "Authentication",
"AuthenticationMethodHelpText": "Require Username and Password to access Radarr", "AuthenticationMethodHelpText": "Require Username and Password to access Radarr",
"AutoDownloadPropersHelpText": "Should Radarr automatically upgrade to propers when available?",
"Automatic": "Automatic", "Automatic": "Automatic",
"AutoRedownloadFailedHelpText": "Automatically search for and attempt to download a different release", "AutoRedownloadFailedHelpText": "Automatically search for and attempt to download a different release",
"AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Movies deleted from disk are automatically unmonitored in Radarr", "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Movies deleted from disk are automatically unmonitored in Radarr",
@ -185,7 +184,10 @@
"DownloadFailedCheckDownloadClientForMoreDetails": "Download failed: check download client for more details", "DownloadFailedCheckDownloadClientForMoreDetails": "Download failed: check download client for more details",
"DownloadFailedInterp": "Download failed: {0}", "DownloadFailedInterp": "Download failed: {0}",
"Downloading": "Downloading", "Downloading": "Downloading",
"DownloadPropers": "Download Propers", "DownloadPropersAndRepacks": "Propers and Repacks",
"DownloadPropersAndRepacksHelpText1": "Whether or not to automatically upgrade to Propers/Repacks",
"DownloadPropersAndRepacksHelpText2": "Use 'Do not Prefer' to sort by preferred word score over propers/repacks",
"DownloadPropersAndRepacksHelpTextWarning": "Use preferred words for automatic upgrades to propers/repacks",
"DownloadWarning": "Download warning: {0}", "DownloadWarning": "Download warning: {0}",
"DownloadWarningCheckDownloadClientForMoreDetails": "Download warning: check download client for more details", "DownloadWarningCheckDownloadClientForMoreDetails": "Download warning: check download client for more details",
"Edit": "Edit", "Edit": "Edit",

@ -20,7 +20,6 @@ namespace NzbDrone.Core.Profiles
public int MinFormatScore { get; set; } public int MinFormatScore { get; set; }
public int CutoffFormatScore { get; set; } public int CutoffFormatScore { get; set; }
public List<ProfileFormatItem> FormatItems { get; set; } public List<ProfileFormatItem> FormatItems { get; set; }
public List<string> PreferredTags { get; set; }
public Language Language { get; set; } public Language Language { get; set; }
public bool UpgradeAllowed { get; set; } public bool UpgradeAllowed { get; set; }

@ -0,0 +1,9 @@
namespace NzbDrone.Core.Qualities
{
public enum ProperDownloadTypes
{
PreferAndUpgrade,
DoNotUpgrade,
DoNotPrefer
}
}

@ -1,5 +1,6 @@
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Qualities;
using Radarr.Http.REST; using Radarr.Http.REST;
namespace Radarr.Api.V3.Config namespace Radarr.Api.V3.Config
@ -9,7 +10,7 @@ namespace Radarr.Api.V3.Config
public bool AutoUnmonitorPreviouslyDownloadedMovies { get; set; } public bool AutoUnmonitorPreviouslyDownloadedMovies { get; set; }
public string RecycleBin { get; set; } public string RecycleBin { get; set; }
public int RecycleBinCleanupDays { get; set; } public int RecycleBinCleanupDays { get; set; }
public bool AutoDownloadPropers { get; set; } public ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
public bool CreateEmptyMovieFolders { get; set; } public bool CreateEmptyMovieFolders { get; set; }
public bool DeleteEmptyFolders { get; set; } public bool DeleteEmptyFolders { get; set; }
public FileDateType FileDate { get; set; } public FileDateType FileDate { get; set; }
@ -37,7 +38,7 @@ namespace Radarr.Api.V3.Config
AutoUnmonitorPreviouslyDownloadedMovies = model.AutoUnmonitorPreviouslyDownloadedMovies, AutoUnmonitorPreviouslyDownloadedMovies = model.AutoUnmonitorPreviouslyDownloadedMovies,
RecycleBin = model.RecycleBin, RecycleBin = model.RecycleBin,
RecycleBinCleanupDays = model.RecycleBinCleanupDays, RecycleBinCleanupDays = model.RecycleBinCleanupDays,
AutoDownloadPropers = model.AutoDownloadPropers, DownloadPropersAndRepacks = model.DownloadPropersAndRepacks,
CreateEmptyMovieFolders = model.CreateEmptyMovieFolders, CreateEmptyMovieFolders = model.CreateEmptyMovieFolders,
DeleteEmptyFolders = model.DeleteEmptyFolders, DeleteEmptyFolders = model.DeleteEmptyFolders,
FileDate = model.FileDate, FileDate = model.FileDate,

@ -12,7 +12,6 @@ namespace Radarr.Api.V3.Profiles.Quality
public string Name { get; set; } public string Name { get; set; }
public bool UpgradeAllowed { get; set; } public bool UpgradeAllowed { get; set; }
public int Cutoff { get; set; } public int Cutoff { get; set; }
public string PreferredTags { get; set; }
public List<QualityProfileQualityItemResource> Items { get; set; } public List<QualityProfileQualityItemResource> Items { get; set; }
public int MinFormatScore { get; set; } public int MinFormatScore { get; set; }
public int CutoffFormatScore { get; set; } public int CutoffFormatScore { get; set; }
@ -55,7 +54,6 @@ namespace Radarr.Api.V3.Profiles.Quality
Name = model.Name, Name = model.Name,
UpgradeAllowed = model.UpgradeAllowed, UpgradeAllowed = model.UpgradeAllowed,
Cutoff = model.Cutoff, Cutoff = model.Cutoff,
PreferredTags = model.PreferredTags != null ? string.Join(",", model.PreferredTags) : "",
Items = model.Items.ConvertAll(ToResource), Items = model.Items.ConvertAll(ToResource),
MinFormatScore = model.MinFormatScore, MinFormatScore = model.MinFormatScore,
CutoffFormatScore = model.CutoffFormatScore, CutoffFormatScore = model.CutoffFormatScore,
@ -104,7 +102,6 @@ namespace Radarr.Api.V3.Profiles.Quality
Name = resource.Name, Name = resource.Name,
UpgradeAllowed = resource.UpgradeAllowed, UpgradeAllowed = resource.UpgradeAllowed,
Cutoff = resource.Cutoff, Cutoff = resource.Cutoff,
PreferredTags = resource.PreferredTags.Split(',').ToList(),
Items = resource.Items.ConvertAll(ToModel), Items = resource.Items.ConvertAll(ToModel),
MinFormatScore = resource.MinFormatScore, MinFormatScore = resource.MinFormatScore,
CutoffFormatScore = resource.CutoffFormatScore, CutoffFormatScore = resource.CutoffFormatScore,

Loading…
Cancel
Save