using System; using System.Linq; using NzbDrone.Common.Extensions; using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.Download.Pending; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Queue; using NzbDrone.SignalR; using Lidarr.Http; using Lidarr.Http.Extensions; namespace Lidarr.Api.V3.Queue { public class QueueModule : LidarrRestModuleWithSignalR, IHandle, IHandle { private readonly IQueueService _queueService; private readonly IPendingReleaseService _pendingReleaseService; public QueueModule(IBroadcastSignalRMessage broadcastSignalRMessage, IQueueService queueService, IPendingReleaseService pendingReleaseService) : base(broadcastSignalRMessage) { _queueService = queueService; _pendingReleaseService = pendingReleaseService; GetResourcePaged = GetQueue; } private PagingResource GetQueue(PagingResource pagingResource) { var pagingSpec = pagingResource.MapToPagingSpec("timeleft", SortDirection.Ascending); var includeSeries = Request.GetBooleanQueryParameter("includeSeries"); var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode"); return ApplyToPage(GetQueue, pagingSpec, (q) => MapToResource(q, includeSeries, includeEpisode)); } private PagingSpec GetQueue(PagingSpec pagingSpec) { var ascending = pagingSpec.SortDirection == SortDirection.Ascending; var orderByFunc = GetOrderByFunc(pagingSpec); var queue = _queueService.GetQueue(); var pending = _pendingReleaseService.GetPendingQueue(); var fullQueue = queue.Concat(pending).ToList(); IOrderedEnumerable ordered; if (pagingSpec.SortKey == "timeleft") { ordered = ascending ? fullQueue.OrderBy(q => q.Timeleft, new TimeleftComparer()) : fullQueue.OrderByDescending(q => q.Timeleft, new TimeleftComparer()); } else if (pagingSpec.SortKey == "estimatedCompletionTime") { ordered = ascending ? fullQueue.OrderBy(q => q.EstimatedCompletionTime, new EstimatedCompletionTimeComparer()) : fullQueue.OrderByDescending(q => q.EstimatedCompletionTime, new EstimatedCompletionTimeComparer()); } else { ordered = ascending ? fullQueue.OrderBy(orderByFunc) : fullQueue.OrderByDescending(orderByFunc); } ordered = ordered.ThenByDescending(q => 100 - q.Sizeleft / q.Size * 100); pagingSpec.Records = ordered.Skip((pagingSpec.Page - 1) * pagingSpec.PageSize).Take(pagingSpec.PageSize).ToList(); pagingSpec.TotalRecords = fullQueue.Count; if (pagingSpec.Records.Empty() && pagingSpec.Page > 1) { pagingSpec.Page = (int)Math.Max(Math.Ceiling((decimal)(pagingSpec.TotalRecords / pagingSpec.PageSize)), 1); pagingSpec.Records = ordered.Skip((pagingSpec.Page - 1) * pagingSpec.PageSize).Take(pagingSpec.PageSize).ToList(); } return pagingSpec; } private Func GetOrderByFunc(PagingSpec pagingSpec) { switch (pagingSpec.SortKey) { case "series.sortTitle": return q => q.Artist.SortName; case "episode": return q => q.Album; case "episode.title": return q => q.Album.Title; case "quality": return q => q.Quality; case "progress": return q => 100 - q.Sizeleft / q.Size * 100; default: return q => q.Timeleft; } } private QueueResource MapToResource(NzbDrone.Core.Queue.Queue queueItem, bool includeSeries, bool includeEpisode) { return queueItem.ToResource(includeSeries, includeEpisode); } public void Handle(QueueUpdatedEvent message) { BroadcastResourceChange(ModelAction.Sync); } public void Handle(PendingReleasesUpdatedEvent message) { BroadcastResourceChange(ModelAction.Sync); } } }