mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-19 21:13:28 -07:00
New: Drone now uses the Download Client API to determine if a download is ready for import. (User configuration is required to replace the drone factory with this feature)
This commit is contained in:
parent
dcb586b937
commit
2035fe8578
196 changed files with 3961 additions and 2223 deletions
|
@ -14,35 +14,25 @@ namespace NzbDrone.Core.Download
|
|||
public interface IFailedDownloadService
|
||||
{
|
||||
void MarkAsFailed(int historyId);
|
||||
void CheckForFailedItem(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> grabbedHistory, List<History.History> failedHistory);
|
||||
}
|
||||
|
||||
public class FailedDownloadService : IFailedDownloadService, IExecute<CheckForFailedDownloadCommand>
|
||||
public class FailedDownloadService : IFailedDownloadService
|
||||
{
|
||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private readonly ICached<FailedDownload> _failedDownloads;
|
||||
|
||||
private static string DOWNLOAD_CLIENT = "downloadClient";
|
||||
private static string DOWNLOAD_CLIENT_ID = "downloadClientId";
|
||||
|
||||
public FailedDownloadService(IProvideDownloadClient downloadClientProvider,
|
||||
IHistoryService historyService,
|
||||
public FailedDownloadService(IHistoryService historyService,
|
||||
IEventAggregator eventAggregator,
|
||||
IConfigService configService,
|
||||
ICacheManager cacheManager,
|
||||
Logger logger)
|
||||
{
|
||||
_downloadClientProvider = downloadClientProvider;
|
||||
_historyService = historyService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
|
||||
_failedDownloads = cacheManager.GetCache<FailedDownload>(GetType());
|
||||
}
|
||||
|
||||
public void MarkAsFailed(int historyId)
|
||||
|
@ -51,149 +41,92 @@ namespace NzbDrone.Core.Download
|
|||
PublishDownloadFailedEvent(new List<History.History> { item }, "Manually marked as failed");
|
||||
}
|
||||
|
||||
private void CheckQueue(List<History.History> grabbedHistory, List<History.History> failedHistory)
|
||||
public void CheckForFailedItem(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> grabbedHistory, List<History.History> failedHistory)
|
||||
{
|
||||
var downloadClient = GetDownloadClient();
|
||||
|
||||
if (downloadClient == null)
|
||||
if (!_configService.EnableFailedDownloadHandling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadClientQueue = downloadClient.GetQueue().ToList();
|
||||
var failedItems = downloadClientQueue.Where(q => q.Title.StartsWith("ENCRYPTED / ")).ToList();
|
||||
|
||||
if (!failedItems.Any())
|
||||
if (trackedDownload.DownloadItem.IsEncrypted && trackedDownload.State == TrackedDownloadState.Downloading)
|
||||
{
|
||||
_logger.Debug("Yay! No encrypted downloads");
|
||||
return;
|
||||
}
|
||||
var grabbedItems = GetHistoryItems(grabbedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
foreach (var failedItem in failedItems)
|
||||
{
|
||||
var failedLocal = failedItem;
|
||||
var historyItems = GetHistoryItems(grabbedHistory, failedLocal.Id);
|
||||
|
||||
if (!historyItems.Any())
|
||||
if (!grabbedItems.Any())
|
||||
{
|
||||
_logger.Debug("Unable to find matching history item");
|
||||
continue;
|
||||
_logger.Debug("Download was not grabbed by drone, ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (failedHistory.Any(h => failedLocal.Id.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID))))
|
||||
trackedDownload.State = TrackedDownloadState.DownloadFailed;
|
||||
|
||||
var failedItems = GetHistoryItems(failedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (failedItems.Any())
|
||||
{
|
||||
_logger.Debug("Already added to history as failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
PublishDownloadFailedEvent(historyItems, "Encrypted download detected");
|
||||
|
||||
if (_configService.RemoveFailedDownloads)
|
||||
else
|
||||
{
|
||||
_logger.Info("Removing encrypted download from queue: {0}", failedItem.Title.Replace("ENCRYPTED / ", ""));
|
||||
downloadClient.RemoveFromQueue(failedItem.Id);
|
||||
PublishDownloadFailedEvent(grabbedItems, "Encrypted download detected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckHistory(List<History.History> grabbedHistory, List<History.History> failedHistory)
|
||||
{
|
||||
var downloadClient = GetDownloadClient();
|
||||
|
||||
if (downloadClient == null)
|
||||
if (trackedDownload.DownloadItem.Status == DownloadItemStatus.Failed && trackedDownload.State == TrackedDownloadState.Downloading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var grabbedItems = GetHistoryItems(grabbedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
var downloadClientHistory = downloadClient.GetHistory(0, 20).ToList();
|
||||
var failedItems = downloadClientHistory.Where(h => h.Status == HistoryStatus.Failed).ToList();
|
||||
|
||||
if (!failedItems.Any())
|
||||
{
|
||||
_logger.Debug("Yay! No failed downloads");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var failedItem in failedItems)
|
||||
{
|
||||
var failedLocal = failedItem;
|
||||
var historyItems = GetHistoryItems(grabbedHistory, failedLocal.Id);
|
||||
|
||||
if (!historyItems.Any())
|
||||
if (!grabbedItems.Any())
|
||||
{
|
||||
_logger.Debug("Unable to find matching history item");
|
||||
continue;
|
||||
_logger.Debug("Download was not grabbed by drone, ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: Make this more configurable (ignore failure reasons) to support changes and other failures that should be ignored
|
||||
if (failedLocal.Message.Equals("Unpacking failed, write error or disk is full?",
|
||||
if (trackedDownload.DownloadItem.Message.Equals("Unpacking failed, write error or disk is full?",
|
||||
StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Failed due to lack of disk space, do not blacklist");
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (FailedDownloadForRecentRelease(failedItem, historyItems))
|
||||
if (FailedDownloadForRecentRelease(downloadClient, trackedDownload, grabbedItems))
|
||||
{
|
||||
_logger.Debug("Recent release Failed, do not blacklist");
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (failedHistory.Any(h => failedLocal.Id.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID))))
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.DownloadFailed;
|
||||
|
||||
var failedItems = GetHistoryItems(failedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (failedItems.Any())
|
||||
{
|
||||
_logger.Debug("Already added to history as failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
PublishDownloadFailedEvent(historyItems, failedItem.Message);
|
||||
|
||||
if (_configService.RemoveFailedDownloads)
|
||||
else
|
||||
{
|
||||
_logger.Info("Removing failed download from history: {0}", failedItem.Title);
|
||||
downloadClient.RemoveFromHistory(failedItem.Id);
|
||||
PublishDownloadFailedEvent(grabbedItems, trackedDownload.DownloadItem.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (_configService.RemoveFailedDownloads && trackedDownload.State == TrackedDownloadState.DownloadFailed)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Info("Removing failed download from client: {0}", trackedDownload.DownloadItem.Title);
|
||||
downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Removed;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
_logger.Debug("Removing item not supported by your download client");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<History.History> GetHistoryItems(List<History.History> grabbedHistory, string downloadClientId)
|
||||
{
|
||||
return grabbedHistory.Where(h => downloadClientId.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void PublishDownloadFailedEvent(List<History.History> historyItems, string message)
|
||||
{
|
||||
var historyItem = historyItems.First();
|
||||
|
||||
var downloadFailedEvent = new DownloadFailedEvent
|
||||
{
|
||||
SeriesId = historyItem.SeriesId,
|
||||
EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(),
|
||||
Quality = historyItem.Quality,
|
||||
SourceTitle = historyItem.SourceTitle,
|
||||
DownloadClient = historyItem.Data.GetValueOrDefault(DOWNLOAD_CLIENT),
|
||||
DownloadClientId = historyItem.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID),
|
||||
Message = message
|
||||
};
|
||||
|
||||
downloadFailedEvent.Data = downloadFailedEvent.Data.Merge(historyItem.Data);
|
||||
|
||||
_eventAggregator.PublishEvent(downloadFailedEvent);
|
||||
}
|
||||
|
||||
private IDownloadClient GetDownloadClient()
|
||||
{
|
||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||
|
||||
if (downloadClient == null)
|
||||
{
|
||||
_logger.Debug("No download client is configured");
|
||||
}
|
||||
|
||||
return downloadClient;
|
||||
}
|
||||
|
||||
private bool FailedDownloadForRecentRelease(HistoryItem failedDownloadHistoryItem, List<History.History> matchingHistoryItems)
|
||||
private bool FailedDownloadForRecentRelease(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> matchingHistoryItems)
|
||||
{
|
||||
double ageHours;
|
||||
|
||||
|
@ -209,31 +142,23 @@ namespace NzbDrone.Core.Download
|
|||
return false;
|
||||
}
|
||||
|
||||
var tracked = _failedDownloads.Get(failedDownloadHistoryItem.Id, () => new FailedDownload
|
||||
{
|
||||
DownloadClientHistoryItem = failedDownloadHistoryItem,
|
||||
LastRetry = DateTime.UtcNow
|
||||
}
|
||||
);
|
||||
|
||||
if (tracked.RetryCount >= _configService.BlacklistRetryLimit)
|
||||
if (trackedDownload.RetryCount >= _configService.BlacklistRetryLimit)
|
||||
{
|
||||
_logger.Debug("Retry limit reached");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tracked.LastRetry.AddMinutes(_configService.BlacklistRetryInterval) < DateTime.UtcNow)
|
||||
if (trackedDownload.RetryCount == 0 || trackedDownload.LastRetry.AddMinutes(_configService.BlacklistRetryInterval) < DateTime.UtcNow)
|
||||
{
|
||||
_logger.Debug("Retrying failed release");
|
||||
tracked.LastRetry = DateTime.UtcNow;
|
||||
tracked.RetryCount++;
|
||||
trackedDownload.LastRetry = DateTime.UtcNow;
|
||||
trackedDownload.RetryCount++;
|
||||
|
||||
try
|
||||
{
|
||||
GetDownloadClient().RetryDownload(failedDownloadHistoryItem.Id);
|
||||
downloadClient.RetryDownload(trackedDownload.DownloadItem.DownloadClientId);
|
||||
}
|
||||
|
||||
catch (NotImplementedException ex)
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
_logger.Debug("Retrying failed downloads is not supported by your download client");
|
||||
return false;
|
||||
|
@ -243,19 +168,30 @@ namespace NzbDrone.Core.Download
|
|||
return true;
|
||||
}
|
||||
|
||||
public void Execute(CheckForFailedDownloadCommand message)
|
||||
private List<History.History> GetHistoryItems(List<History.History> grabbedHistory, string downloadClientId)
|
||||
{
|
||||
if (!_configService.EnableFailedDownloadHandling)
|
||||
return grabbedHistory.Where(h => downloadClientId.Equals(h.Data.GetValueOrDefault(DownloadTrackingService.DOWNLOAD_CLIENT_ID)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void PublishDownloadFailedEvent(List<History.History> historyItems, string message)
|
||||
{
|
||||
var historyItem = historyItems.First();
|
||||
|
||||
var downloadFailedEvent = new DownloadFailedEvent
|
||||
{
|
||||
_logger.Debug("Failed Download Handling is not enabled");
|
||||
return;
|
||||
}
|
||||
SeriesId = historyItem.SeriesId,
|
||||
EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(),
|
||||
Quality = historyItem.Quality,
|
||||
SourceTitle = historyItem.SourceTitle,
|
||||
DownloadClient = historyItem.Data.GetValueOrDefault(DownloadTrackingService.DOWNLOAD_CLIENT),
|
||||
DownloadClientId = historyItem.Data.GetValueOrDefault(DownloadTrackingService.DOWNLOAD_CLIENT_ID),
|
||||
Message = message
|
||||
};
|
||||
|
||||
var grabbedHistory = _historyService.Grabbed();
|
||||
var failedHistory = _historyService.Failed();
|
||||
downloadFailedEvent.Data = downloadFailedEvent.Data.Merge(historyItem.Data);
|
||||
|
||||
CheckQueue(grabbedHistory, failedHistory);
|
||||
CheckHistory(grabbedHistory, failedHistory);
|
||||
_eventAggregator.PublishEvent(downloadFailedEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue