Failed downloads are removed from queue/history (opt out)

This commit is contained in:
Mark McDowall 2013-10-24 22:55:32 -07:00
parent 769fcdfc80
commit d634dd1e5c
10 changed files with 174 additions and 28 deletions

View File

@ -268,6 +268,13 @@ namespace NzbDrone.Core.Configuration
set { SetValue("AutoRedownloadFailed", value); } set { SetValue("AutoRedownloadFailed", value); }
} }
public Boolean RemoveFailedDownloads
{
get { return GetValueBoolean("RemoveFailedDownloads", true); }
set { SetValue("RemoveFailedDownloads", value); }
}
public string DownloadClientWorkingFolders public string DownloadClientWorkingFolders
{ {
get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); } get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); }

View File

@ -40,6 +40,7 @@ namespace NzbDrone.Core.Configuration
Boolean AutoDownloadPropers { get; set; } Boolean AutoDownloadPropers { get; set; }
String DownloadClientWorkingFolders { get; set; } String DownloadClientWorkingFolders { get; set; }
Boolean AutoRedownloadFailed { get; set; } Boolean AutoRedownloadFailed { get; set; }
Boolean RemoveFailedDownloads { get; set; }
void SaveValues(Dictionary<string, object> configValues); void SaveValues(Dictionary<string, object> configValues);
} }
} }

View File

@ -57,5 +57,13 @@ namespace NzbDrone.Core.Download.Clients
{ {
return new HistoryItem[0]; return new HistoryItem[0];
} }
public void RemoveFromQueue(string id)
{
}
public void RemoveFromHistory(string id)
{
}
} }
} }

View File

@ -96,6 +96,16 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
return new HistoryItem[0]; 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) 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 //Get saved values if any of these are defaults

View File

@ -70,6 +70,14 @@ namespace NzbDrone.Core.Download.Clients
return new HistoryItem[0]; return new HistoryItem[0];
} }
public void RemoveFromQueue(string id)
{
}
public void RemoveFromHistory(string id)
{
}
public virtual bool IsInQueue(RemoteEpisode newEpisode) public virtual bool IsInQueue(RemoteEpisode newEpisode)
{ {
return false; return false;

View File

@ -9,6 +9,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
public interface ISabCommunicationProxy public interface ISabCommunicationProxy
{ {
string DownloadNzb(Stream nzb, string name, string category, int priority); string DownloadNzb(Stream nzb, string name, string category, int priority);
void RemoveFrom(string source, string id);
string ProcessRequest(IRestRequest restRequest, string action); string ProcessRequest(IRestRequest restRequest, string action);
} }
@ -31,6 +32,14 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return ProcessRequest(request, action); 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) public string ProcessRequest(IRestRequest restRequest, string action)
{ {
var client = BuildClient(action); var client = BuildClient(action);

View File

@ -89,7 +89,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
queueItem.Timeleft = sabQueueItem.Timeleft; queueItem.Timeleft = sabQueueItem.Timeleft;
queueItem.Status = sabQueueItem.Status; queueItem.Status = sabQueueItem.Status;
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title); var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title.Replace("ENCRYPTED / ", ""));
if (parsedEpisodeInfo == null) continue; if (parsedEpisodeInfo == null) continue;
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0); var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
@ -133,6 +133,16 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return historyItems; 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) 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 //Get saved values if any of these are defaults

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
@ -12,44 +14,53 @@ namespace NzbDrone.Core.Download
private readonly IProvideDownloadClient _downloadClientProvider; private readonly IProvideDownloadClient _downloadClientProvider;
private readonly IHistoryService _historyService; private readonly IHistoryService _historyService;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly IConfigService _configService;
private readonly Logger _logger; private readonly Logger _logger;
private readonly IDownloadClient _downloadClient;
private static string DOWNLOAD_CLIENT = "downloadClient"; private static string DOWNLOAD_CLIENT = "downloadClient";
private static string DOWNLOAD_CLIENT_ID = "downloadClientId"; private static string DOWNLOAD_CLIENT_ID = "downloadClientId";
public FailedDownloadService(IProvideDownloadClient downloadClientProvider, public FailedDownloadService(IProvideDownloadClient downloadClientProvider,
IHistoryService historyService, IHistoryService historyService,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
IConfigService configService,
Logger logger) Logger logger)
{ {
_downloadClientProvider = downloadClientProvider; _downloadClientProvider = downloadClientProvider;
_historyService = historyService; _historyService = historyService;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_configService = configService;
_logger = logger; _logger = logger;
_downloadClient = _downloadClientProvider.GetDownloadClient();
} }
private void CheckForFailedDownloads() private void CheckForFailedDownloads()
{ {
var downloadClient = _downloadClientProvider.GetDownloadClient(); var grabbedHistory = _historyService.Grabbed();
var downloadClientHistory = downloadClient.GetHistory(0, 20).ToList(); var failedHistory = _historyService.Failed();
var failedItems = downloadClientHistory.Where(h => h.Status == HistoryStatus.Failed).ToList(); CheckQueue(grabbedHistory, failedHistory);
CheckHistory(grabbedHistory, failedHistory);
}
private void CheckQueue(List<History.History> grabbedHistory, List<History.History> failedHistory)
{
var downloadClientQueue = _downloadClient.GetQueue().ToList();
var failedItems = downloadClientQueue.Where(q => q.Title.StartsWith("ENCRYPTED / ")).ToList();
if (!failedItems.Any()) if (!failedItems.Any())
{ {
_logger.Trace("Yay! No failed downloads"); _logger.Trace("Yay! No encrypted downloads");
return; return;
} }
var grabbedHistory = _historyService.Grabbed();
var failedHistory = _historyService.Failed();
foreach (var failedItem in failedItems) foreach (var failedItem in failedItems)
{ {
var failedLocal = failedItem; var failedLocal = failedItem;
var historyItems = grabbedHistory.Where(h => h.Data.ContainsKey(DOWNLOAD_CLIENT) && var historyItems = GetHistoryItems(grabbedHistory, failedLocal.Id);
h.Data[DOWNLOAD_CLIENT_ID].Equals(failedLocal.Id))
.ToList();
if (!historyItems.Any()) if (!historyItems.Any())
{ {
@ -64,21 +75,77 @@ namespace NzbDrone.Core.Download
continue; continue;
} }
var historyItem = historyItems.First(); PublishDownloadFailedEvent(historyItems, "Encypted download detected");
_eventAggregator.PublishEvent(new DownloadFailedEvent if (_configService.RemoveFailedDownloads)
{ {
SeriesId = historyItem.SeriesId, _logger.Info("Removing encrypted download from queue: {0}", failedItem.Title.Replace("ENCRYPTED / ", ""));
EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(), _downloadClient.RemoveFromQueue(failedItem.Id);
Quality = historyItem.Quality, }
SourceTitle = historyItem.SourceTitle,
DownloadClient = historyItem.Data[DOWNLOAD_CLIENT],
DownloadClientId = historyItem.Data[DOWNLOAD_CLIENT_ID],
Message = failedItem.Message
});
} }
} }
private void CheckHistory(List<History.History> grabbedHistory, List<History.History> failedHistory)
{
var downloadClientHistory = _downloadClient.GetHistory(0, 20).ToList();
var failedItems = downloadClientHistory.Where(h => h.Status == HistoryStatus.Failed).ToList();
if (!failedItems.Any())
{
_logger.Trace("Yay! No failed 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, failedItem.Message);
if (_configService.RemoveFailedDownloads)
{
_logger.Info("Removing failed download from history: {0}", failedItem.Title);
_downloadClient.RemoveFromHistory(failedItem.Id);
}
}
}
private List<History.History> GetHistoryItems(List<History.History> grabbedHistory, string downloadClientId)
{
return grabbedHistory.Where(h => h.Data.ContainsKey(DOWNLOAD_CLIENT) &&
h.Data[DOWNLOAD_CLIENT_ID].Equals(downloadClientId))
.ToList();
}
private void PublishDownloadFailedEvent(List<History.History> 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) public void Execute(FailedDownloadCommand message)
{ {
CheckForFailedDownloads(); CheckForFailedDownloads();

View File

@ -9,5 +9,7 @@ namespace NzbDrone.Core.Download
bool IsConfigured { get; } bool IsConfigured { get; }
IEnumerable<QueueItem> GetQueue(); IEnumerable<QueueItem> GetQueue();
IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0); IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0);
void RemoveFromQueue(string id);
void RemoveFromHistory(string id);
} }
} }

View File

@ -42,7 +42,22 @@
</div> </div>
<div class="control-group"> <div class="control-group">
<label class="control-label">Redownload Failed</label> <label class="control-label">Recycling Bin</label>
<div class="controls">
<input type="text" name="recycleBin" class="x-path"/>
<span class="help-inline">
<i class="icon-nd-form-info" title="Episode files will go here when deleted instead of being permanently deleted"/>
</span>
</div>
</div>
</fieldset>
<fieldset class="advanced-setting">
<legend>Failed Download Handling</legend>
<div class="control-group">
<label class="control-label">Redownload</label>
<div class="controls"> <div class="controls">
<label class="checkbox toggle well"> <label class="checkbox toggle well">
@ -56,19 +71,28 @@
</label> </label>
<span class="help-inline-checkbox"> <span class="help-inline-checkbox">
<i class="icon-question-sign" title="Should NzbDrone automatically search for and attempt to download another release when a download fails?"/> <i class="icon-question-sign" title="Automatically search for and attempt to download another release when a download fails?"/>
</span> </span>
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label class="control-label">Recycling Bin</label> <label class="control-label">Remove</label>
<div class="controls"> <div class="controls">
<input type="text" name="recycleBin" class="x-path"/> <label class="checkbox toggle well">
<span class="help-inline"> <input type="checkbox" name="removeFailedDownloads"/>
<i class="icon-nd-form-info" title="Episode files will go here when deleted instead of being permanently deleted"/> <p>
<span>Yes</span>
<span>No</span>
</p>
<div class="btn btn-primary slide-button"/>
</label>
<span class="help-inline-checkbox">
<i class="icon-question-sign" title="Automatically remove failed downloads from history and encrypted downloads from queue?"/>
</span> </span>
</div> </div>
</div> </div>
</fieldset> </fieldset>