1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-22 22:16:13 -04:00

Store releases when download client is unavailable

New: Retry releases when download client was unavailable
Closes #949
This commit is contained in:
Mark McDowall
2017-06-03 20:41:32 -07:00
committed by GitHub
parent a1edbafa8a
commit 0c89a4ae8f
27 changed files with 465 additions and 147 deletions
@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using NLog;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Download.Pending;
using NzbDrone.Core.Indexers;
namespace NzbDrone.Core.Download
{
@@ -36,37 +39,33 @@ namespace NzbDrone.Core.Download
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(qualifiedReports);
var grabbed = new List<DownloadDecision>();
var pending = new List<DownloadDecision>();
var failed = new List<DownloadDecision>();
var usenetFailed = false;
var torrentFailed = false;
foreach (var report in prioritizedDecisions)
{
var remoteEpisode = report.RemoteEpisode;
var downloadProtocol = report.RemoteEpisode.Release.DownloadProtocol;
var episodeIds = remoteEpisode.Episodes.Select(e => e.Id).ToList();
//Skip if already grabbed
if (grabbed.SelectMany(r => r.RemoteEpisode.Episodes)
.Select(e => e.Id)
.ToList()
.Intersect(episodeIds)
.Any())
// Skip if already grabbed
if (IsEpisodeProcessed(grabbed, report))
{
continue;
}
if (report.TemporarilyRejected)
{
_pendingReleaseService.Add(report);
_pendingReleaseService.Add(report, PendingReleaseReason.Delay);
pending.Add(report);
continue;
}
if (pending.SelectMany(r => r.RemoteEpisode.Episodes)
.Select(e => e.Id)
.ToList()
.Intersect(episodeIds)
.Any())
if (downloadProtocol == DownloadProtocol.Usenet && usenetFailed ||
downloadProtocol == DownloadProtocol.Torrent && torrentFailed)
{
continue;
failed.Add(report);
}
try
@@ -74,14 +73,31 @@ namespace NzbDrone.Core.Download
_downloadService.DownloadReport(remoteEpisode);
grabbed.Add(report);
}
catch (Exception e)
catch (Exception ex)
{
//TODO: support for store & forward
//We'll need to differentiate between a download client error and an indexer error
_logger.Warn(e, "Couldn't add report to download queue. " + remoteEpisode);
if (ex is DownloadClientUnavailableException || ex is DownloadClientAuthenticationException)
{
_logger.Debug("Failed to send release to download client, storing until later");
failed.Add(report);
if (downloadProtocol == DownloadProtocol.Usenet)
{
usenetFailed = true;
}
else if (downloadProtocol == DownloadProtocol.Torrent)
{
torrentFailed = true;
}
}
else
{
_logger.Warn(ex, "Couldn't add report to download queue. " + remoteEpisode);
}
}
}
pending.AddRange(ProcessFailedGrabs(grabbed, failed));
return new ProcessedDecisions(grabbed, pending, decisions.Where(d => d.Rejected).ToList());
}
@@ -90,5 +106,50 @@ namespace NzbDrone.Core.Download
//Process both approved and temporarily rejected
return decisions.Where(c => (c.Approved || c.TemporarilyRejected) && c.RemoteEpisode.Episodes.Any()).ToList();
}
private bool IsEpisodeProcessed(List<DownloadDecision> decisions, DownloadDecision report)
{
var episodeIds = report.RemoteEpisode.Episodes.Select(e => e.Id).ToList();
return decisions.SelectMany(r => r.RemoteEpisode.Episodes)
.Select(e => e.Id)
.ToList()
.Intersect(episodeIds)
.Any();
}
private List<DownloadDecision> ProcessFailedGrabs(List<DownloadDecision> grabbed, List<DownloadDecision> failed)
{
var pending = new List<DownloadDecision>();
var stored = new List<DownloadDecision>();
foreach (var report in failed)
{
// If a release was already grabbed with matching episodes we should store it as a fallback
// and filter it out the next time it is processed incase a higher quality release failed to
// add to the download client, but a lower quality release was sent to another client
// If the release wasn't grabbed already, but was already stored, store it as a fallback,
// otherwise store it as DownloadClientUnavailable.
if (IsEpisodeProcessed(grabbed, report))
{
_pendingReleaseService.Add(report, PendingReleaseReason.Fallback);
pending.Add(report);
}
else if (IsEpisodeProcessed(stored, report))
{
_pendingReleaseService.Add(report, PendingReleaseReason.Fallback);
pending.Add(report);
}
else
{
_pendingReleaseService.Add(report, PendingReleaseReason.DownloadClientUnavailable);
pending.Add(report);
stored.Add(report);
}
}
return pending;
}
}
}