1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-12-16 11:37:58 +02:00

Disk scan is much much much much faster.

This commit is contained in:
kay.one 2013-07-18 22:05:07 -07:00
parent c21ff235b6
commit b676f868ce
10 changed files with 112 additions and 81 deletions

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using NLog;
@ -83,9 +84,12 @@ public void PublishCommand<TCommand>(TCommand command) where TCommand : class, I
_logger.Debug("{0} -> {1}", command.GetType().Name, handler.GetType().Name);
var sw = Stopwatch.StartNew();
try
{
handler.Execute(command);
sw.Stop();
PublishEvent(new CommandCompletedEvent(command));
}
catch (Exception e)
@ -98,7 +102,7 @@ public void PublishCommand<TCommand>(TCommand command) where TCommand : class, I
PublishEvent(new CommandExecutedEvent(command));
}
_logger.Debug("{0} <- {1}", command.GetType().Name, handler.GetType().Name);
_logger.Debug("{0} <- {1} [{2}]", command.GetType().Name, handler.GetType().Name, sw.Elapsed.ToString(""));
}
public void PublishCommand(string commandTypeName)

View File

@ -1,44 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.MediaFileTests.EpisodeImportTests
{
[TestFixture]
public class NotAlreadyImportedSpecificationFixture : CoreTest<NotAlreadyImportedSpecification>
{
private LocalEpisode _localEpisode;
[SetUp]
public void Setup()
{
_localEpisode = new LocalEpisode
{
Path = @"C:\Test\30 Rock\30.rock.s01e01.avi"
};
}
[Test]
public void should_return_false_if_path_is_already_in_episodeFiles()
{
Mocker.GetMock<IMediaFileService>()
.Setup(s => s.Exists(_localEpisode.Path))
.Returns(true);
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
}
[Test]
public void should_return_true_if_new_file()
{
Mocker.GetMock<IMediaFileService>()
.Setup(s => s.Exists(_localEpisode.Path))
.Returns(false);
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
}
}
}

View File

@ -112,5 +112,18 @@ public void should_return_true_if_over_size_and_length()
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
}
[Test]
public void should_not_check_lenght_if_file_is_large_enough()
{
WithFileSize(100.Megabytes());
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
Mocker.GetMock<IVideoFileInfoReader>().Verify(c => c.GetRunTime(It.IsAny<string>()), Times.Never());
}
}
}

View File

@ -1,4 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Organizer;
@ -11,10 +14,70 @@ public class MediaFileServiceTest : CoreTest<MediaFileService>
{
[Test]
[TestCase("Law & Order: Criminal Intent - S10E07 - Icarus [HDTV-720p]", "Law & Order- Criminal Intent - S10E07 - Icarus [HDTV-720p]")]
[TestCase("Law & Order: Criminal Intent - S10E07 - Icarus [HDTV-720p]",
"Law & Order- Criminal Intent - S10E07 - Icarus [HDTV-720p]")]
public void CleanFileName(string name, string expectedName)
{
FileNameBuilder.CleanFilename(name).Should().Be(expectedName);
}
[Test]
public void filter_should_return_all_files_if_no_existing_files()
{
var files = new List<string>()
{
"c:\\file1.avi",
"c:\\file2.avi",
"c:\\file3.avi",
};
Mocker.GetMock<IMediaFileRepository>()
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
.Returns(new List<EpisodeFile>());
Subject.FilterExistingFiles(files, 10).Should().BeEquivalentTo(files);
}
[Test]
public void filter_should_return_none_if_all_files_exist()
{
var files = new List<string>()
{
"c:\\file1.avi",
"c:\\file2.avi",
"c:\\file3.avi",
};
Mocker.GetMock<IMediaFileRepository>()
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
.Returns(files.Select(f => new EpisodeFile { Path = f }).ToList());
Subject.FilterExistingFiles(files, 10).Should().BeEmpty();
}
[Test]
public void filter_should_return_none_existing_files()
{
var files = new List<string>()
{
"c:\\file1.avi",
"c:\\file2.avi",
"c:\\file3.avi",
};
Mocker.GetMock<IMediaFileRepository>()
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
.Returns(new List<EpisodeFile>
{
new EpisodeFile{Path = "c:\\file2.avi"}
});
Subject.FilterExistingFiles(files, 10).Should().HaveCount(2);
Subject.FilterExistingFiles(files, 10).Should().NotContain("c:\\file2.avi");
}
}
}

View File

@ -153,7 +153,6 @@
<Compile Include="MediaFileTests\EpisodeImportTests\UpgradeSpecificationFixture.cs" />
<Compile Include="MediaFileTests\EpisodeImportTests\NotSampleSpecificationFixture.cs" />
<Compile Include="MediaFileTests\EpisodeImportTests\ImportDecisionMakerFixture.cs" />
<Compile Include="MediaFileTests\EpisodeImportTests\NotAlreadyImportedSpecificationFixture.cs" />
<Compile Include="MediaFileTests\MediaFileTableCleanupServiceFixture.cs" />
<Compile Include="MediaFileTests\MediaFileRepositoryFixture.cs" />
<Compile Include="MediaFileTests\EpisodeFileMoverFixture.cs" />

View File

@ -4,6 +4,7 @@
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
@ -20,23 +21,31 @@ public class ImportDecisionMaker : IMakeImportDecision
{
private readonly IEnumerable<IRejectWithReason> _specifications;
private readonly IParsingService _parsingService;
private readonly IMediaFileService _mediaFileService;
private readonly IDiskProvider _diskProvider;
private readonly Logger _logger;
public ImportDecisionMaker(IEnumerable<IRejectWithReason> specifications,
IParsingService parsingService,
IMediaFileService mediaFileService,
IDiskProvider diskProvider,
Logger logger)
{
_specifications = specifications;
_parsingService = parsingService;
_mediaFileService = mediaFileService;
_diskProvider = diskProvider;
_logger = logger;
}
public List<ImportDecision> GetImportDecisions(IEnumerable<String> videoFiles, Series series)
{
return GetDecisions(videoFiles, series).ToList();
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series.Id);
_logger.Debug("Analysing {0}/{1} files.", newFiles.Count, videoFiles.Count());
return GetDecisions(newFiles, series).ToList();
}
private IEnumerable<ImportDecision> GetDecisions(IEnumerable<String> videoFiles, Series series)

View File

@ -1,30 +0,0 @@
using NLog;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{
public class NotAlreadyImportedSpecification : IImportDecisionEngineSpecification
{
private readonly IMediaFileService _mediaFileService;
private readonly Logger _logger;
public NotAlreadyImportedSpecification(IMediaFileService mediaFileService, Logger logger)
{
_mediaFileService = mediaFileService;
_logger = logger;
}
public string RejectionReason { get { return "Is Sample"; } }
public bool IsSatisfiedBy(LocalEpisode localEpisode)
{
if (_mediaFileService.Exists(localEpisode.Path))
{
_logger.Trace("[{0}] already exists in the database. skipping.", localEpisode.Path);
return false;
}
return true;
}
}
}

View File

@ -41,11 +41,16 @@ public bool IsSatisfiedBy(LocalEpisode localEpisode)
return true;
}
if (localEpisode.Size > SampleSizeLimit)
{
return true;
}
var runTime = _videoFileInfoReader.GetRunTime(localEpisode.Path);
if (localEpisode.Size < SampleSizeLimit && runTime.TotalMinutes < 3)
if (runTime.TotalMinutes < 3)
{
_logger.Trace("[{0}] appears to be a sample.", localEpisode.Path);
_logger.Trace("[{0}] appears to be a sample. Size: {1} Runtime: {2}", localEpisode.Path, localEpisode.Size, runTime);
return false;
}

View File

@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Configuration;
@ -15,6 +17,8 @@ public interface IMediaFileService
bool Exists(string path);
EpisodeFile GetFileByPath(string path);
List<EpisodeFile> GetFilesBySeries(int seriesId);
List<string> FilterExistingFiles(List<string> files, int seriesId);
}
public class MediaFileService : IMediaFileService, IHandleAsync<SeriesDeletedEvent>
@ -65,6 +69,15 @@ public List<EpisodeFile> GetFilesBySeries(int seriesId)
return _mediaFileRepository.GetFilesBySeries(seriesId);
}
public List<string> FilterExistingFiles(List<string> files, int seriesId)
{
var seriesFiles = GetFilesBySeries(seriesId);
if (!seriesFiles.Any()) return files;
return files.Select(f => f.Normalize()).Except(seriesFiles.Select(c => c.Path)).ToList();
}
public void HandleAsync(SeriesDeletedEvent message)
{
var files = GetFilesBySeries(message.Series.Id);

View File

@ -276,7 +276,6 @@
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotExistingFileSpecification.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotAlreadyImportedSpecification.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecification.cs" />
<Compile Include="MediaFiles\Events\EpisodeImportedEvent.cs" />