diff --git a/src/NzbDrone.Core/Blocklisting/BlocklistService.cs b/src/NzbDrone.Core/Blocklisting/BlocklistService.cs index 93203cc81..808e3dff5 100644 --- a/src/NzbDrone.Core/Blocklisting/BlocklistService.cs +++ b/src/NzbDrone.Core/Blocklisting/BlocklistService.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.Blocklisting public interface IBlocklistService { bool Blocklisted(int seriesId, ReleaseInfo release); + bool BlocklistedTorrentHash(int seriesId, string hash); PagingSpec Paged(PagingSpec pagingSpec); void Block(RemoteEpisode remoteEpisode, string message); void Delete(int id); @@ -61,6 +62,12 @@ namespace NzbDrone.Core.Blocklisting .Any(b => SameNzb(b, release)); } + public bool BlocklistedTorrentHash(int seriesId, string hash) + { + return _blocklistRepository.BlocklistedByTorrentInfoHash(seriesId, hash).Any(b => + b.TorrentInfoHash.Equals(hash, StringComparison.InvariantCultureIgnoreCase)); + } + public PagingSpec Paged(PagingSpec pagingSpec) { return _blocklistRepository.GetPaged(pagingSpec); diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs index 223af1286..621b8937e 100644 --- a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs @@ -7,6 +7,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaFiles.TorrentInfo; @@ -28,9 +29,10 @@ namespace NzbDrone.Core.Download.Clients.Aria2 IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; } diff --git a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs index 62a9a4255..282ededa1 100644 --- a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs +++ b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs @@ -7,6 +7,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaFiles.TorrentInfo; @@ -30,9 +31,10 @@ namespace NzbDrone.Core.Download.Clients.Blackhole IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _scanWatchFolder = scanWatchFolder; diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs index 725c86521..10716c699 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs @@ -7,6 +7,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaFiles.TorrentInfo; @@ -26,9 +27,10 @@ namespace NzbDrone.Core.Download.Clients.Deluge IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; } diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs index 72b3ebbcb..612be692d 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs @@ -8,6 +8,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients.DownloadStation.Proxies; using NzbDrone.Core.Localization; @@ -37,9 +38,10 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _dsInfoProxy = dsInfoProxy; _dsTaskProxySelector = dsTaskProxySelector; diff --git a/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs b/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs index f101f715d..6e091e4e6 100644 --- a/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs +++ b/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs @@ -7,6 +7,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients.Flood.Models; using NzbDrone.Core.Localization; @@ -29,9 +30,10 @@ namespace NzbDrone.Core.Download.Clients.Flood IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; _downloadSeedConfigProvider = downloadSeedConfigProvider; diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs index 6f020b57b..07f435a34 100644 --- a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using FluentValidation.Results; @@ -6,6 +6,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses; using NzbDrone.Core.Localization; @@ -25,9 +26,10 @@ namespace NzbDrone.Core.Download.Clients.FreeboxDownload IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; } diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs index 2d50030e7..a29be7f4c 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs @@ -5,6 +5,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients.Hadouken.Models; using NzbDrone.Core.Localization; @@ -25,9 +26,10 @@ namespace NzbDrone.Core.Download.Clients.Hadouken IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; } diff --git a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs index 3b7187a63..cec43775a 100644 --- a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Net; using Newtonsoft.Json; diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs index 77cbeef17..c1d6f9f4f 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs @@ -8,6 +8,7 @@ using NzbDrone.Common.Cache; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaFiles.TorrentInfo; @@ -35,9 +36,10 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, ICacheManager cacheManager, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxySelector = proxySelector; diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs b/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs index 8c9f858bc..1cfc134c5 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs @@ -1,10 +1,11 @@ -using System; +using System; using System.Collections.Generic; using System.Text.RegularExpressions; using FluentValidation.Results; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaFiles.TorrentInfo; @@ -20,9 +21,10 @@ namespace NzbDrone.Core.Download.Clients.Transmission IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { } diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs index f08ab547c..48a268275 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs @@ -6,6 +6,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaFiles.TorrentInfo; @@ -25,9 +26,10 @@ namespace NzbDrone.Core.Download.Clients.Transmission IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; } diff --git a/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs b/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs index 14ab2534f..db12ea64f 100644 --- a/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs +++ b/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs @@ -2,6 +2,7 @@ using FluentValidation.Results; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients.Transmission; using NzbDrone.Core.Localization; @@ -20,9 +21,10 @@ namespace NzbDrone.Core.Download.Clients.Vuze IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { } diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs index bbfb2fe8e..d1e129949 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs @@ -8,6 +8,7 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients.rTorrent; using NzbDrone.Core.Exceptions; @@ -35,9 +36,10 @@ namespace NzbDrone.Core.Download.Clients.RTorrent IRemotePathMappingService remotePathMappingService, IDownloadSeedConfigProvider downloadSeedConfigProvider, IRTorrentDirectoryValidator rTorrentDirectoryValidator, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; _rTorrentDirectoryValidator = rTorrentDirectoryValidator; diff --git a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs index 0c2c30e31..cecc76dd7 100644 --- a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs @@ -8,6 +8,7 @@ using NzbDrone.Common.Cache; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaFiles.TorrentInfo; @@ -29,9 +30,10 @@ namespace NzbDrone.Core.Download.Clients.UTorrent IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) - : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger, localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger) { _proxy = proxy; diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index 3032f4394..9f07145ca 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -104,6 +104,11 @@ namespace NzbDrone.Core.Download _logger.Trace("Release {0} no longer available on indexer.", remoteEpisode); throw; } + catch (ReleaseBlockedException) + { + _logger.Trace("Release {0} previously added to blocklist, not sending to download client again.", remoteEpisode); + throw; + } catch (DownloadClientRejectedReleaseException) { _logger.Trace("Release {0} rejected by download client, possible duplicate.", remoteEpisode); @@ -128,7 +133,7 @@ namespace NzbDrone.Core.Download episodeGrabbedEvent.DownloadClientId = downloadClient.Definition.Id; episodeGrabbedEvent.DownloadClientName = downloadClient.Definition.Name; - if (!string.IsNullOrWhiteSpace(downloadClientId)) + if (downloadClientId.IsNotNullOrWhiteSpace()) { episodeGrabbedEvent.DownloadId = downloadClientId; } diff --git a/src/NzbDrone.Core/Download/FailedDownloadService.cs b/src/NzbDrone.Core/Download/FailedDownloadService.cs index f7687ab41..3e540a256 100644 --- a/src/NzbDrone.Core/Download/FailedDownloadService.cs +++ b/src/NzbDrone.Core/Download/FailedDownloadService.cs @@ -129,7 +129,7 @@ namespace NzbDrone.Core.Download private void PublishDownloadFailedEvent(List historyItems, string message, TrackedDownload trackedDownload = null, bool skipRedownload = false) { - var historyItem = historyItems.First(); + var historyItem = historyItems.Last(); Enum.TryParse(historyItem.Data.GetValueOrDefault(EpisodeHistory.RELEASE_SOURCE, ReleaseSourceType.Unknown.ToString()), out ReleaseSourceType releaseSource); var downloadFailedEvent = new DownloadFailedEvent diff --git a/src/NzbDrone.Core/Download/TorrentClientBase.cs b/src/NzbDrone.Core/Download/TorrentClientBase.cs index 872b2e9ba..7f93b3395 100644 --- a/src/NzbDrone.Core/Download/TorrentClientBase.cs +++ b/src/NzbDrone.Core/Download/TorrentClientBase.cs @@ -6,6 +6,7 @@ using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Blocklisting; using NzbDrone.Core.Configuration; using NzbDrone.Core.Exceptions; using NzbDrone.Core.Indexers; @@ -22,6 +23,7 @@ namespace NzbDrone.Core.Download where TSettings : IProviderConfig, new() { protected readonly IHttpClient _httpClient; + private readonly IBlocklistService _blocklistService; protected readonly ITorrentFileInfoReader _torrentFileInfoReader; protected TorrentClientBase(ITorrentFileInfoReader torrentFileInfoReader, @@ -29,11 +31,13 @@ namespace NzbDrone.Core.Download IConfigService configService, IDiskProvider diskProvider, IRemotePathMappingService remotePathMappingService, - Logger logger, - ILocalizationService localizationService) + ILocalizationService localizationService, + IBlocklistService blocklistService, + Logger logger) : base(configService, diskProvider, remotePathMappingService, logger, localizationService) { _httpClient = httpClient; + _blocklistService = blocklistService; _torrentFileInfoReader = torrentFileInfoReader; } @@ -88,7 +92,7 @@ namespace NzbDrone.Core.Download { try { - return DownloadFromMagnetUrl(remoteEpisode, magnetUrl); + return DownloadFromMagnetUrl(remoteEpisode, indexer, magnetUrl); } catch (NotSupportedException ex) { @@ -102,7 +106,7 @@ namespace NzbDrone.Core.Download { try { - return DownloadFromMagnetUrl(remoteEpisode, magnetUrl); + return DownloadFromMagnetUrl(remoteEpisode, indexer, magnetUrl); } catch (NotSupportedException ex) { @@ -149,7 +153,7 @@ namespace NzbDrone.Core.Download { if (locationHeader.StartsWith("magnet:")) { - return DownloadFromMagnetUrl(remoteEpisode, locationHeader); + return DownloadFromMagnetUrl(remoteEpisode, indexer, locationHeader); } request.Url += new HttpUri(locationHeader); @@ -192,6 +196,9 @@ namespace NzbDrone.Core.Download var filename = string.Format("{0}.torrent", FileNameBuilder.CleanFileName(remoteEpisode.Release.Title)); var hash = _torrentFileInfoReader.GetHashFromTorrentFile(torrentFile); + + EnsureReleaseIsNotBlocklisted(remoteEpisode, indexer, hash); + var actualHash = AddFromTorrentFile(remoteEpisode, hash, filename, torrentFile); if (actualHash.IsNotNullOrWhiteSpace() && hash != actualHash) @@ -205,7 +212,7 @@ namespace NzbDrone.Core.Download return actualHash; } - private string DownloadFromMagnetUrl(RemoteEpisode remoteEpisode, string magnetUrl) + private string DownloadFromMagnetUrl(RemoteEpisode remoteEpisode, IIndexer indexer, string magnetUrl) { string hash = null; string actualHash = null; @@ -223,6 +230,8 @@ namespace NzbDrone.Core.Download if (hash != null) { + EnsureReleaseIsNotBlocklisted(remoteEpisode, indexer, hash); + actualHash = AddFromMagnetLink(remoteEpisode, hash, magnetUrl); } @@ -236,5 +245,30 @@ namespace NzbDrone.Core.Download return actualHash; } + + private void EnsureReleaseIsNotBlocklisted(RemoteEpisode remoteEpisode, IIndexer indexer, string hash) + { + var indexerSettings = indexer?.Definition?.Settings as ITorrentIndexerSettings; + var torrentInfo = remoteEpisode.Release as TorrentInfo; + var torrentInfoHash = torrentInfo?.InfoHash; + + // If the release didn't come from an interactive search, + // the hash wasn't known during processing and the + // indexer is configured to reject blocklisted releases + // during grab check if it's already been blocklisted. + + if (torrentInfo != null && torrentInfoHash.IsNullOrWhiteSpace()) + { + // If the hash isn't known from parsing we set it here so it can be used for blocklisting. + torrentInfo.InfoHash = hash; + + if (remoteEpisode.ReleaseSource != ReleaseSourceType.InteractiveSearch && + indexerSettings?.RejectBlocklistedTorrentHashesWhileGrabbing == true && + _blocklistService.BlocklistedTorrentHash(remoteEpisode.Series.Id, hash)) + { + throw new ReleaseBlockedException(remoteEpisode.Release, "Release previously added to blocklist"); + } + } + } } } diff --git a/src/NzbDrone.Core/Exceptions/ReleaseBlockedException.cs b/src/NzbDrone.Core/Exceptions/ReleaseBlockedException.cs new file mode 100644 index 000000000..73d8b8f8d --- /dev/null +++ b/src/NzbDrone.Core/Exceptions/ReleaseBlockedException.cs @@ -0,0 +1,28 @@ +using System; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Exceptions +{ + public class ReleaseBlockedException : ReleaseDownloadException + { + public ReleaseBlockedException(ReleaseInfo release, string message, params object[] args) + : base(release, message, args) + { + } + + public ReleaseBlockedException(ReleaseInfo release, string message) + : base(release, message) + { + } + + public ReleaseBlockedException(ReleaseInfo release, string message, Exception innerException, params object[] args) + : base(release, message, innerException, args) + { + } + + public ReleaseBlockedException(ReleaseInfo release, string message, Exception innerException) + : base(release, message, innerException) + { + } + } +} diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 86fe74846..813329908 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -175,9 +175,7 @@ namespace NzbDrone.Core.History history.Data.Add("ReleaseHash", message.Episode.ParsedEpisodeInfo.ReleaseHash); } - var torrentRelease = message.Episode.Release as TorrentInfo; - - if (torrentRelease != null) + if (message.Episode.Release is TorrentInfo torrentRelease) { history.Data.Add("TorrentInfoHash", torrentRelease.InfoHash); } diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs index 4d3a688de..4adf2745b 100644 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs +++ b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs @@ -37,6 +37,9 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet [FieldDefinition(3)] public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings(); + [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/FileList/FileListSettings.cs b/src/NzbDrone.Core/Indexers/FileList/FileListSettings.cs index f149ef8f4..59eb7c13d 100644 --- a/src/NzbDrone.Core/Indexers/FileList/FileListSettings.cs +++ b/src/NzbDrone.Core/Indexers/FileList/FileListSettings.cs @@ -58,6 +58,9 @@ namespace NzbDrone.Core.Indexers.FileList [FieldDefinition(7)] public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings(); + [FieldDefinition(8, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs b/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs index c6525771d..1e35ca310 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs @@ -55,6 +55,9 @@ namespace NzbDrone.Core.Indexers.HDBits [FieldDefinition(7)] public SeedCriteriaSettings SeedCriteria { get; set; } = new (); + [FieldDefinition(8, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs index 473bc9f8e..f1c3bb490 100644 --- a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs +++ b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs @@ -40,6 +40,9 @@ namespace NzbDrone.Core.Indexers.IPTorrents [FieldDefinition(2)] public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings(); + [FieldDefinition(3, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs b/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs index 6a9070475..eb507c0c9 100644 --- a/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs +++ b/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs @@ -6,5 +6,6 @@ namespace NzbDrone.Core.Indexers // TODO: System.Text.Json requires setter be public for sub-object deserialization in 3.0. https://github.com/dotnet/corefx/issues/42515 SeedCriteriaSettings SeedCriteria { get; set; } + bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } } } diff --git a/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs b/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs index 25741b13b..f6c40e713 100644 --- a/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs +++ b/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs @@ -42,6 +42,9 @@ namespace NzbDrone.Core.Indexers.Nyaa [FieldDefinition(4)] public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings(); + [FieldDefinition(5, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs index 298fce7ce..6543b5a7f 100644 --- a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs +++ b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs @@ -40,6 +40,9 @@ namespace NzbDrone.Core.Indexers.TorrentRss [FieldDefinition(4)] public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings(); + [FieldDefinition(5, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs index 09ad61bff..51e21b31c 100644 --- a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs +++ b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs @@ -37,6 +37,9 @@ namespace NzbDrone.Core.Indexers.Torrentleech [FieldDefinition(3)] public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings(); + [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs b/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs index 983c3d594..7e3ce1295 100644 --- a/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs @@ -57,6 +57,9 @@ namespace NzbDrone.Core.Indexers.Torznab [FieldDefinition(8)] public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings(); + [FieldDefinition(9, Type = FieldType.Checkbox, Label = "Reject Blocklisted Torrent Hashes While Grabbing", HelpText = "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.", Advanced = true)] + public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; } + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this));