diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQualityFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQualityFixture.cs index b7c218ebe..ea6477df3 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQualityFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQualityFixture.cs @@ -37,10 +37,10 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators .Returns(AugmentQualityResult.ResolutionOnly(1080, Confidence.MediaInfo)); _fileExtensionAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) - .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Fallback, 720, Confidence.Fallback, new Revision())); + .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Fallback, 720, Confidence.Fallback, new Revision(), Confidence.Fallback)); _nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) - .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Default, 480, Confidence.Default, new Revision())); + .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Default, 480, Confidence.Default, new Revision(), Confidence.Default)); _releaseNameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) .Returns(AugmentQualityResult.SourceOnly(QualitySource.Web, Confidence.MediaInfo)); @@ -114,5 +114,61 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators result.Quality.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Name); result.Quality.Quality.Should().Be(Quality.WEBDL480p); } + + [Test] + public void should_return_version_1_when_no_version_specified() + { + GivenAugmenters(_nameAugmenter, _releaseNameAugmenter); + + var result = Subject.Aggregate(new LocalEpisode(), new DownloadClientItem(), false); + + result.Quality.Revision.Version.Should().Be(1); + result.Quality.RevisionDetectionSource.Should().Be(QualityDetectionSource.Unknown); + } + + [Test] + public void should_return_version_2_when_name_indicates_proper() + { + _nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) + .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Default, 480, Confidence.Default, new Revision(2), Confidence.Tag)); + + GivenAugmenters(_nameAugmenter, _releaseNameAugmenter); + + var result = Subject.Aggregate(new LocalEpisode(), new DownloadClientItem(), false); + + result.Quality.Revision.Version.Should().Be(2); + result.Quality.RevisionDetectionSource.Should().Be(QualityDetectionSource.Name); + } + + [Test] + public void should_return_version_0_when_file_name_indicates_v0() + { + _nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) + .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Default, 480, Confidence.Default, new Revision(0), Confidence.Tag)); + + GivenAugmenters(_nameAugmenter, _releaseNameAugmenter); + + var result = Subject.Aggregate(new LocalEpisode(), new DownloadClientItem(), false); + + result.Quality.Revision.Version.Should().Be(0); + result.Quality.RevisionDetectionSource.Should().Be(QualityDetectionSource.Name); + } + + [Test] + public void should_return_version_2_when_file_name_indicates_v0_and_release_name_indicates_v2() + { + _nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) + .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Default, 480, Confidence.Default, new Revision(0), Confidence.Tag)); + + _releaseNameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) + .Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Default, 480, Confidence.Default, new Revision(2), Confidence.Tag)); + + GivenAugmenters(_nameAugmenter, _releaseNameAugmenter); + + var result = Subject.Aggregate(new LocalEpisode(), new DownloadClientItem(), false); + + result.Quality.Revision.Version.Should().Be(2); + result.Quality.RevisionDetectionSource.Should().Be(QualityDetectionSource.Name); + } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs index 5f338a019..e4c26a951 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs @@ -26,7 +26,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators var sourceConfidence = Confidence.Default; var resolution = 0; var resolutionConfidence = Confidence.Default; - var revision = new Revision(); + var revision = new Revision(1); + var revisionConfidence = Confidence.Default; foreach (var augmentQuality in _augmentQualities) { @@ -52,9 +53,23 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators resolutionConfidence = augmentedQuality.ResolutionConfidence; } - if (augmentedQuality.Revision != null && augmentedQuality.Revision > revision) + if (augmentedQuality.Revision != null) { - revision = augmentedQuality.Revision; + // Update the revision and confidence if it is higher than the current confidence, + // this will allow explicitly detected v0 to override the v1 default. + if (augmentedQuality.RevisionConfidence > revisionConfidence) + { + revision = augmentedQuality.Revision; + revisionConfidence = augmentedQuality.RevisionConfidence; + } + // Update the revision and confidence if it is the same confidence and the revision is higher, + // this will allow the best revision to be used in the event there is a disagreement. + else if (augmentedQuality.RevisionConfidence == revisionConfidence && + augmentedQuality.Revision > revision) + { + revision = augmentedQuality.Revision; + revisionConfidence = augmentedQuality.RevisionConfidence; + } } } @@ -84,6 +99,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators quality.SourceDetectionSource = QualityDetectionSource.Name; } + quality.RevisionDetectionSource = revisionConfidence == Confidence.Tag ? QualityDetectionSource.Name : QualityDetectionSource.Unknown; + _logger.Debug("Using quality: {0}", quality); localEpisode.Quality = quality; diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs index fdb47d2fa..7b3ed20d0 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs @@ -26,11 +26,16 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augment ? Confidence.Tag : Confidence.Fallback; + var revisionConfidends = quality.RevisionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + return new AugmentQualityResult(quality.Quality.Source, sourceConfidence, quality.Quality.Resolution, resolutionConfidence, - quality.Revision); + quality.Revision, + revisionConfidends); } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs index 0a88217fd..17ddf82d1 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs @@ -26,11 +26,16 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augment ? Confidence.Tag : Confidence.Fallback; + var revisionConfidends = quality.RevisionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + return new AugmentQualityResult(quality.Quality.Source, sourceConfidence, quality.Quality.Resolution, resolutionConfidence, - quality.Revision); + quality.Revision, + revisionConfidends); } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs index f1006c3f7..cda422b24 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs @@ -26,11 +26,16 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augment ? Confidence.Tag : Confidence.Fallback; + var revisionConfidends = quality.RevisionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + return new AugmentQualityResult(quality.Quality.Source, sourceConfidence, quality.Quality.Resolution, resolutionConfidence, - quality.Revision); + quality.Revision, + revisionConfidends); } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseName.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseName.cs index 653dc1f2b..d81c19db4 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseName.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseName.cs @@ -43,7 +43,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augment ? Confidence.Tag : Confidence.Fallback; - return new AugmentQualityResult(historyQuality.Quality.Source, sourceConfidence, historyQuality.Quality.Resolution, resolutionConfidence, historyQuality.Revision); + var revisionConfidends = historyQuality.RevisionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + return new AugmentQualityResult(historyQuality.Quality.Source, sourceConfidence, historyQuality.Quality.Resolution, resolutionConfidence, historyQuality.Revision, revisionConfidends); } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs index 3285ddfad..4fb22ffa5 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs @@ -10,28 +10,31 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augment public int Resolution { get; set; } public Confidence ResolutionConfidence { get; set; } public Revision Revision { get; set; } + public Confidence RevisionConfidence { get; set; } public AugmentQualityResult(QualitySource source, Confidence sourceConfidence, int resolution, Confidence resolutionConfidence, - Revision revision) + Revision revision, + Confidence revisionConfidence) { Source = source; SourceConfidence = sourceConfidence; Resolution = resolution; ResolutionConfidence = resolutionConfidence; Revision = revision; + RevisionConfidence = revisionConfidence; } public static AugmentQualityResult SourceOnly(QualitySource source, Confidence sourceConfidence) { - return new AugmentQualityResult(source, sourceConfidence, 0, Confidence.Default, null); + return new AugmentQualityResult(source, sourceConfidence, 0, Confidence.Default, null, Confidence.Default); } public static AugmentQualityResult ResolutionOnly(int resolution, Confidence resolutionConfidence) { - return new AugmentQualityResult(QualitySource.Unknown, Confidence.Default, resolution, resolutionConfidence, null); + return new AugmentQualityResult(QualitySource.Unknown, Confidence.Default, resolution, resolutionConfidence, null, Confidence.Default); } } } diff --git a/src/NzbDrone.Core/Parser/QualityParser.cs b/src/NzbDrone.Core/Parser/QualityParser.cs index 23f5b6d68..3101157a4 100644 --- a/src/NzbDrone.Core/Parser/QualityParser.cs +++ b/src/NzbDrone.Core/Parser/QualityParser.cs @@ -543,12 +543,14 @@ namespace NzbDrone.Core.Parser if (ProperRegex.IsMatch(normalizedName)) { result.Revision.Version = 2; + result.RevisionDetectionSource = QualityDetectionSource.Name; } if (RepackRegex.IsMatch(normalizedName)) { result.Revision.Version = 2; result.Revision.IsRepack = true; + result.RevisionDetectionSource = QualityDetectionSource.Name; } var versionRegexResult = VersionRegex.Match(normalizedName); @@ -556,6 +558,7 @@ namespace NzbDrone.Core.Parser if (versionRegexResult.Success) { result.Revision.Version = Convert.ToInt32(versionRegexResult.Groups["version"].Value); + result.RevisionDetectionSource = QualityDetectionSource.Name; } // TODO: re-enable this when we have a reliable way to determine real @@ -565,6 +568,7 @@ namespace NzbDrone.Core.Parser if (realRegexResult.Count > 0) { result.Revision.Real = realRegexResult.Count; + result.RevisionDetectionSource = QualityDetectionSource.Name; } return result; diff --git a/src/NzbDrone.Core/Qualities/QualityModel.cs b/src/NzbDrone.Core/Qualities/QualityModel.cs index 883c26a85..7695464d1 100644 --- a/src/NzbDrone.Core/Qualities/QualityModel.cs +++ b/src/NzbDrone.Core/Qualities/QualityModel.cs @@ -16,6 +16,9 @@ namespace NzbDrone.Core.Qualities [JsonIgnore] public QualityDetectionSource ResolutionDetectionSource { get; set; } + [JsonIgnore] + public QualityDetectionSource RevisionDetectionSource { get; set; } + public QualityModel() : this(Quality.Unknown, new Revision()) {