Fixed: Don't mark a download as successful unless all valid files are imported

This commit is contained in:
Mark McDowall 2014-08-21 17:57:23 -07:00
parent 059028da02
commit 2651cd63a8
11 changed files with 155 additions and 91 deletions

View File

@ -9,7 +9,6 @@ using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.MediaFiles.EpisodeImport;
@ -104,9 +103,9 @@ namespace NzbDrone.Core.Test.Download
{ {
Mocker.GetMock<IDownloadedEpisodesImportService>() Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>())) .Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportDecision>() .Returns(new List<ImportResult>
{ {
new ImportDecision(null) new ImportResult(null)
}); });
} }
@ -114,9 +113,9 @@ namespace NzbDrone.Core.Test.Download
{ {
Mocker.GetMock<IDownloadedEpisodesImportService>() Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>())) .Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportDecision>() .Returns(new List<ImportResult>()
{ {
new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }, "Test Failure") new ImportResult(new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }, "Test Failure"))
}); });
} }
@ -448,5 +447,37 @@ namespace NzbDrone.Core.Test.Download
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Once()); .Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Once());
} }
[Test]
public void should_not_mark_as_successful_if_no_files_were_imported()
{
GivenCompletedDownloadClientHistory();
var history = Builder<History.History>.CreateListOfSize(1)
.Build()
.ToList();
GivenGrabbedHistory(history);
GivenNoImportedHistory();
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"}),
"Test Failure")
});
history.First().Data.Add("downloadClient", "SabnzbdClient");
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
Subject.Execute(new CheckForFinishedDownloadCommand());
Mocker.GetMock<IDiskProvider>()
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Never());
ExceptionVerification.ExpectedErrors(1);
}
} }
} }

View File

@ -1,10 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.MediaFiles
Mocker.GetMock<IImportApprovedEpisodes>() Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null)) .Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
.Returns(new List<ImportDecision>()); .Returns(new List<ImportResult>());
} }
private void GivenValidSeries() private void GivenValidSeries()
@ -125,7 +125,7 @@ namespace NzbDrone.Core.Test.MediaFiles
{ {
Mocker.GetMock<IImportApprovedEpisodes>() Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), false, null)) .Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), false, null))
.Returns(new List<ImportDecision>()); .Returns(new List<ImportResult>());
Subject.Execute(new DownloadedEpisodesScanCommand()); Subject.Execute(new DownloadedEpisodesScanCommand());
@ -149,7 +149,7 @@ namespace NzbDrone.Core.Test.MediaFiles
Mocker.GetMock<IImportApprovedEpisodes>() Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null)) .Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
.Returns(imported); .Returns(imported.Select(i => new ImportResult(i)).ToList());
Subject.Execute(new DownloadedEpisodesScanCommand()); Subject.Execute(new DownloadedEpisodesScanCommand());
@ -175,7 +175,7 @@ namespace NzbDrone.Core.Test.MediaFiles
Mocker.GetMock<IImportApprovedEpisodes>() Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null)) .Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
.Returns(imported); .Returns(imported.Select(i => new ImportResult(i)).ToList());
Mocker.GetMock<ISampleService>() Mocker.GetMock<ISampleService>()
.Setup(s => s.IsSample(It.IsAny<Series>(), .Setup(s => s.IsSample(It.IsAny<Series>(),

View File

@ -65,9 +65,11 @@ namespace NzbDrone.Core.Test.MediaFiles
} }
[Test] [Test]
public void should_return_empty_list_if_there_are_no_approved_decisions() public void should_not_import_any_if_there_are_no_approved_decisions()
{ {
Subject.Import(_rejectedDecisions, false).Should().BeEmpty(); Subject.Import(_rejectedDecisions, false).Where(i => i.Result == ImportResultType.Imported).Should().BeEmpty();
Mocker.GetMock<IMediaFileService>().Verify(v => v.Add(It.IsAny<EpisodeFile>()), Times.Never());
} }
[Test] [Test]
@ -83,7 +85,10 @@ namespace NzbDrone.Core.Test.MediaFiles
all.AddRange(_rejectedDecisions); all.AddRange(_rejectedDecisions);
all.AddRange(_approvedDecisions); all.AddRange(_approvedDecisions);
Subject.Import(all, false).Should().HaveCount(5); var result = Subject.Import(all, false);
result.Should().HaveCount(all.Count);
result.Where(i => i.Result == ImportResultType.Imported).Should().HaveCount(_approvedDecisions.Count);
} }
[Test] [Test]
@ -93,7 +98,9 @@ namespace NzbDrone.Core.Test.MediaFiles
all.AddRange(_approvedDecisions); all.AddRange(_approvedDecisions);
all.Add(new ImportDecision(_approvedDecisions.First().LocalEpisode)); all.Add(new ImportDecision(_approvedDecisions.First().LocalEpisode));
Subject.Import(all, false).Should().HaveCount(5); var result = Subject.Import(all, false);
result.Where(i => i.Result == ImportResultType.Imported).Should().HaveCount(_approvedDecisions.Count);
} }
[Test] [Test]
@ -136,7 +143,7 @@ namespace NzbDrone.Core.Test.MediaFiles
{ {
Series = fileDecision.LocalEpisode.Series, Series = fileDecision.LocalEpisode.Series,
Episodes = new List<Episode> {fileDecision.LocalEpisode.Episodes.First()}, Episodes = new List<Episode> {fileDecision.LocalEpisode.Episodes.First()},
Path = @"C:\Test\TV\30 Rock\30 Rock - S01E01 - Pilit.avi".AsOsAgnostic(), Path = @"C:\Test\TV\30 Rock\30 Rock - S01E01 - Pilot.avi".AsOsAgnostic(),
Quality = new QualityModel(Quality.Bluray720p), Quality = new QualityModel(Quality.Bluray720p),
Size = 80.Megabytes() Size = 80.Megabytes()
}); });
@ -148,8 +155,9 @@ namespace NzbDrone.Core.Test.MediaFiles
var results = Subject.Import(all, false); var results = Subject.Import(all, false);
results.Should().HaveCount(1); results.Should().HaveCount(all.Count);
results.Should().ContainSingle(d => d.LocalEpisode.Size == fileDecision.LocalEpisode.Size); results.Should().ContainSingle(d => d.Result == ImportResultType.Imported);
results.Should().ContainSingle(d => d.Result == ImportResultType.Imported && d.ImportDecision.LocalEpisode.Size == fileDecision.LocalEpisode.Size);
} }
} }
} }

View File

@ -3,19 +3,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using System.IO; using System.IO;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Download namespace NzbDrone.Core.Download
{ {
@ -97,51 +91,15 @@ namespace NzbDrone.Core.Download
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath)) if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath))
{ {
var decisions = _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem); var importResults = _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
if (!decisions.Any()) ProcessImportResults(trackedDownload, importResults);
{
UpdateStatusMessage(trackedDownload, LogLevel.Error, "No files found eligible for import in {0}", trackedDownload.DownloadItem.OutputPath);
}
else if (decisions.Any(v => v.Approved))
{
UpdateStatusMessage(trackedDownload, LogLevel.Info, "Imported {0} files.", decisions.Count(v => v.Approved));
trackedDownload.State = TrackedDownloadState.Imported;
}
else
{
var rejections = decisions
.Where(v => !v.Approved)
.Select(v => v.Rejections.Aggregate(Path.GetFileName(v.LocalEpisode.Path), (a, r) => a + "\r\n- " + r))
.Aggregate("Failed to import:", (a, r) => a + "\r\n" + r);
UpdateStatusMessage(trackedDownload, LogLevel.Error, rejections);
}
} }
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath)) else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath))
{ {
var decisions = _downloadedEpisodesImportService.ProcessFile(new FileInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem); var importResults = _downloadedEpisodesImportService.ProcessFile(new FileInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
if (!decisions.Any()) ProcessImportResults(trackedDownload, importResults);
{
UpdateStatusMessage(trackedDownload, LogLevel.Error, "No files found eligible for import in {0}", trackedDownload.DownloadItem.OutputPath);
}
else if (decisions.Any(v => v.Approved))
{
UpdateStatusMessage(trackedDownload, LogLevel.Info, "Imported {0} files.", decisions.Count(v => v.Approved));
trackedDownload.State = TrackedDownloadState.Imported;
}
else
{
var rejections = decisions
.Where(v => !v.Approved)
.Select(v => v.Rejections.Aggregate(Path.GetFileName(v.LocalEpisode.Path), (a, r) => a + "\r\n- " + r))
.Aggregate("Failed to import:", (a, r) => a + "\r\n" + r);
UpdateStatusMessage(trackedDownload, LogLevel.Error, rejections);
}
} }
else else
{ {
@ -222,5 +180,28 @@ namespace NzbDrone.Core.Download
_logger.Debug(logMessage); _logger.Debug(logMessage);
} }
} }
private void ProcessImportResults(TrackedDownload trackedDownload, List<ImportResult> importResults)
{
if (importResults.Empty())
{
UpdateStatusMessage(trackedDownload, LogLevel.Error, "No files found are eligible for import in {0}", trackedDownload.DownloadItem.OutputPath);
}
else if (importResults.All(v => v.Result == ImportResultType.Imported || v.Result == ImportResultType.Rejected))
{
UpdateStatusMessage(trackedDownload, LogLevel.Info, "Imported {0} files.", importResults.Count(v => v.Result == ImportResultType.Imported));
trackedDownload.State = TrackedDownloadState.Imported;
}
else
{
var errors = importResults
.Where(v => v.Result == ImportResultType.Skipped || v.Result == ImportResultType.Rejected)
.Select(v => v.Errors.Aggregate(Path.GetFileName(v.ImportDecision.LocalEpisode.Path), (a, r) => a + "\r\n- " + r))
.Aggregate("Failed to import:", (a, r) => a + "\r\n" + r);
UpdateStatusMessage(trackedDownload, LogLevel.Error, errors);
}
}
} }
} }

View File

@ -14,6 +14,7 @@ namespace NzbDrone.Core.Download
public Int32 RetryCount { get; set; } public Int32 RetryCount { get; set; }
public Boolean HasError { get; set; } public Boolean HasError { get; set; }
public String StatusMessage { get; set; } public String StatusMessage { get; set; }
public List<String> StatusMessages { get; set; }
} }
public enum TrackedDownloadState public enum TrackedDownloadState

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using NLog; using NLog;
@ -12,7 +11,6 @@ using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
@ -20,8 +18,8 @@ namespace NzbDrone.Core.MediaFiles
{ {
public interface IDownloadedEpisodesImportService public interface IDownloadedEpisodesImportService
{ {
List<ImportDecision> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem); List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem);
List<ImportDecision> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem); List<ImportResult> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem);
} }
public class DownloadedEpisodesImportService : IDownloadedEpisodesImportService, IExecute<DownloadedEpisodesScanCommand> public class DownloadedEpisodesImportService : IDownloadedEpisodesImportService, IExecute<DownloadedEpisodesScanCommand>
@ -57,7 +55,7 @@ namespace NzbDrone.Core.MediaFiles
_logger = logger; _logger = logger;
} }
public List<ImportDecision> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem) public List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem)
{ {
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var series = _parsingService.GetSeries(cleanedUpName); var series = _parsingService.GetSeries(cleanedUpName);
@ -67,39 +65,35 @@ namespace NzbDrone.Core.MediaFiles
if (series == null) if (series == null)
{ {
_logger.Debug("Unknown Series {0}", cleanedUpName); _logger.Debug("Unknown Series {0}", cleanedUpName);
return new List<ImportDecision>(); return new List<ImportResult>();
} }
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality); var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality);
var importedDecisions = _importApprovedEpisodes.Import(decisions, true, downloadClientItem); var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
if (!downloadClientItem.IsReadOnly && importedDecisions.Any() && ShouldDeleteFolder(directoryInfo)) if (!downloadClientItem.IsReadOnly && importResults.Any() && ShouldDeleteFolder(directoryInfo))
{ {
_logger.Debug("Deleting folder after importing valid files"); _logger.Debug("Deleting folder after importing valid files");
_diskProvider.DeleteFolder(directoryInfo.FullName, true); _diskProvider.DeleteFolder(directoryInfo.FullName, true);
} }
return importedDecisions.Union(decisions).ToList(); return importResults;
} }
public List<ImportDecision> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem) public List<ImportResult> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem)
{ {
var series = _parsingService.GetSeries(Path.GetFileNameWithoutExtension(fileInfo.Name)); var series = _parsingService.GetSeries(Path.GetFileNameWithoutExtension(fileInfo.Name));
if (series == null) if (series == null)
{ {
_logger.Debug("Unknown Series for file: {0}", fileInfo.Name); _logger.Debug("Unknown Series for file: {0}", fileInfo.Name);
return new List<ImportDecision>(); return new List<ImportResult>();
} }
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, true, null); var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, true);
return _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
var importedDecisions = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
return importedDecisions.Union(decisions).ToList();
} }
private void ProcessDownloadedEpisodesFolder() private void ProcessDownloadedEpisodesFolder()
@ -136,7 +130,7 @@ namespace NzbDrone.Core.MediaFiles
} }
} }
private List<ImportDecision> ProcessFolder(DirectoryInfo directoryInfo) private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo)
{ {
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var series = _parsingService.GetSeries(cleanedUpName); var series = _parsingService.GetSeries(cleanedUpName);
@ -146,7 +140,7 @@ namespace NzbDrone.Core.MediaFiles
if (series == null) if (series == null)
{ {
_logger.Debug("Unknown Series {0}", cleanedUpName); _logger.Debug("Unknown Series {0}", cleanedUpName);
return new List<ImportDecision>(); return new List<ImportResult>();
} }
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
@ -156,7 +150,7 @@ namespace NzbDrone.Core.MediaFiles
if (_diskProvider.IsFileLocked(videoFile)) if (_diskProvider.IsFileLocked(videoFile))
{ {
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile); _logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
return new List<ImportDecision>(); return new List<ImportResult>();
} }
} }

View File

@ -8,7 +8,6 @@ using NzbDrone.Common.Disk;
using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
@ -16,7 +15,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{ {
public interface IImportApprovedEpisodes public interface IImportApprovedEpisodes
{ {
List<ImportDecision> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem historyItem = null); List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem historyItem = null);
} }
public class ImportApprovedEpisodes : IImportApprovedEpisodes public class ImportApprovedEpisodes : IImportApprovedEpisodes
@ -40,7 +39,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
_logger = logger; _logger = logger;
} }
public List<ImportDecision> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem historyItem = null) public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem historyItem = null)
{ {
var qualifiedImports = decisions.Where(c => c.Approved) var qualifiedImports = decisions.Where(c => c.Approved)
.GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s .GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s
@ -49,7 +48,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
.SelectMany(c => c) .SelectMany(c => c)
.ToList(); .ToList();
var imported = new List<ImportDecision>(); var importResults = new List<ImportResult>();
foreach (var importDecision in qualifiedImports.OrderByDescending(e => e.LocalEpisode.Size)) foreach (var importDecision in qualifiedImports.OrderByDescending(e => e.LocalEpisode.Size))
{ {
@ -59,11 +58,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
try try
{ {
//check if already imported //check if already imported
if (imported.SelectMany(r => r.LocalEpisode.Episodes) if (importResults.SelectMany(r => r.ImportDecision.LocalEpisode.Episodes)
.Select(e => e.Id) .Select(e => e.Id)
.Intersect(localEpisode.Episodes.Select(e => e.Id)) .Intersect(localEpisode.Episodes.Select(e => e.Id))
.Any()) .Any())
{ {
importResults.Add(new ImportResult(importDecision, "Episode has already been imported"));
continue; continue;
} }
@ -92,7 +92,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
} }
_mediaFileService.Add(episodeFile); _mediaFileService.Add(episodeFile);
imported.Add(importDecision); importResults.Add(new ImportResult(importDecision));
if (historyItem != null) if (historyItem != null)
{ {
@ -111,10 +111,15 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
catch (Exception e) catch (Exception e)
{ {
_logger.WarnException("Couldn't import episode " + localEpisode, e); _logger.WarnException("Couldn't import episode " + localEpisode, e);
importResults.Add(new ImportResult(importDecision, "Failed to import episode"));
} }
} }
return imported; //Adding all the rejected decisions
importResults.AddRange(decisions.Where(c => !c.Approved)
.Select(d => new ImportResult(d, d.Rejections.ToArray())));
return importResults;
} }
} }
} }

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common;
namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
public class ImportResult
{
public ImportDecision ImportDecision { get; private set; }
public List<String> Errors { get; private set; }
public ImportResultType Result
{
get
{
//Approved and imported
if (Errors.Empty()) return ImportResultType.Imported;
//Decision was approved, but it was not imported
if (ImportDecision.Approved) return ImportResultType.Skipped;
//Decision was rejected
return ImportResultType.Rejected;
}
}
public ImportResult(ImportDecision importDecision, params String[] errors)
{
ImportDecision = importDecision;
Errors = errors.ToList();
}
}
}

View File

@ -0,0 +1,9 @@
namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
public enum ImportResultType
{
Imported,
Rejected,
Skipped
}
}

View File

@ -468,10 +468,12 @@
<Compile Include="MediaFiles\EpisodeFile.cs" /> <Compile Include="MediaFiles\EpisodeFile.cs" />
<Compile Include="MediaFiles\EpisodeFileMoveResult.cs" /> <Compile Include="MediaFiles\EpisodeFileMoveResult.cs" />
<Compile Include="MediaFiles\EpisodeFileMovingService.cs" /> <Compile Include="MediaFiles\EpisodeFileMovingService.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportResult.cs" />
<Compile Include="MediaFiles\EpisodeImport\IImportDecisionEngineSpecification.cs" /> <Compile Include="MediaFiles\EpisodeImport\IImportDecisionEngineSpecification.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" /> <Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportDecision.cs" /> <Compile Include="MediaFiles\EpisodeImport\ImportDecision.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" /> <Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportResultType.cs" />
<Compile Include="MediaFiles\EpisodeImport\SampleService.cs" /> <Compile Include="MediaFiles\EpisodeImport\SampleService.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecification.cs" /> <Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecification.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" /> <Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" />

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using NLog;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
namespace NzbDrone.Core.Queue namespace NzbDrone.Core.Queue