From c21ffcb5e4038c8cfa5cb116a4b26f8d53752a48 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 1 Aug 2014 18:08:32 -0700 Subject: [PATCH] New: Show processing time for pending items on Calendar and Queue --- src/NzbDrone.Api/Queue/QueueResource.cs | 2 +- .../Download/Pending/PendingReleaseService.cs | 12 ++++----- src/NzbDrone.Core/Queue/Queue.cs | 1 + src/NzbDrone.Core/Queue/QueueService.cs | 10 ++++++-- src/UI/Calendar/CalendarView.js | 25 ++++++++++++++++++- src/UI/Calendar/calendar.less | 4 +++ src/UI/History/Queue/TimeleftCell.js | 7 +++--- 7 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/NzbDrone.Api/Queue/QueueResource.cs b/src/NzbDrone.Api/Queue/QueueResource.cs index 72df87f84..0cc002347 100644 --- a/src/NzbDrone.Api/Queue/QueueResource.cs +++ b/src/NzbDrone.Api/Queue/QueueResource.cs @@ -1,7 +1,6 @@ using System; using NzbDrone.Api.REST; using NzbDrone.Core.Qualities; -using NzbDrone.Core.Tv; using NzbDrone.Api.Series; using NzbDrone.Api.Episodes; @@ -16,6 +15,7 @@ namespace NzbDrone.Api.Queue public String Title { get; set; } public Decimal Sizeleft { get; set; } public TimeSpan? Timeleft { get; set; } + public DateTime? EstimatedCompletionTime { get; set; } public String Status { get; set; } public String ErrorMessage { get; set; } } diff --git a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs index 9be579624..a800bfe84 100644 --- a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs +++ b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs @@ -29,21 +29,18 @@ namespace NzbDrone.Core.Download.Pending private readonly IPendingReleaseRepository _repository; private readonly ISeriesService _seriesService; private readonly IParsingService _parsingService; - private readonly IDownloadService _downloadService; private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; public PendingReleaseService(IPendingReleaseRepository repository, ISeriesService seriesService, IParsingService parsingService, - IDownloadService downloadService, IEventAggregator eventAggregator, Logger logger) { _repository = repository; _seriesService = seriesService; _parsingService = parsingService; - _downloadService = downloadService; _eventAggregator = eventAggregator; _logger = logger; } @@ -141,6 +138,9 @@ namespace NzbDrone.Core.Download.Pending { foreach (var episode in pendingRelease.RemoteEpisode.Episodes) { + var ect = pendingRelease.Release.PublishDate.AddHours( + pendingRelease.RemoteEpisode.Series.Profile.Value.GrabDelay); + var queue = new Queue.Queue { Id = episode.Id ^ (pendingRelease.Id << 16), @@ -150,10 +150,8 @@ namespace NzbDrone.Core.Download.Pending Title = pendingRelease.Title, Size = pendingRelease.RemoteEpisode.Release.Size, Sizeleft = pendingRelease.RemoteEpisode.Release.Size, - Timeleft = - pendingRelease.Release.PublishDate.AddHours( - pendingRelease.RemoteEpisode.Series.Profile.Value.GrabDelay) - .Subtract(DateTime.UtcNow), + Timeleft = ect.Subtract(DateTime.UtcNow), + EstimatedCompletionTime = ect, Status = "Pending", RemoteEpisode = pendingRelease.RemoteEpisode }; diff --git a/src/NzbDrone.Core/Queue/Queue.cs b/src/NzbDrone.Core/Queue/Queue.cs index 0cc67c2dc..de889939e 100644 --- a/src/NzbDrone.Core/Queue/Queue.cs +++ b/src/NzbDrone.Core/Queue/Queue.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.Queue public String Title { get; set; } public Decimal Sizeleft { get; set; } public TimeSpan? Timeleft { get; set; } + public DateTime? EstimatedCompletionTime { get; set; } public String Status { get; set; } public String ErrorMessage { get; set; } public RemoteEpisode RemoteEpisode { get; set; } diff --git a/src/NzbDrone.Core/Queue/QueueService.cs b/src/NzbDrone.Core/Queue/QueueService.cs index f7dac3139..bf36068de 100644 --- a/src/NzbDrone.Core/Queue/QueueService.cs +++ b/src/NzbDrone.Core/Queue/QueueService.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Collections.Generic; using NLog; using NzbDrone.Core.Download; @@ -52,11 +53,16 @@ namespace NzbDrone.Core.Queue RemoteEpisode = queueItem.DownloadItem.RemoteEpisode }; - if (queueItem.HasError) + if (queueItem.HasError) { queue.ErrorMessage = queueItem.StatusMessage; } + if (queue.Timeleft.HasValue) + { + queue.EstimatedCompletionTime = DateTime.UtcNow.Add(queue.Timeleft.Value); + } + queued.Add(queue); } } diff --git a/src/UI/Calendar/CalendarView.js b/src/UI/Calendar/CalendarView.js index c6dc6de65..3378da240 100644 --- a/src/UI/Calendar/CalendarView.js +++ b/src/UI/Calendar/CalendarView.js @@ -10,10 +10,11 @@ define( 'System/StatusModel', 'History/Queue/QueueCollection', 'Config', + 'Shared/FormatHelpers', 'Mixins/backbone.signalr.mixin', 'fullcalendar', 'jquery.easypiechart' - ], function ($, vent, Marionette, moment, CalendarCollection, StatusModel, QueueCollection, Config) { + ], function ($, vent, Marionette, moment, CalendarCollection, StatusModel, QueueCollection, Config, FormatHelpers) { return Marionette.ItemView.extend({ storageKey: 'calendar.view', @@ -62,6 +63,16 @@ define( container: 'body' }); } + + if (event.pending) { + this.$(element).find('.fc-event-time') + .after(''); + + this.$(element).find('.pending').tooltip({ + title: 'Release will be processed {0}'.format(event.pending), + container: 'body' + }); + } }, _getEvents: function (view) { @@ -94,7 +105,9 @@ define( allDay : false, statusLevel : self._getStatusLevel(model, end), progress : self._getDownloadProgress(model), + pending : self._getPendingInfo(model), releaseTitle: self._getReleaseTitle(model), + downloading : QueueCollection.findEpisode(model.get('id')), model : model }; @@ -151,6 +164,16 @@ define( return 100 - (downloading.get('sizeleft') / downloading.get('size') * 100); }, + _getPendingInfo: function (element) { + var pending = QueueCollection.findEpisode(element.get('id')); + + if (!pending || pending.get('status').toLocaleLowerCase() !== 'pending') { + return undefined; + } + + return new moment(pending.get('estimatedCompletionTime')).fromNow(); + }, + _getReleaseTitle: function (element) { var downloading = QueueCollection.findEpisode(element.get('id')); diff --git a/src/UI/Calendar/calendar.less b/src/UI/Calendar/calendar.less index 865206cb8..82525175c 100644 --- a/src/UI/Calendar/calendar.less +++ b/src/UI/Calendar/calendar.less @@ -21,6 +21,10 @@ .fc-event { .clickable; + + .pending { + margin-right : 4px; + } } th { diff --git a/src/UI/History/Queue/TimeleftCell.js b/src/UI/History/Queue/TimeleftCell.js index 043efdf52..892ed690d 100644 --- a/src/UI/History/Queue/TimeleftCell.js +++ b/src/UI/History/Queue/TimeleftCell.js @@ -3,8 +3,9 @@ define( [ 'Cells/NzbDroneCell', - 'filesize' - ], function (NzbDroneCell, fileSize) { + 'filesize', + 'moment' + ], function (NzbDroneCell, fileSize, Moment) { return NzbDroneCell.extend({ className: 'timeleft-cell', @@ -17,7 +18,7 @@ define( //If the release is pending we want to use the timeleft as the time it will be processed at if (this.cellValue.get('status').toLowerCase() === 'pending') { this.$el.html('-'); - this.$el.attr('title', 'Will be processed again in: {0}'.format(this.cellValue.get('timeleft'))); + this.$el.attr('title', 'Will be processed {0}'.format(new Moment(this.cellValue.get('estimatedCompletionTime')).calendar())); this.$el.attr('data-container', 'body'); return this;