mirror of
https://github.com/Sonarr/Sonarr
synced 2025-03-15 00:21:42 +00:00
New: The History->Queue UI now show some elementary error information for failed imports.
This commit is contained in:
parent
981ffb09fc
commit
47089d360d
16 changed files with 167 additions and 49 deletions
|
@ -37,6 +37,7 @@ module.exports = function (grunt) {
|
|||
'Content/theme.less',
|
||||
'Content/overrides.less',
|
||||
'Series/series.less',
|
||||
'History/history.less',
|
||||
'AddSeries/addSeries.less',
|
||||
'Calendar/calendar.less',
|
||||
'Cells/cells.less',
|
||||
|
|
|
@ -17,5 +17,6 @@ namespace NzbDrone.Api.Queue
|
|||
public Decimal Sizeleft { get; set; }
|
||||
public TimeSpan? Timeleft { get; set; }
|
||||
public String Status { get; set; }
|
||||
public String ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ using NzbDrone.Core.History;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -103,14 +104,20 @@ namespace NzbDrone.Core.Test.Download
|
|||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
|
||||
.Returns(new List<Core.MediaFiles.EpisodeImport.ImportDecision>() { new Core.MediaFiles.EpisodeImport.ImportDecision(null) });
|
||||
.Returns(new List<ImportDecision>()
|
||||
{
|
||||
new ImportDecision(null)
|
||||
});
|
||||
}
|
||||
|
||||
private void GivenFailedImport()
|
||||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
|
||||
.Returns(new List<Core.MediaFiles.EpisodeImport.ImportDecision>());
|
||||
.Returns(new List<ImportDecision>()
|
||||
{
|
||||
new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }, "Test Failure")
|
||||
});
|
||||
}
|
||||
|
||||
private void VerifyNoImports()
|
||||
|
@ -265,6 +272,8 @@ namespace NzbDrone.Core.Test.Download
|
|||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoImports();
|
||||
|
||||
ExceptionVerification.IgnoreErrors();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -289,6 +298,8 @@ namespace NzbDrone.Core.Test.Download
|
|||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoImports();
|
||||
|
||||
ExceptionVerification.IgnoreWarns();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -412,6 +423,8 @@ namespace NzbDrone.Core.Test.Download
|
|||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
|
||||
ExceptionVerification.IgnoreErrors();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
if (!grabbedItems.Any() && trackedDownload.DownloadItem.Category.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Trace("Ignoring download that wasn't grabbed by drone: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Debug, "Download wasn't grabbed by drone or not in a category, ignoring download.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
|
||||
_logger.Trace("Already added to history as imported: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Debug, "Already added to history as imported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -85,13 +85,13 @@ namespace NzbDrone.Core.Download
|
|||
string downloadItemOutputPath = trackedDownload.DownloadItem.OutputPath;
|
||||
if (downloadItemOutputPath.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Trace("Storage path not specified: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Warn, "Download doesn't contain intermediate path, ignoring download.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!downloadedEpisodesFolder.IsNullOrWhiteSpace() && (downloadedEpisodesFolder.PathEquals(downloadItemOutputPath) || downloadedEpisodesFolder.IsParentPath(downloadItemOutputPath)))
|
||||
{
|
||||
_logger.Trace("Storage path inside drone factory, ignoring download: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Warn, "Intermediate Download path inside drone factory, ignoring download.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -99,19 +99,49 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
var decisions = _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
|
||||
|
||||
if (decisions.Any())
|
||||
if (!decisions.Any())
|
||||
{
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Error, "No files found eligible for import in {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
}
|
||||
else if (decisions.Any(v => v.Approved))
|
||||
{
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Info, "Imported {0} files.", decisions.Count(v => v.Approved));
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rejections = decisions
|
||||
.Where(v => !v.Approved)
|
||||
.Select(v => v.Rejections.Aggregate(Path.GetFileName(v.LocalEpisode.Path), (a, r) => a + "\r\n- " + r))
|
||||
.Aggregate("Failed to import:", (a, r) => a + "\r\n" + r);
|
||||
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Error, rejections);
|
||||
}
|
||||
}
|
||||
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath))
|
||||
{
|
||||
var decisions = _downloadedEpisodesImportService.ProcessFile(new FileInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
|
||||
|
||||
if (decisions.Any())
|
||||
if (!decisions.Any())
|
||||
{
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Error, "No files found eligible for import in {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
}
|
||||
else if (decisions.Any(v => v.Approved))
|
||||
{
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Info, "Imported {0} files.", decisions.Count(v => v.Approved));
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rejections = decisions
|
||||
.Where(v => !v.Approved)
|
||||
.Select(v => v.Rejections.Aggregate(Path.GetFileName(v.LocalEpisode.Path), (a, r) => a + "\r\n- " + r))
|
||||
.Aggregate("Failed to import:", (a, r) => a + "\r\n" + r);
|
||||
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Error, rejections);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -137,13 +167,13 @@ namespace NzbDrone.Core.Download
|
|||
importedItems.First().Data[DownloadTrackingService.DOWNLOAD_CLIENT_ID] = grabbedItems.First().Data[DownloadTrackingService.DOWNLOAD_CLIENT_ID];
|
||||
_historyService.UpdateHistoryData(importedItems.First().Id, importedItems.First().Data);
|
||||
|
||||
_logger.Trace("Storage path does not exist, but found probable drone factory ImportEvent: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Debug, "Intermediate Download path does not exist, but found probable drone factory ImportEvent.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Trace("Storage path does not exist: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Error, "Intermediate Download path does not exist: {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -153,17 +183,17 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
try
|
||||
{
|
||||
_logger.Info("Removing completed download from history: {0}", trackedDownload.DownloadItem.Title);
|
||||
_logger.Debug("[{0}] Removing completed download from history.", trackedDownload.DownloadItem.Title);
|
||||
downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath))
|
||||
{
|
||||
_logger.Info("Removing completed download directory: {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
_logger.Debug("Removing completed download directory: {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath, true);
|
||||
}
|
||||
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath))
|
||||
{
|
||||
_logger.Info("Removing completed download file: {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
_logger.Debug("Removing completed download file: {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
_diskProvider.DeleteFile(trackedDownload.DownloadItem.OutputPath);
|
||||
}
|
||||
|
||||
|
@ -171,9 +201,26 @@ namespace NzbDrone.Core.Download
|
|||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
_logger.Debug("Removing item not supported by your download client");
|
||||
UpdateStatusMessage(trackedDownload, LogLevel.Debug, "Removing item not supported by your download client.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStatusMessage(TrackedDownload trackedDownload, LogLevel logLevel, String message, params object[] args)
|
||||
{
|
||||
var statusMessage = String.Format(message, args);
|
||||
var logMessage = String.Format("[{0}] {1}", trackedDownload.DownloadItem.Title, statusMessage);
|
||||
|
||||
if (trackedDownload.StatusMessage != statusMessage)
|
||||
{
|
||||
trackedDownload.HasError = logLevel >= LogLevel.Warn;
|
||||
trackedDownload.StatusMessage = statusMessage;
|
||||
_logger.Log(logLevel, logMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug(logMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace NzbDrone.Core.Download
|
|||
TrackedDownload[] GetQueuedDownloads();
|
||||
}
|
||||
|
||||
public class DownloadTrackingService : IDownloadTrackingService, IExecute<CheckForFinishedDownloadCommand>, IHandle<ApplicationStartedEvent>, IHandle<EpisodeGrabbedEvent>
|
||||
public class DownloadTrackingService : IDownloadTrackingService, IExecute<CheckForFinishedDownloadCommand>, IHandleAsync<ApplicationStartedEvent>, IHandle<EpisodeGrabbedEvent>
|
||||
{
|
||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||
private readonly IHistoryService _historyService;
|
||||
|
@ -201,7 +201,7 @@ namespace NzbDrone.Core.Download
|
|||
ProcessTrackedDownloads();
|
||||
}
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
public void HandleAsync(ApplicationStartedEvent message)
|
||||
{
|
||||
ProcessTrackedDownloads();
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
if (!grabbedItems.Any())
|
||||
{
|
||||
_logger.Trace("Download was not grabbed by drone, ignoring download: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(LogLevel.Debug, trackedDownload, "Download was not grabbed by drone, ignoring download");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
if (failedItems.Any())
|
||||
{
|
||||
_logger.Trace("Already added to history as failed: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(LogLevel.Debug, trackedDownload, "Already added to history as failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
if (!grabbedItems.Any())
|
||||
{
|
||||
_logger.Trace("Download was not grabbed by drone, ignoring download: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(LogLevel.Debug, trackedDownload, "Download wasn't grabbed by drone or not in a category, ignoring download.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -86,13 +86,13 @@ namespace NzbDrone.Core.Download
|
|||
if (trackedDownload.DownloadItem.Message.Equals("Unpacking failed, write error or disk is full?",
|
||||
StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Trace("Failed due to lack of disk space, do not blacklist: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(LogLevel.Error, trackedDownload, "Download failed due to lack of disk space, not blacklisting.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (FailedDownloadForRecentRelease(downloadClient, trackedDownload, grabbedItems))
|
||||
{
|
||||
_logger.Trace("Recent release Failed, do not blacklist: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(LogLevel.Debug, trackedDownload, "Recent release Failed, do not blacklist.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
if (failedItems.Any())
|
||||
{
|
||||
_logger.Trace("Already added to history as failed: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(LogLevel.Debug, trackedDownload, "Already added to history as failed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
if (grabbedItems.Any() && failedItems.Any())
|
||||
{
|
||||
_logger.Trace("Already added to history as failed, updating tracked state: " + trackedDownload.DownloadItem.Title);
|
||||
UpdateStatusMessage(LogLevel.Debug, trackedDownload, "Already added to history as failed, updating tracked state.");
|
||||
trackedDownload.State = TrackedDownloadState.DownloadFailed;
|
||||
}
|
||||
}
|
||||
|
@ -126,14 +126,14 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
try
|
||||
{
|
||||
_logger.Info("Removing failed download from client: {0}", trackedDownload.DownloadItem.Title);
|
||||
_logger.Debug("[{0}] Removing failed download from client", trackedDownload.DownloadItem.Title);
|
||||
downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Removed;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
_logger.Trace("Removing item not supported by your download client");
|
||||
UpdateStatusMessage(LogLevel.Debug, trackedDownload, "Removing item not supported by your download client.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,25 +144,25 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
if (!Double.TryParse(matchingHistoryItems.First().Data.GetValueOrDefault("ageHours"), out ageHours))
|
||||
{
|
||||
_logger.Debug("Unable to determine age of failed download: " + trackedDownload.DownloadItem.Title);
|
||||
_logger.Info("[{0}] Unable to determine age of failed download.", trackedDownload.DownloadItem.Title);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ageHours > _configService.BlacklistGracePeriod)
|
||||
{
|
||||
_logger.Debug("Failed download is older than the grace period: " + trackedDownload.DownloadItem.Title);
|
||||
_logger.Info("[{0}] Failed download is older than the grace period.", trackedDownload.DownloadItem.Title);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (trackedDownload.RetryCount >= _configService.BlacklistRetryLimit)
|
||||
{
|
||||
_logger.Debug("Retry limit reached: " + trackedDownload.DownloadItem.Title);
|
||||
_logger.Info("[{0}] Retry limit reached.", trackedDownload.DownloadItem.Title);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (trackedDownload.RetryCount == 0 || trackedDownload.LastRetry.AddMinutes(_configService.BlacklistRetryInterval) < DateTime.UtcNow)
|
||||
{
|
||||
_logger.Debug("Retrying failed release: " + trackedDownload.DownloadItem.Title);
|
||||
_logger.Info("[{0}] Retrying failed release.", trackedDownload.DownloadItem.Title);
|
||||
trackedDownload.LastRetry = DateTime.UtcNow;
|
||||
trackedDownload.RetryCount++;
|
||||
|
||||
|
@ -205,5 +205,22 @@ namespace NzbDrone.Core.Download
|
|||
|
||||
_eventAggregator.PublishEvent(downloadFailedEvent);
|
||||
}
|
||||
|
||||
private void UpdateStatusMessage(LogLevel logLevel, TrackedDownload trackedDownload, String message, params object[] args)
|
||||
{
|
||||
var statusMessage = String.Format(message, args);
|
||||
var logMessage = String.Format("[{0}] {1}", trackedDownload.DownloadItem.Title, message);
|
||||
|
||||
if (trackedDownload.StatusMessage != statusMessage)
|
||||
{
|
||||
trackedDownload.HasError = logLevel >= LogLevel.Warn;
|
||||
trackedDownload.StatusMessage = statusMessage;
|
||||
_logger.Log(logLevel, statusMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug(logMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace NzbDrone.Core.Download
|
|||
public DateTime StartedTracking { get; set; }
|
||||
public DateTime LastRetry { get; set; }
|
||||
public Int32 RetryCount { get; set; }
|
||||
public Boolean HasError { get; set; }
|
||||
public String StatusMessage { get; set; }
|
||||
}
|
||||
|
||||
public enum TrackedDownloadState
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_diskProvider.DeleteFolder(directoryInfo.FullName, true);
|
||||
}
|
||||
|
||||
return importedDecisions;
|
||||
return importedDecisions.Union(decisions).ToList();
|
||||
}
|
||||
|
||||
public List<ImportDecision> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem)
|
||||
|
@ -99,7 +99,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
var importedDecisions = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
|
||||
|
||||
return importedDecisions;
|
||||
return importedDecisions.Union(decisions).ToList();
|
||||
}
|
||||
|
||||
private void ProcessDownloadedEpisodesFolder()
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace NzbDrone.Core.Queue
|
|||
public Decimal Sizeleft { get; set; }
|
||||
public TimeSpan? Timeleft { get; set; }
|
||||
public String Status { get; set; }
|
||||
public String ErrorMessage { get; set; }
|
||||
public RemoteEpisode RemoteEpisode { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,32 +25,37 @@ namespace NzbDrone.Core.Queue
|
|||
public List<Queue> GetQueue()
|
||||
{
|
||||
var queueItems = _downloadTrackingService.GetQueuedDownloads()
|
||||
.Select(v => v.DownloadItem)
|
||||
.OrderBy(v => v.RemainingTime)
|
||||
.OrderBy(v => v.DownloadItem.RemainingTime)
|
||||
.ToList();
|
||||
|
||||
return MapQueue(queueItems);
|
||||
}
|
||||
|
||||
private List<Queue> MapQueue(IEnumerable<DownloadClientItem> queueItems)
|
||||
private List<Queue> MapQueue(IEnumerable<TrackedDownload> queueItems)
|
||||
{
|
||||
var queued = new List<Queue>();
|
||||
|
||||
foreach (var queueItem in queueItems)
|
||||
{
|
||||
foreach (var episode in queueItem.RemoteEpisode.Episodes)
|
||||
foreach (var episode in queueItem.DownloadItem.RemoteEpisode.Episodes)
|
||||
{
|
||||
var queue = new Queue();
|
||||
queue.Id = queueItem.DownloadClientId.GetHashCode() + episode.Id;
|
||||
queue.Series = queueItem.RemoteEpisode.Series;
|
||||
queue.Id = queueItem.DownloadItem.DownloadClientId.GetHashCode() + episode.Id;
|
||||
queue.Series = queueItem.DownloadItem.RemoteEpisode.Series;
|
||||
queue.Episode = episode;
|
||||
queue.Quality = queueItem.RemoteEpisode.ParsedEpisodeInfo.Quality;
|
||||
queue.Title = queueItem.Title;
|
||||
queue.Size = queueItem.TotalSize;
|
||||
queue.Sizeleft = queueItem.RemainingSize;
|
||||
queue.Timeleft = queueItem.RemainingTime;
|
||||
queue.Status = queueItem.Status.ToString();
|
||||
queue.RemoteEpisode = queueItem.RemoteEpisode;
|
||||
queue.Quality = queueItem.DownloadItem.RemoteEpisode.ParsedEpisodeInfo.Quality;
|
||||
queue.Title = queueItem.DownloadItem.Title;
|
||||
queue.Size = queueItem.DownloadItem.TotalSize;
|
||||
queue.Sizeleft = queueItem.DownloadItem.RemainingSize;
|
||||
queue.Timeleft = queueItem.DownloadItem.RemainingTime;
|
||||
queue.Status = queueItem.DownloadItem.Status.ToString();
|
||||
queue.RemoteEpisode = queueItem.DownloadItem.RemoteEpisode;
|
||||
|
||||
if (queueItem.HasError)
|
||||
{
|
||||
queue.ErrorMessage = queueItem.StatusMessage;
|
||||
}
|
||||
|
||||
queued.Add(queue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,6 +163,11 @@
|
|||
color : purple;
|
||||
}
|
||||
|
||||
.icon-nd-import-failed:before {
|
||||
.icon(@download-alt);
|
||||
color: @brand-danger;
|
||||
}
|
||||
|
||||
.icon-nd-download-failed:before {
|
||||
.icon(@cloud-download);
|
||||
color: @brand-danger;
|
||||
|
|
|
@ -13,6 +13,7 @@ define(
|
|||
|
||||
if (this.cellValue) {
|
||||
var status = this.cellValue.get('status').toLowerCase();
|
||||
var errorMessage = (this.cellValue.get('errorMessage') || '');
|
||||
var icon = 'icon-nd-downloading';
|
||||
var title = 'Downloading';
|
||||
|
||||
|
@ -31,7 +32,29 @@ define(
|
|||
title = 'Downloaded';
|
||||
}
|
||||
|
||||
this.$el.html('<i class="{0}" title="{1}"></i>'.format(icon, title));
|
||||
if (errorMessage !== '') {
|
||||
if (status === 'completed') {
|
||||
icon = 'icon-nd-import-failed';
|
||||
title = "Import failed";
|
||||
}
|
||||
else {
|
||||
icon = 'icon-nd-download-failed';
|
||||
title = "Download failed";
|
||||
}
|
||||
this.$el.html('<i class="{0}"></i>'.format(icon));
|
||||
|
||||
this.$el.popover({
|
||||
content : errorMessage.replace(new RegExp('\r\n', 'g'), '<br/>'),
|
||||
html : true,
|
||||
trigger : 'hover',
|
||||
title : title,
|
||||
placement: 'right',
|
||||
container: this.$el
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.$el.html('<i class="{0}" title="{1}"></i>'.format(icon, title));
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
|
|
|
@ -22,9 +22,8 @@ define(
|
|||
this.$el.html("-");
|
||||
}
|
||||
else {
|
||||
this.$el.html(timeleft);
|
||||
this.$el.html('<span title="{1} / {2}">{0}</span>'.format(timeleft, remainingSize, totalSize));
|
||||
}
|
||||
this.$el.attr('title', '{0} / {1}'.format(remainingSize, totalSize));
|
||||
}
|
||||
|
||||
return this;
|
||||
|
|
4
src/UI/History/history.less
Normal file
4
src/UI/History/history.less
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
.queue-status-cell .popover {
|
||||
max-width: 800px;
|
||||
}
|
|
@ -11,8 +11,7 @@ define(
|
|||
render: function () {
|
||||
|
||||
var date = Moment(this._getValue());
|
||||
this.$el.html(date.format('LT'));
|
||||
this.$el.attr('title', date.format('LLLL'));
|
||||
this.$el.html('<span title="{1}">{0}</span>'.format(date.format('LT'), date.format('LLLL')));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<link href="/Content/theme.css" rel='stylesheet' type='text/css'/>
|
||||
<link href="/Cells/cells.css" rel='stylesheet' type='text/css'>
|
||||
<link href="/Series/series.css" rel='stylesheet' type='text/css'/>
|
||||
<link href="/History/history.css" rel='stylesheet' type='text/css'/>
|
||||
<link href="/System/Logs/logs.css" rel='stylesheet' type='text/css'/>
|
||||
<link href="/Settings/settings.css" rel='stylesheet' type='text/css'/>
|
||||
<link href="/AddSeries/addSeries.css" rel='stylesheet' type='text/css'/>
|
||||
|
|
Loading…
Add table
Reference in a new issue