mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-12-16 11:37:58 +02:00
Fixed: Improve sample rejection message when MediaInfo is not available
Closes #1967
This commit is contained in:
parent
eea3419849
commit
8cf028e071
@ -164,11 +164,9 @@ public void should_delete_folder_if_files_were_imported_and_only_sample_files_re
|
||||
|
||||
Mocker.GetMock<IDetectSample>()
|
||||
.Setup(s => s.IsSample(It.IsAny<Series>(),
|
||||
It.IsAny<QualityModel>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<long>(),
|
||||
It.IsAny<bool>()))
|
||||
.Returns(true);
|
||||
.Returns(DetectSampleResult.Sample);
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
|
||||
@ -236,11 +234,9 @@ public void should_not_delete_if_there_is_large_rar_file()
|
||||
|
||||
Mocker.GetMock<IDetectSample>()
|
||||
.Setup(s => s.IsSample(It.IsAny<Series>(),
|
||||
It.IsAny<QualityModel>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<long>(),
|
||||
It.IsAny<bool>()))
|
||||
.Returns(true);
|
||||
.Returns(DetectSampleResult.Sample);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
|
||||
@ -347,11 +343,9 @@ public void should_not_delete_if_no_files_were_imported()
|
||||
|
||||
Mocker.GetMock<IDetectSample>()
|
||||
.Setup(s => s.IsSample(It.IsAny<Series>(),
|
||||
It.IsAny<QualityModel>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<long>(),
|
||||
It.IsAny<bool>()))
|
||||
.Returns(true);
|
||||
.Returns(DetectSampleResult.Sample);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFileSize(It.IsAny<string>()))
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
||||
{
|
||||
[TestFixture]
|
||||
public class SampleServiceFixture : CoreTest<DetectSample>
|
||||
public class DetectSampleFixture : CoreTest<DetectSample>
|
||||
{
|
||||
private Series _series;
|
||||
private LocalEpisode _localEpisode;
|
||||
@ -42,11 +42,6 @@ public void Setup()
|
||||
};
|
||||
}
|
||||
|
||||
private void GivenFileSize(long size)
|
||||
{
|
||||
_localEpisode.Size = size;
|
||||
}
|
||||
|
||||
private void GivenRuntime(int seconds)
|
||||
{
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
@ -58,7 +53,7 @@ private void GivenRuntime(int seconds)
|
||||
public void should_return_false_if_season_zero()
|
||||
{
|
||||
_localEpisode.Episodes[0].SeasonNumber = 0;
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -66,7 +61,7 @@ public void should_return_false_for_flv()
|
||||
{
|
||||
_localEpisode.Path = @"C:\Test\some.show.s01e01.flv";
|
||||
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>().Verify(c => c.GetRunTime(It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
@ -76,7 +71,7 @@ public void should_return_false_for_strm()
|
||||
{
|
||||
_localEpisode.Path = @"C:\Test\some.show.s01e01.strm";
|
||||
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>().Verify(c => c.GetRunTime(It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
@ -85,12 +80,9 @@ public void should_return_false_for_strm()
|
||||
public void should_use_runtime()
|
||||
{
|
||||
GivenRuntime(120);
|
||||
GivenFileSize(1000.Megabytes());
|
||||
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Quality,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.Size,
|
||||
_localEpisode.IsSpecial);
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>().Verify(v => v.GetRunTime(It.IsAny<string>()), Times.Once());
|
||||
@ -101,7 +93,7 @@ public void should_return_true_if_runtime_is_less_than_minimum()
|
||||
{
|
||||
GivenRuntime(60);
|
||||
|
||||
ShouldBeTrue();
|
||||
ShouldBeSample();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -109,7 +101,7 @@ public void should_return_false_if_runtime_greater_than_minimum()
|
||||
{
|
||||
GivenRuntime(600);
|
||||
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -118,7 +110,7 @@ public void should_return_false_if_runtime_greater_than_webisode_minimum()
|
||||
_series.Runtime = 6;
|
||||
GivenRuntime(299);
|
||||
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -127,7 +119,7 @@ public void should_return_false_if_runtime_greater_than_anime_short_minimum()
|
||||
_series.Runtime = 2;
|
||||
GivenRuntime(60);
|
||||
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -136,29 +128,19 @@ public void should_return_true_if_runtime_less_than_anime_short_minimum()
|
||||
_series.Runtime = 2;
|
||||
GivenRuntime(10);
|
||||
|
||||
ShouldBeTrue();
|
||||
ShouldBeSample();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_fall_back_to_file_size_if_mediainfo_dll_not_found_acceptable_size()
|
||||
public void should_return_indeterminate_if_mediainfo_result_is_null()
|
||||
{
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Setup(s => s.GetRunTime(It.IsAny<string>()))
|
||||
.Throws<DllNotFoundException>();
|
||||
|
||||
GivenFileSize(1000.Megabytes());
|
||||
ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_fall_back_to_file_size_if_mediainfo_dll_not_found_undersize()
|
||||
{
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Setup(s => s.GetRunTime(It.IsAny<string>()))
|
||||
.Throws<DllNotFoundException>();
|
||||
|
||||
GivenFileSize(1.Megabytes());
|
||||
ShouldBeTrue();
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.IsSpecial).Should().Be(DetectSampleResult.Indeterminate);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -167,7 +149,7 @@ public void should_not_treat_daily_episode_a_special()
|
||||
GivenRuntime(600);
|
||||
_series.SeriesType = SeriesTypes.Daily;
|
||||
_localEpisode.Episodes[0].SeasonNumber = 0;
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -176,25 +158,21 @@ public void should_return_false_for_anime_special()
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_localEpisode.Episodes[0].SeasonNumber = 0;
|
||||
|
||||
ShouldBeFalse();
|
||||
ShouldBeNotSample();
|
||||
}
|
||||
|
||||
private void ShouldBeTrue()
|
||||
private void ShouldBeSample()
|
||||
{
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Quality,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.Size,
|
||||
_localEpisode.IsSpecial).Should().BeTrue();
|
||||
}
|
||||
|
||||
private void ShouldBeFalse()
|
||||
{
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Quality,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.Size,
|
||||
_localEpisode.IsSpecial).Should().BeFalse();
|
||||
_localEpisode.IsSpecial).Should().Be(DetectSampleResult.Sample);
|
||||
}
|
||||
|
||||
private void ShouldBeNotSample()
|
||||
{
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.IsSpecial).Should().Be(DetectSampleResult.NotSample);
|
||||
}
|
||||
}
|
||||
}
|
@ -333,8 +333,16 @@ public void should_use_folder_when_only_one_video_file_and_a_sample()
|
||||
GivenVideoFiles(videoFiles.ToList());
|
||||
|
||||
Mocker.GetMock<IDetectSample>()
|
||||
.Setup(s => s.IsSample(_series, It.IsAny<QualityModel>(), It.Is<string>(c => c.Contains("sample")), It.IsAny<long>(), It.IsAny<bool>()))
|
||||
.Returns(true);
|
||||
.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");
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@ -30,11 +30,9 @@ public void get_runtime()
|
||||
{
|
||||
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "H264_sample.mp4");
|
||||
|
||||
Subject.GetRunTime(path).Seconds.Should().Be(10);
|
||||
|
||||
Subject.GetRunTime(path).Value.Seconds.Should().Be(10);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void get_info()
|
||||
{
|
||||
@ -86,7 +84,6 @@ public void get_info_unicode()
|
||||
info.VideoCodec.Should().Be("AVC");
|
||||
info.VideoFps.Should().Be(24);
|
||||
info.Width.Should().Be(480);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -284,7 +284,7 @@
|
||||
<Compile Include="MediaFiles\DownloadedEpisodesImportServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeFileMovingServiceTests\MoveEpisodeFileFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMakerFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\SampleServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\DetectSampleFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameFileSpecificationFixture.cs" />
|
||||
|
@ -113,10 +113,7 @@ public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Series series)
|
||||
return false;
|
||||
}
|
||||
|
||||
var size = _diskProvider.GetFileSize(videoFile);
|
||||
var quality = QualityParser.ParseQuality(videoFile);
|
||||
|
||||
if (!_detectSample.IsSample(series, quality, videoFile, size, episodeParseResult.IsPossibleSpecialEpisode))
|
||||
if (_detectSample.IsSample(series, videoFile, episodeParseResult.IsPossibleSpecialEpisode) != DetectSampleResult.Sample)
|
||||
{
|
||||
_logger.Warn("Non-sample file detected: [{0}]", videoFile);
|
||||
return false;
|
||||
|
@ -1,16 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
public interface IDetectSample
|
||||
{
|
||||
bool IsSample(Series series, QualityModel quality, string path, long size, bool isSpecial);
|
||||
DetectSampleResult IsSample(Series series, string path, bool isSpecial);
|
||||
}
|
||||
|
||||
public class DetectSample : IDetectSample
|
||||
@ -18,22 +16,18 @@ public class DetectSample : IDetectSample
|
||||
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private static List<Quality> _largeSampleSizeQualities = new List<Quality> { Quality.HDTV1080p, Quality.WEBDL1080p, Quality.Bluray1080p };
|
||||
|
||||
public DetectSample(IVideoFileInfoReader videoFileInfoReader, Logger logger)
|
||||
{
|
||||
_videoFileInfoReader = videoFileInfoReader;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public static long SampleSizeLimit => 70.Megabytes();
|
||||
|
||||
public bool IsSample(Series series, QualityModel quality, string path, long size, bool isSpecial)
|
||||
public DetectSampleResult IsSample(Series series, string path, bool isSpecial)
|
||||
{
|
||||
if (isSpecial)
|
||||
{
|
||||
_logger.Debug("Special, skipping sample check");
|
||||
return false;
|
||||
return DetectSampleResult.NotSample;
|
||||
}
|
||||
|
||||
var extension = Path.GetExtension(path);
|
||||
@ -41,61 +35,39 @@ public bool IsSample(Series series, QualityModel quality, string path, long size
|
||||
if (extension != null && extension.Equals(".flv", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Skipping sample check for .flv file");
|
||||
return false;
|
||||
return DetectSampleResult.NotSample;
|
||||
}
|
||||
|
||||
if (extension != null && extension.Equals(".strm", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Skipping sample check for .strm file");
|
||||
return false;
|
||||
return DetectSampleResult.NotSample;
|
||||
}
|
||||
|
||||
try
|
||||
var runTime = _videoFileInfoReader.GetRunTime(path);
|
||||
|
||||
if (!runTime.HasValue)
|
||||
{
|
||||
var runTime = _videoFileInfoReader.GetRunTime(path);
|
||||
var minimumRuntime = GetMinimumAllowedRuntime(series);
|
||||
|
||||
if (runTime.TotalMinutes.Equals(0))
|
||||
{
|
||||
_logger.Error("[{0}] has a runtime of 0, is it a valid video file?", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (runTime.TotalSeconds < minimumRuntime)
|
||||
{
|
||||
_logger.Debug("[{0}] appears to be a sample. Runtime: {1} seconds. Expected at least: {2} seconds", path, runTime, minimumRuntime);
|
||||
return true;
|
||||
}
|
||||
_logger.Error("Failed to get runtime from the file, make sure mediainfo is available");
|
||||
return DetectSampleResult.Indeterminate;
|
||||
}
|
||||
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
_logger.Debug("Falling back to file size detection");
|
||||
var minimumRuntime = GetMinimumAllowedRuntime(series);
|
||||
|
||||
return CheckSize(size, quality);
|
||||
if (runTime.Value.TotalMinutes.Equals(0))
|
||||
{
|
||||
_logger.Error("[{0}] has a runtime of 0, is it a valid video file?", path);
|
||||
return DetectSampleResult.Sample;
|
||||
}
|
||||
|
||||
if (runTime.Value.TotalSeconds < minimumRuntime)
|
||||
{
|
||||
_logger.Debug("[{0}] appears to be a sample. Runtime: {1} seconds. Expected at least: {2} seconds", path, runTime, minimumRuntime);
|
||||
return DetectSampleResult.Sample;
|
||||
}
|
||||
|
||||
_logger.Debug("Runtime is over 90 seconds");
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CheckSize(long size, QualityModel quality)
|
||||
{
|
||||
{
|
||||
if (size < SampleSizeLimit * 2)
|
||||
{
|
||||
_logger.Debug("1080p file is less than sample limit");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (size < SampleSizeLimit)
|
||||
{
|
||||
_logger.Debug("File is less than sample limit");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return DetectSampleResult.NotSample;
|
||||
}
|
||||
|
||||
private int GetMinimumAllowedRuntime(Series series)
|
||||
|
@ -0,0 +1,9 @@
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
public enum DetectSampleResult
|
||||
{
|
||||
Indeterminate,
|
||||
Sample,
|
||||
NotSample
|
||||
}
|
||||
}
|
@ -170,11 +170,9 @@ private bool ShouldUseFolderName(List<string> videoFiles, Series series, ParsedE
|
||||
|
||||
return videoFiles.Count(file =>
|
||||
{
|
||||
var size = _diskProvider.GetFileSize(file);
|
||||
var fileQuality = QualityParser.ParseQuality(file);
|
||||
var sample = _detectSample.IsSample(series, GetQuality(folderInfo, fileQuality, series), file, size, folderInfo.IsPossibleSpecialEpisode);
|
||||
var sample = _detectSample.IsSample(series, file, folderInfo.IsPossibleSpecialEpisode);
|
||||
|
||||
if (sample)
|
||||
if (sample == DetectSampleResult.Sample)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -26,16 +26,19 @@ public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem down
|
||||
}
|
||||
|
||||
var sample = _detectSample.IsSample(localEpisode.Series,
|
||||
localEpisode.Quality,
|
||||
localEpisode.Path,
|
||||
localEpisode.Size,
|
||||
localEpisode.IsSpecial);
|
||||
|
||||
if (sample)
|
||||
if (sample == DetectSampleResult.Sample)
|
||||
{
|
||||
return Decision.Reject("Sample");
|
||||
}
|
||||
|
||||
else if (sample == DetectSampleResult.Indeterminate)
|
||||
{
|
||||
return Decision.Reject("Unable to determine if file is a sample");
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
public interface IVideoFileInfoReader
|
||||
{
|
||||
MediaInfoModel GetMediaInfo(string filename);
|
||||
TimeSpan GetRunTime(string filename);
|
||||
TimeSpan? GetRunTime(string filename);
|
||||
}
|
||||
|
||||
public class VideoFileInfoReader : IVideoFileInfoReader
|
||||
@ -181,16 +181,11 @@ public MediaInfoModel GetMediaInfo(string filename)
|
||||
return null;
|
||||
}
|
||||
|
||||
public TimeSpan GetRunTime(string filename)
|
||||
public TimeSpan? GetRunTime(string filename)
|
||||
{
|
||||
var info = GetMediaInfo(filename);
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
return new TimeSpan();
|
||||
}
|
||||
|
||||
return info.RunTime;
|
||||
return info?.RunTime;
|
||||
}
|
||||
|
||||
private TimeSpan GetBestRuntime(int audio, int video, int general)
|
||||
|
@ -745,6 +745,7 @@
|
||||
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
||||
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
|
||||
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\DetectSampleResult.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportMode.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RenameSeriesCommand.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user