From 7e79ccd7102ade7b34a7b4e397a3f1b3ebb00b91 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 21 Sep 2018 12:30:09 -0700 Subject: [PATCH] Fixed: Finding files with unexpected quality in the filename --- .../NzbDrone.Core.Test.csproj | 1 + .../Qualities/QualityFinderFixture.cs | 38 ++++++++++++++++++ .../Aggregators/AggregateQuality.cs | 4 +- .../Manual/ManualImportService.cs | 10 ++++- src/NzbDrone.Core/NzbDrone.Core.csproj | 1 + src/NzbDrone.Core/Qualities/Quality.cs | 21 +++------- src/NzbDrone.Core/Qualities/QualityFinder.cs | 40 +++++++++++++++++++ src/NzbDrone.Core/Tv/SeriesRepository.cs | 11 ++++- src/NzbDrone.Core/Tv/SeriesService.cs | 6 +++ 9 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Qualities/QualityFinderFixture.cs create mode 100644 src/NzbDrone.Core/Qualities/QualityFinder.cs diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 99270c8f8..8ad0e40c0 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -345,6 +345,7 @@ + diff --git a/src/NzbDrone.Core.Test/Qualities/QualityFinderFixture.cs b/src/NzbDrone.Core.Test/Qualities/QualityFinderFixture.cs new file mode 100644 index 000000000..4b8ecccf4 --- /dev/null +++ b/src/NzbDrone.Core.Test/Qualities/QualityFinderFixture.cs @@ -0,0 +1,38 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Qualities; + +namespace NzbDrone.Core.Test.Qualities +{ + [TestFixture] + public class QualityFinderFixture + { + [TestCase(QualitySource.Television, 480)] + [TestCase(QualitySource.Unknown, 480)] + public void should_return_SDTV(QualitySource source, int resolution) + { + QualityFinder.FindBySourceAndResolution(source, resolution).Should().Be(Quality.SDTV); + } + + [TestCase(QualitySource.Television, 720)] + [TestCase(QualitySource.Unknown, 720)] + public void should_return_HDTV_720p(QualitySource source, int resolution) + { + QualityFinder.FindBySourceAndResolution(source, resolution).Should().Be(Quality.HDTV720p); + } + + [TestCase(QualitySource.Television, 1080)] + [TestCase(QualitySource.Unknown, 1080)] + public void should_return_HDTV_1080p(QualitySource source, int resolution) + { + QualityFinder.FindBySourceAndResolution(source, resolution).Should().Be(Quality.HDTV1080p); + } + + [TestCase(QualitySource.Bluray, 720)] + [TestCase(QualitySource.DVD, 720)] + public void should_return_Bluray720p(QualitySource source, int resolution) + { + QualityFinder.FindBySourceAndResolution(source, resolution).Should().Be(Quality.Bluray720p); + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs index c4cf27b5e..9679d1132 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Aggregation/Aggregators/AggregateQuality.cs @@ -53,7 +53,9 @@ public LocalEpisode Aggregate(LocalEpisode localEpisode, bool otherFiles) } } - var quality = new QualityModel(Quality.FindBySourceAndResolution(source, resolution), revison); + _logger.Trace("Finding quality. Source: {0}. Resolution: {1}", source, resolution); + + var quality = new QualityModel(QualityFinder.FindBySourceAndResolution(source, resolution), revison); if (resolutionConfidence == Confidence.MediaInfo) { diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs index 2048b82e8..f9dfd8d42 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs @@ -114,6 +114,13 @@ private List ProcessFolder(string rootFolder, string baseFolde } } + // Try a lookup by the path if the series is still unknown, this will handle + // the case where the series folder doesn't match the series title. + if (series == null) + { + series = _seriesService.FindByPath(rootFolder); + } + if (series == null) { var files = _diskScanService.FilterFiles(baseFolder, _diskScanService.GetVideoFiles(baseFolder, false)); @@ -175,8 +182,7 @@ private ManualImportItem ProcessFile(string rootFolder, string baseFolder, strin return MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), rootFolder, downloadId, null); } - var importDecisions = _importDecisionMaker.GetImportDecisions(new List {file}, - series, downloadClientItem, null, SceneSource(series, baseFolder)); + var importDecisions = _importDecisionMaker.GetImportDecisions(new List {file}, series, downloadClientItem, null, SceneSource(series, baseFolder)); if (importDecisions.Any()) { diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index d7e0dfd51..157fcd514 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -1006,6 +1006,7 @@ + diff --git a/src/NzbDrone.Core/Qualities/Quality.cs b/src/NzbDrone.Core/Qualities/Quality.cs index f710b3ee5..d6ddceccd 100644 --- a/src/NzbDrone.Core/Qualities/Quality.cs +++ b/src/NzbDrone.Core/Qualities/Quality.cs @@ -109,11 +109,7 @@ static Quality() Bluray2160pRemux }; - AllLookup = new Quality[All.Select(v => v.Id).Max() + 1]; - foreach (var quality in All) - { - AllLookup[quality.Id] = quality; - } + AllLookup = All.ToDictionary(q => q.Id, q => q); DefaultQualityDefinitions = new HashSet { @@ -143,7 +139,7 @@ static Quality() public static readonly List All; - public static readonly Quality[] AllLookup; + public static readonly Dictionary AllLookup; public static readonly HashSet DefaultQualityDefinitions; @@ -151,11 +147,11 @@ public static Quality FindById(int id) { if (id == 0) return Unknown; - var quality = AllLookup[id]; - - if (quality == null) + if (!AllLookup.TryGetValue(id, out var quality)) + { throw new ArgumentException("ID does not match a known quality", nameof(id)); - + } + return quality; } @@ -168,10 +164,5 @@ public static explicit operator int(Quality quality) { return quality.Id; } - - public static Quality FindBySourceAndResolution(QualitySource source, int resolution) - { - return All.SingleOrDefault(q => q.Source == source && q.Resolution == resolution); - } } } diff --git a/src/NzbDrone.Core/Qualities/QualityFinder.cs b/src/NzbDrone.Core/Qualities/QualityFinder.cs new file mode 100644 index 000000000..8c75468ee --- /dev/null +++ b/src/NzbDrone.Core/Qualities/QualityFinder.cs @@ -0,0 +1,40 @@ +using System.Linq; +using NLog; +using NzbDrone.Common.Instrumentation; + +namespace NzbDrone.Core.Qualities +{ + public static class QualityFinder + { + private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(QualityFinder)); + + public static Quality FindBySourceAndResolution(QualitySource source, int resolution) + { + var matchingQuality = Quality.All.SingleOrDefault(q => q.Source == source && q.Resolution == resolution); + + if (matchingQuality != null) + { + return matchingQuality; + } + + var matchingResolution = Quality.All.Where(q => q.Resolution == resolution) + .OrderBy(q => q.Source) + .ToList(); + + var nearestQuality = Quality.Unknown; + + foreach (var quality in matchingResolution) + { + if (quality.Source >= source) + { + nearestQuality = quality; + break; + } + } + + Logger.Warn("Unable to find exact quality for {0} and {1}. Using {2} as fallback", source, resolution, nearestQuality); + + return nearestQuality; + } + } +} diff --git a/src/NzbDrone.Core/Tv/SeriesRepository.cs b/src/NzbDrone.Core/Tv/SeriesRepository.cs index d5bc343ff..16d35a89a 100644 --- a/src/NzbDrone.Core/Tv/SeriesRepository.cs +++ b/src/NzbDrone.Core/Tv/SeriesRepository.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using NzbDrone.Core.Datastore; using NzbDrone.Core.Messaging.Events; @@ -12,6 +12,7 @@ public interface ISeriesRepository : IBasicRepository Series FindByTitle(string cleanTitle, int year); Series FindByTvdbId(int tvdbId); Series FindByTvRageId(int tvRageId); + Series FindByPath(string path); } public class SeriesRepository : BasicRepository, ISeriesRepository @@ -52,5 +53,11 @@ public Series FindByTvRageId(int tvRageId) { return Query.Where(s => s.TvRageId == tvRageId).SingleOrDefault(); } + + public Series FindByPath(string path) + { + return Query.Where(s => s.Path == path) + .FirstOrDefault(); + } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Tv/SeriesService.cs b/src/NzbDrone.Core/Tv/SeriesService.cs index e02195e5d..f888c8ada 100644 --- a/src/NzbDrone.Core/Tv/SeriesService.cs +++ b/src/NzbDrone.Core/Tv/SeriesService.cs @@ -21,6 +21,7 @@ public interface ISeriesService Series FindByTitle(string title); Series FindByTitle(string title, int year); Series FindByTitleInexact(string title); + Series FindByPath(string path); void DeleteSeries(int seriesId, bool deleteFiles); List GetAllSeries(); List AllForTag(int tagId); @@ -134,6 +135,11 @@ public Series FindByTitleInexact(string title) return match; } + public Series FindByPath(string path) + { + return _seriesRepository.FindByPath(path); + } + public Series FindByTitle(string title, int year) { return _seriesRepository.FindByTitle(title.CleanSeriesTitle(), year);