New: Use media info during import to extract resolution for quality
Closes #448 Closes #1105
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ using NUnit.Framework;
|
|||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
@ -15,6 +14,7 @@ using NzbDrone.Core.Tv;
|
|||
using NzbDrone.Test.Common;
|
||||
using FizzWare.NBuilder;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
||||
{
|
||||
|
@ -67,10 +67,6 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
Path = @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi"
|
||||
};
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()))
|
||||
.Returns(_localEpisode);
|
||||
|
||||
GivenVideoFiles(new List<string> { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi".AsOsAgnostic() });
|
||||
}
|
||||
|
||||
|
@ -88,20 +84,31 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
.Returns(_videoFiles);
|
||||
}
|
||||
|
||||
private void GivenAugmentationSuccess()
|
||||
{
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Setup(s => s.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
||||
.Callback<LocalEpisode, bool>((localEpisode, otherFiles) =>
|
||||
{
|
||||
localEpisode.Episodes = _localEpisode.Episodes;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_call_all_specifications()
|
||||
{
|
||||
var downloadClientItem = Builder<DownloadClientItem>.CreateNew().Build();
|
||||
GivenAugmentationSuccess();
|
||||
GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3);
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, new Series(), downloadClientItem, null, false);
|
||||
|
||||
_fail1.Verify(c => c.IsSatisfiedBy(_localEpisode, downloadClientItem), Times.Once());
|
||||
_fail2.Verify(c => c.IsSatisfiedBy(_localEpisode, downloadClientItem), Times.Once());
|
||||
_fail3.Verify(c => c.IsSatisfiedBy(_localEpisode, downloadClientItem), Times.Once());
|
||||
_pass1.Verify(c => c.IsSatisfiedBy(_localEpisode, downloadClientItem), Times.Once());
|
||||
_pass2.Verify(c => c.IsSatisfiedBy(_localEpisode, downloadClientItem), Times.Once());
|
||||
_pass3.Verify(c => c.IsSatisfiedBy(_localEpisode, downloadClientItem), Times.Once());
|
||||
_fail1.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalEpisode>(), downloadClientItem), Times.Once());
|
||||
_fail2.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalEpisode>(), downloadClientItem), Times.Once());
|
||||
_fail3.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalEpisode>(), downloadClientItem), Times.Once());
|
||||
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalEpisode>(), downloadClientItem), Times.Once());
|
||||
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalEpisode>(), downloadClientItem), Times.Once());
|
||||
_pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalEpisode>(), downloadClientItem), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -125,8 +132,9 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_pass_if_all_specs_pass()
|
||||
public void should_return_approved_if_all_specs_pass()
|
||||
{
|
||||
GivenAugmentationSuccess();
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, new Series());
|
||||
|
@ -137,6 +145,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
[Test]
|
||||
public void should_have_same_number_of_rejections_as_specs_that_failed()
|
||||
{
|
||||
GivenAugmentationSuccess();
|
||||
GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3);
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, new Series());
|
||||
|
@ -148,8 +157,8 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
{
|
||||
GivenSpecifications(_pass1);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()))
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Setup(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
||||
.Throws<TestException>();
|
||||
|
||||
_videoFiles = new List<string>
|
||||
|
@ -163,76 +172,17 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
|
||||
Subject.GetImportDecisions(_videoFiles, _series);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Verify(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
||||
|
||||
ExceptionVerification.ExpectedErrors(3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_file_quality_if_folder_quality_is_null()
|
||||
{
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
var expectedQuality = QualityParser.ParseQuality(_videoFiles.Single());
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series);
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_file_quality_if_file_quality_was_determined_by_name()
|
||||
{
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
var expectedQuality = QualityParser.ParseQuality(_videoFiles.Single());
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series, null, new ParsedEpisodeInfo{Quality = new QualityModel(Quality.SDTV)}, true);
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_folder_quality_when_file_quality_was_determined_by_the_extension()
|
||||
{
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
GivenVideoFiles(new string[] { @"C:\Test\Unsorted\The.Office.S03E115.mkv".AsOsAgnostic() });
|
||||
|
||||
_localEpisode.Path = _videoFiles.Single();
|
||||
_localEpisode.Quality.QualitySource = QualitySource.Extension;
|
||||
_localEpisode.Quality.Quality = Quality.HDTV720p;
|
||||
|
||||
var expectedQuality = new QualityModel(Quality.SDTV);
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series, null, new ParsedEpisodeInfo { Quality = expectedQuality }, true);
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_folder_quality_when_greater_than_file_quality()
|
||||
{
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
GivenVideoFiles(new string[] { @"C:\Test\Unsorted\The.Office.S03E115.mkv".AsOsAgnostic() });
|
||||
|
||||
_localEpisode.Path = _videoFiles.Single();
|
||||
_localEpisode.Quality.Quality = Quality.HDTV720p;
|
||||
|
||||
var expectedQuality = new QualityModel(Quality.Bluray720p);
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series, null, new ParsedEpisodeInfo { Quality = expectedQuality }, true);
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_throw_if_episodes_are_not_found()
|
||||
{
|
||||
GivenSpecifications(_pass1);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()))
|
||||
.Returns(new LocalEpisode() { Path = "test", ParsedEpisodeInfo = new ParsedEpisodeInfo { } });
|
||||
|
||||
_videoFiles = new List<string>
|
||||
{
|
||||
"The.Office.S03E115.DVDRip.XviD-OSiTV",
|
||||
|
@ -244,162 +194,18 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
|
||||
var decisions = Subject.GetImportDecisions(_videoFiles, _series);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Verify(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
||||
|
||||
decisions.Should().HaveCount(3);
|
||||
decisions.First().Rejections.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_use_folder_for_full_season()
|
||||
{
|
||||
var videoFiles = new[]
|
||||
{
|
||||
@"C:\Test\Unsorted\Series.Title.S01\S01E01.mkv".AsOsAgnostic(),
|
||||
@"C:\Test\Unsorted\Series.Title.S01\S01E02.mkv".AsOsAgnostic(),
|
||||
@"C:\Test\Unsorted\Series.Title.S01\S01E03.mkv".AsOsAgnostic()
|
||||
};
|
||||
|
||||
GivenSpecifications(_pass1);
|
||||
GivenVideoFiles(videoFiles);
|
||||
|
||||
var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01");
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, _series, null, folderInfo, true);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), null, true), Times.Exactly(3));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.Is<ParsedEpisodeInfo>(p => p != null), true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_use_folder_when_it_contains_more_than_one_valid_video_file()
|
||||
{
|
||||
var videoFiles = new[]
|
||||
{
|
||||
@"C:\Test\Unsorted\Series.Title.S01E01\S01E01.mkv".AsOsAgnostic(),
|
||||
@"C:\Test\Unsorted\Series.Title.S01E01\1x01.mkv".AsOsAgnostic()
|
||||
};
|
||||
|
||||
GivenSpecifications(_pass1);
|
||||
GivenVideoFiles(videoFiles);
|
||||
|
||||
var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, _series, null, folderInfo, true);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), null, true), Times.Exactly(2));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.Is<ParsedEpisodeInfo>(p => p != null), true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_folder_when_only_one_video_file()
|
||||
{
|
||||
var videoFiles = new[]
|
||||
{
|
||||
@"C:\Test\Unsorted\Series.Title.S01E01\S01E01.mkv".AsOsAgnostic()
|
||||
};
|
||||
|
||||
GivenSpecifications(_pass1);
|
||||
GivenVideoFiles(videoFiles);
|
||||
|
||||
var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, _series, null, folderInfo, true);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), true), Times.Exactly(1));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), null, true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_folder_when_only_one_video_file_and_a_sample()
|
||||
{
|
||||
var videoFiles = new[]
|
||||
{
|
||||
@"C:\Test\Unsorted\Series.Title.S01E01\S01E01.mkv".AsOsAgnostic(),
|
||||
@"C:\Test\Unsorted\Series.Title.S01E01\S01E01.sample.mkv".AsOsAgnostic()
|
||||
};
|
||||
|
||||
GivenSpecifications(_pass1);
|
||||
GivenVideoFiles(videoFiles.ToList());
|
||||
|
||||
Mocker.GetMock<IDetectSample>()
|
||||
.Setup(s => s.IsSample(_series, It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Returns((Series s, string path, bool special) =>
|
||||
{
|
||||
if (path.Contains("sample"))
|
||||
{
|
||||
return DetectSampleResult.Sample;
|
||||
}
|
||||
|
||||
return DetectSampleResult.NotSample;
|
||||
});
|
||||
|
||||
var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, _series, null, folderInfo, true);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), true), Times.Exactly(2));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), null, true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_use_folder_name_if_file_name_is_scene_name()
|
||||
{
|
||||
var videoFiles = new[]
|
||||
{
|
||||
@"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-LOL\Series.Title.S01E01.720p.HDTV-LOL.mkv".AsOsAgnostic()
|
||||
};
|
||||
|
||||
GivenSpecifications(_pass1);
|
||||
GivenVideoFiles(videoFiles);
|
||||
|
||||
var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01.720p.HDTV-LOL");
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, _series, null, folderInfo, true);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), null, true), Times.Exactly(1));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.Is<ParsedEpisodeInfo>(p => p != null), true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_use_folder_quality_when_it_is_unknown()
|
||||
{
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
|
||||
_series.Profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.Unknown)
|
||||
};
|
||||
|
||||
|
||||
var folderQuality = new QualityModel(Quality.Unknown);
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series, null, new ParsedEpisodeInfo { Quality = folderQuality}, true);
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(_quality);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_a_decision_when_exception_is_caught()
|
||||
{
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()))
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Setup(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
||||
.Throws<TestException>();
|
||||
|
||||
_videoFiles = new List<string>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
|
||||
|
@ -22,7 +22,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
|||
Path = @"C:\Test\30 Rock\30.rock.s01e01.avi".AsOsAgnostic(),
|
||||
Size = 100,
|
||||
Series = Builder<Series>.CreateNew().Build(),
|
||||
ParsedEpisodeInfo = new ParsedEpisodeInfo
|
||||
FileEpisodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
FullSeason = false
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
|||
[Test]
|
||||
public void should_return_false_when_file_contains_the_full_season()
|
||||
{
|
||||
_localEpisode.ParsedEpisodeInfo.FullSeason = true;
|
||||
_localEpisode.FileEpisodeInfo.FullSeason = true;
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
|
||||
|
@ -18,7 +18,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
|||
{
|
||||
_localEpisode = Builder<LocalEpisode>.CreateNew()
|
||||
.With(l => l.Path = @"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-Sonarr\S01E05.mkv".AsOsAgnostic())
|
||||
.With(l => l.ParsedEpisodeInfo =
|
||||
.With(l => l.FileEpisodeInfo =
|
||||
Builder<ParsedEpisodeInfo>.CreateNew()
|
||||
.With(p => p.EpisodeNumbers = new[] {5})
|
||||
.With(p => p.FullSeason = false)
|
||||
|
@ -53,7 +53,8 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
|||
[Test]
|
||||
public void should_be_accepted_if_file_and_folder_have_the_same_episode()
|
||||
{
|
||||
_localEpisode.ParsedEpisodeInfo.EpisodeNumbers = new[] { 1 };
|
||||
_localEpisode.FileEpisodeInfo.EpisodeNumbers = new[] { 1 };
|
||||
_localEpisode.FolderEpisodeInfo.EpisodeNumbers = new[] { 1 };
|
||||
_localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-Sonarr\S01E01.mkv".AsOsAgnostic();
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
@ -61,7 +62,8 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
|||
[Test]
|
||||
public void should_be_accepted_if_file_is_one_episode_in_folder()
|
||||
{
|
||||
_localEpisode.ParsedEpisodeInfo.EpisodeNumbers = new[] { 1 };
|
||||
_localEpisode.FileEpisodeInfo.EpisodeNumbers = new[] { 1 };
|
||||
_localEpisode.FolderEpisodeInfo.EpisodeNumbers = new[] { 1 };
|
||||
_localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01E01E02.720p.HDTV-Sonarr\S01E01.mkv".AsOsAgnostic();
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
@ -76,9 +78,10 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
|||
[Test]
|
||||
public void should_be_rejected_if_file_and_folder_do_not_have_same_episodes()
|
||||
{
|
||||
_localEpisode.ParsedEpisodeInfo.EpisodeNumbers = new[] { 5, 6 };
|
||||
_localEpisode.FileEpisodeInfo.EpisodeNumbers = new[] { 5, 6 };
|
||||
_localEpisode.FolderEpisodeInfo.EpisodeNumbers = new[] { 1, 2 };
|
||||
_localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01E01E02.720p.HDTV-Sonarr\S01E05E06.mkv".AsOsAgnostic();
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,10 +58,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
Episodes = new List<Episode> { episode },
|
||||
Path = Path.Combine(series.Path, "30 Rock - S01E01 - Pilot.avi"),
|
||||
Quality = new QualityModel(Quality.Bluray720p),
|
||||
ParsedEpisodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
ReleaseGroup = "DRONE"
|
||||
}
|
||||
ReleaseGroup = "DRONE"
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -301,6 +301,9 @@
|
|||
<Compile Include="MediaFiles\DownloadedEpisodesCommandServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\DownloadedEpisodesImportServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeFileMovingServiceTests\MoveEpisodeFileFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\AggregateEpisodesFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\AggregateQualityFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\AugmentQualityFromMediaInfoFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMakerFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\DetectSampleFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\EpisodeTitleSpecificationFixture.cs" />
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
public void should_parse_quality_from_extension(string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(title).Quality.Quality.Should().NotBe(Quality.Unknown);
|
||||
Parser.Parser.ParseTitle(title).Quality.QualitySource.Should().Be(QualitySource.Extension);
|
||||
Parser.Parser.ParseTitle(title).Quality.QualityDetectionSource.Should().Be(QualityDetectionSource.Extension);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -283,7 +283,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("White.Van.Man.2011.S02E01.WS.PDTV.x264-REPACK-TLA")]
|
||||
public void should_parse_quality_from_name(string title)
|
||||
{
|
||||
QualityParser.ParseQuality(title).QualitySource.Should().Be(QualitySource.Name);
|
||||
QualityParser.ParseQuality(title).QualityDetectionSource.Should().Be(QualityDetectionSource.Name);
|
||||
}
|
||||
|
||||
[TestCase("Revolution.S01E02.Chained.Heat.mkv")]
|
||||
|
@ -292,7 +292,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("[CR] Sailor Moon - 004 [48CE2D0F].avi")]
|
||||
public void should_parse_quality_from_extension(string title)
|
||||
{
|
||||
QualityParser.ParseQuality(title).QualitySource.Should().Be(QualitySource.Extension);
|
||||
QualityParser.ParseQuality(title).QualityDetectionSource.Should().Be(QualityDetectionSource.Extension);
|
||||
}
|
||||
|
||||
private void ParseAndVerifyQuality(string title, Quality quality, bool proper)
|
||||
|
|
|
@ -6,7 +6,9 @@ using NzbDrone.Common.Extensions;
|
|||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.Extras.Subtitles;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
|
@ -14,18 +16,18 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||
public class ExistingMetadataImporter : ImportExistingExtraFilesBase<MetadataFile>
|
||||
{
|
||||
private readonly IExtraFileService<MetadataFile> _metadataFileService;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IAugmentingService _augmentingService;
|
||||
private readonly Logger _logger;
|
||||
private readonly List<IMetadata> _consumers;
|
||||
|
||||
public ExistingMetadataImporter(IExtraFileService<MetadataFile> metadataFileService,
|
||||
IEnumerable<IMetadata> consumers,
|
||||
IParsingService parsingService,
|
||||
IAugmentingService augmentingService,
|
||||
Logger logger)
|
||||
: base(metadataFileService)
|
||||
{
|
||||
_metadataFileService = metadataFileService;
|
||||
_parsingService = parsingService;
|
||||
_augmentingService = augmentingService;
|
||||
_logger = logger;
|
||||
_consumers = consumers.ToList();
|
||||
}
|
||||
|
@ -60,9 +62,18 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||
if (metadata.Type == MetadataType.EpisodeImage ||
|
||||
metadata.Type == MetadataType.EpisodeMetadata)
|
||||
{
|
||||
var localEpisode = _parsingService.GetLocalEpisode(possibleMetadataFile, series);
|
||||
var localEpisode = new LocalEpisode
|
||||
{
|
||||
FileEpisodeInfo = Parser.Parser.ParsePath(possibleMetadataFile),
|
||||
Series = series,
|
||||
Path = possibleMetadataFile
|
||||
};
|
||||
|
||||
if (localEpisode == null)
|
||||
try
|
||||
{
|
||||
_augmentingService.Augment(localEpisode, false);
|
||||
}
|
||||
catch (AugmentingFailedException ex)
|
||||
{
|
||||
_logger.Debug("Unable to parse extra file: {0}", possibleMetadataFile);
|
||||
continue;
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Others
|
||||
|
@ -12,16 +15,16 @@ namespace NzbDrone.Core.Extras.Others
|
|||
public class ExistingOtherExtraImporter : ImportExistingExtraFilesBase<OtherExtraFile>
|
||||
{
|
||||
private readonly IExtraFileService<OtherExtraFile> _otherExtraFileService;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IAugmentingService _augmentingService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ExistingOtherExtraImporter(IExtraFileService<OtherExtraFile> otherExtraFileService,
|
||||
IParsingService parsingService,
|
||||
IAugmentingService augmentingService,
|
||||
Logger logger)
|
||||
: base(otherExtraFileService)
|
||||
{
|
||||
_otherExtraFileService = otherExtraFileService;
|
||||
_parsingService = parsingService;
|
||||
_augmentingService = augmentingService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -44,9 +47,18 @@ namespace NzbDrone.Core.Extras.Others
|
|||
continue;
|
||||
}
|
||||
|
||||
var localEpisode = _parsingService.GetLocalEpisode(possibleExtraFile, series);
|
||||
var localEpisode = new LocalEpisode
|
||||
{
|
||||
FileEpisodeInfo = Parser.Parser.ParsePath(possibleExtraFile),
|
||||
Series = series,
|
||||
Path = possibleExtraFile
|
||||
};
|
||||
|
||||
if (localEpisode == null)
|
||||
try
|
||||
{
|
||||
_augmentingService.Augment(localEpisode, false);
|
||||
}
|
||||
catch (AugmentingFailedException ex)
|
||||
{
|
||||
_logger.Debug("Unable to parse extra file: {0}", possibleExtraFile);
|
||||
continue;
|
||||
|
|
|
@ -4,7 +4,9 @@ using System.Linq;
|
|||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Subtitles
|
||||
|
@ -12,16 +14,16 @@ namespace NzbDrone.Core.Extras.Subtitles
|
|||
public class ExistingSubtitleImporter : ImportExistingExtraFilesBase<SubtitleFile>
|
||||
{
|
||||
private readonly IExtraFileService<SubtitleFile> _subtitleFileService;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IAugmentingService _augmentingService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ExistingSubtitleImporter(IExtraFileService<SubtitleFile> subtitleFileService,
|
||||
IParsingService parsingService,
|
||||
IAugmentingService augmentingService,
|
||||
Logger logger)
|
||||
: base (subtitleFileService)
|
||||
{
|
||||
_subtitleFileService = subtitleFileService;
|
||||
_parsingService = parsingService;
|
||||
_augmentingService = augmentingService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -40,11 +42,20 @@ namespace NzbDrone.Core.Extras.Subtitles
|
|||
|
||||
if (SubtitleFileExtensions.Extensions.Contains(extension))
|
||||
{
|
||||
var localEpisode = _parsingService.GetLocalEpisode(possibleSubtitleFile, series);
|
||||
|
||||
if (localEpisode == null)
|
||||
var localEpisode = new LocalEpisode
|
||||
{
|
||||
_logger.Debug("Unable to parse subtitle file: {0}", possibleSubtitleFile);
|
||||
FileEpisodeInfo = Parser.Parser.ParsePath(possibleSubtitleFile),
|
||||
Series = series,
|
||||
Path = possibleSubtitleFile
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
_augmentingService.Augment(localEpisode, false);
|
||||
}
|
||||
catch (AugmentingFailedException ex)
|
||||
{
|
||||
_logger.Debug("Unable to parse extra file: {0}", possibleSubtitleFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -156,14 +156,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return new List<ImportResult>();
|
||||
}
|
||||
|
||||
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
|
||||
var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
|
||||
|
||||
if (folderInfo != null)
|
||||
{
|
||||
_logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
|
||||
}
|
||||
|
||||
var videoFiles = _diskScanService.FilterFiles(directoryInfo.FullName, _diskScanService.GetVideoFiles(directoryInfo.FullName));
|
||||
|
||||
if (downloadClientItem == null)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
return DetectSampleResult.NotSample;
|
||||
}
|
||||
|
||||
// TODO: Use MediaInfo from the import process, no need to re-process the file again here
|
||||
var runTime = _videoFileInfoReader.GetRunTime(path);
|
||||
|
||||
if (!runTime.HasValue)
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
episodeFile.MediaInfo = localEpisode.MediaInfo;
|
||||
episodeFile.SeasonNumber = localEpisode.SeasonNumber;
|
||||
episodeFile.Episodes = localEpisode.Episodes;
|
||||
episodeFile.ReleaseGroup = localEpisode.ParsedEpisodeInfo.ReleaseGroup;
|
||||
episodeFile.ReleaseGroup = localEpisode.ReleaseGroup;
|
||||
|
||||
bool copyOnly;
|
||||
switch (importMode)
|
||||
|
|
|
@ -7,12 +7,9 @@ using NzbDrone.Common.Disk;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
|
@ -25,26 +22,23 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
public class ImportDecisionMaker : IMakeImportDecision
|
||||
{
|
||||
private readonly IEnumerable<IImportDecisionEngineSpecification> _specifications;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IAugmentingService _augmentingService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||
private readonly IDetectSample _detectSample;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
|
||||
IParsingService parsingService,
|
||||
IMediaFileService mediaFileService,
|
||||
IAugmentingService augmentingService,
|
||||
IDiskProvider diskProvider,
|
||||
IVideoFileInfoReader videoFileInfoReader,
|
||||
IDetectSample detectSample,
|
||||
Logger logger)
|
||||
{
|
||||
_specifications = specifications;
|
||||
_parsingService = parsingService;
|
||||
_mediaFileService = mediaFileService;
|
||||
_augmentingService = augmentingService;
|
||||
_diskProvider = diskProvider;
|
||||
_videoFileInfoReader = videoFileInfoReader;
|
||||
_detectSample = detectSample;
|
||||
_logger = logger;
|
||||
}
|
||||
|
@ -60,78 +54,81 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
|
||||
_logger.Debug("Analyzing {0}/{1} files.", newFiles.Count, videoFiles.Count());
|
||||
|
||||
var shouldUseFolderName = ShouldUseFolderName(videoFiles, series, folderInfo);
|
||||
ParsedEpisodeInfo downloadClientItemInfo = null;
|
||||
|
||||
if (downloadClientItem != null)
|
||||
{
|
||||
downloadClientItemInfo = Parser.Parser.ParseTitle(downloadClientItem.Title);
|
||||
}
|
||||
|
||||
var nonSampleVideoFileCount = GetNonSampleVideoFileCount(newFiles, series, downloadClientItemInfo, folderInfo);
|
||||
|
||||
var decisions = new List<ImportDecision>();
|
||||
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
decisions.AddIfNotNull(GetDecision(file, series, downloadClientItem, folderInfo, sceneSource, shouldUseFolderName));
|
||||
var localEpisode = new LocalEpisode
|
||||
{
|
||||
Series = series,
|
||||
DownloadClientEpisodeInfo = downloadClientItemInfo,
|
||||
FolderEpisodeInfo = folderInfo,
|
||||
Path = file,
|
||||
SceneSource = sceneSource
|
||||
};
|
||||
|
||||
decisions.AddIfNotNull(GetDecision(localEpisode, downloadClientItem, nonSampleVideoFileCount > 1));
|
||||
}
|
||||
|
||||
return decisions;
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(string file, Series series, DownloadClientItem downloadClientItem, ParsedEpisodeInfo folderInfo, bool sceneSource, bool shouldUseFolderName)
|
||||
private ImportDecision GetDecision(LocalEpisode localEpisode, DownloadClientItem downloadClientItem, bool otherFiles)
|
||||
{
|
||||
ImportDecision decision = null;
|
||||
|
||||
var fileEpisodeInfo = Parser.Parser.ParsePath(localEpisode.Path);
|
||||
|
||||
localEpisode.FileEpisodeInfo = fileEpisodeInfo;
|
||||
localEpisode.Size = _diskProvider.GetFileSize(localEpisode.Path);
|
||||
|
||||
try
|
||||
{
|
||||
var localEpisode = _parsingService.GetLocalEpisode(file, series, shouldUseFolderName ? folderInfo : null, sceneSource);
|
||||
_augmentingService.Augment(localEpisode, otherFiles);
|
||||
|
||||
if (localEpisode != null)
|
||||
if (localEpisode.Episodes.Empty())
|
||||
{
|
||||
localEpisode.Quality = GetQuality(folderInfo, localEpisode.Quality, series);
|
||||
localEpisode.Size = _diskProvider.GetFileSize(file);
|
||||
|
||||
_logger.Debug("Size: {0}", localEpisode.Size);
|
||||
|
||||
//TODO: make it so media info doesn't ruin the import process of a new series
|
||||
if (sceneSource)
|
||||
if (IsPartialSeason(localEpisode))
|
||||
{
|
||||
localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Partial season packs are not supported"));
|
||||
}
|
||||
|
||||
if (localEpisode.Episodes.Empty())
|
||||
else if (IsSeasonExtra(localEpisode))
|
||||
{
|
||||
if (localEpisode.ParsedEpisodeInfo.IsPartialSeason)
|
||||
{
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Partial season packs are not supported"));
|
||||
}
|
||||
else if (localEpisode.ParsedEpisodeInfo.IsSeasonExtra)
|
||||
{
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Extras are not supported"));
|
||||
}
|
||||
else
|
||||
{
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Invalid season or episode"));
|
||||
}
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Extras are not supported"));
|
||||
}
|
||||
else
|
||||
{
|
||||
decision = GetDecision(localEpisode, downloadClientItem);
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Invalid season or episode"));
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
localEpisode = new LocalEpisode();
|
||||
localEpisode.Path = file;
|
||||
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Unable to parse file"));
|
||||
decision = GetDecision(localEpisode, downloadClientItem);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (AugmentingFailedException)
|
||||
{
|
||||
_logger.Error(e, "Couldn't import file. {0}", file);
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Unable to parse file"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Couldn't import file. {0}", localEpisode.Path);
|
||||
|
||||
var localEpisode = new LocalEpisode { Path = file };
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Unexpected error processing file"));
|
||||
}
|
||||
|
||||
if (decision == null)
|
||||
{
|
||||
_logger.Error("Unable to make a decision on {0}", file);
|
||||
_logger.Error("Unable to make a decision on {0}", localEpisode.Path);
|
||||
}
|
||||
else if (decision.Rejections.Any())
|
||||
{
|
||||
|
@ -175,65 +172,66 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
return null;
|
||||
}
|
||||
|
||||
private bool ShouldUseFolderName(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo)
|
||||
private int GetNonSampleVideoFileCount(List<string> videoFiles, Series series, ParsedEpisodeInfo downloadClientItemInfo, ParsedEpisodeInfo folderInfo)
|
||||
{
|
||||
if (folderInfo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (folderInfo.FullSeason)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var isPossibleSpecialEpisode = downloadClientItemInfo?.IsPossibleSpecialEpisode ?? false;
|
||||
// If we might already have a special, don't try to get it from the folder info.
|
||||
isPossibleSpecialEpisode = isPossibleSpecialEpisode || (folderInfo?.IsPossibleSpecialEpisode ?? false);
|
||||
|
||||
return videoFiles.Count(file =>
|
||||
{
|
||||
var sample = _detectSample.IsSample(series, file, folderInfo.IsPossibleSpecialEpisode);
|
||||
var sample = _detectSample.IsSample(series, file, isPossibleSpecialEpisode);
|
||||
|
||||
if (sample == DetectSampleResult.Sample)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SceneChecker.IsSceneTitle(Path.GetFileName(file)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}) == 1;
|
||||
});
|
||||
}
|
||||
|
||||
private QualityModel GetQuality(ParsedEpisodeInfo folderInfo, QualityModel fileQuality, Series series)
|
||||
private bool IsPartialSeason(LocalEpisode localEpisode)
|
||||
{
|
||||
if (UseFolderQuality(folderInfo, fileQuality, series))
|
||||
{
|
||||
_logger.Debug("Using quality from folder: {0}", folderInfo.Quality);
|
||||
return folderInfo.Quality;
|
||||
}
|
||||
var downloadClientEpisodeInfo = localEpisode.DownloadClientEpisodeInfo;
|
||||
var folderEpisodeInfo = localEpisode.FolderEpisodeInfo;
|
||||
var fileEpisodeInfo = localEpisode.FileEpisodeInfo;
|
||||
|
||||
return fileQuality;
|
||||
}
|
||||
|
||||
private bool UseFolderQuality(ParsedEpisodeInfo folderInfo, QualityModel fileQuality, Series series)
|
||||
{
|
||||
if (folderInfo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (folderInfo.Quality.Quality == Quality.Unknown)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileQuality.QualitySource == QualitySource.Extension)
|
||||
if (downloadClientEpisodeInfo != null && downloadClientEpisodeInfo.IsPartialSeason)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (new QualityModelComparer(series.Profile).Compare(folderInfo.Quality, fileQuality) > 0)
|
||||
if (folderEpisodeInfo != null && folderEpisodeInfo.IsPartialSeason)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fileEpisodeInfo != null && fileEpisodeInfo.IsPartialSeason)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsSeasonExtra(LocalEpisode localEpisode)
|
||||
{
|
||||
var downloadClientEpisodeInfo = localEpisode.DownloadClientEpisodeInfo;
|
||||
var folderEpisodeInfo = localEpisode.FolderEpisodeInfo;
|
||||
var fileEpisodeInfo = localEpisode.FileEpisodeInfo;
|
||||
|
||||
if (downloadClientEpisodeInfo != null && downloadClientEpisodeInfo.IsSeasonExtra)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (folderEpisodeInfo != null && folderEpisodeInfo.IsSeasonExtra)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fileEpisodeInfo != null && fileEpisodeInfo.IsSeasonExtra)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
var file = message.Files[i];
|
||||
var series = _seriesService.GetSeries(file.SeriesId);
|
||||
var episodes = _episodeService.GetEpisodes(file.EpisodeIds);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo();
|
||||
var fileEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo();
|
||||
var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
|
||||
var existingFile = series.Path.IsParentPath(file.Path);
|
||||
|
||||
|
@ -254,7 +254,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
ExistingFile = false,
|
||||
Episodes = episodes,
|
||||
MediaInfo = mediaInfo,
|
||||
ParsedEpisodeInfo = parsedEpisodeInfo,
|
||||
FileEpisodeInfo = fileEpisodeInfo,
|
||||
Path = file.Path,
|
||||
Quality = file.Quality,
|
||||
Series = series,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using NLog;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -16,7 +16,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (localEpisode.ParsedEpisodeInfo.FullSeason)
|
||||
if (localEpisode.FileEpisodeInfo.FullSeason)
|
||||
{
|
||||
_logger.Debug("Single episode file detected as containing all episodes in the season");
|
||||
return Decision.Reject("Single episode file contains all episodes in seasons");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
|
@ -32,7 +32,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var folderInfo = Parser.Parser.ParseTitle(dirInfo.Name);
|
||||
var folderInfo = localEpisode.FileEpisodeInfo;
|
||||
|
||||
if (folderInfo != null && folderInfo.IsPossibleSceneSeasonSpecial)
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var unexpected = localEpisode.ParsedEpisodeInfo.EpisodeNumbers.Where(f => !folderInfo.EpisodeNumbers.Contains(f)).ToList();
|
||||
var unexpected = localEpisode.FileEpisodeInfo.EpisodeNumbers.Where(f => !folderInfo.EpisodeNumbers.Contains(f)).ToList();
|
||||
|
||||
if (unexpected.Any())
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
|
@ -36,6 +36,8 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
|
||||
MediaInfo mediaInfo = null;
|
||||
|
||||
// TODO: Cache media info by path, mtime and length so we don't need to read files multiple times
|
||||
|
||||
try
|
||||
{
|
||||
mediaInfo = new MediaInfo();
|
||||
|
|
|
@ -763,7 +763,20 @@
|
|||
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
||||
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
|
||||
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\AggregateEpisodes.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\AggregateQuality.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\AggregateReleaseGroup.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\AugmentQualityFromFileName.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\AugmentQualityFromFolder.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\AugmentQualityFromDownloadClientItem.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\AugmentQualityFromMediaInfo.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\AugmentQualityResult.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\Confidence.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\Augmenters\Quality\IAugmentQuality.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\IAggregateLocalEpisode.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\AggregationService.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\DetectSampleResult.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\AggregationFailedException.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportMode.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RenameSeriesCommand.cs" />
|
||||
|
@ -953,6 +966,7 @@
|
|||
<Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" />
|
||||
<Compile Include="Profiles\ProfileRepository.cs" />
|
||||
<Compile Include="ProgressMessaging\ProgressMessageContext.cs" />
|
||||
<Compile Include="Qualities\QualityDetectionSource.cs" />
|
||||
<Compile Include="Qualities\QualitySource.cs" />
|
||||
<Compile Include="Qualities\Revision.cs" />
|
||||
<Compile Include="RemotePathMappings\RemotePathMapping.cs" />
|
||||
|
|
|
@ -16,12 +16,16 @@ namespace NzbDrone.Core.Parser.Model
|
|||
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; }
|
||||
public ParsedEpisodeInfo FileEpisodeInfo { get; set; }
|
||||
public ParsedEpisodeInfo DownloadClientEpisodeInfo { get; set; }
|
||||
public ParsedEpisodeInfo FolderEpisodeInfo { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public List<Episode> Episodes { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
public bool ExistingFile { get; set; }
|
||||
public bool SceneSource { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
|
||||
public int SeasonNumber
|
||||
{
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
@ -13,13 +11,12 @@ namespace NzbDrone.Core.Parser
|
|||
{
|
||||
public interface IParsingService
|
||||
{
|
||||
LocalEpisode GetLocalEpisode(string filename, Series series);
|
||||
LocalEpisode GetLocalEpisode(string filename, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource);
|
||||
Series GetSeries(string title);
|
||||
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds);
|
||||
List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null);
|
||||
ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||
ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, Series series);
|
||||
}
|
||||
|
||||
public class ParsingService : IParsingService
|
||||
|
@ -40,60 +37,6 @@ namespace NzbDrone.Core.Parser
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public LocalEpisode GetLocalEpisode(string filename, Series series)
|
||||
{
|
||||
return GetLocalEpisode(filename, series, null, false);
|
||||
}
|
||||
|
||||
public LocalEpisode GetLocalEpisode(string filename, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource)
|
||||
{
|
||||
ParsedEpisodeInfo parsedEpisodeInfo;
|
||||
|
||||
if (folderInfo != null)
|
||||
{
|
||||
parsedEpisodeInfo = folderInfo.JsonClone();
|
||||
parsedEpisodeInfo.Quality = QualityParser.ParseQuality(Path.GetFileName(filename));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
parsedEpisodeInfo = Parser.ParsePath(filename);
|
||||
}
|
||||
|
||||
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
|
||||
{
|
||||
var title = Path.GetFileNameWithoutExtension(filename);
|
||||
var specialEpisodeInfo = ParseSpecialEpisodeTitle(parsedEpisodeInfo, title, series);
|
||||
|
||||
if (specialEpisodeInfo != null)
|
||||
{
|
||||
parsedEpisodeInfo = specialEpisodeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if (parsedEpisodeInfo == null)
|
||||
{
|
||||
if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(filename)))
|
||||
{
|
||||
_logger.Warn("Unable to parse episode info from path {0}", filename);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var episodes = GetEpisodes(parsedEpisodeInfo, series, sceneSource);
|
||||
|
||||
return new LocalEpisode
|
||||
{
|
||||
Series = series,
|
||||
Quality = parsedEpisodeInfo.Quality,
|
||||
Episodes = episodes,
|
||||
Path = filename,
|
||||
ParsedEpisodeInfo = parsedEpisodeInfo,
|
||||
ExistingFile = series.Path.IsParentPath(filename)
|
||||
};
|
||||
}
|
||||
|
||||
public Series GetSeries(string title)
|
||||
{
|
||||
var parsedEpisodeInfo = Parser.ParseTitle(title);
|
||||
|
@ -225,7 +168,7 @@ namespace NzbDrone.Core.Parser
|
|||
return ParseSpecialEpisodeTitle(parsedEpisodeInfo, releaseTitle, series);
|
||||
}
|
||||
|
||||
private ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, Series series)
|
||||
public ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, Series series)
|
||||
{
|
||||
// SxxE00 episodes are sometimes mapped via TheXEM, don't use episode title parsing in that case.
|
||||
if (parsedEpisodeInfo != null && parsedEpisodeInfo.IsPossibleSceneSeasonSpecial && series.UseSceneNumbering)
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace NzbDrone.Core.Parser
|
|||
try
|
||||
{
|
||||
result.Quality = MediaFileExtensions.GetQualityForExtension(Path.GetExtension(name));
|
||||
result.QualitySource = QualitySource.Extension;
|
||||
result.QualityDetectionSource = QualityDetectionSource.Extension;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
@ -9,15 +9,19 @@ namespace NzbDrone.Core.Qualities
|
|||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public QualitySource Source { get; set; }
|
||||
public int Resolution { get; set; }
|
||||
|
||||
public Quality()
|
||||
{
|
||||
}
|
||||
|
||||
private Quality(int id, string name)
|
||||
private Quality(int id, string name, QualitySource source, int resolution)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Source = source;
|
||||
Resolution = resolution;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
@ -55,26 +59,26 @@ namespace NzbDrone.Core.Qualities
|
|||
return !Equals(left, right);
|
||||
}
|
||||
|
||||
public static Quality Unknown => new Quality(0, "Unknown");
|
||||
public static Quality SDTV => new Quality(1, "SDTV");
|
||||
public static Quality DVD => new Quality(2, "DVD");
|
||||
public static Quality WEBDL1080p => new Quality(3, "WEBDL-1080p");
|
||||
public static Quality HDTV720p => new Quality(4, "HDTV-720p");
|
||||
public static Quality WEBDL720p => new Quality(5, "WEBDL-720p");
|
||||
public static Quality Bluray720p => new Quality(6, "Bluray-720p");
|
||||
public static Quality Bluray1080p => new Quality(7, "Bluray-1080p");
|
||||
public static Quality WEBDL480p => new Quality(8, "WEBDL-480p");
|
||||
public static Quality HDTV1080p => new Quality(9, "HDTV-1080p");
|
||||
public static Quality RAWHD => new Quality(10, "Raw-HD");
|
||||
//public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p"); } }
|
||||
//public static Quality WEBRip480p { get { return new Quality(12, "WEBRip-480p"); } }
|
||||
//public static Quality Bluray480p { get { return new Quality(13, "Bluray-480p"); } }
|
||||
//public static Quality WEBRip720p { get { return new Quality(14, "WEBRip-720p"); } }
|
||||
//public static Quality WEBRip1080p { get { return new Quality(15, "WEBRip-1080p"); } }
|
||||
public static Quality HDTV2160p => new Quality(16, "HDTV-2160p");
|
||||
//public static Quality WEBRip2160p { get { return new Quality(17, "WEBRip-2160p"); } }
|
||||
public static Quality WEBDL2160p => new Quality(18, "WEBDL-2160p");
|
||||
public static Quality Bluray2160p => new Quality(19, "Bluray-2160p");
|
||||
public static Quality Unknown => new Quality(0, "Unknown", QualitySource.Unknown, 0);
|
||||
public static Quality SDTV => new Quality(1, "SDTV", QualitySource.Television, 480);
|
||||
public static Quality DVD => new Quality(2, "DVD", QualitySource.DVD, 480);
|
||||
public static Quality WEBDL1080p => new Quality(3, "WEBDL-1080p", QualitySource.Web, 1080);
|
||||
public static Quality HDTV720p => new Quality(4, "HDTV-720p", QualitySource.Television, 720);
|
||||
public static Quality WEBDL720p => new Quality(5, "WEBDL-720p", QualitySource.Web, 720);
|
||||
public static Quality Bluray720p => new Quality(6, "Bluray-720p", QualitySource.Bluray, 720);
|
||||
public static Quality Bluray1080p => new Quality(7, "Bluray-1080p", QualitySource.Bluray, 1080);
|
||||
public static Quality WEBDL480p => new Quality(8, "WEBDL-480p", QualitySource.Web, 480);
|
||||
public static Quality HDTV1080p => new Quality(9, "HDTV-1080p", QualitySource.Television, 1080);
|
||||
public static Quality RAWHD => new Quality(10, "Raw-HD", QualitySource.TelevisionRaw, 1080);
|
||||
//public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p", QualitySource.Television, 480); } }
|
||||
//public static Quality WEBRip480p { get { return new Quality(12, "WEBRip-480p", QualitySource.WebRip, 480); } }
|
||||
//public static Quality Bluray480p { get { return new Quality(13, "Bluray-480p", QualitySource.Bluray, 480); } }
|
||||
//public static Quality WEBRip720p { get { return new Quality(14, "WEBRip-720p", QualitySource.WebRip, 720); } }
|
||||
//public static Quality WEBRip1080p { get { return new Quality(15, "WEBRip-1080p", QualitySource.WebRip, 1080); } }
|
||||
public static Quality HDTV2160p => new Quality(16, "HDTV-2160p", QualitySource.Television, 2160);
|
||||
//public static Quality WEBRip2160p { get { return new Quality(17, "WEBRip-2160p", QualitySource.WebRip, 2160); } }
|
||||
public static Quality WEBDL2160p => new Quality(18, "WEBDL-2160p", QualitySource.Web, 2160);
|
||||
public static Quality Bluray2160p => new Quality(19, "Bluray-2160p", QualitySource.Bluray, 2160);
|
||||
|
||||
static Quality()
|
||||
{
|
||||
|
@ -148,5 +152,10 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public enum QualityDetectionSource
|
||||
{
|
||||
Name,
|
||||
Extension,
|
||||
MediaInfo
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
|
@ -10,8 +10,8 @@ namespace NzbDrone.Core.Qualities
|
|||
public Revision Revision { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public QualitySource QualitySource { get; set; }
|
||||
|
||||
public QualityDetectionSource QualityDetectionSource { get; set; }
|
||||
|
||||
public QualityModel()
|
||||
: this(Quality.Unknown, new Revision())
|
||||
{
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
namespace NzbDrone.Core.Qualities
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public enum QualitySource
|
||||
{
|
||||
Name,
|
||||
Extension,
|
||||
MediaInfo
|
||||
Unknown,
|
||||
Television,
|
||||
TelevisionRaw,
|
||||
Web,
|
||||
WebRip,
|
||||
DVD,
|
||||
Bluray
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue