diff --git a/src/NzbDrone.Common/Extensions/PathExtensions.cs b/src/NzbDrone.Common/Extensions/PathExtensions.cs index 4820f5dc8..49b1fbc72 100644 --- a/src/NzbDrone.Common/Extensions/PathExtensions.cs +++ b/src/NzbDrone.Common/Extensions/PathExtensions.cs @@ -62,6 +62,17 @@ public static bool PathEquals(this string firstPath, string secondPath, StringCo return string.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), comparison.Value); } + public static string GetPathExtension(this string path) + { + var idx = path.LastIndexOf('.'); + if (idx == -1 || idx == path.Length - 1) + { + return string.Empty; + } + + return path.Substring(idx); + } + public static string GetRelativePath(this string parentPath, string childPath) { if (!parentPath.IsParentPath(childPath)) diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguageFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguageFixture.cs index 541201337..32adde708 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguageFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguageFixture.cs @@ -4,6 +4,7 @@ using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Core.Download; using NzbDrone.Core.Languages; using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators; using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language; @@ -41,16 +42,16 @@ private void GivenAugmenters(List fileNameLanguages, List fo var clientInfoAugmenter = new Mock(); var mediaInfoAugmenter = new Mock(); - fileNameAugmenter.Setup(s => s.AugmentLanguage(It.IsAny())) + fileNameAugmenter.Setup(s => s.AugmentLanguage(It.IsAny(), It.IsAny())) .Returns(new AugmentLanguageResult(fileNameLanguages, Confidence.Filename)); - folderNameAugmenter.Setup(s => s.AugmentLanguage(It.IsAny())) + folderNameAugmenter.Setup(s => s.AugmentLanguage(It.IsAny(), It.IsAny())) .Returns(new AugmentLanguageResult(folderNameLanguages, Confidence.Foldername)); - clientInfoAugmenter.Setup(s => s.AugmentLanguage(It.IsAny())) + clientInfoAugmenter.Setup(s => s.AugmentLanguage(It.IsAny(), It.IsAny())) .Returns(new AugmentLanguageResult(clientLanguages, Confidence.DownloadClientItem)); - mediaInfoAugmenter.Setup(s => s.AugmentLanguage(It.IsAny())) + mediaInfoAugmenter.Setup(s => s.AugmentLanguage(It.IsAny(), It.IsAny())) .Returns(new AugmentLanguageResult(mediaInfoLanguages, Confidence.MediaInfo)); var mocks = new List> { fileNameAugmenter, folderNameAugmenter, clientInfoAugmenter, mediaInfoAugmenter }; @@ -69,7 +70,7 @@ private ParsedMovieInfo GetParsedMovieInfo(List languages) [Test] public void should_return_default_if_no_info_is_known() { - var result = Subject.Aggregate(_localMovie, false); + var result = Subject.Aggregate(_localMovie, null, false); result.Languages.Should().Contain(_movie.OriginalLanguage); } @@ -82,7 +83,7 @@ public void should_return_file_language_when_only_file_info_is_known() null, null); - Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List { Language.French }); + Subject.Aggregate(_localMovie, null, false).Languages.Should().Equal(new List { Language.French }); } [Test] @@ -93,7 +94,7 @@ public void should_return_folder_language_when_folder_info_is_known() null, null); - var aggregation = Subject.Aggregate(_localMovie, false); + var aggregation = Subject.Aggregate(_localMovie, null, false); aggregation.Languages.Should().Equal(new List { Language.German }); } @@ -106,7 +107,7 @@ public void should_return_download_client_item_language_when_download_client_ite new List { Language.Spanish }, null); - Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List { Language.Spanish }); + Subject.Aggregate(_localMovie, null, false).Languages.Should().Equal(new List { Language.Spanish }); } [Test] @@ -117,7 +118,7 @@ public void should_return_multi_language() new List { Language.Unknown }, null); - Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List { Language.French, Language.German }); + Subject.Aggregate(_localMovie, null, false).Languages.Should().Equal(new List { Language.French, Language.German }); } [Test] @@ -128,7 +129,7 @@ public void should_use_mediainfo_over_others() new List { Language.Unknown }, new List { Language.Japanese, Language.English }); - Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List { Language.Japanese, Language.English }); + Subject.Aggregate(_localMovie, null, false).Languages.Should().Equal(new List { Language.Japanese, Language.English }); } [Test] @@ -139,7 +140,7 @@ public void should_not_use_mediainfo_if_unknown() new List { Language.Unknown }, new List { Language.Unknown }); - Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List { Language.French, Language.German }); + Subject.Aggregate(_localMovie, null, false).Languages.Should().Equal(new List { Language.French, Language.German }); } } } diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQualityFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQualityFixture.cs index a9bc45f96..657ff5333 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQualityFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQualityFixture.cs @@ -3,6 +3,7 @@ using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Core.Download; using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators; using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality; using NzbDrone.Core.Parser; @@ -13,11 +14,12 @@ namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Aggregation.Aggregators { [TestFixture] - public class AugmentQualityFixture : CoreTest + public class AggregateQualityFixture : CoreTest { private Mock _mediaInfoAugmenter; private Mock _fileExtensionAugmenter; private Mock _nameAugmenter; + private Mock _releaseNameAugmenter; [SetUp] public void Setup() @@ -25,15 +27,23 @@ public void Setup() _mediaInfoAugmenter = new Mock(); _fileExtensionAugmenter = new Mock(); _nameAugmenter = new Mock(); + _releaseNameAugmenter = new Mock(); - _mediaInfoAugmenter.Setup(s => s.AugmentQuality(It.IsAny())) - .Returns(AugmentQualityResult.ResolutionOnly((int)Resolution.R1080p, Confidence.MediaInfo)); + _fileExtensionAugmenter.SetupGet(s => s.Order).Returns(1); + _nameAugmenter.SetupGet(s => s.Order).Returns(2); + _mediaInfoAugmenter.SetupGet(s => s.Order).Returns(4); + _releaseNameAugmenter.SetupGet(s => s.Order).Returns(5); - _fileExtensionAugmenter.Setup(s => s.AugmentQuality(It.IsAny())) + _mediaInfoAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())).Returns(AugmentQualityResult.ResolutionOnly((int)Resolution.R1080p, Confidence.MediaInfo)); + + _fileExtensionAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) .Returns(new AugmentQualityResult(Source.TV, Confidence.Fallback, (int)Resolution.R720p, Confidence.Fallback, Modifier.NONE, Confidence.Fallback, new Revision())); - _nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny())) - .Returns(new AugmentQualityResult(Source.TV, Confidence.Default, (int)Resolution.R480p, Confidence.Default, Modifier.NONE, Confidence.Default, new Revision())); + _nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) + .Returns(new AugmentQualityResult(Source.TV, Confidence.Default, 480, Confidence.Default, Modifier.NONE, Confidence.Fallback, new Revision())); + + _releaseNameAugmenter.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) + .Returns(AugmentQualityResult.SourceOnly(Source.WEBDL, Confidence.MediaInfo)); } private void GivenAugmenters(params Mock[] mocks) @@ -45,14 +55,15 @@ private void GivenAugmenters(params Mock[] mocks) public void should_return_HDTV720_from_extension_when_other_augments_are_null() { var nullMock = new Mock(); - nullMock.Setup(s => s.AugmentQuality(It.IsAny())) - .Returns(l => null); + nullMock.Setup(s => s.AugmentQuality(It.IsAny(), It.IsAny())) + .Returns((l, d) => null); GivenAugmenters(_fileExtensionAugmenter, nullMock); - var result = Subject.Aggregate(new LocalMovie(), false); + var result = Subject.Aggregate(new LocalMovie(), null, false); - result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.Extension); + result.Quality.SourceDetectionSource.Should().Be(QualityDetectionSource.Extension); + result.Quality.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Extension); result.Quality.Quality.Should().Be(Quality.HDTV720p); } @@ -61,9 +72,10 @@ public void should_return_SDTV_when_HDTV720_came_from_extension() { GivenAugmenters(_fileExtensionAugmenter, _nameAugmenter); - var result = Subject.Aggregate(new LocalMovie(), false); + var result = Subject.Aggregate(new LocalMovie(), null, false); - result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.Name); + result.Quality.SourceDetectionSource.Should().Be(QualityDetectionSource.Name); + result.Quality.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Name); result.Quality.Quality.Should().Be(Quality.SDTV); } @@ -72,9 +84,10 @@ public void should_return_HDTV1080p_when_HDTV720_came_from_extension_and_mediain { GivenAugmenters(_fileExtensionAugmenter, _mediaInfoAugmenter); - var result = Subject.Aggregate(new LocalMovie(), false); + var result = Subject.Aggregate(new LocalMovie(), null, false); - result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.MediaInfo); + result.Quality.SourceDetectionSource.Should().Be(QualityDetectionSource.Extension); + result.Quality.ResolutionDetectionSource.Should().Be(QualityDetectionSource.MediaInfo); result.Quality.Quality.Should().Be(Quality.HDTV1080p); } @@ -83,10 +96,23 @@ public void should_return_HDTV1080p_when_SDTV_came_from_name_and_mediainfo_indic { GivenAugmenters(_nameAugmenter, _mediaInfoAugmenter); - var result = Subject.Aggregate(new LocalMovie(), false); + var result = Subject.Aggregate(new LocalMovie(), null, false); - result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.MediaInfo); + result.Quality.SourceDetectionSource.Should().Be(QualityDetectionSource.Name); + result.Quality.ResolutionDetectionSource.Should().Be(QualityDetectionSource.MediaInfo); result.Quality.Quality.Should().Be(Quality.HDTV1080p); } + + [Test] + public void should_return_WEBDL480p_when_file_name_has_HDTV480p_but_release_name_indicates_webdl_source() + { + GivenAugmenters(_nameAugmenter, _releaseNameAugmenter); + + var result = Subject.Aggregate(new LocalMovie(), new DownloadClientItem(), false); + + result.Quality.SourceDetectionSource.Should().Be(QualityDetectionSource.Name); + result.Quality.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Name); + result.Quality.Quality.Should().Be(Quality.WEBDL480p); + } } } diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroupFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroupFixture.cs index 975ee0f5b..a7506e046 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroupFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroupFixture.cs @@ -35,7 +35,7 @@ public void should_prefer_downloadclient() Movie = _movie }; - Subject.Aggregate(localMovie, false); + Subject.Aggregate(localMovie, null, false); localMovie.ReleaseGroup.Should().Be("Viva"); } @@ -55,7 +55,7 @@ public void should_prefer_folder() Movie = _movie }; - Subject.Aggregate(localMovie, false); + Subject.Aggregate(localMovie, null, false); localMovie.ReleaseGroup.Should().Be("Drone"); } @@ -75,7 +75,7 @@ public void should_fallback_to_file() Movie = _movie }; - Subject.Aggregate(localMovie, false); + Subject.Aggregate(localMovie, null, false); localMovie.ReleaseGroup.Should().Be("Wizzy"); } diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfoFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfoFixture.cs index e7bd14bc1..9e580e257 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfoFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfoFixture.cs @@ -20,7 +20,7 @@ public void should_return_null_if_media_info_is_null() .With(l => l.MediaInfo = null) .Build(); - Subject.AugmentLanguage(localMovie).Should().Be(null); + Subject.AugmentLanguage(localMovie, null).Should().Be(null); } [Test] @@ -34,7 +34,7 @@ public void should_return_language_for_single_known_language() .With(l => l.MediaInfo = mediaInfo) .Build(); - var result = Subject.AugmentLanguage(localMovie); + var result = Subject.AugmentLanguage(localMovie, null); result.Languages.Count.Should().Be(1); result.Languages.Should().Contain(Core.Languages.Language.English); @@ -51,7 +51,7 @@ public void should_only_return_one_when_language_duplicated() .With(l => l.MediaInfo = mediaInfo) .Build(); - var result = Subject.AugmentLanguage(localMovie); + var result = Subject.AugmentLanguage(localMovie, null); result.Languages.Count.Should().Be(1); result.Languages.Should().Contain(Core.Languages.Language.English); @@ -68,7 +68,7 @@ public void should_return_null_if_all_unknown() .With(l => l.MediaInfo = mediaInfo) .Build(); - var result = Subject.AugmentLanguage(localMovie); + var result = Subject.AugmentLanguage(localMovie, null); result.Should().BeNull(); } @@ -84,7 +84,7 @@ public void should_return_known_languages_only() .With(l => l.MediaInfo = mediaInfo) .Build(); - var result = Subject.AugmentLanguage(localMovie); + var result = Subject.AugmentLanguage(localMovie, null); result.Languages.Count.Should().Be(1); result.Languages.Should().Contain(Core.Languages.Language.English); @@ -101,7 +101,7 @@ public void should_return_multiple_known_languages() .With(l => l.MediaInfo = mediaInfo) .Build(); - var result = Subject.AugmentLanguage(localMovie); + var result = Subject.AugmentLanguage(localMovie, null); result.Languages.Count.Should().Be(2); result.Languages.Should().Contain(Core.Languages.Language.English); diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs index c52ebf676..00e0d3a12 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs @@ -19,7 +19,7 @@ public void should_return_null_if_media_info_is_null() .With(l => l.MediaInfo = null) .Build(); - Subject.AugmentQuality(localMovie).Should().Be(null); + Subject.AugmentQuality(localMovie, null).Should().Be(null); } [Test] @@ -33,34 +33,36 @@ public void should_return_null_if_media_info_width_is_zero() .With(l => l.MediaInfo = mediaInfo) .Build(); - Subject.AugmentQuality(localMovie).Should().Be(null); + Subject.AugmentQuality(localMovie, null).Should().Be(null); } - [TestCase(4096, Resolution.R2160p)] // True 4K - [TestCase(4000, Resolution.R2160p)] - [TestCase(3840, Resolution.R2160p)] // 4K UHD - [TestCase(3200, Resolution.R2160p)] - [TestCase(2000, Resolution.R1080p)] - [TestCase(1920, Resolution.R1080p)] // Full HD - [TestCase(1800, Resolution.R1080p)] - [TestCase(1490, Resolution.R720p)] - [TestCase(1280, Resolution.R720p)] // HD - [TestCase(1200, Resolution.R720p)] - [TestCase(800, Resolution.R480p)] - [TestCase(720, Resolution.R480p)] // SDTV - [TestCase(600, Resolution.R480p)] - [TestCase(100, Resolution.R480p)] - public void should_return_closest_resolution(int mediaInfoWidth, Resolution expectedResolution) + [TestCase(4096, 1, Resolution.R2160p)] // True 4K + [TestCase(4000, 1, Resolution.R2160p)] + [TestCase(3840, 1, Resolution.R2160p)] // 4K UHD + [TestCase(3200, 1, Resolution.R2160p)] + [TestCase(2000, 1, Resolution.R1080p)] + [TestCase(1920, 1, Resolution.R1080p)] // Full HD + [TestCase(1440, 1080, Resolution.R1080p)] // 4:3 FullHD + [TestCase(1800, 1, Resolution.R1080p)] + [TestCase(1490, 1, Resolution.R720p)] + [TestCase(1280, 1, Resolution.R720p)] // HD + [TestCase(1200, 1, Resolution.R720p)] + [TestCase(800, 1, Resolution.R480p)] + [TestCase(720, 1, Resolution.R480p)] // SDTV + [TestCase(600, 1, Resolution.R480p)] + [TestCase(100, 1, Resolution.R480p)] + public void should_return_closest_resolution(int mediaInfoWidth, int mediaInfoHeight, Resolution expectedResolution) { var mediaInfo = Builder.CreateNew() .With(m => m.Width = mediaInfoWidth) + .With(m => m.Height = mediaInfoHeight) .Build(); var localMovie = Builder.CreateNew() .With(l => l.MediaInfo = mediaInfo) .Build(); - var result = Subject.AugmentQuality(localMovie); + var result = Subject.AugmentQuality(localMovie, null); result.Should().NotBe(null); result.Resolution.Should().Be((int)expectedResolution); diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseNameFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseNameFixture.cs new file mode 100644 index 000000000..e65c17a0b --- /dev/null +++ b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseNameFixture.cs @@ -0,0 +1,78 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Download; +using NzbDrone.Core.Download.History; +using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality +{ + [TestFixture] + public class AugmentQualityFromReleaseNameFixture : CoreTest + { + private LocalMovie _localMovie; + private DownloadClientItem _downloadClientItem; + private ParsedMovieInfo _hdtvParsedEpisodeInfo; + private ParsedMovieInfo _webdlParsedEpisodeInfo; + + [SetUp] + public void Setup() + { + _hdtvParsedEpisodeInfo = Builder.CreateNew() + .With(p => p.Quality = + new QualityModel(Core.Qualities.Quality.HDTV720p)) + .Build(); + + _webdlParsedEpisodeInfo = Builder.CreateNew() + .With(p => p.Quality = + new QualityModel(Core.Qualities.Quality.WEBDL720p)) + .Build(); + + _localMovie = Builder.CreateNew() + .Build(); + + _downloadClientItem = Builder.CreateNew() + .Build(); + } + + [Test] + public void should_return_null_if_download_client_item_is_null() + { + Subject.AugmentQuality(_localMovie, null).Should().BeNull(); + } + + [Test] + public void should_return_null_if_no_grabbed_history() + { + Mocker.GetMock() + .Setup(s => s.GetLatestGrab(It.IsAny())) + .Returns((DownloadHistory)null); + + Subject.AugmentQuality(_localMovie, _downloadClientItem).Should().BeNull(); + } + + [TestCase("Series.Title.S01E01.1080p.WEB.x264", Source.WEBDL, Confidence.Tag, 1080, Confidence.Tag)] + [TestCase("Series.Title.S01E01.WEB.x264", Source.WEBDL, Confidence.Tag, 480, Confidence.Fallback)] + [TestCase("Series.Title.S01E01.720p.x264", Source.TV, Confidence.Fallback, 720, Confidence.Tag)] + public void should_return_augmented_quality(string title, Source source, Confidence sourceConfidence, int resolution, Confidence resolutionConfidence) + { + Mocker.GetMock() + .Setup(s => s.GetLatestGrab(It.IsAny())) + .Returns(Builder.CreateNew() + .With(h => h.SourceTitle = title) + .Build()); + + var result = Subject.AugmentQuality(_localMovie, _downloadClientItem); + + result.Should().NotBe(null); + result.Source.Should().Be(source); + result.SourceConfidence.Should().Be(sourceConfidence); + result.Resolution.Should().Be(resolution); + result.ResolutionConfidence.Should().Be(resolutionConfidence); + } + } +} diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/ImportDecisionMakerFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/ImportDecisionMakerFixture.cs index d4b9abb49..2e5a7762d 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/ImportDecisionMakerFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/ImportDecisionMakerFixture.cs @@ -102,8 +102,8 @@ private void GivenVideoFiles(IEnumerable videoFiles) private void GivenAugmentationSuccess() { Mocker.GetMock() - .Setup(s => s.Augment(It.IsAny(), It.IsAny())) - .Callback((localMovie, otherFiles) => + .Setup(s => s.Augment(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((localMovie, downloadClientItem, otherFiles) => { localMovie.Movie = _localMovie.Movie; }); @@ -173,7 +173,7 @@ public void should_not_blowup_the_process_due_to_failed_parse() GivenSpecifications(_pass1); Mocker.GetMock() - .Setup(c => c.Augment(It.IsAny(), It.IsAny())) + .Setup(c => c.Augment(It.IsAny(), It.IsAny(), It.IsAny())) .Throws(); _videoFiles = new List @@ -188,7 +188,7 @@ public void should_not_blowup_the_process_due_to_failed_parse() Subject.GetImportDecisions(_videoFiles, _movie); Mocker.GetMock() - .Verify(c => c.Augment(It.IsAny(), It.IsAny()), Times.Exactly(_videoFiles.Count)); + .Verify(c => c.Augment(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(_videoFiles.Count)); ExceptionVerification.ExpectedErrors(3); } @@ -209,7 +209,7 @@ public void should_call_parsing_service_with_filename_as_simpletitle() var fileNames = _videoFiles.Select(System.IO.Path.GetFileName); Mocker.GetMock() - .Setup(c => c.Augment(It.IsAny(), It.IsAny())) + .Setup(c => c.Augment(It.IsAny(), It.IsAny(), It.IsAny())) .Throws(); } @@ -217,7 +217,7 @@ public void should_call_parsing_service_with_filename_as_simpletitle() public void should_return_a_decision_when_exception_is_caught() { Mocker.GetMock() - .Setup(c => c.Augment(It.IsAny(), It.IsAny())) + .Setup(c => c.Augment(It.IsAny(), It.IsAny(), It.IsAny())) .Throws(); _videoFiles = new List diff --git a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Specifications/DifferentQualitySpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Specifications/DifferentQualitySpecificationFixture.cs deleted file mode 100644 index 8e92a67ed..000000000 --- a/src/NzbDrone.Core.Test/MediaFiles/MovieImport/Specifications/DifferentQualitySpecificationFixture.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Collections.Generic; -using FizzWare.NBuilder; -using FluentAssertions; -using Moq; -using NUnit.Framework; -using NzbDrone.Core.Download; -using NzbDrone.Core.History; -using NzbDrone.Core.MediaFiles.MovieImport.Specifications; -using NzbDrone.Core.Movies; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Profiles; -using NzbDrone.Core.Qualities; -using NzbDrone.Core.Test.Framework; - -namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Specifications -{ - [TestFixture] - public class DifferentQualitySpecificationFixture : CoreTest - { - private LocalMovie _localMovie; - private DownloadClientItem _downloadClientItem; - - [SetUp] - public void Setup() - { - var qualityProfile = new Profile - { - Cutoff = Quality.Bluray1080p.Id, - Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p) - }; - - var fakeMovie = Builder.CreateNew() - .With(c => c.Profile = qualityProfile) - .Build(); - - _localMovie = Builder.CreateNew() - .With(l => l.Quality = new QualityModel(Quality.Bluray1080p)) - .With(l => l.DownloadClientMovieInfo = new ParsedMovieInfo()) - .With(l => l.Movie = fakeMovie) - .Build(); - - _downloadClientItem = Builder.CreateNew() - .Build(); - } - - private void GivenGrabbedMovieHistory(QualityModel quality) - { - var history = Builder.CreateListOfSize(1) - .TheFirst(1) - .With(h => h.Quality = quality) - .With(h => h.EventType = MovieHistoryEventType.Grabbed) - .BuildList(); - - Mocker.GetMock() - .Setup(s => s.FindByDownloadId(It.IsAny())) - .Returns(history); - } - - [Test] - public void should_be_accepted_if_no_download_client_item() - { - Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue(); - } - - [Test] - public void should_be_accepted_if_no_grabbed_movie_history() - { - Mocker.GetMock() - .Setup(s => s.FindByDownloadId(It.IsAny())) - .Returns(new List()); - - _localMovie.Movie = Builder.CreateNew() - .With(e => e.MovieFileId = 0) - .Build(); - - Subject.IsSatisfiedBy(_localMovie, _downloadClientItem).Accepted.Should().BeTrue(); - } - - [Test] - public void should_be_accepted_if_quality_matches() - { - GivenGrabbedMovieHistory(_localMovie.Quality); - - Subject.IsSatisfiedBy(_localMovie, _downloadClientItem).Accepted.Should().BeTrue(); - } - - [Test] - public void should_be_rejected_if_quality_does_not_match() - { - GivenGrabbedMovieHistory(new QualityModel(Quality.SDTV)); - - Subject.IsSatisfiedBy(_localMovie, _downloadClientItem).Accepted.Should().BeFalse(); - } - } -} diff --git a/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs index 17d4e59ea..26c019d07 100644 --- a/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs @@ -326,23 +326,66 @@ public void should_parse_quality_from_other_source(string qualityString, Source } } + [TestCase("Movie - 2018 [HDTV-1080p]")] [TestCase("Saturday.Night.Live.Vintage.S10E09.Eddie.Murphy.The.Honeydrippers.1080i.UPSCALE.HDTV.DD5.1.MPEG2-zebra")] - [TestCase("Dexter - S01E01 - Title [HDTV-1080p]")] - [TestCase("[CR] Sailor Moon - 004 [480p][48CE2D0F]")] - [TestCase("White.Van.Man.2011.S02E01.WS.PDTV.x264-REPACK-TLA")] - public void should_parse_quality_from_name(string title) + [TestCase("Movie.Title.2018.Bluray720p")] + [TestCase("Movie.Title.2018.Bluray1080p")] + [TestCase("Movie.Title.2018.Bluray2160p")] + [TestCase("Movie.Title.2018.848x480.dvd")] + [TestCase("Movie.Title.2018.848x480.Bluray")] + [TestCase("Movie.Title.2018.1280x720.Bluray")] + [TestCase("Movie.Title.2018.1920x1080.Bluray")] + public void should_parse_full_quality_from_name(string title) { - QualityParser.ParseQuality(title).QualityDetectionSource.Should().Be(QualityDetectionSource.Name); + var result = QualityParser.ParseQuality(title); + + result.SourceDetectionSource.Should().Be(QualityDetectionSource.Name); + result.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Name); + } + + [TestCase("Movie.Title.2018.848x480")] + [TestCase("Movie.Title.2018.1280x720")] + [TestCase("Movie.Title.2018.1920x1080")] + public void should_parse_resolution_from_name(string title) + { + var result = QualityParser.ParseQuality(title); + + result.SourceDetectionSource.Should().Be(QualityDetectionSource.Unknown); + result.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Name); + } + + [TestCase("White.Van.Man.2011.S02E01.WS.PDTV.x264-REPACK-TLA")] + [TestCase("Series.Title.S01E01.Bluray")] + [TestCase("Series.Title.S01E01.HD.TV")] + [TestCase("Series.Title.S01E01.SD.TV")] + public void should_parse_source_from_name(string title) + { + var result = QualityParser.ParseQuality(title); + + result.SourceDetectionSource.Should().Be(QualityDetectionSource.Name); + result.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Unknown); } [TestCase("Revolution.S01E02.Chained.Heat.mkv")] - [TestCase("Star.Wars.Episode.VII.The.Force.Awakens.mk3d")] [TestCase("Dexter - S01E01 - Title.avi")] [TestCase("the_x-files.9x18.sunshine_days.avi")] [TestCase("[CR] Sailor Moon - 004 [48CE2D0F].avi")] public void should_parse_quality_from_extension(string title) { - QualityParser.ParseQuality(title).QualityDetectionSource.Should().Be(QualityDetectionSource.Extension); + var result = QualityParser.ParseQuality(title); + + result.SourceDetectionSource.Should().Be(QualityDetectionSource.Extension); + result.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Extension); + } + + [TestCase("Revolution.S01E02.Chained.Heat.1080p.mkv")] + [TestCase("Dexter - S01E01 - Title.720p.avi")] + public void should_parse_resolution_from_name_and_source_from_extension(string title) + { + var result = QualityParser.ParseQuality(title); + + result.SourceDetectionSource.Should().Be(QualityDetectionSource.Extension); + result.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Name); } [TestCase("Movie.Title.2016.1080p.KORSUB.WEBRip.x264.AAC2.0-RADARR", "KORSUB")] diff --git a/src/NzbDrone.Core/Download/History/DownloadHistoryService.cs b/src/NzbDrone.Core/Download/History/DownloadHistoryService.cs index 8ea02d690..bcada9ab0 100644 --- a/src/NzbDrone.Core/Download/History/DownloadHistoryService.cs +++ b/src/NzbDrone.Core/Download/History/DownloadHistoryService.cs @@ -12,6 +12,7 @@ public interface IDownloadHistoryService { bool DownloadAlreadyImported(string downloadId); DownloadHistory GetLatestDownloadHistoryItem(string downloadId); + DownloadHistory GetLatestGrab(string downloadId); } public class DownloadHistoryService : IDownloadHistoryService, @@ -84,6 +85,12 @@ public DownloadHistory GetLatestDownloadHistoryItem(string downloadId) return null; } + public DownloadHistory GetLatestGrab(string downloadId) + { + return _repository.FindByDownloadId(downloadId) + .FirstOrDefault(d => d.EventType == DownloadHistoryEventType.DownloadGrabbed); + } + public void Handle(MovieGrabbedEvent message) { // Don't store grabbed events for clients that don't download IDs diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/AggregationService.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/AggregationService.cs index 6c0ba1114..773c73abf 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/AggregationService.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/AggregationService.cs @@ -4,6 +4,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Download; using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators; using NzbDrone.Core.Parser.Model; @@ -12,7 +13,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation { public interface IAggregationService { - LocalMovie Augment(LocalMovie localMovie, bool otherFiles); + LocalMovie Augment(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles); } public class AggregationService : IAggregationService @@ -36,7 +37,7 @@ public AggregationService(IEnumerable augmenters, _logger = logger; } - public LocalMovie Augment(LocalMovie localMovie, bool otherFiles) + public LocalMovie Augment(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles) { var isMediaFile = MediaFileExtensions.Extensions.Contains(Path.GetExtension(localMovie.Path)); @@ -61,7 +62,7 @@ public LocalMovie Augment(LocalMovie localMovie, bool otherFiles) { try { - augmenter.Aggregate(localMovie, otherFiles); + augmenter.Aggregate(localMovie, downloadClientItem, otherFiles); } catch (Exception ex) { diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateEdition.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateEdition.cs index c601a6330..b0170e573 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateEdition.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateEdition.cs @@ -1,11 +1,12 @@ using NzbDrone.Common.Extensions; +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators { public class AggregateEdition : IAggregateLocalMovie { - public LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles) + public LocalMovie Aggregate(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles) { var movieEdition = localMovie.DownloadClientMovieInfo?.Edition; diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs index eeff26152..3df7c2f0a 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using NLog; +using NzbDrone.Core.Download; using NzbDrone.Core.Languages; using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language; using NzbDrone.Core.Parser.Model; @@ -9,27 +10,31 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators { public class AggregateLanguage : IAggregateLocalMovie { - private readonly IEnumerable _augmentQualities; + private readonly List _augmentLanguages; private readonly Logger _logger; - public AggregateLanguage(IEnumerable augmentQualities, + public AggregateLanguage(IEnumerable augmentLanguages, Logger logger) { - _augmentQualities = augmentQualities; + _augmentLanguages = augmentLanguages.OrderBy(a => a.Order).ToList(); _logger = logger; } - public LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles) + public LocalMovie Aggregate(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles) { - var augmentedLanguages = _augmentQualities.Select(a => a.AugmentLanguage(localMovie)) - .Where(a => a != null) - .OrderBy(a => a.Confidence); - var languages = new List { localMovie.Movie.OriginalLanguage ?? Language.Unknown }; var languagesConfidence = Confidence.Default; - foreach (var augmentedLanguage in augmentedLanguages) + foreach (var augmentLanguage in _augmentLanguages) { + var augmentedLanguage = augmentLanguage.AugmentLanguage(localMovie, downloadClientItem); + if (augmentedLanguage == null) + { + continue; + } + + _logger.Trace("Considering Languages {0} ({1}) from {2}", string.Join(", ", augmentedLanguage.Languages ?? new List()), augmentedLanguage.Confidence, augmentLanguage.Name); + if (augmentedLanguage?.Languages != null && augmentedLanguage.Languages.Count > 0 && !(augmentedLanguage.Languages.Count == 1 && augmentedLanguage.Languages.Contains(Language.Unknown))) { languages = augmentedLanguage.Languages; @@ -37,7 +42,7 @@ public LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles) } } - _logger.Debug("Using languages: {0}", string.Join(", ", languages.ToList())); + _logger.Debug("Selected languages: {0}", string.Join(", ", languages.ToList())); localMovie.Languages = languages; diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQuality.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQuality.cs index 31b862fa8..c7d1125d4 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQuality.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateQuality.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using NLog; +using NzbDrone.Core.Download; using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; @@ -9,40 +10,44 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators { public class AggregateQuality : IAggregateLocalMovie { - private readonly IEnumerable _augmentQualities; + private readonly List _augmentQualities; private readonly Logger _logger; public AggregateQuality(IEnumerable augmentQualities, Logger logger) { - _augmentQualities = augmentQualities; + _augmentQualities = augmentQualities.OrderBy(a => a.Order).ToList(); _logger = logger; } - public LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles) + public LocalMovie Aggregate(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles) { - var augmentedQualities = _augmentQualities.Select(a => a.AugmentQuality(localMovie)) - .Where(a => a != null) - .OrderBy(a => a.SourceConfidence); - var source = Source.UNKNOWN; var sourceConfidence = Confidence.Default; var resolution = 0; var resolutionConfidence = Confidence.Default; var modifier = Modifier.NONE; var modifierConfidence = Confidence.Default; - var revison = new Revision(); + var revision = new Revision(); - foreach (var augmentedQuality in augmentedQualities) + foreach (var augmentQuality in _augmentQualities) { - if (augmentedQuality.Source > source || + var augmentedQuality = augmentQuality.AugmentQuality(localMovie, downloadClientItem); + if (augmentedQuality == null) + { + continue; + } + + _logger.Trace("Considering Source {0} ({1}) Resolution {2} ({3}) Revision {4} from {5}", augmentedQuality.Source, augmentedQuality.SourceConfidence, augmentedQuality.Resolution, augmentedQuality.ResolutionConfidence, augmentedQuality.Revision, augmentQuality.Name); + + if (source == Source.UNKNOWN || (augmentedQuality.SourceConfidence > sourceConfidence && augmentedQuality.Source != Source.UNKNOWN)) { source = augmentedQuality.Source; sourceConfidence = augmentedQuality.SourceConfidence; } - if (augmentedQuality.Resolution > resolution || + if (resolution == 0 || (augmentedQuality.ResolutionConfidence > resolutionConfidence && augmentedQuality.Resolution > 0)) { resolution = augmentedQuality.Resolution; @@ -56,27 +61,36 @@ public LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles) modifierConfidence = augmentedQuality.ModifierConfidence; } - if (augmentedQuality.Revision != null && augmentedQuality.Revision > revison) + if (augmentedQuality.Revision != null && augmentedQuality.Revision > revision) { - revison = augmentedQuality.Revision; + revision = augmentedQuality.Revision; } } - _logger.Trace("Finding quality. Source: {0}. Resolution: {1}. Modifier {2}", source, resolution, modifier); + _logger.Trace("Selected Source {0} ({1}) Resolution {2} ({3}) Revision {4}", source, sourceConfidence, resolution, resolutionConfidence, revision); - var quality = new QualityModel(QualityFinder.FindBySourceAndResolution(source, resolution, modifier), revison); + var quality = new QualityModel(QualityFinder.FindBySourceAndResolution(source, resolution, modifier), revision); if (resolutionConfidence == Confidence.MediaInfo) { - quality.QualityDetectionSource = QualityDetectionSource.MediaInfo; + quality.ResolutionDetectionSource = QualityDetectionSource.MediaInfo; } - else if (sourceConfidence == Confidence.Fallback || resolutionConfidence == Confidence.Fallback) + else if (resolutionConfidence == Confidence.Fallback) { - quality.QualityDetectionSource = QualityDetectionSource.Extension; + quality.ResolutionDetectionSource = QualityDetectionSource.Extension; } else { - quality.QualityDetectionSource = QualityDetectionSource.Name; + quality.ResolutionDetectionSource = QualityDetectionSource.Name; + } + + if (sourceConfidence == Confidence.Fallback) + { + quality.SourceDetectionSource = QualityDetectionSource.Extension; + } + else + { + quality.SourceDetectionSource = QualityDetectionSource.Name; } _logger.Debug("Using quality: {0}", quality); diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroup.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroup.cs index a91ccf23b..af7c0cac9 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroup.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateReleaseGroup.cs @@ -1,11 +1,12 @@ using NzbDrone.Common.Extensions; +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators { public class AggregateReleaseGroup : IAggregateLocalMovie { - public LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles) + public LocalMovie Aggregate(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles) { var releaseGroup = localMovie.DownloadClientMovieInfo?.ReleaseGroup; diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromDownloadClientItem.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromDownloadClientItem.cs index d65a01d02..c78324325 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromDownloadClientItem.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromDownloadClientItem.cs @@ -1,10 +1,14 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language { public class AugmentLanguageFromDownloadClientItem : IAugmentLanguage { - public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie) + public int Order => 3; + public string Name => "DownloadClientItem"; + + public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie, DownloadClientItem downloadClientItem) { var languages = localMovie.DownloadClientMovieInfo?.Languages; diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFileName.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFileName.cs index f762cbf86..44550ef00 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFileName.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFileName.cs @@ -1,10 +1,14 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language { public class AugmentLanguageFromFileName : IAugmentLanguage { - public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie) + public int Order => 1; + public string Name => "FileName"; + + public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie, DownloadClientItem downloadClientItem) { var languages = localMovie.FileMovieInfo?.Languages; diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFolder.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFolder.cs index 1261c7021..d19f6c17a 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFolder.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromFolder.cs @@ -1,10 +1,14 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language { public class AugmentLanguageFromFolder : IAugmentLanguage { - public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie) + public int Order => 2; + public string Name => "FolderName"; + + public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie, DownloadClientItem downloadClientItem) { var languages = localMovie.FolderMovieInfo?.Languages; diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfo.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfo.cs index bc22d9f98..a97619a3e 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfo.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageFromMediaInfo.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Download; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; @@ -8,7 +9,10 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter { public class AugmentLanguageFromMediaInfo : IAugmentLanguage { - public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie) + public int Order => 4; + public string Name => "MediaInfo"; + + public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie, DownloadClientItem downloadClientItem) { if (localMovie.MediaInfo == null) { diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageResult.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageResult.cs index a0faf2b62..5ee42deb2 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageResult.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/AugmentLanguageResult.cs @@ -4,6 +4,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter { public class AugmentLanguageResult { + public string Name { get; set; } public List Languages { get; set; } public Confidence Confidence { get; set; } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/IAugmentLanguage.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/IAugmentLanguage.cs index 79f06b909..95046b2ea 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/IAugmentLanguage.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Language/IAugmentLanguage.cs @@ -1,9 +1,12 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language { public interface IAugmentLanguage { - AugmentLanguageResult AugmentLanguage(LocalMovie localMovie); + int Order { get; } + string Name { get; } + AugmentLanguageResult AugmentLanguage(LocalMovie localMovie, DownloadClientItem downloadClientItem); } } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs index 09f02fe6b..fc499f2fb 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromDownloadClientItem.cs @@ -1,10 +1,15 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality { public class AugmentQualityFromDownloadClientItem : IAugmentQuality { - public AugmentQualityResult AugmentQuality(LocalMovie localMovie) + public int Order => 3; + public string Name => "DownloadClientItem"; + + public AugmentQualityResult AugmentQuality(LocalMovie localMovie, DownloadClientItem downloadClientItem) { var quality = localMovie.DownloadClientMovieInfo?.Quality; @@ -13,12 +18,24 @@ public AugmentQualityResult AugmentQuality(LocalMovie localMovie) return null; } + var sourceConfidence = quality.SourceDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + var resolutionConfidence = quality.ResolutionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + var modifierConfidence = quality.ModifierDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + return new AugmentQualityResult(quality.Quality.Source, - Confidence.Tag, + sourceConfidence, quality.Quality.Resolution, - Confidence.Tag, + resolutionConfidence, quality.Quality.Modifier, - Confidence.Tag, + modifierConfidence, quality.Revision); } } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs index e45db6f80..9bcec42e7 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFileName.cs @@ -1,3 +1,4 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; @@ -5,7 +6,10 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter { public class AugmentQualityFromFileName : IAugmentQuality { - public AugmentQualityResult AugmentQuality(LocalMovie localMovie) + public int Order => 1; + public string Name => "FileName"; + + public AugmentQualityResult AugmentQuality(LocalMovie localMovie, DownloadClientItem downloadClientItem) { var quality = localMovie.FileMovieInfo?.Quality; @@ -14,16 +18,24 @@ public AugmentQualityResult AugmentQuality(LocalMovie localMovie) return null; } - var confidence = quality.QualityDetectionSource == QualityDetectionSource.Extension - ? Confidence.Fallback - : Confidence.Tag; + var sourceConfidence = quality.SourceDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + var resolutionConfidence = quality.ResolutionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + var modifierConfidence = quality.ModifierDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; return new AugmentQualityResult(quality.Quality.Source, - confidence, + sourceConfidence, quality.Quality.Resolution, - confidence, + resolutionConfidence, quality.Quality.Modifier, - confidence, + modifierConfidence, quality.Revision); } } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs index 574212c20..be85f3c98 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromFolder.cs @@ -1,10 +1,15 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality { public class AugmentQualityFromFolder : IAugmentQuality { - public AugmentQualityResult AugmentQuality(LocalMovie localMovie) + public int Order => 2; + public string Name => "FolderName"; + + public AugmentQualityResult AugmentQuality(LocalMovie localMovie, DownloadClientItem downloadClientItem) { var quality = localMovie.FolderMovieInfo?.Quality; @@ -13,12 +18,24 @@ public AugmentQualityResult AugmentQuality(LocalMovie localMovie) return null; } + var sourceConfidence = quality.SourceDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + var resolutionConfidence = quality.ResolutionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + var modifierConfidence = quality.ModifierDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + return new AugmentQualityResult(quality.Quality.Source, - Confidence.Tag, + sourceConfidence, quality.Quality.Resolution, - Confidence.Tag, + resolutionConfidence, quality.Quality.Modifier, - Confidence.Tag, + modifierConfidence, quality.Revision); } } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs index 4de0de53a..dcd6ebcd9 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs @@ -1,3 +1,5 @@ +using NLog; +using NzbDrone.Core.Download; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; @@ -5,7 +7,17 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter { public class AugmentQualityFromMediaInfo : IAugmentQuality { - public AugmentQualityResult AugmentQuality(LocalMovie localMovie) + private readonly Logger _logger; + + public int Order => 4; + public string Name => "MediaInfo"; + + public AugmentQualityFromMediaInfo(Logger logger) + { + _logger = logger; + } + + public AugmentQualityResult AugmentQuality(LocalMovie localMovie, DownloadClientItem downloadClientItem) { if (localMovie.MediaInfo == null) { @@ -13,27 +25,34 @@ public AugmentQualityResult AugmentQuality(LocalMovie localMovie) } var width = localMovie.MediaInfo.Width; + var height = localMovie.MediaInfo.Height; - if (width >= 3200) + if (width >= 3200 || height >= 2100) { + _logger.Trace("Resolution {0}x{1} considered 2160p", width, height); return AugmentQualityResult.ResolutionOnly((int)Resolution.R2160p, Confidence.MediaInfo); } - if (width >= 1800) + if (width >= 1800 || height >= 1000) { + _logger.Trace("Resolution {0}x{1} considered 1080p", width, height); return AugmentQualityResult.ResolutionOnly((int)Resolution.R1080p, Confidence.MediaInfo); } - if (width >= 1200) + if (width >= 1200 || height >= 700) { + _logger.Trace("Resolution {0}x{1} considered 720p", width, height); return AugmentQualityResult.ResolutionOnly((int)Resolution.R720p, Confidence.MediaInfo); } - if (width > 0) + if (width > 0 && height > 0) { + _logger.Trace("Resolution {0}x{1} considered 480p", width, height); return AugmentQualityResult.ResolutionOnly((int)Resolution.R480p, Confidence.MediaInfo); } + _logger.Trace("Resolution {0}x{1}", width, height); + return null; } } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseName.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseName.cs new file mode 100644 index 000000000..f5aa70acf --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromReleaseName.cs @@ -0,0 +1,49 @@ +using NzbDrone.Core.Download; +using NzbDrone.Core.Download.History; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; + +namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality +{ + public class AugmentQualityFromReleaseName : IAugmentQuality + { + public int Order => 5; + public string Name => "ReleaseName"; + + private readonly IDownloadHistoryService _downloadHistoryService; + + public AugmentQualityFromReleaseName(IDownloadHistoryService downloadHistoryService) + { + _downloadHistoryService = downloadHistoryService; + } + + public AugmentQualityResult AugmentQuality(LocalMovie localMovie, DownloadClientItem downloadClientItem) + { + // Don't try to augment if we can't lookup the grabbed history by downloadId + if (downloadClientItem == null) + { + return null; + } + + var history = _downloadHistoryService.GetLatestGrab(downloadClientItem.DownloadId); + if (history == null) + { + return null; + } + + var historyQuality = QualityParser.ParseQuality(history.SourceTitle); + var sourceConfidence = historyQuality.SourceDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + var resolutionConfidence = historyQuality.ResolutionDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + var modifierConfidence = historyQuality.ModifierDetectionSource == QualityDetectionSource.Name + ? Confidence.Tag + : Confidence.Fallback; + + return new AugmentQualityResult(historyQuality.Quality.Source, sourceConfidence, historyQuality.Quality.Resolution, resolutionConfidence, historyQuality.Quality.Modifier, modifierConfidence, historyQuality.Revision); + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs index b8b9f841b..144487702 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityResult.cs @@ -4,6 +4,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter { public class AugmentQualityResult { + public string Name { get; set; } public Source Source { get; set; } public Confidence SourceConfidence { get; set; } public int Resolution { get; set; } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/IAugmentQuality.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/IAugmentQuality.cs index 14b2648fe..6d183b379 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/IAugmentQuality.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/Augmenters/Quality/IAugmentQuality.cs @@ -1,9 +1,13 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality { public interface IAugmentQuality { - AugmentQualityResult AugmentQuality(LocalMovie localMovie); + int Order { get; } + string Name { get; } + + AugmentQualityResult AugmentQuality(LocalMovie localMovie, DownloadClientItem downloadClientItem); } } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/IAggregateLocalMovie.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/IAggregateLocalMovie.cs index ada6fdc14..29f53d8ef 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/IAggregateLocalMovie.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/IAggregateLocalMovie.cs @@ -1,9 +1,10 @@ +using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators { public interface IAggregateLocalMovie { - LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles); + LocalMovie Aggregate(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles); } } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs index 3382b6128..bdfc2e48e 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs @@ -109,7 +109,7 @@ private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem dow try { - _aggregationService.Augment(localMovie, otherFiles); + _aggregationService.Augment(localMovie, downloadClientItem, otherFiles); if (localMovie.Movie == null) { diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs index 5362af5e7..e388b9874 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs @@ -266,7 +266,7 @@ public void Execute(ManualImportCommand message) localMovie.FolderMovieInfo = Parser.Parser.ParseMovieTitle(file.FolderName); } - localMovie = _aggregationService.Augment(localMovie, false); + localMovie = _aggregationService.Augment(localMovie, trackedDownload?.DownloadItem, false); // Apply the user-chosen values. localMovie.Movie = movie; diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Specifications/DifferentQualitySpecification.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Specifications/DifferentQualitySpecification.cs deleted file mode 100644 index 4ad1d968f..000000000 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Specifications/DifferentQualitySpecification.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Linq; -using NLog; -using NzbDrone.Core.DecisionEngine; -using NzbDrone.Core.Download; -using NzbDrone.Core.History; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Qualities; - -namespace NzbDrone.Core.MediaFiles.MovieImport.Specifications -{ - public class DifferentQualitySpecification : IImportDecisionEngineSpecification - { - private readonly IHistoryService _historyService; - private readonly Logger _logger; - - public DifferentQualitySpecification(IHistoryService historyService, Logger logger) - { - _historyService = historyService; - _logger = logger; - } - - public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem) - { - if (downloadClientItem == null) - { - _logger.Debug("No download client item, skipping"); - return Decision.Accept(); - } - - var grabbedMovieHistory = _historyService.FindByDownloadId(downloadClientItem.DownloadId) - .OrderByDescending(h => h.Date) - .FirstOrDefault(h => h.EventType == MovieHistoryEventType.Grabbed); - - if (grabbedMovieHistory == null) - { - _logger.Debug("No grabbed history for this download item, skipping"); - return Decision.Accept(); - } - - var qualityComparer = new QualityModelComparer(localMovie.Movie.Profile); - var qualityCompare = qualityComparer.Compare(localMovie.Quality, grabbedMovieHistory.Quality); - - if (qualityCompare != 0) - { - _logger.Debug("Quality of file ({0}) does not match quality of grabbed history ({1})", localMovie.Quality, grabbedMovieHistory.Quality); - return Decision.Reject("Quality of file ({0}) does not match quality of grabbed release ({1})", localMovie.Quality, grabbedMovieHistory.Quality); - } - - return Decision.Accept(); - } - } -} diff --git a/src/NzbDrone.Core/Parser/Augmenters/AugmentWithMediaInfo.cs b/src/NzbDrone.Core/Parser/Augmenters/AugmentWithMediaInfo.cs index 47db36369..5ab1a410d 100644 --- a/src/NzbDrone.Core/Parser/Augmenters/AugmentWithMediaInfo.cs +++ b/src/NzbDrone.Core/Parser/Augmenters/AugmentWithMediaInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; @@ -46,7 +46,7 @@ public ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper if (existing != quality.Quality.Resolution) { //_logger.Debug("Overwriting resolution info {0} with info from media info {1}", existing, quality.Resolution); - quality.QualityDetectionSource = QualityDetectionSource.MediaInfo; + quality.ResolutionDetectionSource = QualityDetectionSource.MediaInfo; movieInfo.Quality = quality; } } diff --git a/src/NzbDrone.Core/Parser/QualityParser.cs b/src/NzbDrone.Core/Parser/QualityParser.cs index 0894a1637..88a31a3e9 100644 --- a/src/NzbDrone.Core/Parser/QualityParser.cs +++ b/src/NzbDrone.Core/Parser/QualityParser.cs @@ -62,7 +62,7 @@ public class QualityParser private static readonly Regex OtherSourceRegex = new Regex(@"(?HD[-_. ]TV)|(?SD[-_. ]TV)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex AnimeBlurayRegex = new Regex(@"bd(?:720|1080)|(?<=[-_. (\[])bd(?=[-_. )\]])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex AnimeBlurayRegex = new Regex(@"bd(?:720|1080|2160)|(?<=[-_. (\[])bd(?=[-_. )\]])", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex HighDefPdtvRegex = new Regex(@"hr[-_. ]ws", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -87,7 +87,9 @@ public static QualityModel ParseQuality(string name) try { result.Quality = MediaFileExtensions.GetQualityForExtension(Path.GetExtension(name)); - result.QualityDetectionSource = QualityDetectionSource.Extension; + result.SourceDetectionSource = QualityDetectionSource.Extension; + result.ResolutionDetectionSource = QualityDetectionSource.Extension; + result.ModifierDetectionSource = QualityDetectionSource.Extension; } catch (ArgumentException) { @@ -124,8 +126,15 @@ public static QualityModel ParseQualityName(string name) var remuxMatch = RemuxRegex.IsMatch(normalizedName); var brDiskMatch = BRDISKRegex.IsMatch(normalizedName); + if (resolution != Resolution.Unknown) + { + result.ResolutionDetectionSource = QualityDetectionSource.Name; + } + if (sourceMatch != null && sourceMatch.Success) { + result.SourceDetectionSource = QualityDetectionSource.Name; + if (sourceMatch.Groups["bluray"].Success) { if (brDiskMatch) @@ -348,6 +357,7 @@ public static QualityModel ParseQualityName(string name) if (HighDefPdtvRegex.IsMatch(normalizedName)) { + result.ResolutionDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.HDTV720p; return result; } @@ -360,20 +370,25 @@ public static QualityModel ParseQualityName(string name) // Anime Bluray matching if (AnimeBlurayRegex.Match(normalizedName).Success) { + result.SourceDetectionSource = QualityDetectionSource.Name; + if (resolution == Resolution.R360p || resolution == Resolution.R480p || resolution == Resolution.R576p || normalizedName.ContainsIgnoreCase("480p")) { + result.ResolutionDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.DVD; return result; } if (resolution == Resolution.R1080p || normalizedName.ContainsIgnoreCase("1080p")) { + result.ResolutionDetectionSource = QualityDetectionSource.Name; result.Quality = remuxMatch ? Quality.Remux1080p : Quality.Bluray1080p; return result; } if (resolution == Resolution.R2160p || normalizedName.ContainsIgnoreCase("2160p")) { + result.ResolutionDetectionSource = QualityDetectionSource.Name; result.Quality = remuxMatch ? Quality.Remux2160p : Quality.Bluray2160p; return result; } @@ -389,28 +404,78 @@ public static QualityModel ParseQualityName(string name) return result; } - if (resolution == Resolution.R2160p) + if (resolution != Resolution.Unknown) { - result.Quality = remuxMatch ? Quality.Remux2160p : Quality.HDTV2160p; - return result; - } + var source = Source.UNKNOWN; + var modifier = Modifier.NONE; - if (resolution == Resolution.R1080p) - { - result.Quality = remuxMatch ? Quality.Remux1080p : Quality.HDTV1080p; - return result; - } + if (remuxMatch) + { + result.SourceDetectionSource = QualityDetectionSource.Name; + source = Source.BLURAY; + modifier = Modifier.REMUX; + } + else + { + try + { + var quality = MediaFileExtensions.GetQualityForExtension(name.GetPathExtension()); - if (resolution == Resolution.R720p) - { - result.Quality = Quality.HDTV720p; - return result; - } + if (quality != Quality.Unknown) + { + result.SourceDetectionSource = QualityDetectionSource.Extension; + source = quality.Source; + } + } + catch (ArgumentException ex) + { + Logger.Debug(ex, "Unable to parse quality from extension"); + } + } - if (resolution == Resolution.R360p || resolution == Resolution.R480p) - { - result.Quality = Quality.SDTV; - return result; + if (resolution == Resolution.R2160p) + { + result.ResolutionDetectionSource = QualityDetectionSource.Name; + + result.Quality = source == Source.UNKNOWN + ? Quality.HDTV2160p + : QualityFinder.FindBySourceAndResolution(source, 2160, modifier); + + return result; + } + + if (resolution == Resolution.R1080p) + { + result.ResolutionDetectionSource = QualityDetectionSource.Name; + + result.Quality = source == Source.UNKNOWN + ? Quality.HDTV1080p + : QualityFinder.FindBySourceAndResolution(source, 1080, modifier); + + return result; + } + + if (resolution == Resolution.R720p) + { + result.ResolutionDetectionSource = QualityDetectionSource.Name; + + result.Quality = source == Source.UNKNOWN + ? Quality.HDTV720p + : QualityFinder.FindBySourceAndResolution(source, 720, modifier); + + return result; + } + + if (resolution == Resolution.R360p || resolution == Resolution.R480p) + { + result.ResolutionDetectionSource = QualityDetectionSource.Name; + + result.Quality = source == Source.UNKNOWN + ? Quality.SDTV + : QualityFinder.FindBySourceAndResolution(source, 480, modifier); + + return result; + } } if (codecRegex.Groups["x264"].Success) @@ -421,53 +486,92 @@ public static QualityModel ParseQualityName(string name) if (normalizedName.ContainsIgnoreCase("848x480")) { - if (normalizedName.ContainsIgnoreCase("dvd")) + result.ResolutionDetectionSource = QualityDetectionSource.Name; + + if (normalizedName.Contains("dvd")) { + result.SourceDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.DVD; } + else if (normalizedName.ContainsIgnoreCase("bluray")) + { + result.SourceDetectionSource = QualityDetectionSource.Name; + result.Quality = Quality.Bluray480p; + } + else + { + result.Quality = Quality.SDTV; + } - result.Quality = Quality.SDTV; + return result; } if (normalizedName.ContainsIgnoreCase("1280x720")) { + result.ResolutionDetectionSource = QualityDetectionSource.Name; + if (normalizedName.ContainsIgnoreCase("bluray")) { + result.SourceDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.Bluray720p; } + else + { + result.Quality = Quality.HDTV720p; + } - result.Quality = Quality.HDTV720p; + return result; } if (normalizedName.ContainsIgnoreCase("1920x1080")) { + result.ResolutionDetectionSource = QualityDetectionSource.Name; + if (normalizedName.ContainsIgnoreCase("bluray")) { + result.SourceDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.Bluray1080p; } + else + { + result.Quality = Quality.HDTV1080p; + } - result.Quality = Quality.HDTV1080p; + return result; } if (normalizedName.ContainsIgnoreCase("bluray720p")) { + result.SourceDetectionSource = QualityDetectionSource.Name; + result.ResolutionDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.Bluray720p; + + return result; } if (normalizedName.ContainsIgnoreCase("bluray1080p")) { + result.SourceDetectionSource = QualityDetectionSource.Name; + result.ResolutionDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.Bluray1080p; + + return result; } if (normalizedName.ContainsIgnoreCase("bluray2160p")) { + result.SourceDetectionSource = QualityDetectionSource.Name; + result.ResolutionDetectionSource = QualityDetectionSource.Name; result.Quality = Quality.Bluray2160p; + + return result; } var otherSourceMatch = OtherSourceMatch(normalizedName); if (otherSourceMatch != Quality.Unknown) { + result.SourceDetectionSource = QualityDetectionSource.Name; result.Quality = otherSourceMatch; } diff --git a/src/NzbDrone.Core/Qualities/QualityDetectionSource.cs b/src/NzbDrone.Core/Qualities/QualityDetectionSource.cs index 3f7695214..63751b71d 100644 --- a/src/NzbDrone.Core/Qualities/QualityDetectionSource.cs +++ b/src/NzbDrone.Core/Qualities/QualityDetectionSource.cs @@ -1,7 +1,8 @@ -namespace NzbDrone.Core.Qualities +namespace NzbDrone.Core.Qualities { public enum QualityDetectionSource { + Unknown, Name, Extension, MediaInfo diff --git a/src/NzbDrone.Core/Qualities/QualityModel.cs b/src/NzbDrone.Core/Qualities/QualityModel.cs index c8dcfa0bb..1bdb5a090 100644 --- a/src/NzbDrone.Core/Qualities/QualityModel.cs +++ b/src/NzbDrone.Core/Qualities/QualityModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using Newtonsoft.Json; using NzbDrone.Core.Datastore; @@ -13,7 +13,13 @@ public class QualityModel : IEmbeddedDocument, IEquatable public string HardcodedSubs { get; set; } [JsonIgnore] - public QualityDetectionSource QualityDetectionSource { get; set; } + public QualityDetectionSource SourceDetectionSource { get; set; } + + [JsonIgnore] + public QualityDetectionSource ResolutionDetectionSource { get; set; } + + [JsonIgnore] + public QualityDetectionSource ModifierDetectionSource { get; set; } public QualityModel() : this(Quality.Unknown, new Revision())