diff --git a/frontend/src/Indexer/Index/Table/MovieIndexRow.css b/frontend/src/Indexer/Index/Table/IndexerIndexRow.css similarity index 87% rename from frontend/src/Indexer/Index/Table/MovieIndexRow.css rename to frontend/src/Indexer/Index/Table/IndexerIndexRow.css index 308bbab2b..cb40642c7 100644 --- a/frontend/src/Indexer/Index/Table/MovieIndexRow.css +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.css @@ -56,8 +56,8 @@ margin-top: 0; } -.externalLinks { - margin: 0 2px; - width: 22px; - text-align: center; +.externalLink { + composes: link from '~Components/Link/Link.css'; + + color: $textColor; } diff --git a/frontend/src/Indexer/Index/Table/MovieIndexRow.js b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js similarity index 95% rename from frontend/src/Indexer/Index/Table/MovieIndexRow.js rename to frontend/src/Indexer/Index/Table/IndexerIndexRow.js index 64c03738c..40c54d3b2 100644 --- a/frontend/src/Indexer/Index/Table/MovieIndexRow.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js @@ -14,9 +14,9 @@ import translate from 'Utilities/String/translate'; import CapabilitiesLabel from './CapabilitiesLabel'; import IndexerStatusCell from './IndexerStatusCell'; import ProtocolLabel from './ProtocolLabel'; -import styles from './MovieIndexRow.css'; +import styles from './IndexerIndexRow.css'; -class MovieIndexRow extends Component { +class IndexerIndexRow extends Component { // // Lifecycle @@ -61,6 +61,7 @@ class MovieIndexRow extends Component { const { id, name, + baseUrl, enable, tags, protocol, @@ -213,8 +214,10 @@ class MovieIndexRow extends Component { className={styles[column.name]} > ("Indexers").RegisterModel() .Ignore(x => x.ImplementationName) + .Ignore(i => i.BaseUrl) .Ignore(i => i.Protocol) .Ignore(i => i.Privacy) .Ignore(i => i.SupportsRss) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 9b72100be..dac347dd7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -15,7 +15,7 @@ public class Cardigann : HttpIndexerBase private readonly IIndexerDefinitionUpdateService _definitionService; public override string Name => "Cardigann"; - public override string BaseUrl => throw new System.NotImplementedException(); + public override string BaseUrl => ""; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; @@ -76,6 +76,24 @@ private IndexerDefinition GetDefinition(CardigannMetaDefinition definition) }; } + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + var generator = (CardigannRequestGenerator)GetRequestGenerator(); + + SetCookieFunctions(generator); + + return generator.CheckIfLoginIsNeeded(httpResponse); + } + + protected override void DoLogin() + { + var generator = (CardigannRequestGenerator)GetRequestGenerator(); + + SetCookieFunctions(generator); + + generator.DoLogin(); + } + protected override void Test(List failures) { base.Test(failures); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 1eb4eac7f..850285e37 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -155,15 +155,10 @@ private Dictionary GetQueryVariableDefaults(SearchCriteriaBase s return variables; } - private void Authenticate() + public void DoLogin() { var login = _definition.Login; - if (login == null || TestLogin()) - { - return; - } - if (login.Method == "post") { var pairs = new Dictionary(); @@ -725,7 +720,7 @@ protected string GetRedirectDomainHint(string requestUrl, string redirectUrl) protected string GetRedirectDomainHint(HttpResponse result) => GetRedirectDomainHint(result.Request.Url.ToString(), result.Headers.GetSingleValue("Location")); - protected bool CheckIfLoginIsNeeded(HttpResponse response, IHtmlDocument document) + public bool CheckIfLoginIsNeeded(HttpResponse response) { if (response.HasHttpRedirect) { @@ -745,6 +740,9 @@ protected bool CheckIfLoginIsNeeded(HttpResponse response, IHtmlDocument documen return false; } + var parser = new HtmlParser(); + var document = parser.ParseDocument(response.Content); + if (_definition.Login.Test.Selector != null) { var selection = document.QuerySelectorAll(_definition.Login.Test.Selector); @@ -759,13 +757,6 @@ protected bool CheckIfLoginIsNeeded(HttpResponse response, IHtmlDocument documen private IEnumerable GetRequest(Dictionary variables) { - Cookies = GetCookies(); - - if (Cookies == null || !Cookies.Any()) - { - Authenticate(); - } - var search = _definition.Search; var mappedCategories = MapTorznabCapsToTrackers((int[])variables[".Query.Categories"]); @@ -890,14 +881,6 @@ private IEnumerable GetRequest(Dictionary variab } } - if (Cookies != null) - { - foreach (var cookie in Cookies) - { - request.HttpRequest.Cookies.Add(cookie.Key, cookie.Value); - } - } - request.HttpRequest.Method = method; yield return request; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs index 091155af1..9dda57ff7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs @@ -72,8 +72,6 @@ protected override void DoLogin() cookies = response.GetCookies(); - Cookies = cookies; - UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); _logger.Debug("Gazelle authentication succeeded."); diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index f1e115dd1..8eabe0473 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -65,7 +65,6 @@ protected override void DoLogin() var response = _httpClient.Execute(authLoginRequest); cookies = response.GetCookies(); - Cookies = cookies; UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); _logger.Debug("HDTorrents authentication succeeded."); diff --git a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs index c4aa05f5d..963f23d6f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs @@ -304,6 +304,7 @@ public IList ParseResponse(IndexerResponse indexerResponse) Title = title, Guid = details.AbsoluteUri, DownloadUrl = link.AbsoluteUri, + InfoUrl = details.AbsoluteUri, PublishDate = publishDate, Category = cat, Size = size, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index a971ed4dd..e3de9680b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -16,7 +16,7 @@ public class Newznab : HttpIndexerBase private readonly INewznabCapabilitiesProvider _capabilitiesProvider; public override string Name => "Newznab"; - public override string BaseUrl => Settings.BaseUrl; + public override string BaseUrl => GetBaseUrlFromSettings(); public override bool FollowRedirect => true; public override DownloadProtocol Protocol => DownloadProtocol.Usenet; @@ -40,6 +40,18 @@ public override IParseIndexerResponse GetParser() return new NewznabRssParser(Settings); } + public string GetBaseUrlFromSettings() + { + var baseUrl = ""; + + if (Definition == null || Settings == null || Settings.Categories == null) + { + return baseUrl; + } + + return Settings.BaseUrl; + } + public IndexerCapabilities GetCapabilitiesFromSettings() { var caps = new IndexerCapabilities(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs index 9cb2c9fd3..92c4c48df 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs @@ -242,6 +242,7 @@ public IList ParseResponse(IndexerResponse indexerResponse) Title = title, Guid = details.AbsoluteUri, DownloadUrl = link.AbsoluteUri, + InfoUrl = details.AbsoluteUri, PublishDate = publishDate, Category = _categories.MapTrackerCatToNewznab(row.c.ToString()), Size = (long)row.size, diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index 56e30a12e..3b1e54c8d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -66,7 +66,6 @@ protected override void DoLogin() var response = _httpClient.Execute(authLoginRequest); cookies = response.GetCookies(); - Cookies = cookies; UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); _logger.Debug("TorrentLeech authentication succeeded."); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 557fd71f5..6aab1a176 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -17,7 +17,7 @@ public class Torznab : HttpIndexerBase private readonly INewznabCapabilitiesProvider _capabilitiesProvider; public override string Name => "Torznab"; - public override string BaseUrl => Settings.BaseUrl; + public override string BaseUrl => ""; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index e202dbbfc..d3d2d7078 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -136,7 +136,7 @@ protected IIndexerRequestGenerator SetCookieFunctions(IIndexerRequestGenerator g generator.CookiesUpdater = (cookies, expiration) => { - _indexerStatusService.UpdateCookies(Definition.Id, cookies, expiration); + UpdateCookies(cookies, expiration); }; return generator; @@ -156,6 +156,7 @@ protected IDictionary GetCookies() protected void UpdateCookies(IDictionary cookies, DateTime? expiration) { + Cookies = cookies; _indexerStatusService.UpdateCookies(Definition.Id, cookies, expiration); } @@ -434,6 +435,8 @@ protected virtual IndexerResponse FetchIndexerResponse(IndexerRequest request) response = _httpClient.Execute(request.HttpRequest); } + UpdateCookies(Cookies, DateTime.Now + TimeSpan.FromDays(30)); + return new IndexerResponse(request, response, stopWatch.ElapsedMilliseconds); } diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index ce19c9dec..e9f6a94de 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -10,6 +10,7 @@ public interface IIndexer : IProvider bool SupportsSearch { get; } IndexerCapabilities Capabilities { get; } + string BaseUrl { get; } DownloadProtocol Protocol { get; } IndexerPrivacy Privacy { get; } diff --git a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs index fba0eadf6..31f42d5ee 100644 --- a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs +++ b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs @@ -7,6 +7,7 @@ namespace NzbDrone.Core.Indexers { public class IndexerDefinition : ProviderDefinition { + public string BaseUrl { get; set; } public DownloadProtocol Protocol { get; set; } public IndexerPrivacy Privacy { get; set; } public bool SupportsRss { get; set; } diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 108d46bfb..4af697fdb 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -52,6 +52,7 @@ public override List All() var settings = (CardigannSettings)definition.Settings; var defFile = _definitionService.GetDefinition(settings.DefinitionFile); definition.ExtraFields = defFile.Settings; + definition.BaseUrl = defFile.Links.First(); definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); @@ -71,6 +72,7 @@ public override IndexerDefinition Get(int id) var settings = (CardigannSettings)definition.Settings; var defFile = _definitionService.GetDefinition(settings.DefinitionFile); definition.ExtraFields = defFile.Settings; + definition.BaseUrl = defFile.Links.First(); definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); @@ -158,6 +160,7 @@ public override void SetProviderCharacteristics(IIndexer provider, IndexerDefini //We want to use the definition Caps and Privacy for Cardigann instead of the provider. if (definition.Implementation != typeof(Cardigann.Cardigann).Name) { + definition.BaseUrl = provider.BaseUrl; definition.Privacy = provider.Privacy; definition.Capabilities = provider.Capabilities; } diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs index dfdf02b4a..c5dcc2c26 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs @@ -10,6 +10,7 @@ namespace Prowlarr.Api.V1.Indexers { public class IndexerResource : ProviderResource { + public string BaseUrl { get; set; } public bool Enable { get; set; } public bool SupportsRss { get; set; } public bool SupportsSearch { get; set; } @@ -49,6 +50,7 @@ public override IndexerResource ToResource(IndexerDefinition definition) } } + resource.BaseUrl = definition.BaseUrl; resource.Enable = definition.Enable; resource.SupportsRss = definition.SupportsRss; resource.SupportsSearch = definition.SupportsSearch; @@ -85,6 +87,7 @@ public override IndexerDefinition ToModel(IndexerResource resource) } definition.Enable = resource.Enable; + definition.BaseUrl = resource.BaseUrl; definition.Priority = resource.Priority; definition.Privacy = resource.Privacy; definition.Added = resource.Added;