Closes #448 Closes #1105pull/2463/head
parent
650d18797a
commit
81e385bebf
@ -0,0 +1,109 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AugmentEpisodesFixture : CoreTest<AggregateEpisodes>
|
||||||
|
{
|
||||||
|
private Series _series;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_series = Builder<Series>.CreateNew().Build();
|
||||||
|
|
||||||
|
var augmenters = new List<Mock<IAggregateLocalEpisode>>
|
||||||
|
{
|
||||||
|
new Mock<IAggregateLocalEpisode>()
|
||||||
|
};
|
||||||
|
|
||||||
|
Mocker.SetConstant(augmenters.Select(c => c.Object));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_use_folder_for_full_season()
|
||||||
|
{
|
||||||
|
var fileEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||||
|
var folderEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01");
|
||||||
|
var localEpisode = new LocalEpisode
|
||||||
|
{
|
||||||
|
FileEpisodeInfo = fileEpisodeInfo,
|
||||||
|
FolderEpisodeInfo = folderEpisodeInfo,
|
||||||
|
Path = @"C:\Test\Unsorted TV\Series.Title.S01\Series.Title.S01E01.mkv".AsOsAgnostic(),
|
||||||
|
Series = _series
|
||||||
|
};
|
||||||
|
|
||||||
|
Subject.Aggregate(localEpisode, false);
|
||||||
|
|
||||||
|
Mocker.GetMock<IParsingService>()
|
||||||
|
.Verify(v => v.GetEpisodes(fileEpisodeInfo, _series, localEpisode.SceneSource, null), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_use_folder_when_it_contains_more_than_one_valid_video_file()
|
||||||
|
{
|
||||||
|
var fileEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||||
|
var folderEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01");
|
||||||
|
var localEpisode = new LocalEpisode
|
||||||
|
{
|
||||||
|
FileEpisodeInfo = fileEpisodeInfo,
|
||||||
|
FolderEpisodeInfo = folderEpisodeInfo,
|
||||||
|
Path = @"C:\Test\Unsorted TV\Series.Title.S01\Series.Title.S01E01.mkv".AsOsAgnostic(),
|
||||||
|
Series = _series
|
||||||
|
};
|
||||||
|
|
||||||
|
Subject.Aggregate(localEpisode, true);
|
||||||
|
|
||||||
|
Mocker.GetMock<IParsingService>()
|
||||||
|
.Verify(v => v.GetEpisodes(fileEpisodeInfo, _series, localEpisode.SceneSource, null), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_use_folder_name_if_file_name_is_scene_name()
|
||||||
|
{
|
||||||
|
var fileEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||||
|
var folderEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||||
|
var localEpisode = new LocalEpisode
|
||||||
|
{
|
||||||
|
FileEpisodeInfo = fileEpisodeInfo,
|
||||||
|
FolderEpisodeInfo = folderEpisodeInfo,
|
||||||
|
Path = @"C:\Test\Unsorted TV\Series.Title.S01E01\Series.Title.S01E01.720p.HDTV-Sonarr.mkv".AsOsAgnostic(),
|
||||||
|
Series = _series
|
||||||
|
};
|
||||||
|
|
||||||
|
Subject.Aggregate(localEpisode, false);
|
||||||
|
|
||||||
|
Mocker.GetMock<IParsingService>()
|
||||||
|
.Verify(v => v.GetEpisodes(fileEpisodeInfo, _series, localEpisode.SceneSource, null), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_use_folder_when_only_one_video_file()
|
||||||
|
{
|
||||||
|
var fileEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||||
|
var folderEpisodeInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||||
|
var localEpisode = new LocalEpisode
|
||||||
|
{
|
||||||
|
FileEpisodeInfo = fileEpisodeInfo,
|
||||||
|
FolderEpisodeInfo = folderEpisodeInfo,
|
||||||
|
Path = @"C:\Test\Unsorted TV\Series.Title.S01E01\Series.Title.S01E01.mkv".AsOsAgnostic(),
|
||||||
|
Series = _series
|
||||||
|
};
|
||||||
|
|
||||||
|
Subject.Aggregate(localEpisode, false);
|
||||||
|
|
||||||
|
Mocker.GetMock<IParsingService>()
|
||||||
|
.Verify(v => v.GetEpisodes(folderEpisodeInfo, _series, localEpisode.SceneSource, null), Times.Once());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.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
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AugmentQualityFixture : CoreTest<AggregateQuality>
|
||||||
|
{
|
||||||
|
private Mock<IAugmentQuality> _mediaInfoAugmenter;
|
||||||
|
private Mock<IAugmentQuality> _fileExtensionAugmenter;
|
||||||
|
private Mock<IAugmentQuality> _nameAugmenter;
|
||||||
|
|
||||||
|
private IEnumerable<IAugmentQuality> _qualityAugmenters;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_mediaInfoAugmenter = new Mock<IAugmentQuality>();
|
||||||
|
_fileExtensionAugmenter = new Mock<IAugmentQuality>();
|
||||||
|
_nameAugmenter = new Mock<IAugmentQuality>();
|
||||||
|
|
||||||
|
_mediaInfoAugmenter.Setup(s => s.AugmentQuality(It.IsAny<LocalEpisode>()))
|
||||||
|
.Returns(AugmentQualityResult.ResolutionOnly(1080, Confidence.MediaInfo));
|
||||||
|
|
||||||
|
_fileExtensionAugmenter.Setup(s => s.AugmentQuality(It.IsAny<LocalEpisode>()))
|
||||||
|
.Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Fallback, 720, Confidence.Fallback, new Revision()));
|
||||||
|
|
||||||
|
_nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny<LocalEpisode>()))
|
||||||
|
.Returns(new AugmentQualityResult(QualitySource.Television, Confidence.Default, 480, Confidence.Default, new Revision()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenAugmenters(params Mock<IAugmentQuality>[] mocks)
|
||||||
|
{
|
||||||
|
Mocker.SetConstant<IEnumerable<IAugmentQuality>>(mocks.Select(c => c.Object));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_HDTV720_from_extension_when_other_augments_are_null()
|
||||||
|
{
|
||||||
|
var nullMock = new Mock<IAugmentQuality>();
|
||||||
|
nullMock.Setup(s => s.AugmentQuality(It.IsAny<LocalEpisode>()))
|
||||||
|
.Returns<LocalEpisode>(l => null);
|
||||||
|
|
||||||
|
GivenAugmenters(_fileExtensionAugmenter, nullMock);
|
||||||
|
|
||||||
|
var result = Subject.Aggregate(new LocalEpisode(), false);
|
||||||
|
|
||||||
|
result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.Extension);
|
||||||
|
result.Quality.Quality.Should().Be(Quality.HDTV720p);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_SDTV_when_HDTV720_came_from_extension()
|
||||||
|
{
|
||||||
|
GivenAugmenters(_fileExtensionAugmenter, _nameAugmenter);
|
||||||
|
|
||||||
|
var result = Subject.Aggregate(new LocalEpisode(), false);
|
||||||
|
|
||||||
|
result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.Name);
|
||||||
|
result.Quality.Quality.Should().Be(Quality.SDTV);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_HDTV1080p_when_HDTV720_came_from_extension_and_mediainfo_indicates_1080()
|
||||||
|
{
|
||||||
|
GivenAugmenters(_fileExtensionAugmenter, _mediaInfoAugmenter);
|
||||||
|
|
||||||
|
var result = Subject.Aggregate(new LocalEpisode(), false);
|
||||||
|
|
||||||
|
result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.MediaInfo);
|
||||||
|
result.Quality.Quality.Should().Be(Quality.HDTV1080p);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_HDTV1080p_when_SDTV_came_from_name_and_mediainfo_indicates_1080()
|
||||||
|
{
|
||||||
|
GivenAugmenters(_nameAugmenter, _mediaInfoAugmenter);
|
||||||
|
|
||||||
|
var result = Subject.Aggregate(new LocalEpisode(), false);
|
||||||
|
|
||||||
|
result.Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.MediaInfo);
|
||||||
|
result.Quality.Quality.Should().Be(Quality.HDTV1080p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
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.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AugmentQualityFromMediaInfoFixture : CoreTest<AugmentQualityFromMediaInfo>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_return_null_if_media_info_is_null()
|
||||||
|
{
|
||||||
|
var localEpisode = Builder<LocalEpisode>.CreateNew()
|
||||||
|
.With(l => l.MediaInfo = null)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Subject.AugmentQuality(localEpisode).Should().Be(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_null_if_media_info_width_is_zero()
|
||||||
|
{
|
||||||
|
var mediaInfo = Builder<MediaInfoModel>.CreateNew()
|
||||||
|
.With(m => m.Width = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var localEpisode = Builder<LocalEpisode>.CreateNew()
|
||||||
|
.With(l => l.MediaInfo = mediaInfo)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Subject.AugmentQuality(localEpisode).Should().Be(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(4096, 2160)] // True 4K
|
||||||
|
[TestCase(4000, 2160)]
|
||||||
|
[TestCase(3840, 2160)] // 4K UHD
|
||||||
|
[TestCase(3200, 2160)]
|
||||||
|
[TestCase(2000, 1080)]
|
||||||
|
[TestCase(1920, 1080)] // Full HD
|
||||||
|
[TestCase(1800, 1080)]
|
||||||
|
[TestCase(1490, 720)]
|
||||||
|
[TestCase(1280, 720)] // HD
|
||||||
|
[TestCase(1200, 720)]
|
||||||
|
[TestCase(800, 480)]
|
||||||
|
[TestCase(720, 480)] // SDTV
|
||||||
|
[TestCase(600, 480)]
|
||||||
|
[TestCase(100, 480)]
|
||||||
|
public void should_return_closest_resolution(int mediaInfoWidth, int expectedResolution)
|
||||||
|
{
|
||||||
|
var mediaInfo = Builder<MediaInfoModel>.CreateNew()
|
||||||
|
.With(m => m.Width = mediaInfoWidth)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var localEpisode = Builder<LocalEpisode>.CreateNew()
|
||||||
|
.With(l => l.MediaInfo = mediaInfo)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var result = Subject.AugmentQuality(localEpisode);
|
||||||
|
|
||||||
|
result.Should().NotBe(null);
|
||||||
|
result.Resolution.Should().Be(expectedResolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using NzbDrone.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation
|
||||||
|
{
|
||||||
|
public class AugmentingFailedException : NzbDroneException
|
||||||
|
{
|
||||||
|
public AugmentingFailedException(string message, params object[] args) : base(message, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AugmentingFailedException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AugmentingFailedException(string message, Exception innerException, params object[] args) : base(message, innerException, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AugmentingFailedException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators;
|
||||||
|
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation
|
||||||
|
{
|
||||||
|
public interface IAugmentingService
|
||||||
|
{
|
||||||
|
LocalEpisode Augment(LocalEpisode localEpisode, bool otherFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AugmentingService : IAugmentingService
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<IAggregateLocalEpisode> _augmenters;
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public AugmentingService(IEnumerable<IAggregateLocalEpisode> augmenters,
|
||||||
|
IDiskProvider diskProvider,
|
||||||
|
IVideoFileInfoReader videoFileInfoReader,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_augmenters = augmenters;
|
||||||
|
_diskProvider = diskProvider;
|
||||||
|
_videoFileInfoReader = videoFileInfoReader;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalEpisode Augment(LocalEpisode localEpisode, bool otherFiles)
|
||||||
|
{
|
||||||
|
if (localEpisode.DownloadClientEpisodeInfo == null &&
|
||||||
|
localEpisode.FolderEpisodeInfo == null &&
|
||||||
|
localEpisode.FileEpisodeInfo == null)
|
||||||
|
{
|
||||||
|
if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(localEpisode.Path)))
|
||||||
|
{
|
||||||
|
throw new AugmentingFailedException("Unable to parse episode info from path: {0}", localEpisode.Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localEpisode.Size = _diskProvider.GetFileSize(localEpisode.Path);
|
||||||
|
localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(localEpisode.Path);
|
||||||
|
|
||||||
|
foreach (var augmenter in _augmenters)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
augmenter.Aggregate(localEpisode, otherFiles);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return localEpisode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
using System.IO;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
||||||
|
{
|
||||||
|
public class AggregateEpisodes : IAggregateLocalEpisode
|
||||||
|
{
|
||||||
|
private readonly IParsingService _parsingService;
|
||||||
|
|
||||||
|
public AggregateEpisodes(IParsingService parsingService)
|
||||||
|
{
|
||||||
|
_parsingService = parsingService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalEpisode Aggregate(LocalEpisode localEpisode, bool otherFiles)
|
||||||
|
{
|
||||||
|
var bestEpisodeInfoForEpisodes = GetBestEpisodeInfo(localEpisode, otherFiles);
|
||||||
|
|
||||||
|
localEpisode.Episodes = _parsingService.GetEpisodes(bestEpisodeInfoForEpisodes, localEpisode.Series, localEpisode.SceneSource);
|
||||||
|
|
||||||
|
return localEpisode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParsedEpisodeInfo GetBestEpisodeInfo(LocalEpisode localEpisode, bool otherFiles)
|
||||||
|
{
|
||||||
|
var parsedEpisodeInfo = localEpisode.FileEpisodeInfo;
|
||||||
|
var downloadClientEpisodeInfo = localEpisode.DownloadClientEpisodeInfo;
|
||||||
|
var folderEpisodeInfo = localEpisode.FolderEpisodeInfo;
|
||||||
|
|
||||||
|
if (!otherFiles && !SceneChecker.IsSceneTitle(Path.GetFileNameWithoutExtension(localEpisode.Path)))
|
||||||
|
{
|
||||||
|
if (downloadClientEpisodeInfo != null && !downloadClientEpisodeInfo.FullSeason)
|
||||||
|
{
|
||||||
|
parsedEpisodeInfo = localEpisode.DownloadClientEpisodeInfo;
|
||||||
|
}
|
||||||
|
else if (folderEpisodeInfo != null && !folderEpisodeInfo.FullSeason)
|
||||||
|
{
|
||||||
|
parsedEpisodeInfo = localEpisode.FolderEpisodeInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
|
||||||
|
{
|
||||||
|
var title = Path.GetFileNameWithoutExtension(localEpisode.Path);
|
||||||
|
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, title, localEpisode.Series);
|
||||||
|
|
||||||
|
return specialEpisodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedEpisodeInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
||||||
|
{
|
||||||
|
public class AggregateQuality : IAggregateLocalEpisode
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<IAugmentQuality> _augmentQualities;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public AggregateQuality(IEnumerable<IAugmentQuality> augmentQualities,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_augmentQualities = augmentQualities;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalEpisode Aggregate(LocalEpisode localEpisode, bool otherFiles)
|
||||||
|
{
|
||||||
|
var augmentedQualities = _augmentQualities.Select(a => a.AugmentQuality(localEpisode))
|
||||||
|
.Where(a => a != null)
|
||||||
|
.OrderBy(a => a.SourceConfidence);
|
||||||
|
|
||||||
|
var source = QualitySource.Unknown;
|
||||||
|
var sourceConfidence = Confidence.Default;
|
||||||
|
var resolution = 0;
|
||||||
|
var resolutionConfidence = Confidence.Default;
|
||||||
|
var revison = new Revision();
|
||||||
|
|
||||||
|
foreach (var augmentedQuality in augmentedQualities)
|
||||||
|
{
|
||||||
|
if (augmentedQuality.Source > source ||
|
||||||
|
augmentedQuality.SourceConfidence > sourceConfidence && augmentedQuality.Source != QualitySource.Unknown)
|
||||||
|
{
|
||||||
|
source = augmentedQuality.Source;
|
||||||
|
sourceConfidence = augmentedQuality.SourceConfidence;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (augmentedQuality.Resolution > resolution ||
|
||||||
|
augmentedQuality.ResolutionConfidence > resolutionConfidence && augmentedQuality.Resolution > 0)
|
||||||
|
{
|
||||||
|
resolution = augmentedQuality.Resolution;
|
||||||
|
resolutionConfidence = augmentedQuality.ResolutionConfidence;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (augmentedQuality.Revision != null && augmentedQuality.Revision > revison)
|
||||||
|
{
|
||||||
|
revison = augmentedQuality.Revision;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var quality = new QualityModel(Quality.FindBySourceAndResolution(source, resolution), revison);
|
||||||
|
|
||||||
|
if (resolutionConfidence == Confidence.MediaInfo)
|
||||||
|
{
|
||||||
|
quality.QualityDetectionSource = QualityDetectionSource.MediaInfo;
|
||||||
|
}
|
||||||
|
else if (sourceConfidence == Confidence.Fallback || resolutionConfidence == Confidence.Fallback)
|
||||||
|
{
|
||||||
|
quality.QualityDetectionSource = QualityDetectionSource.Extension;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quality.QualityDetectionSource = QualityDetectionSource.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Using quality: {0}", quality);
|
||||||
|
|
||||||
|
localEpisode.Quality = quality;
|
||||||
|
|
||||||
|
return localEpisode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
||||||
|
{
|
||||||
|
public class AggregateReleaseGroup : IAggregateLocalEpisode
|
||||||
|
{
|
||||||
|
public LocalEpisode Aggregate(LocalEpisode localEpisode, bool otherFiles)
|
||||||
|
{
|
||||||
|
var releaseGroup = localEpisode.DownloadClientEpisodeInfo?.ReleaseGroup;
|
||||||
|
|
||||||
|
if (releaseGroup.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
releaseGroup = localEpisode.FolderEpisodeInfo?.ReleaseGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (releaseGroup.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
releaseGroup = localEpisode.FileEpisodeInfo?.ReleaseGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
localEpisode.ReleaseGroup = releaseGroup;
|
||||||
|
|
||||||
|
return localEpisode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
public class AugmentQualityFromDownloadClientItem : IAugmentQuality
|
||||||
|
{
|
||||||
|
public AugmentQualityResult AugmentQuality(LocalEpisode localEpisode)
|
||||||
|
{
|
||||||
|
var quality = localEpisode.DownloadClientEpisodeInfo?.Quality;
|
||||||
|
|
||||||
|
if (quality == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AugmentQualityResult(quality.Quality.Source,
|
||||||
|
Confidence.Tag,
|
||||||
|
quality.Quality.Resolution,
|
||||||
|
Confidence.Tag,
|
||||||
|
quality.Revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
public class AugmentQualityFromFileName : IAugmentQuality
|
||||||
|
{
|
||||||
|
public AugmentQualityResult AugmentQuality(LocalEpisode localEpisode)
|
||||||
|
{
|
||||||
|
var quality = localEpisode.FileEpisodeInfo?.Quality;
|
||||||
|
|
||||||
|
if (quality == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var confidence = quality.QualityDetectionSource == QualityDetectionSource.Extension
|
||||||
|
? Confidence.Fallback
|
||||||
|
: Confidence.Tag;
|
||||||
|
|
||||||
|
return new AugmentQualityResult(quality.Quality.Source,
|
||||||
|
confidence,
|
||||||
|
quality.Quality.Resolution,
|
||||||
|
confidence,
|
||||||
|
quality.Revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
public class AugmentQualityFromFolder : IAugmentQuality
|
||||||
|
{
|
||||||
|
public AugmentQualityResult AugmentQuality(LocalEpisode localEpisode)
|
||||||
|
{
|
||||||
|
var quality = localEpisode.FolderEpisodeInfo?.Quality;
|
||||||
|
|
||||||
|
if (quality == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AugmentQualityResult(quality.Quality.Source,
|
||||||
|
Confidence.Tag,
|
||||||
|
quality.Quality.Resolution,
|
||||||
|
Confidence.Tag,
|
||||||
|
quality.Revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
public class AugmentQualityFromMediaInfo : IAugmentQuality
|
||||||
|
{
|
||||||
|
public AugmentQualityResult AugmentQuality(LocalEpisode localEpisode)
|
||||||
|
{
|
||||||
|
if (localEpisode.MediaInfo == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var width = localEpisode.MediaInfo.Width;
|
||||||
|
|
||||||
|
if (width >= 3200)
|
||||||
|
{
|
||||||
|
return AugmentQualityResult.ResolutionOnly(2160, Confidence.MediaInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width >= 1800)
|
||||||
|
{
|
||||||
|
return AugmentQualityResult.ResolutionOnly(1080, Confidence.MediaInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width >= 1200)
|
||||||
|
{
|
||||||
|
return AugmentQualityResult.ResolutionOnly(720, Confidence.MediaInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width > 0)
|
||||||
|
{
|
||||||
|
return AugmentQualityResult.ResolutionOnly(480, Confidence.MediaInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
public class AugmentQualityResult
|
||||||
|
{
|
||||||
|
public QualitySource Source { get; set; }
|
||||||
|
public Confidence SourceConfidence { get; set; }
|
||||||
|
public int Resolution { get; set; }
|
||||||
|
public Confidence ResolutionConfidence { get; set; }
|
||||||
|
public Revision Revision { get; set; }
|
||||||
|
|
||||||
|
public AugmentQualityResult(QualitySource source,
|
||||||
|
Confidence sourceConfidence,
|
||||||
|
int resolution,
|
||||||
|
Confidence resolutionConfidence,
|
||||||
|
Revision revision)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
SourceConfidence = sourceConfidence;
|
||||||
|
Resolution = resolution;
|
||||||
|
ResolutionConfidence = resolutionConfidence;
|
||||||
|
Revision = revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AugmentQualityResult SourceOnly(QualitySource source, Confidence sourceConfidence)
|
||||||
|
{
|
||||||
|
return new AugmentQualityResult(source, sourceConfidence, 0, Confidence.Default, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AugmentQualityResult ResolutionOnly(int resolution, Confidence resolutionConfidence)
|
||||||
|
{
|
||||||
|
return new AugmentQualityResult(QualitySource.Unknown, Confidence.Default, resolution, resolutionConfidence, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
public enum Confidence
|
||||||
|
{
|
||||||
|
Fallback,
|
||||||
|
Default,
|
||||||
|
Tag,
|
||||||
|
MediaInfo
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators.Augmenters.Quality
|
||||||
|
{
|
||||||
|
public interface IAugmentQuality
|
||||||
|
{
|
||||||
|
AugmentQualityResult AugmentQuality(LocalEpisode localEpisode);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
||||||
|
{
|
||||||
|
public interface IAggregateLocalEpisode
|
||||||
|
{
|
||||||
|
LocalEpisode Aggregate(LocalEpisode localEpisode, bool otherFiles);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue