diff --git a/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs b/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs index 3cab28655..480a33bfa 100644 --- a/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs +++ b/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Core.Download public interface IProcessDownloadDecisions { Task ProcessDecisions(List decisions); + Task ProcessDecision(DownloadDecision decision, int? downloadClientId); } public class ProcessDownloadDecisions : IProcessDownloadDecisions @@ -49,7 +50,6 @@ namespace NzbDrone.Core.Download foreach (var report in prioritizedDecisions) { - var remoteEpisode = report.RemoteEpisode; var downloadProtocol = report.RemoteEpisode.Release.DownloadProtocol; // Skip if already grabbed @@ -71,37 +71,48 @@ namespace NzbDrone.Core.Download continue; } - try - { - _logger.Trace("Grabbing from Indexer {0} at priority {1}.", remoteEpisode.Release.Indexer, remoteEpisode.Release.IndexerPriority); - await _downloadService.DownloadReport(remoteEpisode, null); - grabbed.Add(report); - } - catch (ReleaseUnavailableException) - { - _logger.Warn("Failed to download release from indexer, no longer available. " + remoteEpisode); - rejected.Add(report); - } - catch (Exception ex) - { - if (ex is DownloadClientUnavailableException || ex is DownloadClientAuthenticationException) - { - _logger.Debug(ex, "Failed to send release to download client, storing until later. " + remoteEpisode); - PreparePending(pendingAddQueue, grabbed, pending, report, PendingReleaseReason.DownloadClientUnavailable); + var result = await ProcessDecisionInternal(report); - if (downloadProtocol == DownloadProtocol.Usenet) + switch (result) + { + case ProcessedDecisionResult.Grabbed: { - usenetFailed = true; + grabbed.Add(report); + break; } - else if (downloadProtocol == DownloadProtocol.Torrent) + + case ProcessedDecisionResult.Pending: { - torrentFailed = true; + PreparePending(pendingAddQueue, grabbed, pending, report, PendingReleaseReason.Delay); + break; + } + + case ProcessedDecisionResult.Rejected: + { + rejected.Add(report); + break; + } + + case ProcessedDecisionResult.Failed: + { + PreparePending(pendingAddQueue, grabbed, pending, report, PendingReleaseReason.DownloadClientUnavailable); + + if (downloadProtocol == DownloadProtocol.Usenet) + { + usenetFailed = true; + } + else if (downloadProtocol == DownloadProtocol.Torrent) + { + torrentFailed = true; + } + + break; + } + + case ProcessedDecisionResult.Skipped: + { + break; } - } - else - { - _logger.Warn(ex, "Couldn't add report to download queue. " + remoteEpisode); - } } } @@ -113,6 +124,30 @@ namespace NzbDrone.Core.Download return new ProcessedDecisions(grabbed, pending, rejected); } + public async Task ProcessDecision(DownloadDecision decision, int? downloadClientId) + { + if (decision == null) + { + return ProcessedDecisionResult.Skipped; + } + + if (decision.TemporarilyRejected) + { + _pendingReleaseService.Add(decision, PendingReleaseReason.Delay); + + return ProcessedDecisionResult.Pending; + } + + var result = await ProcessDecisionInternal(decision, downloadClientId); + + if (result == ProcessedDecisionResult.Failed) + { + _pendingReleaseService.Add(decision, PendingReleaseReason.DownloadClientUnavailable); + } + + return result; + } + internal List GetQualifiedReports(IEnumerable decisions) { // Process both approved and temporarily rejected @@ -147,5 +182,38 @@ namespace NzbDrone.Core.Download queue.Add(Tuple.Create(report, reason)); pending.Add(report); } + + private async Task ProcessDecisionInternal(DownloadDecision decision, int? downloadClientId = null) + { + var remoteEpisode = decision.RemoteEpisode; + + try + { + _logger.Trace("Grabbing from Indexer {0} at priority {1}.", remoteEpisode.Release.Indexer, remoteEpisode.Release.IndexerPriority); + await _downloadService.DownloadReport(remoteEpisode, downloadClientId); + + return ProcessedDecisionResult.Grabbed; + } + catch (ReleaseUnavailableException) + { + _logger.Warn("Failed to download release from indexer, no longer available. " + remoteEpisode); + return ProcessedDecisionResult.Rejected; + } + catch (Exception ex) + { + if (ex is DownloadClientUnavailableException || ex is DownloadClientAuthenticationException) + { + _logger.Debug(ex, + "Failed to send release to download client, storing until later. " + remoteEpisode); + + return ProcessedDecisionResult.Failed; + } + else + { + _logger.Warn(ex, "Couldn't add report to download queue. " + remoteEpisode); + return ProcessedDecisionResult.Skipped; + } + } + } } } diff --git a/src/NzbDrone.Core/Download/ProcessedDecisionResult.cs b/src/NzbDrone.Core/Download/ProcessedDecisionResult.cs new file mode 100644 index 000000000..d1f27ed49 --- /dev/null +++ b/src/NzbDrone.Core/Download/ProcessedDecisionResult.cs @@ -0,0 +1,11 @@ +namespace NzbDrone.Core.Download +{ + public enum ProcessedDecisionResult + { + Grabbed, + Pending, + Rejected, + Failed, + Skipped + } +} diff --git a/src/Sonarr.Api.V3/Indexers/ReleasePushController.cs b/src/Sonarr.Api.V3/Indexers/ReleasePushController.cs index 17358edd4..a8165af46 100644 --- a/src/Sonarr.Api.V3/Indexers/ReleasePushController.cs +++ b/src/Sonarr.Api.V3/Indexers/ReleasePushController.cs @@ -57,22 +57,23 @@ namespace Sonarr.Api.V3.Indexers ResolveIndexer(info); - List decisions; + DownloadDecision decision; lock (PushLock) { - decisions = _downloadDecisionMaker.GetRssDecision(new List { info }); - _downloadDecisionProcessor.ProcessDecisions(decisions).GetAwaiter().GetResult(); + var decisions = _downloadDecisionMaker.GetRssDecision(new List { info }); + + decision = decisions.FirstOrDefault(); + + _downloadDecisionProcessor.ProcessDecision(decision, release.DownloadClientId).GetAwaiter().GetResult(); } - var firstDecision = decisions.FirstOrDefault(); - - if (firstDecision?.RemoteEpisode.ParsedEpisodeInfo == null) + if (decision?.RemoteEpisode.ParsedEpisodeInfo == null) { throw new ValidationException(new List { new ValidationFailure("Title", "Unable to parse", release.Title) }); } - return MapDecisions(new[] { firstDecision }); + return MapDecisions(new[] { decision }); } private void ResolveIndexer(ReleaseInfo release)