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 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators
}
}
- 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 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
}
}
+ // 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 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
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 @@ namespace NzbDrone.Core.Qualities
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 @@ namespace NzbDrone.Core.Qualities
public static readonly List All;
- public static readonly Quality[] AllLookup;
+ public static readonly Dictionary AllLookup;
public static readonly HashSet DefaultQualityDefinitions;
@@ -151,11 +147,11 @@ namespace NzbDrone.Core.Qualities
{
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 @@ namespace NzbDrone.Core.Qualities
{
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 @@ namespace NzbDrone.Core.Tv
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 @@ namespace NzbDrone.Core.Tv
{
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 @@ namespace NzbDrone.Core.Tv
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 @@ namespace NzbDrone.Core.Tv
return match;
}
+ public Series FindByPath(string path)
+ {
+ return _seriesRepository.FindByPath(path);
+ }
+
public Series FindByTitle(string title, int year)
{
return _seriesRepository.FindByTitle(title.CleanSeriesTitle(), year);