mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-11-28 08:58:41 +02:00
New: Option to treat downloads with non-media extensions as failed
Closes #7369
This commit is contained in:
parent
30587856b6
commit
35dafa1061
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Indexers.Torznab;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@ -16,9 +16,9 @@ public class SeedConfigProviderFixture : CoreTest<SeedConfigProvider>
|
||||
[Test]
|
||||
public void should_not_return_config_for_non_existent_indexer()
|
||||
{
|
||||
Mocker.GetMock<IIndexerFactory>()
|
||||
.Setup(v => v.Get(It.IsAny<int>()))
|
||||
.Throws(new ModelNotFoundException(typeof(IndexerDefinition), 0));
|
||||
Mocker.GetMock<ICachedIndexerSettingsProvider>()
|
||||
.Setup(v => v.GetSettings(It.IsAny<int>()))
|
||||
.Returns<CachedIndexerSettings>(null);
|
||||
|
||||
var result = Subject.GetSeedConfiguration(new RemoteEpisode
|
||||
{
|
||||
@ -38,11 +38,12 @@ public void should_return_season_time_for_season_packs()
|
||||
var settings = new TorznabSettings();
|
||||
settings.SeedCriteria.SeasonPackSeedTime = 10;
|
||||
|
||||
Mocker.GetMock<IIndexerFactory>()
|
||||
.Setup(v => v.Get(It.IsAny<int>()))
|
||||
.Returns(new IndexerDefinition
|
||||
Mocker.GetMock<ICachedIndexerSettingsProvider>()
|
||||
.Setup(v => v.GetSettings(It.IsAny<int>()))
|
||||
.Returns(new CachedIndexerSettings
|
||||
{
|
||||
Settings = settings
|
||||
FailDownloads = new HashSet<FailDownloads> { FailDownloads.Executables },
|
||||
SeedCriteriaSettings = settings.SeedCriteria
|
||||
});
|
||||
|
||||
var result = Subject.GetSeedConfiguration(new RemoteEpisode
|
||||
|
@ -15,5 +15,6 @@ public NzbDroneValidationResult Validate()
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ public class CompletedDownloadService : ICompletedDownloadService
|
||||
private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IRejectedImportService _rejectedImportService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public CompletedDownloadService(IEventAggregator eventAggregator,
|
||||
@ -46,6 +47,7 @@ public CompletedDownloadService(IEventAggregator eventAggregator,
|
||||
ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported,
|
||||
IEpisodeService episodeService,
|
||||
IMediaFileService mediaFileService,
|
||||
IRejectedImportService rejectedImportService,
|
||||
Logger logger)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
@ -57,6 +59,7 @@ public CompletedDownloadService(IEventAggregator eventAggregator,
|
||||
_trackedDownloadAlreadyImported = trackedDownloadAlreadyImported;
|
||||
_episodeService = episodeService;
|
||||
_mediaFileService = mediaFileService;
|
||||
_rejectedImportService = rejectedImportService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@ -165,10 +168,8 @@ public void Import(TrackedDownload trackedDownload)
|
||||
{
|
||||
var firstResult = importResults.First();
|
||||
|
||||
if (firstResult.Result == ImportResultType.Rejected && firstResult.ImportDecision.LocalEpisode == null)
|
||||
if (_rejectedImportService.Process(trackedDownload, firstResult))
|
||||
{
|
||||
trackedDownload.Warn(new TrackedDownloadStatusMessage(firstResult.Errors.First(), new List<string>()));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -55,14 +55,18 @@ public void Execute(ProcessMonitoredDownloadsCommand message)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Process completed items followed by failed, this allows failed imports to have
|
||||
// their state changed and be processed immediately instead of the next execution.
|
||||
|
||||
if (enableCompletedDownloadHandling && trackedDownload.State == TrackedDownloadState.ImportPending)
|
||||
{
|
||||
_completedDownloadService.Import(trackedDownload);
|
||||
}
|
||||
|
||||
if (trackedDownload.State == TrackedDownloadState.FailedPending)
|
||||
{
|
||||
_failedDownloadService.ProcessFailed(trackedDownload);
|
||||
}
|
||||
else if (enableCompletedDownloadHandling && trackedDownload.State == TrackedDownloadState.ImportPending)
|
||||
{
|
||||
_completedDownloadService.Import(trackedDownload);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
50
src/NzbDrone.Core/Download/RejectedImportService.cs
Normal file
50
src/NzbDrone.Core/Download/RejectedImportService.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
|
||||
namespace NzbDrone.Core.Download;
|
||||
|
||||
public interface IRejectedImportService
|
||||
{
|
||||
bool Process(TrackedDownload trackedDownload, ImportResult importResult);
|
||||
}
|
||||
|
||||
public class RejectedImportService : IRejectedImportService
|
||||
{
|
||||
private readonly ICachedIndexerSettingsProvider _cachedIndexerSettingsProvider;
|
||||
|
||||
public RejectedImportService(ICachedIndexerSettingsProvider cachedIndexerSettingsProvider)
|
||||
{
|
||||
_cachedIndexerSettingsProvider = cachedIndexerSettingsProvider;
|
||||
}
|
||||
|
||||
public bool Process(TrackedDownload trackedDownload, ImportResult importResult)
|
||||
{
|
||||
if (importResult.Result != ImportResultType.Rejected || importResult.ImportDecision.LocalEpisode != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var indexerSettings = _cachedIndexerSettingsProvider.GetSettings(trackedDownload.RemoteEpisode.Release.IndexerId);
|
||||
var rejectionReason = importResult.ImportDecision.Rejections.FirstOrDefault()?.Reason;
|
||||
|
||||
if (rejectionReason == ImportRejectionReason.DangerousFile &&
|
||||
indexerSettings.FailDownloads.Contains(FailDownloads.PotentiallyDangerous))
|
||||
{
|
||||
trackedDownload.Fail();
|
||||
}
|
||||
else if (rejectionReason == ImportRejectionReason.ExecutableFile &&
|
||||
indexerSettings.FailDownloads.Contains(FailDownloads.Executables))
|
||||
{
|
||||
trackedDownload.Fail();
|
||||
}
|
||||
else
|
||||
{
|
||||
trackedDownload.Warn(new TrackedDownloadStatusMessage(importResult.Errors.First(), new List<string>()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -35,6 +35,12 @@ public void Warn(params TrackedDownloadStatusMessage[] statusMessages)
|
||||
Status = TrackedDownloadStatus.Warning;
|
||||
StatusMessages = statusMessages;
|
||||
}
|
||||
|
||||
public void Fail()
|
||||
{
|
||||
Status = TrackedDownloadStatus.Error;
|
||||
State = TrackedDownloadState.FailedPending;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TrackedDownloadState
|
||||
|
@ -166,6 +166,11 @@ public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, Do
|
||||
{
|
||||
trackedDownload.RemoteEpisode.Release.IndexerFlags = flags;
|
||||
}
|
||||
|
||||
if (downloadHistory != null)
|
||||
{
|
||||
trackedDownload.RemoteEpisode.Release.IndexerId = downloadHistory.IndexerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ public BroadcastheNetSettings()
|
||||
BaseUrl = "https://api.broadcasthe.net/";
|
||||
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
|
||||
@ -48,6 +49,9 @@ public BroadcastheNetSettings()
|
||||
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
69
src/NzbDrone.Core/Indexers/CachedIndexerSettingsProvider.cs
Normal file
69
src/NzbDrone.Core/Indexers/CachedIndexerSettingsProvider.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.ThingiProvider.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers;
|
||||
|
||||
public interface ICachedIndexerSettingsProvider
|
||||
{
|
||||
CachedIndexerSettings GetSettings(int indexerId);
|
||||
}
|
||||
|
||||
public class CachedIndexerSettingsProvider : ICachedIndexerSettingsProvider, IHandle<ProviderUpdatedEvent<IIndexer>>
|
||||
{
|
||||
private readonly IIndexerFactory _indexerFactory;
|
||||
private readonly ICached<CachedIndexerSettings> _cache;
|
||||
|
||||
public CachedIndexerSettingsProvider(IIndexerFactory indexerFactory, ICacheManager cacheManager)
|
||||
{
|
||||
_indexerFactory = indexerFactory;
|
||||
_cache = cacheManager.GetRollingCache<CachedIndexerSettings>(GetType(), "settingsByIndexer", TimeSpan.FromHours(1));
|
||||
}
|
||||
|
||||
public CachedIndexerSettings GetSettings(int indexerId)
|
||||
{
|
||||
if (indexerId == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _cache.Get(indexerId.ToString(), () => FetchIndexerSettings(indexerId));
|
||||
}
|
||||
|
||||
private CachedIndexerSettings FetchIndexerSettings(int indexerId)
|
||||
{
|
||||
var indexer = _indexerFactory.Get(indexerId);
|
||||
var indexerSettings = indexer.Settings as IIndexerSettings;
|
||||
|
||||
if (indexerSettings == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var settings = new CachedIndexerSettings
|
||||
{
|
||||
FailDownloads = indexerSettings.FailDownloads.Select(f => (FailDownloads)f).ToHashSet()
|
||||
};
|
||||
|
||||
if (indexer.Settings is ITorrentIndexerSettings torrentIndexerSettings)
|
||||
{
|
||||
settings.SeedCriteriaSettings = torrentIndexerSettings.SeedCriteria;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public void Handle(ProviderUpdatedEvent<IIndexer> message)
|
||||
{
|
||||
_cache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public class CachedIndexerSettings
|
||||
{
|
||||
public HashSet<FailDownloads> FailDownloads { get; set; }
|
||||
public SeedCriteriaSettings SeedCriteriaSettings { get; set; }
|
||||
}
|
12
src/NzbDrone.Core/Indexers/FailDownloads.cs
Normal file
12
src/NzbDrone.Core/Indexers/FailDownloads.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using NzbDrone.Core.Annotations;
|
||||
|
||||
namespace NzbDrone.Core.Indexers;
|
||||
|
||||
public enum FailDownloads
|
||||
{
|
||||
[FieldOption(Label = "Executables")]
|
||||
Executables = 0,
|
||||
|
||||
[FieldOption(Label = "Potentially Dangerous")]
|
||||
PotentiallyDangerous = 1
|
||||
}
|
@ -24,6 +24,7 @@ public FanzubSettings()
|
||||
{
|
||||
BaseUrl = "http://fanzub.com/rss/";
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "IndexerSettingsRssUrl", HelpText = "IndexerSettingsRssUrlHelpText")]
|
||||
@ -36,6 +37,9 @@ public FanzubSettings()
|
||||
[FieldDefinition(2, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
@ -38,6 +38,7 @@ public FileListSettings()
|
||||
|
||||
AnimeCategories = Array.Empty<int>();
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Username", Privacy = PrivacyLevel.UserName)]
|
||||
@ -67,6 +68,9 @@ public FileListSettings()
|
||||
[FieldDefinition(8, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
|
||||
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
|
||||
|
||||
[FieldDefinition(9, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
@ -32,6 +32,7 @@ public HDBitsSettings()
|
||||
Codecs = Array.Empty<int>();
|
||||
Mediums = Array.Empty<int>();
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
|
||||
@ -64,6 +65,9 @@ public HDBitsSettings()
|
||||
[FieldDefinition(9, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(10, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
@ -8,5 +8,7 @@ public interface IIndexerSettings : IProviderConfig
|
||||
string BaseUrl { get; set; }
|
||||
|
||||
IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
IEnumerable<int> FailDownloads { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ public IPTorrentsSettings()
|
||||
{
|
||||
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "IndexerIPTorrentsSettingsFeedUrl", HelpText = "IndexerIPTorrentsSettingsFeedUrlHelpText")]
|
||||
@ -51,6 +52,9 @@ public IPTorrentsSettings()
|
||||
[FieldDefinition(4, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
@ -59,6 +59,7 @@ public NewznabSettings()
|
||||
Categories = new[] { 5030, 5040 };
|
||||
AnimeCategories = Enumerable.Empty<int>();
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "URL")]
|
||||
@ -86,6 +87,9 @@ public NewznabSettings()
|
||||
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(8, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
// Field 8 is used by TorznabSettings MinimumSeeders
|
||||
// If you need to add another field here, update TorznabSettings as well and this comment
|
||||
|
||||
|
@ -30,6 +30,7 @@ public NyaaSettings()
|
||||
AdditionalParameters = "&cats=1_0&filter=1";
|
||||
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "IndexerSettingsWebsiteUrl")]
|
||||
@ -53,6 +54,9 @@ public NyaaSettings()
|
||||
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Download.Clients;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
@ -14,15 +10,13 @@ public interface ISeedConfigProvider
|
||||
TorrentSeedConfiguration GetSeedConfiguration(int indexerId, bool fullSeason);
|
||||
}
|
||||
|
||||
public class SeedConfigProvider : ISeedConfigProvider, IHandle<ProviderUpdatedEvent<IIndexer>>
|
||||
public class SeedConfigProvider : ISeedConfigProvider
|
||||
{
|
||||
private readonly IIndexerFactory _indexerFactory;
|
||||
private readonly ICached<SeedCriteriaSettings> _cache;
|
||||
private readonly ICachedIndexerSettingsProvider _cachedIndexerSettingsProvider;
|
||||
|
||||
public SeedConfigProvider(IIndexerFactory indexerFactory, ICacheManager cacheManager)
|
||||
public SeedConfigProvider(ICachedIndexerSettingsProvider cachedIndexerSettingsProvider)
|
||||
{
|
||||
_indexerFactory = indexerFactory;
|
||||
_cache = cacheManager.GetRollingCache<SeedCriteriaSettings>(GetType(), "criteriaByIndexer", TimeSpan.FromHours(1));
|
||||
_cachedIndexerSettingsProvider = cachedIndexerSettingsProvider;
|
||||
}
|
||||
|
||||
public TorrentSeedConfiguration GetSeedConfiguration(RemoteEpisode remoteEpisode)
|
||||
@ -47,7 +41,8 @@ public TorrentSeedConfiguration GetSeedConfiguration(int indexerId, bool fullSea
|
||||
return null;
|
||||
}
|
||||
|
||||
var seedCriteria = _cache.Get(indexerId.ToString(), () => FetchSeedCriteria(indexerId));
|
||||
var settings = _cachedIndexerSettingsProvider.GetSettings(indexerId);
|
||||
var seedCriteria = settings?.SeedCriteriaSettings;
|
||||
|
||||
if (seedCriteria == null)
|
||||
{
|
||||
@ -67,25 +62,5 @@ public TorrentSeedConfiguration GetSeedConfiguration(int indexerId, bool fullSea
|
||||
|
||||
return seedConfig;
|
||||
}
|
||||
|
||||
private SeedCriteriaSettings FetchSeedCriteria(int indexerId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var indexer = _indexerFactory.Get(indexerId);
|
||||
var torrentIndexerSettings = indexer.Settings as ITorrentIndexerSettings;
|
||||
|
||||
return torrentIndexerSettings?.SeedCriteria;
|
||||
}
|
||||
catch (ModelNotFoundException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ProviderUpdatedEvent<IIndexer> message)
|
||||
{
|
||||
_cache.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ public TorrentRssIndexerSettings()
|
||||
AllowZeroSize = false;
|
||||
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "IndexerSettingsRssUrl")]
|
||||
@ -51,6 +52,9 @@ public TorrentRssIndexerSettings()
|
||||
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
@ -28,6 +28,7 @@ public TorrentleechSettings()
|
||||
BaseUrl = "http://rss.torrentleech.org";
|
||||
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
|
||||
MultiLanguages = Array.Empty<int>();
|
||||
FailDownloads = Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "IndexerSettingsWebsiteUrl")]
|
||||
@ -48,6 +49,9 @@ public TorrentleechSettings()
|
||||
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
|
||||
public IEnumerable<int> MultiLanguages { get; set; }
|
||||
|
||||
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(FailDownloads), Label = "IndexerSettingsFailDownloads", HelpText = "IndexerSettingsFailDownloadsHelpText", Advanced = true)]
|
||||
public IEnumerable<int> FailDownloads { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
@ -52,13 +52,13 @@ public TorznabSettings()
|
||||
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
|
||||
}
|
||||
|
||||
[FieldDefinition(8, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
|
||||
[FieldDefinition(9, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(9)]
|
||||
[FieldDefinition(10)]
|
||||
public SeedCriteriaSettings SeedCriteria { get; set; } = new ();
|
||||
|
||||
[FieldDefinition(10, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
|
||||
[FieldDefinition(11, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
|
||||
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
|
||||
|
||||
public override NzbDroneValidationResult Validate()
|
||||
|
@ -998,6 +998,8 @@
|
||||
"IndexerSettingsCategoriesHelpText": "Drop down list, leave blank to disable standard/daily shows",
|
||||
"IndexerSettingsCookie": "Cookie",
|
||||
"IndexerSettingsCookieHelpText": "If your site requires a login cookie to access the rss, you'll have to retrieve it via a browser.",
|
||||
"IndexerSettingsFailDownloads": "Fail Downloads",
|
||||
"IndexerSettingsFailDownloadsHelpText": "While processing completed downloads {appName} will treat selected errors preventing importing as failed downloads.",
|
||||
"IndexerSettingsMinimumSeeders": "Minimum Seeders",
|
||||
"IndexerSettingsMinimumSeedersHelpText": "Minimum number of seeders required.",
|
||||
"IndexerSettingsMultiLanguageRelease": "Multi Languages",
|
||||
|
@ -318,6 +318,11 @@ private ImportResult CheckEmptyResultForIssue(string folder)
|
||||
{
|
||||
var files = _diskProvider.GetFiles(folder, true);
|
||||
|
||||
if (files.Any(file => FileExtensions.DangerousExtensions.Contains(Path.GetExtension(file))))
|
||||
{
|
||||
return RejectionResult(ImportRejectionReason.DangerousFile, "Caution: Found potentially dangerous file");
|
||||
}
|
||||
|
||||
if (files.Any(file => FileExtensions.ExecutableExtensions.Contains(Path.GetExtension(file))))
|
||||
{
|
||||
return RejectionResult(ImportRejectionReason.ExecutableFile, "Caution: Found executable file");
|
||||
|
@ -5,6 +5,7 @@ public enum ImportRejectionReason
|
||||
Unknown,
|
||||
FileLocked,
|
||||
UnknownSeries,
|
||||
DangerousFile,
|
||||
ExecutableFile,
|
||||
ArchiveFile,
|
||||
SeriesFolder,
|
||||
|
@ -18,19 +18,27 @@ internal static class FileExtensions
|
||||
".tb2",
|
||||
".tbz2",
|
||||
".tgz",
|
||||
".zip",
|
||||
".zip"
|
||||
};
|
||||
|
||||
private static List<string> _dangerousExtensions = new List<string>
|
||||
{
|
||||
".lnk",
|
||||
".ps1",
|
||||
".vbs",
|
||||
".zipx"
|
||||
};
|
||||
|
||||
private static List<string> _executableExtensions = new List<string>
|
||||
{
|
||||
".exe",
|
||||
".bat",
|
||||
".cmd",
|
||||
".exe",
|
||||
".sh"
|
||||
};
|
||||
|
||||
public static HashSet<string> ArchiveExtensions => new HashSet<string>(_archiveExtensions, StringComparer.OrdinalIgnoreCase);
|
||||
public static HashSet<string> DangerousExtensions => new HashSet<string>(_dangerousExtensions, StringComparer.OrdinalIgnoreCase);
|
||||
public static HashSet<string> ExecutableExtensions => new HashSet<string>(_executableExtensions, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user