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

New: Improved the DownloadedEpisodesScanCommand endpoint to better support external triggers to CDH. (nzbToMedia)

This commit is contained in:
Taloth Saldono 2014-10-27 00:14:47 +01:00
parent ba38160430
commit 0b48630c00
9 changed files with 365 additions and 167 deletions

View File

@ -118,7 +118,7 @@ private void GivenCompletedImport()
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportResult>
{
new ImportResult(null)
new ImportResult(new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }))
});
}

View File

@ -0,0 +1,173 @@
using System.Collections.Generic;
using System.IO;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.MediaFiles
{
[TestFixture]
public class DownloadedEpisodesCommandServiceFixture : CoreTest<DownloadedEpisodesCommandService>
{
private string _droneFactory = "c:\\drop\\".AsOsAgnostic();
private string _downloadFolder = "c:\\drop_other\\Show.S01E01\\".AsOsAgnostic();
private TrackedDownload _trackedDownload;
[SetUp]
public void Setup()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
.Returns(true);
Mocker.GetMock<IConfigService>().SetupGet(c => c.DownloadedEpisodesFolder)
.Returns(_droneFactory);
Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessRootFolder(It.IsAny<DirectoryInfo>()))
.Returns(new List<ImportResult>());
Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportResult>());
var downloadItem = Builder<DownloadClientItem>.CreateNew()
.With(v => v.DownloadClientId = "sab1")
.With(v => v.Status = DownloadItemStatus.Downloading)
.Build();
_trackedDownload = new TrackedDownload
{
DownloadItem = downloadItem,
State = TrackedDownloadState.Downloading
};
}
private void GivenValidQueueItem()
{
var downloadItem = Builder<DownloadClientItem>.CreateNew()
.With(v => v.DownloadClientId = "sab1")
.With(v => v.Status = DownloadItemStatus.Downloading)
.Build();
Mocker.GetMock<IDownloadTrackingService>()
.Setup(s => s.GetQueuedDownloads())
.Returns(new [] { _trackedDownload });
}
private void GivenSuccessfulImport()
{
Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportResult>() {
new ImportResult(new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }))
});
}
private void GivenRejectedImport()
{
Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportResult>() {
new ImportResult(new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }, "Some Rejection"), "I was rejected")
});
}
private void GivenSkippedImport()
{
Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportResult>() {
new ImportResult(new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }), "I was skipped")
});
}
[Test]
public void should_process_dronefactory_if_path_is_not_specified()
{
Subject.Execute(new DownloadedEpisodesScanCommand());
Mocker.GetMock<IDownloadedEpisodesImportService>().Verify(c => c.ProcessRootFolder(It.IsAny<DirectoryInfo>()), Times.Once());
}
[Test]
public void should_skip_import_if_dropfolder_doesnt_exist()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>())).Returns(false);
Subject.Execute(new DownloadedEpisodesScanCommand());
Mocker.GetMock<IDownloadedEpisodesImportService>().Verify(c => c.ProcessRootFolder(It.IsAny<DirectoryInfo>()), Times.Never());
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_ignore_downloadclientid_if_path_is_not_specified()
{
Subject.Execute(new DownloadedEpisodesScanCommand() { DownloadClientId = "sab1" });
Mocker.GetMock<IDownloadedEpisodesImportService>().Verify(c => c.ProcessRootFolder(It.IsAny<DirectoryInfo>()), Times.Once());
}
[Test]
public void should_process_folder_if_downloadclientid_is_not_specified()
{
Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder });
Mocker.GetMock<IDownloadedEpisodesImportService>().Verify(c => c.ProcessFolder(It.IsAny<DirectoryInfo>(), null), Times.Once());
}
[Test]
public void should_process_folder_with_downloadclientitem_if_available()
{
GivenValidQueueItem();
Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" });
Mocker.GetMock<ICompletedDownloadService>().Verify(c => c.Import(It.Is<TrackedDownload>(v => v != null), _downloadFolder), Times.Once());
}
[Test]
public void should_process_folder_without_downloadclientitem_if_not_available()
{
Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" });
Mocker.GetMock<IDownloadedEpisodesImportService>().Verify(c => c.ProcessFolder(It.IsAny<DirectoryInfo>(), null), Times.Once());
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_not_mark_trackeddownload_as_completed_if_import_rejected()
{
GivenValidQueueItem();
GivenRejectedImport();
Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" });
_trackedDownload.State.Should().Be(TrackedDownloadState.Downloading);
}
[Test]
public void should_mark_trackeddownload_as_completed_if_import_skipped()
{
GivenValidQueueItem();
GivenRejectedImport();
Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" });
_trackedDownload.State.Should().Be(TrackedDownloadState.Imported);
}
}
}

View File

@ -22,6 +22,7 @@ namespace NzbDrone.Core.Test.MediaFiles
[TestFixture]
public class DownloadedEpisodesImportServiceFixture : CoreTest<DownloadedEpisodesImportService>
{
private string _droneFactory = "c:\\drop\\".AsOsAgnostic();
private string[] _subFolders = new[] { "c:\\root\\foldername".AsOsAgnostic() };
private string[] _videoFiles = new[] { "c:\\root\\foldername\\30.rock.s01e01.ext".AsOsAgnostic() };
@ -37,9 +38,6 @@ public void Setup()
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
.Returns(true);
Mocker.GetMock<IConfigService>().SetupGet(c => c.DownloadedEpisodesFolder)
.Returns("c:\\drop\\".AsOsAgnostic());
Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
.Returns(new List<ImportResult>());
@ -55,25 +53,11 @@ private void GivenValidSeries()
[Test]
public void should_search_for_series_using_folder_name()
{
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IParsingService>().Verify(c => c.GetSeries("foldername"), Times.Once());
}
[Test]
public void should_skip_import_if_dropfolder_doesnt_exist()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>())).Returns(false);
Subject.Execute(new DownloadedEpisodesScanCommand());
Mocker.GetMock<IDiskProvider>().Verify(c => c.GetDirectories(It.IsAny<string>()), Times.Never());
Mocker.GetMock<IDiskProvider>().Verify(c => c.GetFiles(It.IsAny<string>(), It.IsAny<SearchOption>()), Times.Never());
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_skip_if_file_is_in_use_by_another_process()
{
@ -82,7 +66,7 @@ public void should_skip_if_file_is_in_use_by_another_process()
Mocker.GetMock<IDiskProvider>().Setup(c => c.IsFileLocked(It.IsAny<string>()))
.Returns(true);
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
VerifyNoImport();
}
@ -92,7 +76,7 @@ public void should_skip_if_no_series_found()
{
Mocker.GetMock<IParsingService>().Setup(c => c.GetSeries("foldername")).Returns((Series)null);
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IMakeImportDecision>()
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), It.IsAny<bool>(), It.IsAny<QualityModel>()),
@ -112,7 +96,7 @@ public void should_not_import_if_folder_is_a_series_path()
.Setup(c => c.GetVideoFiles(It.IsAny<string>(), It.IsAny<bool>()))
.Returns(new string[0]);
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IParsingService>()
.Verify(v => v.GetSeries(It.IsAny<String>()), Times.Never());
@ -127,7 +111,7 @@ public void should_not_delete_folder_if_no_files_were_imported()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), false, null))
.Returns(new List<ImportResult>());
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetFolderSize(It.IsAny<String>()), Times.Never());
@ -151,7 +135,7 @@ public void should_not_delete_folder_if_files_were_imported_and_video_files_rema
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.DeleteFolder(It.IsAny<String>(), true), Times.Never());
@ -185,7 +169,7 @@ public void should_delete_folder_if_files_were_imported_and_only_sample_files_re
It.IsAny<Int32>()))
.Returns(true);
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.DeleteFolder(It.IsAny<String>(), true), Times.Once());
@ -202,7 +186,7 @@ public void should_remove_unpack_from_folder_name(string prefix)
.Setup(c => c.GetDirectories(It.IsAny<string>()))
.Returns(folders);
Subject.Execute(new DownloadedEpisodesScanCommand());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IParsingService>()
.Verify(v => v.GetSeries(folderName), Times.Once());

View File

@ -197,6 +197,7 @@
<Compile Include="MediaCoverTests\CoverExistsSpecificationFixture.cs" />
<Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" />
<Compile Include="MediaFiles\DiskScanServiceTests\ScanFixture.cs" />
<Compile Include="MediaFiles\DownloadedEpisodesCommandServiceFixture.cs" />
<Compile Include="MediaFiles\DownloadedEpisodesImportServiceFixture.cs" />
<Compile Include="MediaFiles\EpisodeFileMovingServiceTests\MoveEpisodeFileFixture.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMakerFixture.cs" />

View File

@ -15,7 +15,7 @@ namespace NzbDrone.Core.Download
public interface ICompletedDownloadService
{
void CheckForCompletedItem(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> grabbedHistory, List<History.History> importedHistory);
List<ImportResult> Import(TrackedDownload trackedDownload);
List<ImportResult> Import(TrackedDownload trackedDownload, String overrideOutputPath = null);
}
public class CompletedDownloadService : ICompletedDownloadService
@ -110,21 +110,22 @@ public void CheckForCompletedItem(IDownloadClient downloadClient, TrackedDownloa
}
}
public List<ImportResult> Import(TrackedDownload trackedDownload)
public List<ImportResult> Import(TrackedDownload trackedDownload, String overrideOutputPath = null)
{
var importResults = new List<ImportResult>();
var outputPath = overrideOutputPath ?? trackedDownload.DownloadItem.OutputPath;
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath))
if (_diskProvider.FolderExists(outputPath))
{
importResults = _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
importResults = _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(outputPath), trackedDownload.DownloadItem);
ProcessImportResults(trackedDownload, importResults);
ProcessImportResults(trackedDownload, outputPath, importResults);
}
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath))
else if (_diskProvider.FileExists(outputPath))
{
importResults = _downloadedEpisodesImportService.ProcessFile(new FileInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
importResults = _downloadedEpisodesImportService.ProcessFile(new FileInfo(outputPath), trackedDownload.DownloadItem);
ProcessImportResults(trackedDownload, importResults);
ProcessImportResults(trackedDownload, outputPath, importResults);
}
return importResults;
@ -147,11 +148,11 @@ private void UpdateStatusMessage(TrackedDownload trackedDownload, LogLevel logLe
}
}
private void ProcessImportResults(TrackedDownload trackedDownload, List<ImportResult> importResults)
private void ProcessImportResults(TrackedDownload trackedDownload, String outputPath, List<ImportResult> importResults)
{
if (importResults.Empty())
{
UpdateStatusMessage(trackedDownload, LogLevel.Error, "No files found are eligible for import in {0}", trackedDownload.DownloadItem.OutputPath);
UpdateStatusMessage(trackedDownload, LogLevel.Error, "No files found are eligible for import in {0}", outputPath);
}
else if (importResults.Any(v => v.Result == ImportResultType.Imported) && importResults.All(v => v.Result == ImportResultType.Imported || v.Result == ImportResultType.Rejected))
{

View File

@ -15,5 +15,6 @@ public override bool SendUpdatesToClient
public Boolean SendUpdates { get; set; }
public String Path { get; set; }
public String DownloadClientId { get; set; }
}
}

View File

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.MediaFiles
{
public class DownloadedEpisodesCommandService : IExecute<DownloadedEpisodesScanCommand>
{
private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService;
private readonly IDownloadTrackingService _downloadTrackingService;
private readonly ICompletedDownloadService _completedDownloadService;
private readonly IDiskProvider _diskProvider;
private readonly IConfigService _configService;
private readonly Logger _logger;
public DownloadedEpisodesCommandService(IDownloadedEpisodesImportService downloadedEpisodesImportService,
IDownloadTrackingService downloadTrackingService,
ICompletedDownloadService completedDownloadService,
IDiskProvider diskProvider,
IConfigService configService,
Logger logger)
{
_downloadedEpisodesImportService = downloadedEpisodesImportService;
_downloadTrackingService = downloadTrackingService;
_completedDownloadService = completedDownloadService;
_diskProvider = diskProvider;
_configService = configService;
_logger = logger;
}
private List<ImportResult> ProcessDroneFactoryFolder()
{
var downloadedEpisodesFolder = _configService.DownloadedEpisodesFolder;
if (String.IsNullOrEmpty(downloadedEpisodesFolder))
{
_logger.Trace("Drone Factory folder is not configured");
return new List<ImportResult>();
}
if (!_diskProvider.FolderExists(downloadedEpisodesFolder))
{
_logger.Warn("Drone Factory folder [{0}] doesn't exist.", downloadedEpisodesFolder);
return new List<ImportResult>();
}
return _downloadedEpisodesImportService.ProcessRootFolder(new DirectoryInfo(downloadedEpisodesFolder));
}
private List<ImportResult> ProcessFolder(DownloadedEpisodesScanCommand message)
{
if (!_diskProvider.FolderExists(message.Path))
{
_logger.Warn("Folder specified for import scan [{0}] doesn't exist.", message.Path);
return new List<ImportResult>();
}
if (message.DownloadClientId.IsNotNullOrWhiteSpace())
{
var trackedDownload = _downloadTrackingService.GetQueuedDownloads().Where(v => v.DownloadItem.DownloadClientId == message.DownloadClientId).FirstOrDefault();
if (trackedDownload == null)
{
_logger.Warn("External directory scan request for unknown download {0}, attempting normal import. [{1}]", message.DownloadClientId, message.Path);
return _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(message.Path));
}
else
{
return _completedDownloadService.Import(trackedDownload, message.Path);
}
}
else
{
return _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(message.Path));
}
}
public void Execute(DownloadedEpisodesScanCommand message)
{
List<ImportResult> importResults;
if (message.Path.IsNotNullOrWhiteSpace())
{
importResults = ProcessFolder(message);
}
else
{
importResults = ProcessDroneFactoryFolder();
}
if (importResults == null || !importResults.Any(v => v.Result == ImportResultType.Imported))
{
// Atm we don't report it as a command failure, coz that would cause the download to be failed.
// Changing the message won't do a thing either, coz it will get set to 'Completed' a msec later.
//message.SetMessage("Failed to import");
}
}
}
}

View File

@ -13,16 +13,18 @@
using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles
{
public interface IDownloadedEpisodesImportService
{
List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem);
List<ImportResult> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem);
List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo);
List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem = null);
List<ImportResult> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem = null);
}
public class DownloadedEpisodesImportService : IDownloadedEpisodesImportService, IExecute<DownloadedEpisodesScanCommand>
public class DownloadedEpisodesImportService : IDownloadedEpisodesImportService
{
private readonly IDiskProvider _diskProvider;
private readonly IDiskScanService _diskScanService;
@ -55,8 +57,33 @@ public DownloadedEpisodesImportService(IDiskProvider diskProvider,
_logger = logger;
}
public List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem)
public List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo)
{
var results = new List<ImportResult>();
foreach (var subFolder in _diskProvider.GetDirectories(directoryInfo.FullName))
{
var folderResults = ProcessFolder(new DirectoryInfo(subFolder));
results.AddRange(folderResults);
}
foreach (var videoFile in _diskScanService.GetVideoFiles(directoryInfo.FullName, false))
{
var fileResults = ProcessFile(new FileInfo(videoFile));
results.AddRange(fileResults);
}
return results;
}
public List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem = null)
{
if (_seriesService.SeriesPathExists(directoryInfo.FullName))
{
_logger.Warn("Unable to process folder that contains sorted TV Shows");
return new List<ImportResult>();
}
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var series = _parsingService.GetSeries(cleanedUpName);
var quality = QualityParser.ParseQuality(cleanedUpName);
@ -65,82 +92,10 @@ public List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadCli
if (series == null)
{
_logger.Debug("Unknown Series {0}", cleanedUpName);
return new List<ImportResult>();
}
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality);
var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
if (!downloadClientItem.IsReadOnly && importResults.Any() && ShouldDeleteFolder(directoryInfo))
{
_logger.Debug("Deleting folder after importing valid files");
_diskProvider.DeleteFolder(directoryInfo.FullName, true);
}
return importResults;
}
public List<ImportResult> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem)
{
var series = _parsingService.GetSeries(Path.GetFileNameWithoutExtension(fileInfo.Name));
if (series == null)
{
_logger.Debug("Unknown Series for file: {0}", fileInfo.Name);
return new List<ImportResult>();
}
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, true);
return _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
}
private void ProcessDownloadedEpisodesFolder()
{
var downloadedEpisodesFolder = _configService.DownloadedEpisodesFolder;
if (String.IsNullOrEmpty(downloadedEpisodesFolder))
{
_logger.Trace("Drone Factory folder is not configured");
return;
}
if (!_diskProvider.FolderExists(downloadedEpisodesFolder))
{
_logger.Warn("Drone Factory folder [{0}] doesn't exist.", downloadedEpisodesFolder);
return;
}
foreach (var subFolder in _diskProvider.GetDirectories(downloadedEpisodesFolder))
{
ProcessFolder(subFolder);
}
foreach (var videoFile in _diskScanService.GetVideoFiles(downloadedEpisodesFolder, false))
{
try
{
ProcessVideoFile(videoFile);
}
catch (Exception ex)
{
_logger.ErrorException("An error has occurred while importing video file" + videoFile, ex);
}
}
}
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo)
{
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var series = _parsingService.GetSeries(cleanedUpName);
var quality = QualityParser.ParseQuality(cleanedUpName);
_logger.Debug("{0} folder quality: {1}", cleanedUpName, quality);
if (series == null)
{
_logger.Debug("Unknown Series {0}", cleanedUpName);
return new List<ImportResult>();
return new List<ImportResult>
{
new ImportResult(new ImportDecision(null, "Unknown Series"), "Unknown Series")
};
}
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
@ -150,59 +105,44 @@ private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo)
if (_diskProvider.IsFileLocked(videoFile))
{
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
return new List<ImportResult>();
return new List<ImportResult>
{
new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, "Locked file, try again later"), "Locked file, try again later")
};
}
}
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality);
return _importApprovedEpisodes.Import(decisions, true);
var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) && importResults.Any() && ShouldDeleteFolder(directoryInfo))
{
_logger.Debug("Deleting folder after importing valid files");
_diskProvider.DeleteFolder(directoryInfo.FullName, true);
}
return importResults;
}
private void ProcessVideoFile(string videoFile)
public List<ImportResult> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem = null)
{
var series = _parsingService.GetSeries(Path.GetFileNameWithoutExtension(videoFile));
var series = _parsingService.GetSeries(Path.GetFileNameWithoutExtension(fileInfo.Name));
if (series == null)
{
_logger.Debug("Unknown Series for file: {0}", videoFile);
return;
_logger.Debug("Unknown Series for file: {0}", fileInfo.Name);
return new List<ImportResult>() { new ImportResult(null, String.Format("Unknown Series for file: {0}", fileInfo.Name)) };
}
if (_diskProvider.IsFileLocked(videoFile))
if (_diskProvider.IsFileLocked(fileInfo.FullName))
{
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
return;
_logger.Debug("[{0}] is currently locked by another process, skipping", fileInfo.FullName);
return new List<ImportResult>();
}
var decisions = _importDecisionMaker.GetImportDecisions(new [] { videoFile }.ToList(), series, true, null);
_importApprovedEpisodes.Import(decisions, true);
}
private void ProcessFolder(string path)
{
Ensure.That(path, () => path).IsValidPath();
try
{
if (_seriesService.SeriesPathExists(path))
{
_logger.Warn("Unable to process folder that contains sorted TV Shows");
return;
}
var directoryFolderInfo = new DirectoryInfo(path);
var importedFiles = ProcessFolder(directoryFolderInfo);
if (importedFiles.Any() && ShouldDeleteFolder(directoryFolderInfo))
{
_logger.Debug("Deleting folder after importing valid files");
_diskProvider.DeleteFolder(path, true);
}
}
catch (Exception e)
{
_logger.ErrorException("An error has occurred while importing folder: " + path, e);
}
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, true);
return _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
}
private string GetCleanedUpFolderName(string folder)
@ -242,18 +182,5 @@ private bool ShouldDeleteFolder(DirectoryInfo directoryInfo)
return true;
}
public void Execute(DownloadedEpisodesScanCommand message)
{
if (message.Path.IsNullOrWhiteSpace())
{
ProcessDownloadedEpisodesFolder();
}
else
{
ProcessFolder(message.Path);
}
}
}
}

View File

@ -481,6 +481,7 @@
<Compile Include="MediaFiles\DownloadedEpisodesImportService.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="MediaFiles\DownloadedEpisodesCommandService.cs" />
<Compile Include="MediaFiles\EpisodeFile.cs" />
<Compile Include="MediaFiles\EpisodeFileMoveResult.cs" />
<Compile Include="MediaFiles\EpisodeFileMovingService.cs" />