1
0
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:
Mark McDowall 2017-06-10 18:07:24 -07:00 committed by Mark McDowall
parent eea3419849
commit 8cf028e071
12 changed files with 84 additions and 132 deletions

View File

@ -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>()))

View File

@ -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);
}
}
}

View File

@ -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");

View File

@ -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]

View File

@ -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" />

View File

@ -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;

View File

@ -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)

View File

@ -0,0 +1,9 @@
namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
public enum DetectSampleResult
{
Indeterminate,
Sample,
NotSample
}
}

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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)

View File

@ -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" />