diff --git a/frontend/src/Activity/Queue/QueueRow.css b/frontend/src/Activity/Queue/QueueRow.css index 6aa4a1622..8c8f9e862 100644 --- a/frontend/src/Activity/Queue/QueueRow.css +++ b/frontend/src/Activity/Queue/QueueRow.css @@ -19,5 +19,5 @@ .actions { composes: cell from 'Components/Table/Cells/TableRowCell.css'; - width: 70px; + width: 90px; } diff --git a/frontend/src/Activity/Queue/QueueRow.js b/frontend/src/Activity/Queue/QueueRow.js index 086c633f6..0cbbe4d6d 100644 --- a/frontend/src/Activity/Queue/QueueRow.js +++ b/frontend/src/Activity/Queue/QueueRow.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { icons, kinds } from 'Helpers/Props'; +import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import IconButton from 'Components/Link/IconButton'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import ProgressBar from 'Components/ProgressBar'; @@ -8,6 +8,8 @@ import TableRow from 'Components/Table/TableRow'; import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector'; import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableSelectCell from 'Components/Table/Cells/TableSelectCell'; +import Icon from 'Components/Icon'; +import Popover from 'Components/Tooltip/Popover'; import ProtocolLabel from 'Activity/Queue/ProtocolLabel'; import AlbumTitleLink from 'Album/AlbumTitleLink'; import TrackQuality from 'Album/TrackQuality'; @@ -74,6 +76,7 @@ class QueueRow extends Component { protocol, indexer, downloadClient, + downloadForced, estimatedCompletionTime, timeleft, size, @@ -249,6 +252,21 @@ class QueueRow extends Component { key={name} className={styles.actions} > + { + downloadForced && + + } + title="Manual Download" + body="This release failed parsing checks and was manually downloaded from an interactive search. Import is likely to fail." + position={tooltipPositions.LEFT} + /> + } + { showInteractiveImport && diff --git a/frontend/src/InteractiveSearch/InteractiveSearchRow.js b/frontend/src/InteractiveSearch/InteractiveSearchRow.js index d12fabd52..09908e526 100644 --- a/frontend/src/InteractiveSearch/InteractiveSearchRow.js +++ b/frontend/src/InteractiveSearch/InteractiveSearchRow.js @@ -156,14 +156,13 @@ class InteractiveSearchRow extends Component { { - downloadAllowed && - + } diff --git a/src/Lidarr.Api.V1/Indexers/ReleaseModule.cs b/src/Lidarr.Api.V1/Indexers/ReleaseModule.cs index df6456c86..d1b817d94 100644 --- a/src/Lidarr.Api.V1/Indexers/ReleaseModule.cs +++ b/src/Lidarr.Api.V1/Indexers/ReleaseModule.cs @@ -46,7 +46,6 @@ namespace Lidarr.Api.V1.Indexers GetResourceAll = GetReleases; Post["/"] = x => DownloadRelease(this.Bind()); - PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true); PostValidator.RuleFor(s => s.IndexerId).ValidId(); PostValidator.RuleFor(s => s.Guid).NotEmpty(); diff --git a/src/Lidarr.Api.V1/Queue/QueueResource.cs b/src/Lidarr.Api.V1/Queue/QueueResource.cs index 2fd196d09..33318dc34 100644 --- a/src/Lidarr.Api.V1/Queue/QueueResource.cs +++ b/src/Lidarr.Api.V1/Queue/QueueResource.cs @@ -30,6 +30,7 @@ namespace Lidarr.Api.V1.Queue public DownloadProtocol Protocol { get; set; } public string DownloadClient { get; set; } public string Indexer { get; set; } + public bool DownloadForced { get; set; } } public static class QueueResourceMapper @@ -58,7 +59,8 @@ namespace Lidarr.Api.V1.Queue DownloadId = model.DownloadId, Protocol = model.Protocol, DownloadClient = model.DownloadClient, - Indexer = model.Indexer + Indexer = model.Indexer, + DownloadForced = model.DownloadForced }; } diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/PrioritizeDownloadDecisionFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/PrioritizeDownloadDecisionFixture.cs index d47e35072..287d5e985 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/PrioritizeDownloadDecisionFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/PrioritizeDownloadDecisionFixture.cs @@ -62,6 +62,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests Cutoff = Language.Spanish }).Build(); + remoteAlbum.DownloadAllowed = true; + return remoteAlbum; } diff --git a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs index f353f5fd2..572469309 100644 --- a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs +++ b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs @@ -94,10 +94,20 @@ namespace NzbDrone.Core.DecisionEngine if (remoteAlbum.Artist == null) { decision = new DownloadDecision(remoteAlbum, new Rejection("Unknown Artist")); + // shove in the searched artist in case of forced download in interactive search + if (searchCriteria != null) + { + remoteAlbum.Artist = searchCriteria.Artist; + remoteAlbum.Albums = searchCriteria.Albums; + } } else if (remoteAlbum.Albums.Empty()) { decision = new DownloadDecision(remoteAlbum, new Rejection("Unable to parse albums from release name")); + if (searchCriteria != null) + { + remoteAlbum.Albums = searchCriteria.Albums; + } } else { diff --git a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs index 710cdf2db..dccb46d94 100644 --- a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs +++ b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs @@ -21,13 +21,13 @@ namespace NzbDrone.Core.DecisionEngine public List PrioritizeDecisions(List decisions) { - return decisions.Where(c => c.RemoteAlbum.Artist != null) + return decisions.Where(c => c.RemoteAlbum.DownloadAllowed) .GroupBy(c => c.RemoteAlbum.Artist.Id, (artistId, downloadDecisions) => { return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService)); }) .SelectMany(c => c) - .Union(decisions.Where(c => c.RemoteAlbum.Artist == null)) + .Union(decisions.Where(c => !c.RemoteAlbum.DownloadAllowed)) .ToList(); } } diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index f21c6525d..5f0bc45cb 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -162,6 +162,7 @@ namespace NzbDrone.Core.History history.Data.Add("DownloadUrl", message.Album.Release.DownloadUrl); history.Data.Add("Guid", message.Album.Release.Guid); history.Data.Add("Protocol", ((int)message.Album.Release.DownloadProtocol).ToString()); + history.Data.Add("DownloadForced", (!message.Album.DownloadAllowed).ToString()); if (!message.Album.ParsedAlbumInfo.ReleaseHash.IsNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/Queue/Queue.cs b/src/NzbDrone.Core/Queue/Queue.cs index 2bdddbe22..1ba20977a 100644 --- a/src/NzbDrone.Core/Queue/Queue.cs +++ b/src/NzbDrone.Core/Queue/Queue.cs @@ -28,5 +28,6 @@ namespace NzbDrone.Core.Queue public string DownloadClient { get; set; } public string Indexer { get; set; } public string ErrorMessage { get; set; } + public bool DownloadForced { get; set; } } } diff --git a/src/NzbDrone.Core/Queue/QueueService.cs b/src/NzbDrone.Core/Queue/QueueService.cs index 2b3a1ce7a..a1d41788f 100644 --- a/src/NzbDrone.Core/Queue/QueueService.cs +++ b/src/NzbDrone.Core/Queue/QueueService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Common.Crypto; using NzbDrone.Core.Download.TrackedDownloads; +using NzbDrone.Core.History; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Music; @@ -19,10 +20,13 @@ namespace NzbDrone.Core.Queue { private readonly IEventAggregator _eventAggregator; private static List _queue = new List(); + private readonly IHistoryService _historyService; - public QueueService(IEventAggregator eventAggregator) + public QueueService(IEventAggregator eventAggregator, + IHistoryService historyService) { _eventAggregator = eventAggregator; + _historyService = historyService; } public List GetQueue() @@ -65,6 +69,13 @@ namespace NzbDrone.Core.Queue private Queue MapAlbum(TrackedDownload trackedDownload, Album album) { + bool downloadForced = false; + var history = _historyService.Find(trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed).FirstOrDefault(); + if (history != null && history.Data.ContainsKey("downloadForced")) + { + downloadForced = bool.Parse(history.Data["downloadForced"]); + } + var queue = new Queue { Id = HashConverter.GetHashInt31(string.Format("trackedDownload-{0}-album{1}", trackedDownload.DownloadItem.DownloadId, album.Id)), @@ -83,7 +94,8 @@ namespace NzbDrone.Core.Queue DownloadId = trackedDownload.DownloadItem.DownloadId, Protocol = trackedDownload.Protocol, DownloadClient = trackedDownload.DownloadItem.DownloadClient, - Indexer = trackedDownload.Indexer + Indexer = trackedDownload.Indexer, + DownloadForced = downloadForced }; if (queue.Timeleft.HasValue)