diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcorn.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcorn.cs index 301894f57..e9b9892a8 100644 --- a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcorn.cs +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcorn.cs @@ -1,7 +1,9 @@ using NLog; +using NzbDrone.Common.Cache; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; +using System.Collections.Generic; namespace NzbDrone.Core.Indexers.PassThePopcorn { @@ -13,13 +15,28 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn public override bool SupportsSearch => true; public override int PageSize => 50; - public PassThePopcorn(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger) + private readonly ICached> _authCookieCache; + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public PassThePopcorn(IHttpClient httpClient, ICacheManager cacheManager, IIndexerStatusService indexerStatusService, + IConfigService configService, IParsingService parsingService, Logger logger) : base(httpClient, indexerStatusService, configService, parsingService, logger) - { } + { + _httpClient = httpClient; + _logger = logger; + _authCookieCache = cacheManager.GetCache>(GetType(), "authCookies"); + } public override IIndexerRequestGenerator GetRequestGenerator() { - return new PassThePopcornRequestGenerator() { Settings = Settings }; + return new PassThePopcornRequestGenerator() + { + Settings = Settings, + HttpClient = _httpClient, + Logger = _logger, + AuthCookieCache = _authCookieCache + }; } public override IParseIndexerResponse GetParser() diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornApi.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornApi.cs index 9d7c93ea8..5c04ba5e8 100644 --- a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornApi.cs +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornApi.cs @@ -56,4 +56,12 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn public string PassKey { get; set; } } + public class PassThePopcornAuthResponse + { + public string Result { get; set; } + public string Popcron { get; set; } + public string AntiCsrfToken { get; set; } + + } + } diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornRequestGenerator.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornRequestGenerator.cs index 4d3a76708..dca6314cf 100644 --- a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornRequestGenerator.cs @@ -1,16 +1,30 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json.Linq; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; -using RestSharp; +using NzbDrone.Common.Cache; +using NLog; +using NzbDrone.Common.Serializer; namespace NzbDrone.Core.Indexers.PassThePopcorn { public class PassThePopcornRequestGenerator : IIndexerRequestGenerator { + public PassThePopcornSettings Settings { get; set; } + public ICached> AuthCookieCache { get; set; } + public IHttpClient HttpClient { get; set; } + public Logger Logger { get; set; } + + //public PassThePopcornRequestGenerator(ICacheManager cacheManager, IHttpClient httpClient, Logger logger) + //{ + // _httpClient = httpClient; + // _logger = logger; + + // _authCookieCache = cacheManager.GetCache>(GetType(), "authCookies"); + //} + public virtual IndexerPageableRequestChain GetRecentRequests() { var pageableRequests = new IndexerPageableRequestChain(); @@ -54,42 +68,70 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn private IEnumerable GetRequest(string searchParameters) { + Authenticate(); + var request = new IndexerRequest( $"{Settings.BaseUrl.Trim().TrimEnd('/')}/torrents.php?json=noredirect&searchstr={searchParameters}", HttpAccept.Json); - var cookies = GetPTPCookies(); + var cookies = AuthCookieCache.Find(Settings.BaseUrl.Trim().TrimEnd('/')); foreach (var cookie in cookies) { - request.HttpRequest.Cookies[cookie.Name] = cookie.Value; + request.HttpRequest.Cookies[cookie.Key] = cookie.Value; } yield return request; } - private IList GetPTPCookies() + private void Authenticate() { - var client = new RestClient(Settings.BaseUrl.Trim().TrimEnd('/')); - var request = new RestRequest("/ajax.php?action=login", Method.POST); - request.AddParameter("username", Settings.Username); - request.AddParameter("password", Settings.Password); - request.AddParameter("passkey", Settings.Passkey); - request.AddParameter("keeplogged", "1"); - request.AddParameter("login", "Log In!"); - request.AddHeader("Content-Type", "multipart/form-data"); - - IRestResponse response = client.Execute(request); - var content = response.Content; - - var jsonResponse = JObject.Parse(content); - if (content != null && (string)jsonResponse["Result"] != "Error") + var requestBuilder = new HttpRequestBuilder($"{Settings.BaseUrl.Trim().TrimEnd('/')}") { - return response.Cookies; + LogResponseContent = true + }; + + requestBuilder.Method = HttpMethod.POST; + requestBuilder.Resource("ajax.php?action=login"); + requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); + + var authKey = Settings.BaseUrl.Trim().TrimEnd('/'); + var cookies = AuthCookieCache.Find(authKey); + + if (cookies == null) + { + AuthCookieCache.Remove(authKey); + var authLoginRequest = requestBuilder + .AddFormParameter("username", Settings.Username) + .AddFormParameter("password", Settings.Password) + .AddFormParameter("passkey", Settings.Passkey) + .AddFormParameter("keeplogged", "1") + .AddFormParameter("login", "Log In!") + .SetHeader("Content-Type", "multipart/form-data") + .Accept(HttpAccept.Json) + .Build(); + + // authLoginRequest.Method = HttpMethod.POST; + + var response = HttpClient.Execute(authLoginRequest); + var result = Json.Deserialize(response.Content); + + if (result.Result != "Ok" || string.IsNullOrWhiteSpace(result.Result)) + { + Logger.Debug("PassThePopcorn authentication failed."); + throw new Exception("Failed to authenticate with PassThePopcorn."); + } + + Logger.Debug("PassThePopcorn authentication succeeded."); + + cookies = response.GetCookies(); + AuthCookieCache.Set(authKey, cookies); + requestBuilder.SetCookies(cookies); + } + else + { + requestBuilder.SetCookies(cookies); } - - throw new Exception("Error connecting to PTP invalid username, password, or passkey"); } - } } diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornSettings.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornSettings.cs index aed6f91f9..d7aabeaa3 100644 --- a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornSettings.cs +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornSettings.cs @@ -32,10 +32,10 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn [FieldDefinition(1, Label = "Username", HelpText = "PTP Username")] public string Username { get; set; } - [FieldDefinition(2, Label = "Password", HelpText = "PTP Password")] + [FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "PTP Password")] public string Password { get; set; } - [FieldDefinition(3, Label = "Passkey", Type = FieldType.Password, HelpText = "PTP Passkey")] + [FieldDefinition(3, Label = "Passkey", HelpText = "PTP Passkey")] public string Passkey { get; set; } [FieldDefinition(4, Label = "Prefer Golden", Type = FieldType.Checkbox , HelpText = "Favors Golden Popcorn-releases over all other releases.")]