mirror of https://github.com/lidarr/Lidarr
Fixed: Correctly handle Repack Releases
This commit is contained in:
parent
23316329ed
commit
2f1290d488
|
@ -25,6 +25,12 @@ const allowFingerprintingOptions = [
|
|||
{ 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 = [
|
||||
{ key: 'none', value: 'None' },
|
||||
{ key: 'albumReleaseDate', value: 'Album Release Date' }
|
||||
|
@ -209,14 +215,23 @@ class MediaManagement extends Component {
|
|||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>Download Propers</FormLabel>
|
||||
<FormLabel>Propers and Repacks</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="autoDownloadPropers"
|
||||
helpText="Should Lidarr automatically upgrade to propers when available?"
|
||||
type={inputTypes.SELECT}
|
||||
name="downloadPropersAndRepacks"
|
||||
helpTexts={[
|
||||
'Whether or not to automatically upgrade to Propers/Repacks',
|
||||
'Use \'Do not Prefer\' to sort by preferred word score over propers/repacks'
|
||||
]}
|
||||
helpTextWarning={
|
||||
settings.downloadPropersAndRepacks.value === 'doNotPrefer' ?
|
||||
'Use preferred words for automatic upgrades to propers/repacks' :
|
||||
undefined
|
||||
}
|
||||
values={downloadPropersAndRepacksOptions}
|
||||
onChange={onInputChange}
|
||||
{...settings.autoDownloadPropers}
|
||||
{...settings.downloadPropersAndRepacks}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace Lidarr.Api.V1.Config
|
||||
{
|
||||
|
@ -8,7 +9,7 @@ namespace Lidarr.Api.V1.Config
|
|||
{
|
||||
public bool AutoUnmonitorPreviouslyDownloadedTracks { get; set; }
|
||||
public string RecycleBin { get; set; }
|
||||
public bool AutoDownloadPropers { get; set; }
|
||||
public ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
|
||||
public bool CreateEmptyArtistFolders { get; set; }
|
||||
public bool DeleteEmptyFolders { get; set; }
|
||||
public FileDateType FileDate { get; set; }
|
||||
|
@ -35,7 +36,7 @@ namespace Lidarr.Api.V1.Config
|
|||
{
|
||||
AutoUnmonitorPreviouslyDownloadedTracks = model.AutoUnmonitorPreviouslyDownloadedTracks,
|
||||
RecycleBin = model.RecycleBin,
|
||||
AutoDownloadPropers = model.AutoDownloadPropers,
|
||||
DownloadPropersAndRepacks = model.DownloadPropersAndRepacks,
|
||||
CreateEmptyArtistFolders = model.CreateEmptyArtistFolders,
|
||||
DeleteEmptyFolders = model.DeleteEmptyFolders,
|
||||
FileDate = model.FileDate,
|
||||
|
|
|
@ -17,6 +17,7 @@ using NzbDrone.Core.Test.Framework;
|
|||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Test.Languages;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
|
@ -411,7 +412,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void should_put_higher_quality_before_lower_allways()
|
||||
public void should_put_higher_quality_before_lower_always()
|
||||
{
|
||||
var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), Language.French);
|
||||
var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_320), Language.German);
|
||||
|
@ -423,5 +424,88 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteAlbum.ParsedAlbumInfo.Quality.Quality.Should().Be(Quality.MP3_320);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_prefer_higher_score_over_lower_score()
|
||||
{
|
||||
var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC), Language.English);
|
||||
var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC), Language.English);
|
||||
|
||||
remoteAlbum1.PreferredWordScore = 10;
|
||||
remoteAlbum2.PreferredWordScore = 0;
|
||||
|
||||
var decisions = new List<DownloadDecision>();
|
||||
decisions.Add(new DownloadDecision(remoteAlbum1));
|
||||
decisions.Add(new DownloadDecision(remoteAlbum2));
|
||||
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteAlbum.PreferredWordScore.Should().Be(10);
|
||||
}
|
||||
|
||||
[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 remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC, new Revision(1)), Language.English);
|
||||
var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC, new Revision(2)), Language.English);
|
||||
|
||||
remoteAlbum1.PreferredWordScore = 10;
|
||||
remoteAlbum2.PreferredWordScore = 0;
|
||||
|
||||
var decisions = new List<DownloadDecision>();
|
||||
decisions.Add(new DownloadDecision(remoteAlbum1));
|
||||
decisions.Add(new DownloadDecision(remoteAlbum2));
|
||||
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteAlbum.ParsedAlbumInfo.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 remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC, new Revision(1)), Language.English);
|
||||
var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC, new Revision(2)), Language.English);
|
||||
|
||||
remoteAlbum1.PreferredWordScore = 10;
|
||||
remoteAlbum2.PreferredWordScore = 0;
|
||||
|
||||
var decisions = new List<DownloadDecision>();
|
||||
decisions.Add(new DownloadDecision(remoteAlbum1));
|
||||
decisions.Add(new DownloadDecision(remoteAlbum2));
|
||||
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteAlbum.ParsedAlbumInfo.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 remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC, new Revision(1)), Language.English);
|
||||
var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.FLAC, new Revision(2)), Language.English);
|
||||
|
||||
remoteAlbum1.PreferredWordScore = 10;
|
||||
remoteAlbum2.PreferredWordScore = 0;
|
||||
|
||||
var decisions = new List<DownloadDecision>();
|
||||
decisions.Add(new DownloadDecision(remoteAlbum1));
|
||||
decisions.Add(new DownloadDecision(remoteAlbum2));
|
||||
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteAlbum.ParsedAlbumInfo.Quality.Quality.Should().Be(Quality.FLAC);
|
||||
qualifiedReports.First().RemoteAlbum.ParsedAlbumInfo.Quality.Revision.Version.Should().Be(1);
|
||||
qualifiedReports.First().RemoteAlbum.PreferredWordScore.Should().Be(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Music;
|
||||
using Moq;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class RepackSpecificationFixture : CoreTest<RepackSpecification>
|
||||
{
|
||||
private ParsedAlbumInfo _parsedAlbumInfo;
|
||||
private List<Album> _albums;
|
||||
private List<TrackFile> _trackFiles;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Mocker.Resolve<UpgradableSpecification>();
|
||||
|
||||
_parsedAlbumInfo = Builder<ParsedAlbumInfo>.CreateNew()
|
||||
.With(p => p.Quality = new QualityModel(Quality.FLAC,
|
||||
new Revision(2, 0, false)))
|
||||
.With(p => p.ReleaseGroup = "Lidarr")
|
||||
.Build();
|
||||
|
||||
_albums = Builder<Album>.CreateListOfSize(1)
|
||||
.All()
|
||||
.BuildList();
|
||||
|
||||
_trackFiles = Builder<TrackFile>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(t => t.AlbumId = _albums.First().Id)
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(c => c.GetFilesByAlbum(It.IsAny<int>()))
|
||||
.Returns(_trackFiles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_it_is_not_a_repack()
|
||||
{
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_there_are_is_no_track_files()
|
||||
{
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(c => c.GetFilesByAlbum(It.IsAny<int>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
||||
_parsedAlbumInfo.Quality.Revision.IsRepack = true;
|
||||
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_is_a_repack_for_a_different_quality()
|
||||
{
|
||||
_parsedAlbumInfo.Quality.Revision.IsRepack = true;
|
||||
|
||||
_trackFiles.Select(c => { c.ReleaseGroup = "Lidarr"; return c; }).ToList();
|
||||
_trackFiles.Select(c => { c.Quality = new QualityModel(Quality.MP3_256); return c; }).ToList();
|
||||
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_is_a_repack_for_all_existing_files()
|
||||
{
|
||||
_parsedAlbumInfo.Quality.Revision.IsRepack = true;
|
||||
|
||||
_trackFiles.Select(c => { c.ReleaseGroup = "Lidarr"; return c; }).ToList();
|
||||
_trackFiles.Select(c => { c.Quality = new QualityModel(Quality.FLAC); return c; }).ToList();
|
||||
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_is_a_repack_for_some_but_not_all_trackfiles()
|
||||
{
|
||||
_parsedAlbumInfo.Quality.Revision.IsRepack = true;
|
||||
|
||||
_trackFiles.Select(c => { c.ReleaseGroup = "Lidarr"; return c; }).ToList();
|
||||
_trackFiles.Select(c => { c.Quality = new QualityModel(Quality.FLAC); return c; }).ToList();
|
||||
|
||||
_trackFiles.First().ReleaseGroup = "NotLidarr";
|
||||
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeFalse();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_is_a_repack_for_different_group()
|
||||
{
|
||||
_parsedAlbumInfo.Quality.Revision.IsRepack = true;
|
||||
|
||||
_trackFiles.Select(c => { c.ReleaseGroup = "NotLidarr"; return c; }).ToList();
|
||||
_trackFiles.Select(c => { c.Quality = new QualityModel(Quality.FLAC); return c; }).ToList();
|
||||
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeFalse();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_release_group_for_existing_file_is_unknown()
|
||||
{
|
||||
_parsedAlbumInfo.Quality.Revision.IsRepack = true;
|
||||
|
||||
_trackFiles.Select(c => { c.ReleaseGroup = ""; return c; }).ToList();
|
||||
_trackFiles.Select(c => { c.Quality = new QualityModel(Quality.FLAC); return c; }).ToList();
|
||||
|
||||
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_release_group_for_release_is_unknown()
|
||||
{
|
||||
_parsedAlbumInfo.Quality.Revision.IsRepack = true;
|
||||
_parsedAlbumInfo.ReleaseGroup = null;
|
||||
|
||||
_trackFiles.Select(c => { c.ReleaseGroup = "Lidarr"; return c; }).ToList();
|
||||
_trackFiles.Select(c => { c.Quality = new QualityModel(Quality.FLAC); return c; }).ToList();
|
||||
|
||||
|
||||
var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
|
||||
.With(e => e.ParsedAlbumInfo = _parsedAlbumInfo)
|
||||
.With(e => e.Albums = _albums)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(remoteAlbum, null)
|
||||
.Accepted
|
||||
.Should()
|
||||
.BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,8 +35,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
_firstFile = new TrackFile { Quality = new QualityModel(Quality.FLAC, new Revision(version: 1)), DateAdded = DateTime.Now };
|
||||
_secondFile = new TrackFile { Quality = new QualityModel(Quality.FLAC, new Revision(version: 1)), DateAdded = DateTime.Now };
|
||||
|
||||
var singleEpisodeList = new List<Album> { new Album {}, new Album {} };
|
||||
var doubleEpisodeList = new List<Album> { new Album {}, new Album {}, new Album {} };
|
||||
var singleAlbumList = new List<Album> { new Album {}, new Album {} };
|
||||
var doubleAlbumList = new List<Album> { new Album {}, new Album {}, new Album {} };
|
||||
|
||||
|
||||
var fakeArtist = Builder<Artist>.CreateNew()
|
||||
|
@ -51,14 +51,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
{
|
||||
Artist = fakeArtist,
|
||||
ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)) },
|
||||
Albums = doubleEpisodeList
|
||||
Albums = doubleAlbumList
|
||||
};
|
||||
|
||||
_parseResultSingle = new RemoteAlbum
|
||||
{
|
||||
Artist = fakeArtist,
|
||||
ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)) },
|
||||
Albums = singleEpisodeList
|
||||
Albums = singleAlbumList
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -67,13 +67,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
_firstFile.Quality = new QualityModel(Quality.MP3_192);
|
||||
}
|
||||
|
||||
private void GivenAutoDownloadPropers()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.AutoDownloadPropers)
|
||||
.Returns(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_when_trackFile_was_added_more_than_7_days_ago()
|
||||
{
|
||||
|
@ -124,6 +117,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
[Test]
|
||||
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.MP3_256;
|
||||
|
||||
_firstFile.DateAdded = DateTime.Today;
|
||||
|
@ -133,7 +130,22 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
[Test]
|
||||
public void should_return_true_when_trackFile_was_added_today()
|
||||
{
|
||||
GivenAutoDownloadPropers();
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.DownloadPropersAndRepacks)
|
||||
.Returns(ProperDownloadTypes.PreferAndUpgrade);
|
||||
|
||||
_firstFile.Quality.Quality = Quality.MP3_256;
|
||||
|
||||
_firstFile.DateAdded = DateTime.Today;
|
||||
Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_propers_are_not_preferred()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.DownloadPropersAndRepacks)
|
||||
.Returns(ProperDownloadTypes.DoNotPrefer);
|
||||
|
||||
_firstFile.Quality.Quality = Quality.MP3_256;
|
||||
|
||||
|
|
|
@ -38,17 +38,17 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
private static readonly int NoPreferredWordScore = 0;
|
||||
|
||||
private void GivenAutoDownloadPropers(bool autoDownloadPropers)
|
||||
private void GivenAutoDownloadPropers(ProperDownloadTypes type)
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.AutoDownloadPropers)
|
||||
.Returns(autoDownloadPropers);
|
||||
.SetupGet(s => s.DownloadPropersAndRepacks)
|
||||
.Returns(type);
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(IsUpgradeTestCases))]
|
||||
public void IsUpgradeTest(Quality current, int currentVersion, Quality newQuality, int newVersion, Quality cutoff, bool expected)
|
||||
{
|
||||
GivenAutoDownloadPropers(true);
|
||||
GivenAutoDownloadPropers(ProperDownloadTypes.PreferAndUpgrade);
|
||||
|
||||
var profile = new QualityProfile
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
[Test, TestCaseSource(nameof(IsUpgradeTestCasesLanguages))]
|
||||
public void IsUpgradeTestLanguage(Quality current, int currentVersion, Language currentLanguage, Quality newQuality, int newVersion, Language newLanguage, Quality cutoff, Language languageCutoff, bool expected)
|
||||
{
|
||||
GivenAutoDownloadPropers(true);
|
||||
GivenAutoDownloadPropers(ProperDownloadTypes.PreferAndUpgrade);
|
||||
|
||||
var profile = new QualityProfile
|
||||
{
|
||||
|
@ -107,9 +107,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
}
|
||||
|
||||
[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 QualityProfile
|
||||
{
|
||||
|
@ -126,13 +126,41 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Subject.IsUpgradable(
|
||||
profile,
|
||||
langProfile,
|
||||
new List<QualityModel> { new QualityModel(Quality.MP3_256, new Revision(version: 2)) },
|
||||
new List<QualityModel> { new QualityModel(Quality.MP3_256, new Revision(version: 1)) },
|
||||
new List<Language> { Language.English },
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.MP3_256, new Revision(version: 1)),
|
||||
new QualityModel(Quality.MP3_256, new Revision(version: 2)),
|
||||
Language.English,
|
||||
NoPreferredWordScore)
|
||||
.Should().BeFalse();
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_proper_and_autoDownloadPropers_is_do_not_prefer()
|
||||
{
|
||||
GivenAutoDownloadPropers(ProperDownloadTypes.DoNotPrefer);
|
||||
|
||||
var profile = new QualityProfile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
var langProfile = new LanguageProfile
|
||||
{
|
||||
Languages = LanguageFixture.GetDefaultLanguages(),
|
||||
Cutoff = Language.English
|
||||
};
|
||||
|
||||
Subject.IsUpgradable(
|
||||
profile,
|
||||
langProfile,
|
||||
new List<QualityModel> { new QualityModel(Quality.MP3_256, new Revision(version: 1)) },
|
||||
new List<Language> { Language.English },
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.MP3_256, new Revision(version: 2)),
|
||||
Language.English,
|
||||
NoPreferredWordScore)
|
||||
.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ using NzbDrone.Core.Test.Framework;
|
|||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.TrackImport.Specifications
|
||||
{
|
||||
|
@ -19,6 +20,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport.Specifications
|
|||
public class UpgradeSpecificationFixture : CoreTest<UpgradeSpecification>
|
||||
{
|
||||
private Artist _artist;
|
||||
private Album _album;
|
||||
private LocalTrack _localTrack;
|
||||
|
||||
[SetUp]
|
||||
|
@ -35,12 +37,15 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport.Specifications
|
|||
Cutoff = Language.Spanish,
|
||||
}).Build();
|
||||
|
||||
_album = Builder<Album>.CreateNew().Build();
|
||||
|
||||
_localTrack = new LocalTrack
|
||||
{
|
||||
Path = @"C:\Test\Imagine Dragons\Imagine.Dragons.Song.1.mp3",
|
||||
Quality = new QualityModel(Quality.MP3_256, new Revision(version: 1)),
|
||||
Language = Language.Spanish,
|
||||
Artist = _artist
|
||||
Artist = _artist,
|
||||
Album = _album
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -215,5 +220,71 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport.Specifications
|
|||
|
||||
Subject.IsSatisfiedBy(_localTrack).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_not_a_revision_upgrade_and_prefers_propers()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.DownloadPropersAndRepacks)
|
||||
.Returns(ProperDownloadTypes.PreferAndUpgrade);
|
||||
|
||||
_localTrack.Tracks = Builder<Track>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.TrackFileId = 1)
|
||||
.With(e => e.TrackFile = new LazyLoaded<TrackFile>(
|
||||
new TrackFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2))
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.IsSatisfiedBy(_localTrack).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_not_a_revision_upgrade_and_does_not_prefer_propers()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.DownloadPropersAndRepacks)
|
||||
.Returns(ProperDownloadTypes.DoNotPrefer);
|
||||
|
||||
_localTrack.Tracks = Builder<Track>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.TrackFileId = 1)
|
||||
.With(e => e.TrackFile = new LazyLoaded<TrackFile>(
|
||||
new TrackFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2))
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.IsSatisfiedBy(_localTrack).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_comparing_to_a_lower_quality_proper()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.DownloadPropersAndRepacks)
|
||||
.Returns(ProperDownloadTypes.DoNotPrefer);
|
||||
|
||||
_localTrack.Quality = new QualityModel(Quality.FLAC);
|
||||
|
||||
_localTrack.Tracks = Builder<Track>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.TrackFileId = 1)
|
||||
.With(e => e.TrackFile = new LazyLoaded<TrackFile>(
|
||||
new TrackFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.FLAC, new Revision(version: 2))
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.IsSatisfiedBy(_localTrack).Accepted.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@
|
|||
<Compile Include="DecisionEngineTests\ReleaseRestrictionsSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\PrioritizeDownloadDecisionFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\QualityAllowedByProfileSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RepackSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\UpgradeAllowedSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\UpgradeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\MinimumAgeSpecificationFixture.cs" />
|
||||
|
@ -644,4 +645,4 @@
|
|||
</ItemGroup>
|
||||
<Copy SourceFiles="@(IdentificationTestCases)" DestinationFolder="$(OutputPath)\Files\Identification\" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
|
@ -298,6 +298,16 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
QualityParser.ParseCodec(null, null).Should().Be(Codec.Unknown);
|
||||
}
|
||||
|
||||
[TestCase("Artist Title - Album Title 2017 REPACK FLAC aAF", true)]
|
||||
[TestCase("Artist Title - Album Title 2017 RERIP FLAC aAF", true)]
|
||||
[TestCase("Artist Title - Album Title 2017 PROPER FLAC aAF", false)]
|
||||
public void should_be_able_to_parse_repack(string title, bool isRepack)
|
||||
{
|
||||
var result = QualityParser.ParseQuality(title, null, 0);
|
||||
result.Revision.Version.Should().Be(2);
|
||||
result.Revision.IsRepack.Should().Be(isRepack);
|
||||
}
|
||||
|
||||
private void ParseAndVerifyQuality(string name, string desc, int bitrate, Quality quality, int sampleSize = 0)
|
||||
{
|
||||
var result = QualityParser.ParseQuality(name, desc, bitrate, sampleSize);
|
||||
|
|
|
@ -8,6 +8,7 @@ using NzbDrone.Core.Configuration.Events;
|
|||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Common.Http.Proxy;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Configuration
|
||||
{
|
||||
|
@ -112,11 +113,11 @@ namespace NzbDrone.Core.Configuration
|
|||
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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Common.Http.Proxy;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Configuration
|
||||
{
|
||||
|
@ -24,7 +25,7 @@ namespace NzbDrone.Core.Configuration
|
|||
//Media Management
|
||||
bool AutoUnmonitorPreviouslyDownloadedTracks { get; set; }
|
||||
string RecycleBin { get; set; }
|
||||
bool AutoDownloadPropers { get; set; }
|
||||
ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
|
||||
bool CreateEmptyArtistFolders { get; set; }
|
||||
bool DeleteEmptyFolders { get; set; }
|
||||
FileDateType FileDate { get; set; }
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
using System.Data;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(033)]
|
||||
public class download_propers_config : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Execute.WithConnection(SetConfigValue);
|
||||
Execute.Sql("DELETE FROM Config WHERE Key = 'autodownloadpropers'");
|
||||
}
|
||||
|
||||
private void SetConfigValue(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
public class DownloadDecisionComparer : IComparer<DownloadDecision>
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IDelayProfileService _delayProfileService;
|
||||
|
||||
public delegate int CompareDelegate(DownloadDecision x, DownloadDecision y);
|
||||
public delegate int CompareDelegate<TSubject, TValue>(DownloadDecision x, DownloadDecision y);
|
||||
|
||||
public DownloadDecisionComparer(IDelayProfileService delayProfileService)
|
||||
public DownloadDecisionComparer(IConfigService configService, IDelayProfileService delayProfileService)
|
||||
{
|
||||
_configService = configService;
|
||||
_delayProfileService = delayProfileService;
|
||||
}
|
||||
|
||||
|
@ -57,6 +62,12 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
|
||||
private int CompareQuality(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
if (_configService.DownloadPropersAndRepacks == ProperDownloadTypes.DoNotPrefer)
|
||||
{
|
||||
return CompareAll(CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Artist.QualityProfile.Value.GetIndex(remoteAlbum.ParsedAlbumInfo.Quality.Quality)),
|
||||
CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.ParsedAlbumInfo.Quality.Revision.Real));
|
||||
}
|
||||
|
||||
return CompareAll(CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Artist.QualityProfile.Value.GetIndex(remoteAlbum.ParsedAlbumInfo.Quality.Quality)),
|
||||
CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.ParsedAlbumInfo.Quality.Revision.Real),
|
||||
CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.ParsedAlbumInfo.Quality.Revision.Version));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
|
@ -12,10 +12,12 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
|
||||
public class DownloadDecisionPriorizationService : IPrioritizeDownloadDecision
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IDelayProfileService _delayProfileService;
|
||||
|
||||
public DownloadDecisionPriorizationService(IDelayProfileService delayProfileService)
|
||||
public DownloadDecisionPriorizationService(IConfigService configService, IDelayProfileService delayProfileService)
|
||||
{
|
||||
_configService = configService;
|
||||
_delayProfileService = delayProfileService;
|
||||
}
|
||||
|
||||
|
@ -24,7 +26,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
return decisions.Where(c => c.RemoteAlbum.DownloadAllowed)
|
||||
.GroupBy(c => c.RemoteAlbum.Artist.Id, (artistId, downloadDecisions) =>
|
||||
{
|
||||
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService));
|
||||
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_configService, _delayProfileService));
|
||||
})
|
||||
.SelectMany(c => c)
|
||||
.Union(decisions.Where(c => !c.RemoteAlbum.DownloadAllowed))
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class RepackSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RepackSpecification(IMediaFileService mediaFileService, UpgradableSpecification upgradableSpecification, Logger logger)
|
||||
{
|
||||
_mediaFileService = mediaFileService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public SpecificationPriority Priority => SpecificationPriority.Database;
|
||||
public RejectionType Type => RejectionType.Permanent;
|
||||
|
||||
public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
if (!subject.ParsedAlbumInfo.Quality.Revision.IsRepack)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
foreach (var album in subject.Albums)
|
||||
{
|
||||
var releaseGroup = subject.ParsedAlbumInfo.ReleaseGroup;
|
||||
var trackFiles = _mediaFileService.GetFilesByAlbum(album.Id);
|
||||
|
||||
foreach (var file in trackFiles)
|
||||
{
|
||||
if (_upgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedAlbumInfo.Quality))
|
||||
{
|
||||
var fileReleaseGroup = file.ReleaseGroup;
|
||||
|
||||
if (fileReleaseGroup.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Decision.Reject("Unable to determine release group for the existing file");
|
||||
}
|
||||
|
||||
if (releaseGroup.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Decision.Reject("Unable to determine release group for this release");
|
||||
}
|
||||
|
||||
if (!fileReleaseGroup.Equals(releaseGroup, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Release is a repack for a different release group. Release Group: {0}. File release group: {0}", releaseGroup, fileReleaseGroup);
|
||||
return Decision.Reject("Release is a repack for a different release group. Release Group: {0}. File release group: {0}", releaseGroup, fileReleaseGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using NzbDrone.Core.Configuration;
|
|||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
{
|
||||
|
@ -33,32 +34,34 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var downloadPropersAndRepacks = _configService.DownloadPropersAndRepacks;
|
||||
|
||||
if (downloadPropersAndRepacks == ProperDownloadTypes.DoNotPrefer)
|
||||
{
|
||||
_logger.Debug("Propers are not preferred, skipping check");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
foreach (var album in subject.Albums)
|
||||
{
|
||||
var trackFiles = _mediaFileService.GetFilesByAlbum(album.Id);
|
||||
|
||||
if (trackFiles.Any())
|
||||
foreach (var file in trackFiles)
|
||||
{
|
||||
var lowestQuality = trackFiles.Select(c => c.Quality).OrderBy(c => c.Quality.Id).First();
|
||||
var dateAdded = trackFiles[0].DateAdded;
|
||||
|
||||
_logger.Debug("Comparing file quality with report. Existing file is {0}", lowestQuality);
|
||||
|
||||
if (_qualityUpgradableSpecification.IsRevisionUpgrade(lowestQuality, subject.ParsedAlbumInfo.Quality))
|
||||
if (_qualityUpgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedAlbumInfo.Quality))
|
||||
{
|
||||
if (dateAdded < DateTime.Today.AddDays(-7))
|
||||
{
|
||||
_logger.Debug("Proper for old file, rejecting: {0}", subject);
|
||||
return Decision.Reject("Proper for old file");
|
||||
}
|
||||
|
||||
if (!_configService.AutoDownloadPropers)
|
||||
if (downloadPropersAndRepacks == ProperDownloadTypes.DoNotUpgrade)
|
||||
{
|
||||
_logger.Debug("Auto downloading of propers is disabled");
|
||||
return Decision.Reject("Proper downloading is disabled");
|
||||
}
|
||||
}
|
||||
|
||||
if (file.DateAdded < DateTime.Today.AddDays(-7))
|
||||
{
|
||||
_logger.Debug("Proper for old file, rejecting: {0}", subject);
|
||||
return Decision.Reject("Proper for old file");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using NLog;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
|
@ -19,10 +21,12 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
|
||||
public class UpgradableSpecification : IUpgradableSpecification
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpgradableSpecification(Logger logger)
|
||||
public UpgradableSpecification(IConfigService configService, Logger logger)
|
||||
{
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -77,6 +81,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
if (totalCompare == 0) {
|
||||
return ProfileComparisonResult.Equal;
|
||||
}
|
||||
|
||||
// Quality Treated as Equal if Propers are not Prefered
|
||||
if (_configService.DownloadPropersAndRepacks == ProperDownloadTypes.DoNotPrefer &&
|
||||
newQuality.Revision.CompareTo(currentQualities.Min(q => q.Revision)) > 0)
|
||||
{
|
||||
return ProfileComparisonResult.Equal;
|
||||
}
|
||||
}
|
||||
|
||||
return ProfileComparisonResult.Upgrade;
|
||||
|
|
|
@ -5,35 +5,50 @@ using NzbDrone.Core.DecisionEngine;
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport.Specifications
|
||||
{
|
||||
public class UpgradeSpecification : IImportDecisionEngineSpecification<LocalTrack>
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpgradeSpecification(Logger logger)
|
||||
public UpgradeSpecification(IConfigService configService, Logger logger)
|
||||
{
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
var downloadPropersAndRepacks = _configService.DownloadPropersAndRepacks;
|
||||
var qualityComparer = new QualityModelComparer(localTrack.Artist.QualityProfile);
|
||||
var languageComparer = new LanguageComparer(localTrack.Artist.LanguageProfile);
|
||||
|
||||
if (localTrack.Tracks.Any(e => e.TrackFileId != 0 && qualityComparer.Compare(e.TrackFile.Value.Quality, localTrack.Quality) > 0))
|
||||
foreach (var track in localTrack.Tracks.Where(e => e.TrackFileId > 0))
|
||||
{
|
||||
_logger.Debug("This file isn't a quality upgrade for all tracks. Skipping {0}", localTrack.Path);
|
||||
return Decision.Reject("Not an upgrade for existing track file(s)");
|
||||
}
|
||||
var trackFile = track.TrackFile.Value;
|
||||
var qualityCompare = qualityComparer.Compare(localTrack.Quality.Quality, trackFile.Quality.Quality);
|
||||
|
||||
if (localTrack.Tracks.Any(e => e.TrackFileId != 0 &&
|
||||
languageComparer.Compare(e.TrackFile.Value.Language, localTrack.Language) > 0 &&
|
||||
qualityComparer.Compare(e.TrackFile.Value.Quality, localTrack.Quality) == 0))
|
||||
{
|
||||
_logger.Debug("This file isn't a language upgrade for all tracks. Skipping {0}", localTrack.Path);
|
||||
return Decision.Reject("Not an upgrade for existing track file(s)");
|
||||
if (qualityCompare < 0)
|
||||
{
|
||||
_logger.Debug("This file isn't a quality upgrade for all tracks. Skipping {0}", localTrack.Path);
|
||||
return Decision.Reject("Not an upgrade for existing track file(s)");
|
||||
}
|
||||
|
||||
if (qualityCompare == 0 && downloadPropersAndRepacks != ProperDownloadTypes.DoNotPrefer &&
|
||||
localTrack.Quality.Revision.CompareTo(trackFile.Quality.Revision) < 0)
|
||||
{
|
||||
_logger.Debug("This file isn't a quality upgrade for all tracks. Skipping {0}", localTrack.Path);
|
||||
return Decision.Reject("Not an upgrade for existing track file(s)");
|
||||
}
|
||||
|
||||
if (languageComparer.Compare(localTrack.Language, trackFile.Language) < 0 && qualityCompare == 0)
|
||||
{
|
||||
_logger.Debug("This file isn't a language upgrade for all tracks. Skipping {0}", localTrack.Path);
|
||||
return Decision.Reject("Not an upgrade for existing track file(s)");
|
||||
}
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
|
|
|
@ -173,6 +173,7 @@
|
|||
<Compile Include="Datastore\Migration\030_add_mediafilerepository_mtime.cs" />
|
||||
<Compile Include="Datastore\Migration\031_add_artistmetadataid_constraint.cs" />
|
||||
<Compile Include="Datastore\Migration\032_old_ids_and_artist_alias.cs" />
|
||||
<Compile Include="Datastore\Migration\033_download_propers_config.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationDbFactory.cs" />
|
||||
|
@ -200,6 +201,7 @@
|
|||
<Compile Include="DecisionEngine\IRejectWithReason.cs" />
|
||||
<Compile Include="DecisionEngine\Rejection.cs" />
|
||||
<Compile Include="DecisionEngine\RejectionType.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RepackSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\SameTracksSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\SpecificationPriority.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\AcceptableSizeSpecification.cs" />
|
||||
|
@ -1034,6 +1036,7 @@
|
|||
<Compile Include="Profiles\Releases\TermMatchers\ITermMatcher.cs" />
|
||||
<Compile Include="Profiles\Releases\TermMatchers\RegexTermMatcher.cs" />
|
||||
<Compile Include="ProgressMessaging\ProgressMessageContext.cs" />
|
||||
<Compile Include="Qualities\ProperDownloadTypes.cs" />
|
||||
<Compile Include="Qualities\QualityDetectionSource.cs" />
|
||||
<Compile Include="Qualities\Revision.cs" />
|
||||
<Compile Include="Queue\EstimatedCompletionTimeComparer.cs" />
|
||||
|
@ -1343,4 +1346,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
|
@ -13,7 +13,10 @@ namespace NzbDrone.Core.Parser
|
|||
{
|
||||
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(QualityParser));
|
||||
|
||||
private static readonly Regex ProperRegex = new Regex(@"\b(?<proper>proper|repack|rerip)\b",
|
||||
private static readonly Regex ProperRegex = new Regex(@"\b(?<proper>proper)\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex RepackRegex = new Regex(@"\b(?<repack>repack|rerip)\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex VersionRegex = new Regex(@"\dv(?<version>\d)\b|\[v(?<version>\d)\]",
|
||||
|
@ -286,6 +289,12 @@ namespace NzbDrone.Core.Parser
|
|||
result.Revision.Version = 2;
|
||||
}
|
||||
|
||||
if (RepackRegex.IsMatch(normalizedName))
|
||||
{
|
||||
result.Revision.Version = 2;
|
||||
result.Revision.IsRepack = true;
|
||||
}
|
||||
|
||||
Match versionRegexResult = VersionRegex.Match(normalizedName);
|
||||
|
||||
if (versionRegexResult.Success)
|
||||
|
@ -294,7 +303,6 @@ namespace NzbDrone.Core.Parser
|
|||
}
|
||||
|
||||
//TODO: re-enable this when we have a reliable way to determine real
|
||||
//TODO: Only treat it as a real if it comes AFTER the season/epsiode number
|
||||
MatchCollection realRegexResult = RealRegex.Matches(name);
|
||||
|
||||
if (realRegexResult.Count > 0)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public enum ProperDownloadTypes
|
||||
{
|
||||
PreferAndUpgrade,
|
||||
DoNotUpgrade,
|
||||
DoNotPrefer
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
|
@ -9,14 +9,16 @@ namespace NzbDrone.Core.Qualities
|
|||
{
|
||||
}
|
||||
|
||||
public Revision(int version = 1, int real = 0)
|
||||
public Revision(int version = 1, int real = 0, bool isRepack = false)
|
||||
{
|
||||
Version = version;
|
||||
Real = real;
|
||||
IsRepack = isRepack;
|
||||
}
|
||||
|
||||
public int Version { get; set; }
|
||||
public int Real { get; set; }
|
||||
public bool IsRepack { get; set; }
|
||||
|
||||
public bool Equals(Revision other)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue