1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-12-12 11:15:43 +02:00

Translate Indexers on the backend

This commit is contained in:
Stevie Robinson 2023-11-17 01:30:22 +01:00 committed by GitHub
parent e68b13940d
commit f205cfabab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 160 additions and 89 deletions

View File

@ -11,6 +11,7 @@
using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
@ -70,7 +71,8 @@ protected virtual IIndexer CreateIndexer()
Mocker.Resolve<IIndexerStatusService>(),
Mocker.Resolve<IConfigService>(),
Mocker.Resolve<IParsingService>(),
Mocker.Resolve<Logger>());
Mocker.Resolve<Logger>(),
Mocker.Resolve<ILocalizationService>());
}
protected void VerifyIdentifiable(DownloadClientItem downloadClientItem)

View File

@ -11,6 +11,7 @@
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.Pneumatic;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
@ -51,7 +52,8 @@ public void Setup()
Mocker.Resolve<IIndexerStatusService>(),
Mocker.Resolve<IConfigService>(),
Mocker.Resolve<IParsingService>(),
Mocker.Resolve<Logger>());
Mocker.Resolve<Logger>(),
Mocker.Resolve<ILocalizationService>());
_downloadClientItem = Builder<DownloadClientItem>
.CreateNew().With(d => d.DownloadId = "_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0")

View File

@ -2,6 +2,7 @@
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Test.IndexerTests
@ -15,8 +16,8 @@ public class TestIndexer : HttpIndexerBase<TestIndexerSettings>
public int _supportedPageSize;
public override int PageSize => _supportedPageSize;
public TestIndexer(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public TestIndexer(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -7,14 +7,15 @@
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.TorrentRss;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests
{
public class TestTorrentRssIndexer : TorrentRssIndexer
{
public TestTorrentRssIndexer(ITorrentRssParserFactory torrentRssParserFactory, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(torrentRssParserFactory, httpClient, indexerStatusService, configService, parsingService, logger)
public TestTorrentRssIndexer(ITorrentRssParserFactory torrentRssParserFactory, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(torrentRssParserFactory, httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.BroadcastheNet
@ -14,8 +15,8 @@ public class BroadcastheNet : HttpIndexerBase<BroadcastheNetSettings>
public override bool SupportsSearch => true;
public override int PageSize => 100;
public BroadcastheNet(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public BroadcastheNet(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -25,13 +25,13 @@ public BroadcastheNetSettings()
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
}
[FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
[FieldDefinition(0, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "API Key", Privacy = PrivacyLevel.ApiKey)]
[FieldDefinition(1, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; }
[FieldDefinition(2, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(2, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(3)]

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.Fanzub
@ -11,8 +12,8 @@ public class Fanzub : HttpIndexerBase<FanzubSettings>
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
public Fanzub(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public Fanzub(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -21,10 +21,11 @@ public FanzubSettings()
BaseUrl = "http://fanzub.com/rss/";
}
[FieldDefinition(0, Label = "Rss URL", HelpText = "Enter to URL to an Fanzub compatible RSS feed")]
[FieldDefinition(0, Label = "IndexerSettingsRssUrl", HelpText = "IndexerSettingsRssUrlHelpText")]
[FieldToken(TokenField.HelpText, "IndexerSettingsRssUrl", "indexer", "Fanzub")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "Anime Standard Format Search", Type = FieldType.Checkbox, HelpText = "Also search for anime using the standard numbering")]
[FieldDefinition(1, Label = "IndexerSettingsAnimeStandardFormatSearch", Type = FieldType.Checkbox, HelpText = "IndexerSettingsAnimeStandardFormatSearchHelpText")]
public bool AnimeStandardFormatSearch { get; set; }
public NzbDroneValidationResult Validate()

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.FileList
@ -12,8 +13,8 @@ public class FileList : HttpIndexerBase<FileListSettings>
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public FileList(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public FileList(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -40,19 +40,19 @@ public FileListSettings()
[FieldDefinition(0, Label = "Username", Privacy = PrivacyLevel.UserName)]
public string Username { get; set; }
[FieldDefinition(1, Label = "Passkey", Privacy = PrivacyLevel.ApiKey)]
[FieldDefinition(1, Label = "IndexerSettingsPasskey", Privacy = PrivacyLevel.ApiKey)]
public string Passkey { get; set; }
[FieldDefinition(3, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
[FieldDefinition(3, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
public string BaseUrl { get; set; }
[FieldDefinition(4, Label = "Categories", Type = FieldType.Select, SelectOptions = typeof(FileListCategories), HelpText = "Categories for use in search and feeds, leave blank to disable standard/daily shows")]
[FieldDefinition(4, Label = "IndexerSettingsCategories", Type = FieldType.Select, SelectOptions = typeof(FileListCategories), HelpText = "IndexerSettingsCategoriesHelpText")]
public IEnumerable<int> Categories { get; set; }
[FieldDefinition(5, Label = "Anime Categories", Type = FieldType.Select, SelectOptions = typeof(FileListCategories), HelpText = "Categories for use in search and feeds, leave blank to disable anime")]
[FieldDefinition(5, Label = "IndexerSettingsAnimeCategories", Type = FieldType.Select, SelectOptions = typeof(FileListCategories), HelpText = "IndexerSettingsAnimeCategoriesHelpText")]
public IEnumerable<int> AnimeCategories { get; set; }
[FieldDefinition(6, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(6, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(7)]

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.HDBits
@ -13,8 +14,8 @@ public class HDBits : HttpIndexerBase<HDBitsSettings>
public override bool SupportsSearch => true;
public override int PageSize => 30;
public HDBits(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public HDBits(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -28,13 +28,13 @@ public HDBitsSettings()
[FieldDefinition(0, Label = "Username", Privacy = PrivacyLevel.UserName)]
public string Username { get; set; }
[FieldDefinition(1, Label = "API Key", Privacy = PrivacyLevel.ApiKey)]
[FieldDefinition(1, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; }
[FieldDefinition(2, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
[FieldDefinition(2, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
public string BaseUrl { get; set; }
[FieldDefinition(3, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(3, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(4)]

View File

@ -12,6 +12,7 @@
using NzbDrone.Core.Http.CloudFlare;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@ -34,8 +35,8 @@ public abstract class HttpIndexerBase<TSettings> : IndexerBase<TSettings>
public abstract IIndexerRequestGenerator GetRequestGenerator();
public abstract IParseIndexerResponse GetParser();
public HttpIndexerBase(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(indexerStatusService, configService, parsingService, logger)
public HttpIndexerBase(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(indexerStatusService, configService, parsingService, logger, localizationService)
{
_httpClient = httpClient;
}
@ -376,50 +377,50 @@ protected virtual async Task<ValidationFailure> TestConnection()
if (firstRequest == null)
{
return new ValidationFailure(string.Empty, "No rss feed query available. This may be an issue with the indexer or your indexer category settings.");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationJackettNoRssFeedQueryAvailable"));
}
var releases = await FetchPage(firstRequest, parser);
if (releases.Empty())
{
return new ValidationFailure(string.Empty, "Query successful, but no results in the configured categories were returned from your indexer. This may be an issue with the indexer or your indexer category settings.");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationJackettNoResultsInConfiguredCategories"));
}
}
catch (ApiKeyException ex)
{
_logger.Warn("Indexer returned result for RSS URL, API Key appears to be invalid: " + ex.Message);
return new ValidationFailure("ApiKey", "Invalid API Key");
return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("IndexerValidationInvalidApiKey"));
}
catch (RequestLimitReachedException ex)
{
_logger.Warn("Request limit reached: " + ex.Message);
return new ValidationFailure(string.Empty, "Request limit reached: " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationRequestLimitReached", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
catch (CloudFlareCaptchaException ex)
{
if (ex.IsExpired)
{
return new ValidationFailure("CaptchaToken", "CloudFlare CAPTCHA token expired, please Refresh.");
return new ValidationFailure("CaptchaToken", _localizationService.GetLocalizedString("IndexerValidationCloudFlareCaptchaExpired"));
}
else
{
return new ValidationFailure("CaptchaToken", "Site protected by CloudFlare CAPTCHA. Valid CAPTCHA token required.");
return new ValidationFailure("CaptchaToken", _localizationService.GetLocalizedString("IndexerValidationCloudFlareCaptchaRequired"));
}
}
catch (UnsupportedFeedException ex)
{
_logger.Warn(ex, "Indexer feed is not supported");
return new ValidationFailure(string.Empty, "Indexer feed is not supported: " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationFeedNotSupported", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
catch (IndexerException ex)
{
_logger.Warn(ex, "Unable to connect to indexer");
return new ValidationFailure(string.Empty, "Unable to connect to indexer. " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
catch (HttpException ex)
{
@ -427,33 +428,33 @@ protected virtual async Task<ValidationFailure> TestConnection()
ex.Response.Content.Contains("not support the requested query"))
{
_logger.Warn(ex, "Indexer does not support the query");
return new ValidationFailure(string.Empty, "Indexer does not support the current query. Check if the categories and or searching for seasons/episodes are supported. Check the log for more details.");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationQueryNotSupported"));
}
_logger.Warn(ex, "Unable to connect to indexer");
if (ex.Response.HasHttpServerError)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, indexer's server is unavailable. Try again later. " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnectServerUnavailable", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
if (ex.Response.StatusCode is HttpStatusCode.Forbidden or HttpStatusCode.Unauthorized)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, invalid credentials. " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnectInvalidCredentials", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
return new ValidationFailure(string.Empty, "Unable to connect to indexer, check the log above the ValidationFailure for more details. " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
catch (HttpRequestException ex)
{
_logger.Warn(ex, "Unable to connect to indexer");
return new ValidationFailure(string.Empty, "Unable to connect to indexer, please check your DNS settings and ensure IPv6 is working or disabled. " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnectHttpError", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
catch (TaskCanceledException ex)
{
_logger.Warn(ex, "Unable to connect to indexer");
return new ValidationFailure(string.Empty, "Unable to connect to indexer, possibly due to a timeout. Try again or check your network settings. " + ex.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnectTimeout", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
catch (WebException webException)
{
@ -461,20 +462,20 @@ protected virtual async Task<ValidationFailure> TestConnection()
if (webException.Status is WebExceptionStatus.NameResolutionFailure or WebExceptionStatus.ConnectFailure)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer connection failure. Check your connection to the indexer's server and DNS." + webException.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnectResolutionFailure", new Dictionary<string, object> { { "exceptionMessage", webException.Message } }));
}
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
webException.Message.Contains("504") || webException.Message.Contains("timed out"))
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, indexer's server is unavailable. Try again later. " + webException.Message);
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnectServerUnavailable", new Dictionary<string, object> { { "exceptionMessage", webException.Message } }));
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to connect to indexer");
return new ValidationFailure(string.Empty, $"Unable to connect to indexer: {ex.Message}. Check the log surrounding this error for details");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
return null;

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.IPTorrents
@ -13,8 +14,8 @@ public class IPTorrents : HttpIndexerBase<IPTorrentsSettings>
public override bool SupportsSearch => false;
public override int PageSize => 0;
public IPTorrents(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public IPTorrents(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -31,10 +31,10 @@ public IPTorrentsSettings()
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
}
[FieldDefinition(0, Label = "Feed URL", HelpText = "The full RSS feed url generated by IPTorrents, using only the categories you selected (HD, SD, x264, etc ...)")]
[FieldDefinition(0, Label = "IndexerIPTorrentsSettingsFeedUrl", HelpText = "IndexerIPTorrentsSettingsFeedUrlHelpText")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(1, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(2)]

View File

@ -7,6 +7,7 @@
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
@ -20,6 +21,7 @@ public abstract class IndexerBase<TSettings> : IIndexer
protected readonly IConfigService _configService;
protected readonly IParsingService _parsingService;
protected readonly Logger _logger;
protected readonly ILocalizationService _localizationService;
public abstract string Name { get; }
public abstract DownloadProtocol Protocol { get; }
@ -29,12 +31,13 @@ public abstract class IndexerBase<TSettings> : IIndexer
public abstract bool SupportsRss { get; }
public abstract bool SupportsSearch { get; }
public IndexerBase(IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
public IndexerBase(IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
{
_indexerStatusService = indexerStatusService;
_configService = configService;
_parsingService = parsingService;
_logger = logger;
_localizationService = localizationService;
}
public Type ConfigContract => typeof(TSettings);
@ -105,7 +108,7 @@ public ValidationResult Test()
catch (Exception ex)
{
_logger.Error(ex, "Test aborted due to exception");
failures.Add(new ValidationFailure(string.Empty, "Test was aborted due to an error: " + ex.Message));
failures.Add(new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationTestAbortedDueToError", new Dictionary<string, object> { { "exceptionMessage", ex.Message } })));
}
return new ValidationResult(failures);

View File

@ -7,6 +7,7 @@
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@ -22,8 +23,8 @@ public class Newznab : HttpIndexerBase<NewznabSettings>
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
public override int PageSize => GetProviderPageSize();
public Newznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public Newznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
_capabilitiesProvider = capabilitiesProvider;
}
@ -129,13 +130,13 @@ protected virtual ValidationFailure TestCapabilities()
return null;
}
return new ValidationFailure(string.Empty, "Indexer does not support required search parameters");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationSearchParametersNotSupported"));
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to connect to indexer: " + ex.Message);
return new ValidationFailure(string.Empty, $"Unable to connect to indexer: {ex.Message}. Check the log surrounding this error for details");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
}

View File

@ -60,22 +60,23 @@ public NewznabSettings()
[FieldDefinition(0, Label = "URL")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "API Path", HelpText = "Path to the api, usually /api", Advanced = true)]
[FieldDefinition(1, Label = "IndexerSettingsApiPath", HelpText = "IndexerSettingsApiPathHelpText", Advanced = true)]
[FieldToken(TokenField.HelpText, "IndexerSettingsApiPath", "url", "/api")]
public string ApiPath { get; set; }
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey)]
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Categories", Type = FieldType.Select, SelectOptionsProviderAction = "newznabCategories", HelpText = "Drop down list, leave blank to disable standard/daily shows")]
[FieldDefinition(3, Label = "IndexerSettingsCategories", Type = FieldType.Select, SelectOptionsProviderAction = "newznabCategories", HelpText = "IndexerSettingsCategoriesHelpText")]
public IEnumerable<int> Categories { get; set; }
[FieldDefinition(4, Label = "Anime Categories", Type = FieldType.Select, SelectOptionsProviderAction = "newznabCategories", HelpText = "Drop down list, leave blank to disable anime")]
[FieldDefinition(4, Label = "IndexerSettingsAnimeCategories", Type = FieldType.Select, SelectOptionsProviderAction = "newznabCategories", HelpText = "IndexerSettingsAnimeCategoriesHelpText")]
public IEnumerable<int> AnimeCategories { get; set; }
[FieldDefinition(5, Label = "Anime Standard Format Search", Type = FieldType.Checkbox, HelpText = "Also search for anime using the standard numbering")]
[FieldDefinition(5, Label = "IndexerSettingsAnimeStandardFormatSearch", Type = FieldType.Checkbox, HelpText = "IndexerSettingsAnimeStandardFormatSearchHelpText")]
public bool AnimeStandardFormatSearch { get; set; }
[FieldDefinition(6, Label = "Additional Parameters", HelpText = "Additional Newznab parameters", Advanced = true)]
[FieldDefinition(6, Label = "IndexerSettingsAdditionalParameters", HelpText = "IndexerSettingsAdditionalNewznabParametersHelpText", Advanced = true)]
public string AdditionalParameters { get; set; }
// Field 7 is used by TorznabSettings MinimumSeeders

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.Nyaa
@ -12,8 +13,8 @@ public class Nyaa : HttpIndexerBase<NyaaSettings>
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override int PageSize => 100;
public Nyaa(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public Nyaa(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -27,16 +27,16 @@ public NyaaSettings()
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
}
[FieldDefinition(0, Label = "Website URL")]
[FieldDefinition(0, Label = "IndexerSettingsWebsiteUrl")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "Anime Standard Format Search", Type = FieldType.Checkbox, HelpText = "Also search for anime using the standard numbering")]
[FieldDefinition(1, Label = "IndexerSettingsAnimeStandardFormatSearch", Type = FieldType.Checkbox, HelpText = "IndexerSettingsAnimeStandardFormatSearchHelpText")]
public bool AnimeStandardFormatSearch { get; set; }
[FieldDefinition(2, Label = "Additional Parameters", Advanced = true, HelpText = "Please note if you change the category you will have to add required/restricted rules about the subgroups to avoid foreign language releases.")]
[FieldDefinition(2, Label = "IndexerSettingsAdditionalParameters", Advanced = true, HelpText = "IndexerSettingsAdditionalNewznabParametersHelpText")]
public string AdditionalParameters { get; set; }
[FieldDefinition(3, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(3, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(4)]

View File

@ -48,13 +48,13 @@ public SeedCriteriaSettingsValidator(double seedRatioMinimum = 0.0, int seedTime
public class SeedCriteriaSettings
{
[FieldDefinition(0, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default. Ratio should be at least 1.0 and follow the indexers rules")]
[FieldDefinition(0, Type = FieldType.Textbox, Label = "IndexerSettingsSeedRatio", HelpText = "IndexerSettingsSeedRatioHelpText")]
public double? SeedRatio { get; set; }
[FieldDefinition(1, Type = FieldType.Number, Label = "Seed Time", Unit = "minutes", HelpText = "The time a torrent should be seeded before stopping, empty is download client's default", Advanced = true)]
[FieldDefinition(1, Type = FieldType.Number, Label = "IndexerSettingsSeedTime", Unit = "minutes", HelpText = "IndexerSettingsSeedTimeHelpText", Advanced = true)]
public int? SeedTime { get; set; }
[FieldDefinition(2, Type = FieldType.Number, Label = "Season-Pack Seed Time", Unit = "minutes", HelpText = "The time a torrent should be seeded before stopping, empty is download client's default", Advanced = true)]
[FieldDefinition(2, Type = FieldType.Number, Label = "Season-Pack Seed Time", Unit = "minutes", HelpText = "IndexerSettingsSeasonPackSeedTimeHelpText", Advanced = true)]
public int? SeasonPackSeedTime { get; set; }
}
}

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.TorrentRss
@ -15,8 +16,8 @@ public class TorrentRssIndexer : HttpIndexerBase<TorrentRssIndexerSettings>
private readonly ITorrentRssParserFactory _torrentRssParserFactory;
public TorrentRssIndexer(ITorrentRssParserFactory torrentRssParserFactory, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public TorrentRssIndexer(ITorrentRssParserFactory torrentRssParserFactory, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
_torrentRssParserFactory = torrentRssParserFactory;
}

View File

@ -25,16 +25,16 @@ public TorrentRssIndexerSettings()
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
}
[FieldDefinition(0, Label = "Full RSS Feed URL")]
[FieldDefinition(0, Label = "IndexerSettingsRssUrl")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "Cookie", HelpText = "If you site requires a login cookie to access the rss, you'll have to retrieve it via a browser.")]
[FieldDefinition(1, Label = "IndexerSettingsCookie", HelpText = "IndexerSettingsCookieHelpText")]
public string Cookie { get; set; }
[FieldDefinition(2, Type = FieldType.Checkbox, Label = "Allow Zero Size", HelpText="Enabling this will allow you to use feeds that don't specify release size, but be careful, size related checks will not be performed.")]
[FieldDefinition(2, Type = FieldType.Checkbox, Label = "Allow Zero Size", HelpText="IndexerSettingsAllowZeroSizeHelpText")]
public bool AllowZeroSize { get; set; }
[FieldDefinition(3, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(3, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(4)]

View File

@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.Torrentleech
@ -13,8 +14,8 @@ public class Torrentleech : HttpIndexerBase<TorrentleechSettings>
public override bool SupportsSearch => false;
public override int PageSize => 0;
public Torrentleech(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public Torrentleech(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
}

View File

@ -25,13 +25,13 @@ public TorrentleechSettings()
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
}
[FieldDefinition(0, Label = "Website URL")]
[FieldDefinition(0, Label = "IndexerSettingsWebsiteUrl")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "API Key", Privacy = PrivacyLevel.ApiKey)]
[FieldDefinition(1, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; }
[FieldDefinition(2, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(2, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(3)]

View File

@ -8,6 +8,7 @@
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Newznab;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@ -23,8 +24,8 @@ public class Torznab : HttpIndexerBase<TorznabSettings>
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override int PageSize => GetProviderPageSize();
public Torznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
public Torznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger, ILocalizationService localizationService)
: base(httpClient, indexerStatusService, configService, parsingService, logger, localizationService)
{
_capabilitiesProvider = capabilitiesProvider;
}
@ -123,13 +124,13 @@ protected virtual ValidationFailure TestCapabilities()
return null;
}
return new ValidationFailure(string.Empty, "Indexer does not support required search parameters");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationSearchParametersNotSupported"));
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to connect to indexer: " + ex.Message);
return new ValidationFailure(string.Empty, $"Unable to connect to indexer: {ex.Message}. Check the log surrounding this error for details");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("IndexerValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
}
@ -140,10 +141,10 @@ protected virtual ValidationFailure JackettAll()
Settings.BaseUrl.Contains("/torznab/all") ||
Settings.BaseUrl.Contains("/api/v2.0/indexers/all/results/torznab"))
{
return new NzbDroneValidationFailure("ApiPath", "Jackett's all endpoint is not supported, please add indexers individually")
return new NzbDroneValidationFailure("ApiPath", _localizationService.GetLocalizedString("IndexerValidationJackettAllNotSupported"))
{
IsWarning = true,
DetailedDescription = "Jackett's all endpoint is not supported, please add indexers individually"
DetailedDescription = _localizationService.GetLocalizedString("IndexerValidationJackettAllNotSupportedHelpText")
};
}

View File

@ -51,7 +51,7 @@ public TorznabSettings()
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
}
[FieldDefinition(7, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(7, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(8)]

View File

@ -770,6 +770,8 @@
"Indexer": "Indexer",
"IndexerDownloadClientHealthCheckMessage": "Indexers with invalid download clients: {indexerNames}.",
"IndexerDownloadClientHelpText": "Specify which download client is used for grabs from this indexer",
"IndexerIPTorrentsSettingsFeedUrl": "Feed URL",
"IndexerIPTorrentsSettingsFeedUrlHelpText": "The full RSS feed url generated by IPTorrents, using only the categories you selected (HD, SD, x264, etc ...)",
"IndexerJackettAllHealthCheckMessage": "Indexers using the unsupported Jackett 'all' endpoint: {indexerNames}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "All indexers are unavailable due to failures for more than 6 hours",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexers unavailable due to failures for more than 6 hours: {indexerNames}",
@ -782,9 +784,56 @@
"IndexerSearchNoAvailableIndexersHealthCheckMessage": "All search-capable indexers are temporarily unavailable due to recent indexer errors",
"IndexerSearchNoInteractiveHealthCheckMessage": "No indexers available with Interactive Search enabled, {appName} will not provide any interactive search results",
"IndexerSettings": "Indexer Settings",
"IndexerSettingsAdditionalNewznabParametersHelpText": "Please note if you change the category you will have to add required/restricted rules about the subgroups to avoid foreign language releases.",
"IndexerSettingsAdditionalParameters": "Additional Parameters",
"IndexerSettingsAdditionalParametersNyaa": "Additional Parameters",
"IndexerSettingsAllowZeroSize": "Allow Zero Size",
"IndexerSettingsAllowZeroSizeHelpText": "Enabling this will allow you to use feeds that don't specify release size, but be careful, size related checks will not be performed.",
"IndexerSettingsAnimeCategories": "Anime Categories",
"IndexerSettingsAnimeCategoriesHelpText": "Drop down list, leave blank to disable anime",
"IndexerSettingsAnimeStandardFormatSearch": "Anime Standard Format Search",
"IndexerSettingsAnimeStandardFormatSearchHelpText": "Also search for anime using the standard numbering",
"IndexerSettingsApiPath": "API Path",
"IndexerSettingsApiPathHelpText": "Path to the api, usually {url}",
"IndexerSettingsApiUrl": "API URL",
"IndexerSettingsApiUrlHelpText": "Do not change this unless you know what you're doing. Since your API key will be sent to that host.",
"IndexerSettingsCategories": "Categories",
"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.",
"IndexerSettingsMinimumSeeders": "Minimum Seeders",
"IndexerSettingsMinimumSeedersHelpText": "Minimum number of seeders required.",
"IndexerSettingsPasskey": "Passkey",
"IndexerSettingsRssUrl": "RSS URL",
"IndexerSettingsRssUrlHelpText": "Enter to URL to an {indexer} compatible RSS feed",
"IndexerSettingsSeasonPackSeedTime": "Season-Pack Seed Time",
"IndexerSettingsSeasonPackSeedTimeHelpText": "The time a season-pack torrent should be seeded before stopping, empty uses the download client's default",
"IndexerSettingsSeedRatio": "Seed Ratio",
"IndexerSettingsSeedRatioHelpText": "The ratio a torrent should reach before stopping, empty uses the download client's default. Ratio should be at least 1.0 and follow the indexers rules",
"IndexerSettingsSeedTime": "Seed Time",
"IndexerSettingsSeedTimeHelpText": "The time a torrent should be seeded before stopping, empty uses the download client's default",
"IndexerSettingsWebsiteUrl": "Website URL",
"IndexerStatusAllUnavailableHealthCheckMessage": "All indexers are unavailable due to failures",
"IndexerStatusUnavailableHealthCheckMessage": "Indexers unavailable due to failures: {indexerNames}",
"IndexerTagHelpText": "Only use this indexer for series with at least one matching tag. Leave blank to use with all series.",
"IndexerValidationCloudFlareCaptchaExpired": "CloudFlare CAPTCHA token expired, please refresh it.",
"IndexerValidationCloudFlareCaptchaRequired": "Site protected by CloudFlare CAPTCHA. Valid CAPTCHA token required.",
"IndexerValidationFeedNotSupported": "Indexer feed is not supported: {exceptionMessage}",
"IndexerValidationInvalidApiKey": "Invalid API Key",
"IndexerValidationJackettAllNotSupported": "Jackett's all endpoint is not supported, please add indexers individually",
"IndexerValidationJackettAllNotSupportedHelpText": "Jackett's all endpoint is not supported, please add indexers individually",
"IndexerValidationJackettNoResultsInConfiguredCategories": "Query successful, but no results in the configured categories were returned from your indexer. This may be an issue with the indexer or your indexer category settings.",
"IndexerValidationJackettNoRssFeedQueryAvailable": "No RSS feed query available. This may be an issue with the indexer or your indexer category settings.",
"IndexerValidationQueryNotSupported": "Indexer does not support the current query. Check if the categories and or searching for seasons/episodes are supported. Check the log for more details.",
"IndexerValidationRequestLimitReached": "Request limit reached: {exceptionMessage}",
"IndexerValidationSearchParametersNotSupported": "Indexer does not support required search parameters",
"IndexerValidationTestAbortedDueToError": "Test was aborted due to an error: {exceptionMessage}",
"IndexerValidationUnableToConnect": "Unable to connect to indexer: {exceptionMessage}. Check the log surrounding this error for details",
"IndexerValidationUnableToConnectHttpError": "Unable to connect to indexer, please check your DNS settings and ensure that IPv6 is working or disabled. {exceptionMessage}.",
"IndexerValidationUnableToConnectInvalidCredentials": "Unable to connect to indexer, invalid credentials. {exceptionMessage}.",
"IndexerValidationUnableToConnectResolutionFailure": "Unable to connect to indexer connection failure. Check your connection to the indexer's server and DNS. {exceptionMessage}.",
"IndexerValidationUnableToConnectServerUnavailable": "Unable to connect to indexer, indexer's server is unavailable. Try again later. {exceptionMessage}.",
"IndexerValidationUnableToConnectTimeout": "Unable to connect to indexer, possibly due to a timeout. Try again or check your network settings. {exceptionMessage}.",
"Indexers": "Indexers",
"IndexersLoadError": "Unable to load Indexers",
"IndexersSettingsSummary": "Indexers and indexer options",