diff --git a/src/NzbDrone.Core.Test/Files/Media/H264_sample.mp4 b/src/NzbDrone.Core.Test/Files/Media/H264_sample.mp4 index 35bc6b353..509640fda 100644 Binary files a/src/NzbDrone.Core.Test/Files/Media/H264_sample.mp4 and b/src/NzbDrone.Core.Test/Files/Media/H264_sample.mp4 differ diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs index 367a4cfe3..af72aa538 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfoFixture.cs @@ -4,6 +4,7 @@ using NUnit.Framework; using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality; using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality @@ -65,6 +66,47 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators.Au result.Should().NotBe(null); result.Resolution.Should().Be(expectedResolution); + result.Source.Should().Be(QualitySource.Unknown); + } + + [Test] + public void should_include_source_if_extracted_from_title() + { + var mediaInfo = Builder.CreateNew() + .With(m => m.Width = 1920) + .With(m => m.Height = 1080) + .With(m => m.Title = "Series.Title.S01E05.WEB.x264-Sonarr") + .Build(); + + var localEpisode = Builder.CreateNew() + .With(l => l.MediaInfo = mediaInfo) + .Build(); + + var result = Subject.AugmentQuality(localEpisode, null); + + result.Should().NotBe(null); + result.Resolution.Should().Be(1080); + result.Source.Should().Be(QualitySource.Web); + } + + [Test] + public void should_have_unknown_source_if_no_source_extracted_from_title() + { + var mediaInfo = Builder.CreateNew() + .With(m => m.Width = 1920) + .With(m => m.Height = 1080) + .With(m => m.Title = "Series.Title.S01E05.x264-Sonarr") + .Build(); + + var localEpisode = Builder.CreateNew() + .With(l => l.MediaInfo = mediaInfo) + .Build(); + + var result = Subject.AugmentQuality(localEpisode, null); + + result.Should().NotBe(null); + result.Resolution.Should().Be(1080); + result.Source.Should().Be(QualitySource.Unknown); } } } diff --git a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs index f0826d64b..949a23512 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo info.AudioFormat.Should().Be("aac"); info.AudioCodecID.Should().Be("mp4a"); info.AudioProfile.Should().Be("LC"); - info.AudioBitrate.Should().Be(125488); + info.AudioBitrate.Should().Be(125509); info.AudioChannels.Should().Be(2); info.AudioChannelPositions.Should().Be("stereo"); info.AudioLanguages.Should().BeEquivalentTo("eng"); @@ -59,12 +59,13 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo info.RunTime.Seconds.Should().Be(10); info.ScanType.Should().Be("Progressive"); info.Subtitles.Should().BeEmpty(); - info.VideoBitrate.Should().Be(193328); + info.VideoBitrate.Should().Be(193694); info.VideoFps.Should().Be(24); info.Width.Should().Be(480); info.VideoBitDepth.Should().Be(8); info.VideoColourPrimaries.Should().Be("smpte170m"); info.VideoTransferCharacteristics.Should().Be("bt709"); + info.Title.Should().Be("Sample Title"); } [Test] @@ -87,7 +88,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo info.AudioFormat.Should().Be("aac"); info.AudioCodecID.Should().Be("mp4a"); info.AudioProfile.Should().Be("LC"); - info.AudioBitrate.Should().Be(125488); + info.AudioBitrate.Should().Be(125509); info.AudioChannels.Should().Be(2); info.AudioChannelPositions.Should().Be("stereo"); info.AudioLanguages.Should().BeEquivalentTo("eng"); @@ -95,11 +96,12 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo info.RunTime.Seconds.Should().Be(10); info.ScanType.Should().Be("Progressive"); info.Subtitles.Should().BeEmpty(); - info.VideoBitrate.Should().Be(193328); + info.VideoBitrate.Should().Be(193694); info.VideoFps.Should().Be(24); info.Width.Should().Be(480); info.VideoColourPrimaries.Should().Be("smpte170m"); info.VideoTransferCharacteristics.Should().Be("bt709"); + info.Title.Should().Be("Sample Title"); } [TestCase(8, "", "", "", null, HdrFormat.None)] diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs index ce90c9ff8..d854bbfaa 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/Augmenters/Quality/AugmentQualityFromMediaInfo.cs @@ -1,6 +1,9 @@ using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Download; +using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality { @@ -25,29 +28,45 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augment var width = localEpisode.MediaInfo.Width; var height = localEpisode.MediaInfo.Height; + var source = QualitySource.Unknown; + var sourceConfidence = Confidence.Default; + var title = localEpisode.MediaInfo.Title; + + if (title.IsNotNullOrWhiteSpace()) + { + var parsedQuality = QualityParser.ParseQualityName(title.Trim()); + + // Only use the quality if it's not unknown and the source is from the name (which is MediaInfo's title in this case) + if (parsedQuality.Quality.Source != QualitySource.Unknown && + parsedQuality.SourceDetectionSource == QualityDetectionSource.Name) + { + source = parsedQuality.Quality.Source; + sourceConfidence = Confidence.MediaInfo; + } + } if (width >= 3200 || height >= 2100) { _logger.Trace("Resolution {0}x{1} considered 2160p", width, height); - return AugmentQualityResult.ResolutionOnly(2160, Confidence.MediaInfo); + return AugmentQualityResult.SourceAndResolutionOnly(source, sourceConfidence, 2160, Confidence.MediaInfo); } if (width >= 1800 || height >= 1000) { _logger.Trace("Resolution {0}x{1} considered 1080p", width, height); - return AugmentQualityResult.ResolutionOnly(1080, Confidence.MediaInfo); + return AugmentQualityResult.SourceAndResolutionOnly(source, sourceConfidence, 1080, Confidence.MediaInfo); } if (width >= 1200 || height >= 700) { _logger.Trace("Resolution {0}x{1} considered 720p", width, height); - return AugmentQualityResult.ResolutionOnly(720, Confidence.MediaInfo); + return AugmentQualityResult.SourceAndResolutionOnly(source, sourceConfidence, 720, Confidence.MediaInfo); } if (width > 0 && height > 0) { _logger.Trace("Resolution {0}x{1} considered 480p", width, height); - return AugmentQualityResult.ResolutionOnly(480, Confidence.MediaInfo); + return AugmentQualityResult.SourceAndResolutionOnly(source, sourceConfidence, 480, Confidence.MediaInfo); } _logger.Trace("Resolution {0}x{1}", width, height); 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 4fb22ffa5..d0686df1b 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 @@ -36,5 +36,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augment { return new AugmentQualityResult(QualitySource.Unknown, Confidence.Default, resolution, resolutionConfidence, null, Confidence.Default); } + + public static AugmentQualityResult SourceAndResolutionOnly(QualitySource source, Confidence sourceConfidence, int resolution, Confidence resolutionConfidence) + { + return new AugmentQualityResult(source, sourceConfidence, resolution, resolutionConfidence, null, Confidence.Default); + } } } diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs index 65880f797..41b40596d 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; using FFMpegCore; using NzbDrone.Core.Datastore; @@ -57,5 +58,8 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo public List Subtitles { get; set; } public string ScanType { get; set; } + + [JsonIgnore] + public string Title { get; set; } } } diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs index 6f9b4c39b..98d2d9b87 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs @@ -101,6 +101,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo mediaInfoModel.RawStreamData = ffprobeOutput; mediaInfoModel.SchemaRevision = CURRENT_MEDIA_INFO_SCHEMA_REVISION; + if (analysis.Format.Tags?.TryGetValue("title", out var title) ?? false) + { + mediaInfoModel.Title = title; + } + FFProbeFrames frames = null; // if it looks like PQ10 or similar HDR, do a frame analysis to figure out which type it is