diff --git a/frontend/src/Activity/Queue/Queue.js b/frontend/src/Activity/Queue/Queue.js
index c4463dbff..7d16d75a0 100644
--- a/frontend/src/Activity/Queue/Queue.js
+++ b/frontend/src/Activity/Queue/Queue.js
@@ -279,6 +279,17 @@ class Queue extends Component {
return !!(item && item.seriesId && item.episodeId);
})
)}
+ allPending={isConfirmRemoveModalOpen && (
+ selectedIds.every((id) => {
+ const item = items.find((i) => i.id === id);
+
+ if (!item) {
+ return false;
+ }
+
+ return item.status === 'delay' || item.status === 'downloadClientUnavailable';
+ })
+ )}
onRemovePress={this.onRemoveSelectedConfirmed}
onModalClose={this.onConfirmRemoveModalClose}
/>
diff --git a/frontend/src/Activity/Queue/QueueRow.js b/frontend/src/Activity/Queue/QueueRow.js
index c8a808456..8e6a0ac2f 100644
--- a/frontend/src/Activity/Queue/QueueRow.js
+++ b/frontend/src/Activity/Queue/QueueRow.js
@@ -377,6 +377,7 @@ class QueueRow extends Component {
isOpen={isRemoveQueueItemModalOpen}
sourceTitle={title}
canIgnore={!!series}
+ isPending={isPending}
onRemovePress={this.onRemoveQueueItemModalConfirmed}
onModalClose={this.onRemoveQueueItemModalClose}
/>
diff --git a/frontend/src/Activity/Queue/RemoveQueueItemModal.js b/frontend/src/Activity/Queue/RemoveQueueItemModal.js
index 988748c6e..c2e71a48d 100644
--- a/frontend/src/Activity/Queue/RemoveQueueItemModal.js
+++ b/frontend/src/Activity/Queue/RemoveQueueItemModal.js
@@ -65,7 +65,8 @@ class RemoveQueueItemModal extends Component {
const {
isOpen,
sourceTitle,
- canIgnore
+ canIgnore,
+ isPending
} = this.props;
const { remove, blocklist } = this.state;
@@ -88,18 +89,22 @@ class RemoveQueueItemModal extends Component {
Are you sure you want to remove '{sourceTitle}' from the queue?
-
- Remove From Download Client
+ {
+ isPending ?
+ null :
+
+ Remove From Download Client
-
-
+
+
+ }
Add Release To Blocklist
@@ -137,6 +142,7 @@ RemoveQueueItemModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
sourceTitle: PropTypes.string.isRequired,
canIgnore: PropTypes.bool.isRequired,
+ isPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
diff --git a/frontend/src/Activity/Queue/RemoveQueueItemsModal.js b/frontend/src/Activity/Queue/RemoveQueueItemsModal.js
index 5bf18a7d6..b80427ffe 100644
--- a/frontend/src/Activity/Queue/RemoveQueueItemsModal.js
+++ b/frontend/src/Activity/Queue/RemoveQueueItemsModal.js
@@ -66,7 +66,8 @@ class RemoveQueueItemsModal extends Component {
const {
isOpen,
selectedCount,
- canIgnore
+ canIgnore,
+ allPending
} = this.props;
const { remove, blocklist } = this.state;
@@ -89,18 +90,22 @@ class RemoveQueueItemsModal extends Component {
Are you sure you want to remove {selectedCount} item{selectedCount > 1 ? 's' : ''} from the queue?
-
- Remove From Download Client
+ {
+ allPending ?
+ null :
+
+ Remove From Download Client
-
-
+
+
+ }
@@ -140,6 +145,7 @@ RemoveQueueItemsModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
selectedCount: PropTypes.number.isRequired,
canIgnore: PropTypes.bool.isRequired,
+ allPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
diff --git a/src/NzbDrone.Core/Blocklisting/BlocklistService.cs b/src/NzbDrone.Core/Blocklisting/BlocklistService.cs
index b03179045..a4fb72b6d 100644
--- a/src/NzbDrone.Core/Blocklisting/BlocklistService.cs
+++ b/src/NzbDrone.Core/Blocklisting/BlocklistService.cs
@@ -16,6 +16,7 @@ namespace NzbDrone.Core.Blocklisting
{
bool Blocklisted(int seriesId, ReleaseInfo release);
PagingSpec Paged(PagingSpec pagingSpec);
+ void Block(RemoteEpisode remoteEpisode, string message);
void Delete(int id);
void Delete(List ids);
}
@@ -61,6 +62,32 @@ namespace NzbDrone.Core.Blocklisting
return _blocklistRepository.GetPaged(pagingSpec);
}
+ public void Block(RemoteEpisode remoteEpisode, string message)
+ {
+ var blocklist = new Blocklist
+ {
+ SeriesId = remoteEpisode.Series.Id,
+ EpisodeIds = remoteEpisode.Episodes.Select(e => e.Id).ToList(),
+ SourceTitle = remoteEpisode.Release.Title,
+ Quality = remoteEpisode.ParsedEpisodeInfo.Quality,
+ Date = DateTime.UtcNow,
+ PublishedDate = remoteEpisode.Release.PublishDate,
+ Size = remoteEpisode.Release.Size,
+ Indexer = remoteEpisode.Release.Indexer,
+ Protocol = remoteEpisode.Release.DownloadProtocol,
+ Message = message,
+ Language = remoteEpisode.ParsedEpisodeInfo.Language
+ };
+
+
+ if (remoteEpisode.Release is TorrentInfo torrentRelease)
+ {
+ blocklist.TorrentInfoHash = torrentRelease.InfoHash;
+ }
+
+ _blocklistRepository.Insert(blocklist);
+ }
+
public void Delete(int id)
{
_blocklistRepository.Delete(id);
diff --git a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs
index d0ca1be47..59267fd7e 100644
--- a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs
+++ b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs
@@ -130,13 +130,6 @@ namespace NzbDrone.Core.Download.Pending
}
}
- private ILookup CreateEpisodeLookup(IEnumerable alreadyPending)
- {
- return alreadyPending.SelectMany(v => v.RemoteEpisode.Episodes
- .Select(d => new { Episode = d, PendingRelease = v }))
- .ToLookup(v => v.Episode.Id, v => v.PendingRelease);
- }
-
public List GetPending()
{
var releases = _repository.All().Select(p => p.Release).ToList();
@@ -149,13 +142,6 @@ namespace NzbDrone.Core.Download.Pending
return releases;
}
- private List FilterBlockedIndexers(List releases)
- {
- var blockedIndexers = new HashSet(_indexerStatusService.GetBlockedProviders().Select(v => v.ProviderId));
-
- return releases.Where(release => !blockedIndexers.Contains(release.IndexerId)).ToList();
- }
-
public List GetPendingRemoteEpisodes(int seriesId)
{
return IncludeRemoteEpisodes(_repository.AllBySeriesId(seriesId)).Select(v => v.RemoteEpisode).ToList();
@@ -252,6 +238,20 @@ namespace NzbDrone.Core.Download.Pending
.FirstOrDefault();
}
+ private ILookup CreateEpisodeLookup(IEnumerable alreadyPending)
+ {
+ return alreadyPending.SelectMany(v => v.RemoteEpisode.Episodes
+ .Select(d => new { Episode = d, PendingRelease = v }))
+ .ToLookup(v => v.Episode.Id, v => v.PendingRelease);
+ }
+
+ private List FilterBlockedIndexers(List releases)
+ {
+ var blockedIndexers = new HashSet(_indexerStatusService.GetBlockedProviders().Select(v => v.ProviderId));
+
+ return releases.Where(release => !blockedIndexers.Contains(release.IndexerId)).ToList();
+ }
+
private List GetPendingReleases()
{
return IncludeRemoteEpisodes(_repository.All().ToList());
@@ -345,13 +345,6 @@ namespace NzbDrone.Core.Download.Pending
_eventAggregator.PublishEvent(new PendingReleasesUpdatedEvent());
}
- private static Func MatchingReleasePredicate(ReleaseInfo release)
- {
- return p => p.Title == release.Title &&
- p.Release.PublishDate == release.PublishDate &&
- p.Release.Indexer == release.Indexer;
- }
-
private int GetDelay(RemoteEpisode remoteEpisode)
{
var delayProfile = _delayProfileService.AllForTags(remoteEpisode.Series.Tags).OrderBy(d => d.Order).First();
@@ -446,5 +439,12 @@ namespace NzbDrone.Core.Download.Pending
{
RemoveRejected(message.ProcessedDecisions.Rejected);
}
+
+ private static Func MatchingReleasePredicate(ReleaseInfo release)
+ {
+ return p => p.Title == release.Title &&
+ p.Release.PublishDate == release.PublishDate &&
+ p.Release.Indexer == release.Indexer;
+ }
}
}
diff --git a/src/Sonarr.Api.V3/Queue/QueueActionModule.cs b/src/Sonarr.Api.V3/Queue/QueueActionModule.cs
index 73098fc46..a7fbb0f90 100644
--- a/src/Sonarr.Api.V3/Queue/QueueActionModule.cs
+++ b/src/Sonarr.Api.V3/Queue/QueueActionModule.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Nancy;
+using NzbDrone.Core.Blocklisting;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Pending;
using NzbDrone.Core.Download.TrackedDownloads;
@@ -21,6 +22,7 @@ namespace Sonarr.Api.V3.Queue
private readonly IProvideDownloadClient _downloadClientProvider;
private readonly IPendingReleaseService _pendingReleaseService;
private readonly IDownloadService _downloadService;
+ private readonly IBlocklistService _blocklistService;
public QueueActionModule(IQueueService queueService,
ITrackedDownloadService trackedDownloadService,
@@ -28,7 +30,8 @@ namespace Sonarr.Api.V3.Queue
IIgnoredDownloadService ignoredDownloadService,
IProvideDownloadClient downloadClientProvider,
IPendingReleaseService pendingReleaseService,
- IDownloadService downloadService)
+ IDownloadService downloadService,
+ IBlocklistService blocklistService)
{
_queueService = queueService;
_trackedDownloadService = trackedDownloadService;
@@ -37,6 +40,7 @@ namespace Sonarr.Api.V3.Queue
_downloadClientProvider = downloadClientProvider;
_pendingReleaseService = pendingReleaseService;
_downloadService = downloadService;
+ _blocklistService = blocklistService;
Post(@"/grab/(?[\d]{1,10})", x => Grab((int)x.Id));
Post("/grab/bulk", x => Grab());
@@ -126,6 +130,7 @@ namespace Sonarr.Api.V3.Queue
if (pendingRelease != null)
{
+ _blocklistService.Block(pendingRelease.RemoteEpisode, "Pending release manually blocklisted");
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
return null;