diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index f8f3908b7..b51d92611 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -268,6 +268,13 @@ namespace NzbDrone.Core.Configuration set { SetValue("AutoRedownloadFailed", value); } } + public Boolean RemoveFailedDownloads + { + get { return GetValueBoolean("RemoveFailedDownloads", true); } + + set { SetValue("RemoveFailedDownloads", value); } + } + public string DownloadClientWorkingFolders { get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 59a24c7fe..f4578d4c1 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -40,6 +40,7 @@ namespace NzbDrone.Core.Configuration Boolean AutoDownloadPropers { get; set; } String DownloadClientWorkingFolders { get; set; } Boolean AutoRedownloadFailed { get; set; } + Boolean RemoveFailedDownloads { get; set; } void SaveValues(Dictionary configValues); } } diff --git a/src/NzbDrone.Core/Download/Clients/BlackholeProvider.cs b/src/NzbDrone.Core/Download/Clients/BlackholeProvider.cs index a5d8e5fe2..5f43ca351 100644 --- a/src/NzbDrone.Core/Download/Clients/BlackholeProvider.cs +++ b/src/NzbDrone.Core/Download/Clients/BlackholeProvider.cs @@ -57,5 +57,13 @@ namespace NzbDrone.Core.Download.Clients { return new HistoryItem[0]; } + + public void RemoveFromQueue(string id) + { + } + + public void RemoveFromHistory(string id) + { + } } } diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetClient.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetClient.cs index 94f83ed9d..66acf0f92 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetClient.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetClient.cs @@ -96,6 +96,16 @@ namespace NzbDrone.Core.Download.Clients.Nzbget return new HistoryItem[0]; } + public void RemoveFromQueue(string id) + { + throw new NotImplementedException(); + } + + public void RemoveFromHistory(string id) + { + throw new NotImplementedException(); + } + public virtual VersionModel GetVersion(string host = null, int port = 0, string username = null, string password = null) { //Get saved values if any of these are defaults diff --git a/src/NzbDrone.Core/Download/Clients/PneumaticClient.cs b/src/NzbDrone.Core/Download/Clients/PneumaticClient.cs index 1036f7d9b..f536965b2 100644 --- a/src/NzbDrone.Core/Download/Clients/PneumaticClient.cs +++ b/src/NzbDrone.Core/Download/Clients/PneumaticClient.cs @@ -70,6 +70,14 @@ namespace NzbDrone.Core.Download.Clients return new HistoryItem[0]; } + public void RemoveFromQueue(string id) + { + } + + public void RemoveFromHistory(string id) + { + } + public virtual bool IsInQueue(RemoteEpisode newEpisode) { return false; diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabCommunicationProxy.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabCommunicationProxy.cs index ed26110c6..f1d348b17 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabCommunicationProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabCommunicationProxy.cs @@ -9,6 +9,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd public interface ISabCommunicationProxy { string DownloadNzb(Stream nzb, string name, string category, int priority); + void RemoveFrom(string source, string id); string ProcessRequest(IRestRequest restRequest, string action); } @@ -31,6 +32,14 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd return ProcessRequest(request, action); } + public void RemoveFrom(string source, string id) + { + var request = new RestRequest(); + var action = String.Format("mode={0}&name=delete&del_files=1&value={1}", source, id); + + ProcessRequest(request, action); + } + public string ProcessRequest(IRestRequest restRequest, string action) { var client = BuildClient(action); diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs index cba13d63f..c5799f5ce 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs @@ -89,7 +89,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd queueItem.Timeleft = sabQueueItem.Timeleft; queueItem.Status = sabQueueItem.Status; - var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title); + var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title.Replace("ENCRYPTED / ", "")); if (parsedEpisodeInfo == null) continue; var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0); @@ -133,6 +133,16 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd return historyItems; } + public void RemoveFromQueue(string id) + { + _sabCommunicationProxy.RemoveFrom("queue", id); + } + + public void RemoveFromHistory(string id) + { + _sabCommunicationProxy.RemoveFrom("history", id); + } + public virtual SabCategoryModel GetCategories(string host = null, int port = 0, string apiKey = null, string username = null, string password = null) { //Get saved values if any of these are defaults diff --git a/src/NzbDrone.Core/Download/FailedDownloadService.cs b/src/NzbDrone.Core/Download/FailedDownloadService.cs index 60accd3bc..f83eb9ccc 100644 --- a/src/NzbDrone.Core/Download/FailedDownloadService.cs +++ b/src/NzbDrone.Core/Download/FailedDownloadService.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Linq; using NLog; +using NzbDrone.Core.Configuration; using NzbDrone.Core.History; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; @@ -12,27 +14,80 @@ namespace NzbDrone.Core.Download private readonly IProvideDownloadClient _downloadClientProvider; private readonly IHistoryService _historyService; private readonly IEventAggregator _eventAggregator; + private readonly IConfigService _configService; private readonly Logger _logger; + private readonly IDownloadClient _downloadClient; + private static string DOWNLOAD_CLIENT = "downloadClient"; private static string DOWNLOAD_CLIENT_ID = "downloadClientId"; public FailedDownloadService(IProvideDownloadClient downloadClientProvider, IHistoryService historyService, IEventAggregator eventAggregator, + IConfigService configService, Logger logger) { _downloadClientProvider = downloadClientProvider; _historyService = historyService; _eventAggregator = eventAggregator; + _configService = configService; _logger = logger; + + _downloadClient = _downloadClientProvider.GetDownloadClient(); } private void CheckForFailedDownloads() { - var downloadClient = _downloadClientProvider.GetDownloadClient(); - var downloadClientHistory = downloadClient.GetHistory(0, 20).ToList(); + var grabbedHistory = _historyService.Grabbed(); + var failedHistory = _historyService.Failed(); + + CheckQueue(grabbedHistory, failedHistory); + CheckHistory(grabbedHistory, failedHistory); + } + + private void CheckQueue(List grabbedHistory, List failedHistory) + { + var downloadClientQueue = _downloadClient.GetQueue().ToList(); + var failedItems = downloadClientQueue.Where(q => q.Title.StartsWith("ENCRYPTED / ")).ToList(); + + if (!failedItems.Any()) + { + _logger.Trace("Yay! No encrypted downloads"); + return; + } + + foreach (var failedItem in failedItems) + { + var failedLocal = failedItem; + var historyItems = GetHistoryItems(grabbedHistory, failedLocal.Id); + + if (!historyItems.Any()) + { + _logger.Trace("Unable to find matching history item"); + continue; + } + + if (failedHistory.Any(h => h.Data.ContainsKey(DOWNLOAD_CLIENT_ID) && + h.Data[DOWNLOAD_CLIENT_ID].Equals(failedLocal.Id))) + { + _logger.Trace("Already added to history as failed"); + continue; + } + + PublishDownloadFailedEvent(historyItems, "Encypted download detected"); + + if (_configService.RemoveFailedDownloads) + { + _logger.Info("Removing encrypted download from queue: {0}", failedItem.Title.Replace("ENCRYPTED / ", "")); + _downloadClient.RemoveFromQueue(failedItem.Id); + } + } + } + private void CheckHistory(List grabbedHistory, List failedHistory) + { + var downloadClientHistory = _downloadClient.GetHistory(0, 20).ToList(); var failedItems = downloadClientHistory.Where(h => h.Status == HistoryStatus.Failed).ToList(); if (!failedItems.Any()) @@ -41,15 +96,10 @@ namespace NzbDrone.Core.Download return; } - var grabbedHistory = _historyService.Grabbed(); - var failedHistory = _historyService.Failed(); - foreach (var failedItem in failedItems) { var failedLocal = failedItem; - var historyItems = grabbedHistory.Where(h => h.Data.ContainsKey(DOWNLOAD_CLIENT) && - h.Data[DOWNLOAD_CLIENT_ID].Equals(failedLocal.Id)) - .ToList(); + var historyItems = GetHistoryItems(grabbedHistory, failedLocal.Id); if (!historyItems.Any()) { @@ -64,21 +114,38 @@ namespace NzbDrone.Core.Download continue; } - var historyItem = historyItems.First(); + PublishDownloadFailedEvent(historyItems, failedItem.Message); - _eventAggregator.PublishEvent(new DownloadFailedEvent + if (_configService.RemoveFailedDownloads) { - SeriesId = historyItem.SeriesId, - EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(), - Quality = historyItem.Quality, - SourceTitle = historyItem.SourceTitle, - DownloadClient = historyItem.Data[DOWNLOAD_CLIENT], - DownloadClientId = historyItem.Data[DOWNLOAD_CLIENT_ID], - Message = failedItem.Message - }); + _logger.Info("Removing failed download from history: {0}", failedItem.Title); + _downloadClient.RemoveFromHistory(failedItem.Id); + } } } + private List GetHistoryItems(List grabbedHistory, string downloadClientId) + { + return grabbedHistory.Where(h => h.Data.ContainsKey(DOWNLOAD_CLIENT) && + h.Data[DOWNLOAD_CLIENT_ID].Equals(downloadClientId)) + .ToList(); + } + + private void PublishDownloadFailedEvent(List historyItems, string message) + { + var historyItem = historyItems.First(); + _eventAggregator.PublishEvent(new DownloadFailedEvent + { + SeriesId = historyItem.SeriesId, + EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(), + Quality = historyItem.Quality, + SourceTitle = historyItem.SourceTitle, + DownloadClient = historyItem.Data[DOWNLOAD_CLIENT], + DownloadClientId = historyItem.Data[DOWNLOAD_CLIENT_ID], + Message = message + }); + } + public void Execute(FailedDownloadCommand message) { CheckForFailedDownloads(); diff --git a/src/NzbDrone.Core/Download/IDownloadClient.cs b/src/NzbDrone.Core/Download/IDownloadClient.cs index f330dbc86..42107372b 100644 --- a/src/NzbDrone.Core/Download/IDownloadClient.cs +++ b/src/NzbDrone.Core/Download/IDownloadClient.cs @@ -9,5 +9,7 @@ namespace NzbDrone.Core.Download bool IsConfigured { get; } IEnumerable GetQueue(); IEnumerable GetHistory(int start = 0, int limit = 0); + void RemoveFromQueue(string id); + void RemoveFromHistory(string id); } } diff --git a/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.html b/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.html index e66c50607..2313306db 100644 --- a/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.html +++ b/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.html @@ -42,7 +42,22 @@
- + + +
+ + + + +
+
+ + +
+ Failed Download Handling + +
+
- +
- +
- - - +
-
+ \ No newline at end of file