diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderRow.js b/frontend/src/Components/Filter/Builder/FilterBuilderRow.js index 7110dddf3..0b00c0f03 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderRow.js +++ b/frontend/src/Components/Filter/Builder/FilterBuilderRow.js @@ -13,6 +13,7 @@ import LanguageFilterBuilderRowValue from './LanguageFilterBuilderRowValue'; import ProtocolFilterBuilderRowValue from './ProtocolFilterBuilderRowValue'; import QualityFilterBuilderRowValueConnector from './QualityFilterBuilderRowValueConnector'; import QualityProfileFilterBuilderRowValue from './QualityProfileFilterBuilderRowValue'; +import QueueStatusFilterBuilderRowValue from './QueueStatusFilterBuilderRowValue'; import SeasonsMonitoredStatusFilterBuilderRowValue from './SeasonsMonitoredStatusFilterBuilderRowValue'; import SeriesFilterBuilderRowValue from './SeriesFilterBuilderRowValue'; import SeriesStatusFilterBuilderRowValue from './SeriesStatusFilterBuilderRowValue'; @@ -80,6 +81,9 @@ function getRowValueConnector(selectedFilterBuilderProp) { case filterBuilderValueTypes.QUALITY_PROFILE: return QualityProfileFilterBuilderRowValue; + case filterBuilderValueTypes.QUEUE_STATUS: + return QueueStatusFilterBuilderRowValue; + case filterBuilderValueTypes.SEASONS_MONITORED_STATUS: return SeasonsMonitoredStatusFilterBuilderRowValue; diff --git a/frontend/src/Components/Filter/Builder/QueueStatusFilterBuilderRowValue.tsx b/frontend/src/Components/Filter/Builder/QueueStatusFilterBuilderRowValue.tsx new file mode 100644 index 000000000..1127493a5 --- /dev/null +++ b/frontend/src/Components/Filter/Builder/QueueStatusFilterBuilderRowValue.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import translate from 'Utilities/String/translate'; +import FilterBuilderRowValue from './FilterBuilderRowValue'; +import FilterBuilderRowValueProps from './FilterBuilderRowValueProps'; + +const statusTagList = [ + { + id: 'queued', + get name() { + return translate('Queued'); + }, + }, + { + id: 'paused', + get name() { + return translate('Paused'); + }, + }, + { + id: 'downloading', + get name() { + return translate('Downloading'); + }, + }, + { + id: 'completed', + get name() { + return translate('Completed'); + }, + }, + { + id: 'failed', + get name() { + return translate('Failed'); + }, + }, + { + id: 'warning', + get name() { + return translate('Warning'); + }, + }, + { + id: 'delay', + get name() { + return translate('Delay'); + }, + }, + { + id: 'downloadClientUnavailable', + get name() { + return translate('DownloadClientUnavailable'); + }, + }, + { + id: 'fallback', + get name() { + return translate('Fallback'); + }, + }, +]; + +function QueueStatusFilterBuilderRowValue(props: FilterBuilderRowValueProps) { + return ; +} + +export default QueueStatusFilterBuilderRowValue; diff --git a/frontend/src/Components/Filter/Builder/SeriesStatusFilterBuilderRowValue.js b/frontend/src/Components/Filter/Builder/SeriesStatusFilterBuilderRowValue.js index 3464300f1..e017f72e7 100644 --- a/frontend/src/Components/Filter/Builder/SeriesStatusFilterBuilderRowValue.js +++ b/frontend/src/Components/Filter/Builder/SeriesStatusFilterBuilderRowValue.js @@ -2,7 +2,7 @@ import React from 'react'; import translate from 'Utilities/String/translate'; import FilterBuilderRowValue from './FilterBuilderRowValue'; -const seriesStatusList = [ +const statusTagList = [ { id: 'continuing', get name() { @@ -32,7 +32,7 @@ const seriesStatusList = [ function SeriesStatusFilterBuilderRowValue(props) { return ( ); diff --git a/frontend/src/Helpers/Props/filterBuilderValueTypes.js b/frontend/src/Helpers/Props/filterBuilderValueTypes.js index d9a5d58c7..a6666ba03 100644 --- a/frontend/src/Helpers/Props/filterBuilderValueTypes.js +++ b/frontend/src/Helpers/Props/filterBuilderValueTypes.js @@ -8,6 +8,7 @@ export const LANGUAGE = 'language'; export const PROTOCOL = 'protocol'; export const QUALITY = 'quality'; export const QUALITY_PROFILE = 'qualityProfile'; +export const QUEUE_STATUS = 'queueStatus'; export const SEASONS_MONITORED_STATUS = 'seasonsMonitoredStatus'; export const SERIES = 'series'; export const SERIES_STATUS = 'seriesStatus'; diff --git a/frontend/src/Store/Actions/queueActions.js b/frontend/src/Store/Actions/queueActions.js index 5f91318ad..ca97e5213 100644 --- a/frontend/src/Store/Actions/queueActions.js +++ b/frontend/src/Store/Actions/queueActions.js @@ -212,6 +212,12 @@ export const defaultState = { label: () => translate('Protocol'), type: filterBuilderTypes.EQUAL, valueType: filterBuilderValueTypes.PROTOCOL + }, + { + name: 'status', + label: () => translate('Status'), + type: filterBuilderTypes.EQUAL, + valueType: filterBuilderValueTypes.QUEUE_STATUS } ] } diff --git a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs index 8b6592f73..47d8d0755 100644 --- a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs +++ b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs @@ -15,6 +15,7 @@ using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Qualities; +using NzbDrone.Core.Queue; using NzbDrone.Core.Tv; using NzbDrone.Core.Tv.Events; @@ -389,7 +390,7 @@ namespace NzbDrone.Core.Download.Pending Timeleft = timeleft, EstimatedCompletionTime = ect, Added = pendingRelease.Added, - Status = pendingRelease.Reason.ToString(), + Status = Enum.TryParse(pendingRelease.Reason.ToString(), out QueueStatus outValue) ? outValue : QueueStatus.Unknown, Protocol = pendingRelease.RemoteEpisode.Release.DownloadProtocol, Indexer = pendingRelease.RemoteEpisode.Release.Indexer, DownloadClient = downloadClientName diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 41969de5d..a478ad5b3 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -323,6 +323,7 @@ "DefaultNameCopiedProfile": "{name} - Copy", "DefaultNameCopiedSpecification": "{name} - Copy", "DefaultNotFoundMessage": "You must be lost, nothing to see here.", + "Delay": "Delay", "DelayMinutes": "{delay} Minutes", "DelayProfile": "Delay Profile", "DelayProfileProtocol": "Protocol: {preferredProtocol}", @@ -541,6 +542,7 @@ "DownloadClientStatusSingleClientHealthCheckMessage": "Download clients unavailable due to failures: {downloadClientNames}", "DownloadClientTransmissionSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Transmission location", "DownloadClientTransmissionSettingsUrlBaseHelpText": "Adds a prefix to the {clientName} rpc url, eg {url}, defaults to '{defaultUrl}'", + "DownloadClientUnavailable": "Download Client Unavailable", "DownloadClientUTorrentTorrentStateError": "uTorrent is reporting an error", "DownloadClientValidationApiKeyIncorrect": "API Key Incorrect", "DownloadClientValidationApiKeyRequired": "API Key Required", @@ -689,6 +691,7 @@ "FailedToLoadTagsFromApi": "Failed to load tags from API", "FailedToLoadTranslationsFromApi": "Failed to load translations from API", "FailedToLoadUiSettingsFromApi": "Failed to load UI settings from API", + "Fallback": "Fallback", "False": "False", "FavoriteFolderAdd": "Add Favorite Folder", "FavoriteFolderRemove": "Remove Favorite Folder", @@ -2114,6 +2117,7 @@ "WantMoreControlAddACustomFormat": "Want more control over which downloads are preferred? Add a [Custom Format](/settings/customformats)", "Wanted": "Wanted", "Warn": "Warn", + "Warning": "Warning", "Week": "Week", "WeekColumnHeader": "Week Column Header", "WeekColumnHeaderHelpText": "Shown above each column when week is the active view", diff --git a/src/NzbDrone.Core/Queue/Queue.cs b/src/NzbDrone.Core/Queue/Queue.cs index c5d2a123a..c38749678 100644 --- a/src/NzbDrone.Core/Queue/Queue.cs +++ b/src/NzbDrone.Core/Queue/Queue.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Queue public TimeSpan? Timeleft { get; set; } public DateTime? EstimatedCompletionTime { get; set; } public DateTime? Added { get; set; } - public string Status { get; set; } + public QueueStatus Status { get; set; } public TrackedDownloadStatus? TrackedDownloadStatus { get; set; } public TrackedDownloadState? TrackedDownloadState { get; set; } public List StatusMessages { get; set; } diff --git a/src/NzbDrone.Core/Queue/QueueService.cs b/src/NzbDrone.Core/Queue/QueueService.cs index 8bb11a13c..7142bd03c 100644 --- a/src/NzbDrone.Core/Queue/QueueService.cs +++ b/src/NzbDrone.Core/Queue/QueueService.cs @@ -69,7 +69,7 @@ namespace NzbDrone.Core.Queue Size = trackedDownload.DownloadItem.TotalSize, Sizeleft = trackedDownload.DownloadItem.RemainingSize, Timeleft = trackedDownload.DownloadItem.RemainingTime, - Status = trackedDownload.DownloadItem.Status.ToString(), + Status = Enum.TryParse(trackedDownload.DownloadItem.Status.ToString(), out QueueStatus outValue) ? outValue : QueueStatus.Unknown, TrackedDownloadStatus = trackedDownload.Status, TrackedDownloadState = trackedDownload.State, StatusMessages = trackedDownload.StatusMessages.ToList(), diff --git a/src/NzbDrone.Core/Queue/QueueStatus.cs b/src/NzbDrone.Core/Queue/QueueStatus.cs new file mode 100644 index 000000000..77b0751d9 --- /dev/null +++ b/src/NzbDrone.Core/Queue/QueueStatus.cs @@ -0,0 +1,16 @@ +namespace NzbDrone.Core.Queue +{ + public enum QueueStatus + { + Unknown, + Queued, + Paused, + Downloading, + Completed, + Failed, + Warning, + Delay, + DownloadClientUnavailable, + Fallback + } +} diff --git a/src/Sonarr.Api.V3/Queue/QueueController.cs b/src/Sonarr.Api.V3/Queue/QueueController.cs index 0fc12bb14..6c7438203 100644 --- a/src/Sonarr.Api.V3/Queue/QueueController.cs +++ b/src/Sonarr.Api.V3/Queue/QueueController.cs @@ -136,7 +136,7 @@ namespace Sonarr.Api.V3.Queue [HttpGet] [Produces("application/json")] - public PagingResource GetQueue([FromQuery] PagingRequestResource paging, bool includeUnknownSeriesItems = false, bool includeSeries = false, bool includeEpisode = false, [FromQuery] int[] seriesIds = null, DownloadProtocol? protocol = null, [FromQuery] int[] languages = null, [FromQuery] int[] quality = null) + public PagingResource GetQueue([FromQuery] PagingRequestResource paging, bool includeUnknownSeriesItems = false, bool includeSeries = false, bool includeEpisode = false, [FromQuery] int[] seriesIds = null, DownloadProtocol? protocol = null, [FromQuery] int[] languages = null, [FromQuery] int[] quality = null, [FromQuery] QueueStatus[] status = null) { var pagingResource = new PagingResource(paging); var pagingSpec = pagingResource.MapToPagingSpec( @@ -165,10 +165,10 @@ namespace Sonarr.Api.V3.Queue "timeleft", SortDirection.Ascending); - return pagingSpec.ApplyToPage((spec) => GetQueue(spec, seriesIds?.ToHashSet(), protocol, languages?.ToHashSet(), quality?.ToHashSet(), includeUnknownSeriesItems), (q) => MapToResource(q, includeSeries, includeEpisode)); + return pagingSpec.ApplyToPage((spec) => GetQueue(spec, seriesIds?.ToHashSet(), protocol, languages?.ToHashSet(), quality?.ToHashSet(), status?.ToHashSet(), includeUnknownSeriesItems), (q) => MapToResource(q, includeSeries, includeEpisode)); } - private PagingSpec GetQueue(PagingSpec pagingSpec, HashSet seriesIds, DownloadProtocol? protocol, HashSet languages, HashSet quality, bool includeUnknownSeriesItems) + private PagingSpec GetQueue(PagingSpec pagingSpec, HashSet seriesIds, DownloadProtocol? protocol, HashSet languages, HashSet quality, HashSet status, bool includeUnknownSeriesItems) { var ascending = pagingSpec.SortDirection == SortDirection.Ascending; var orderByFunc = GetOrderByFunc(pagingSpec); @@ -180,6 +180,7 @@ namespace Sonarr.Api.V3.Queue var hasSeriesIdFilter = seriesIds.Any(); var hasLanguageFilter = languages.Any(); var hasQualityFilter = quality.Any(); + var hasStatusFilter = status.Any(); var fullQueue = filteredQueue.Concat(pending).Where(q => { @@ -205,6 +206,11 @@ namespace Sonarr.Api.V3.Queue include &= quality.Contains(q.Quality.Quality.Id); } + if (include && hasStatusFilter) + { + include &= status.Contains(q.Status); + } + return include; }).ToList(); diff --git a/src/Sonarr.Api.V3/Queue/QueueResource.cs b/src/Sonarr.Api.V3/Queue/QueueResource.cs index e5152f1d7..5a0e47e20 100644 --- a/src/Sonarr.Api.V3/Queue/QueueResource.cs +++ b/src/Sonarr.Api.V3/Queue/QueueResource.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Common.Extensions; using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Indexers; using NzbDrone.Core.Languages; using NzbDrone.Core.Qualities; +using NzbDrone.Core.Queue; using Sonarr.Api.V3.CustomFormats; using Sonarr.Api.V3.Episodes; using Sonarr.Api.V3.Series; @@ -30,7 +30,7 @@ namespace Sonarr.Api.V3.Queue public TimeSpan? Timeleft { get; set; } public DateTime? EstimatedCompletionTime { get; set; } public DateTime? Added { get; set; } - public string Status { get; set; } + public QueueStatus Status { get; set; } public TrackedDownloadStatus? TrackedDownloadStatus { get; set; } public TrackedDownloadState? TrackedDownloadState { get; set; } public List StatusMessages { get; set; } @@ -74,7 +74,7 @@ namespace Sonarr.Api.V3.Queue Timeleft = model.Timeleft, EstimatedCompletionTime = model.EstimatedCompletionTime, Added = model.Added, - Status = model.Status.FirstCharToLower(), + Status = model.Status, TrackedDownloadStatus = model.TrackedDownloadStatus, TrackedDownloadState = model.TrackedDownloadState, StatusMessages = model.StatusMessages,