diff --git a/src/Jackett/Content/logos/privatehd.png b/src/Jackett/Content/logos/privatehd.png new file mode 100644 index 000000000..bb3eb495f Binary files /dev/null and b/src/Jackett/Content/logos/privatehd.png differ diff --git a/src/Jackett/Indexers/PrivateHD.cs b/src/Jackett/Indexers/PrivateHD.cs new file mode 100644 index 000000000..6c41ada3d --- /dev/null +++ b/src/Jackett/Indexers/PrivateHD.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models; +using Newtonsoft.Json.Linq; +using NLog; +using Jackett.Utils; +using System.Net; +using System.Net.Http; +using CsQuery; +using System.Web; +using Jackett.Services; +using Jackett.Utils.Clients; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class PrivateHD : BaseIndexer, IIndexer + { + private readonly string LoginUrl = ""; + private readonly string SearchUrl = ""; + private string cookieHeader = ""; + + private IWebClient webclient; + + public PrivateHD(IIndexerManagerService i, IWebClient wc, Logger l) + : base(name: "PrivateHD", + description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows", + link: new Uri("https://privatehd.to"), + caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(), + manager: i, + logger: l) + { + LoginUrl = SiteLink + "auth/login"; + SearchUrl = SiteLink + "torrents?in=1&type=2&search={0}"; + webclient = wc; + } + + public async Task ApplyConfiguration(JToken configJson) + { + var config = new ConfigurationDataBasicLogin(); + config.LoadValuesFromJson(configJson); + + var loginPage = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = LoginUrl, + Type = RequestType.GET, + AutoRedirect = true, + }); + + var token = new Regex("Avz.CSRF_TOKEN = '(.*?)';").Match(loginPage.Content).Groups[1].ToString(); + var pairs = new Dictionary { + { "_token", token }, + { "username_email", config.Username.Value }, + { "password", config.Password.Value }, + { "remember", "on" } + }; + + var response = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = LoginUrl, + PostData = pairs, + Referer = LoginUrl, + Type = RequestType.POST, + AutoRedirect = true, + Cookies = loginPage.Cookies + }); + + if (!response.Content.Contains("auth/logout")) + { + CQ dom = response.Content; + var messageEl = dom[".form-error"]; + var errorMessage = messageEl.Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); + } + else + { + cookieHeader = response.Cookies; + var configSaveData = new JObject(); + configSaveData["cookies"] = cookieHeader; + SaveConfig(configSaveData); + IsConfigured = true; + } + + } + + public async Task Download(Uri link) + { + var response = await webclient.GetBytes(new Utils.Clients.WebRequest() + { + Url = link.ToString(), + Cookies = cookieHeader + }); + + return response.Content; + } + + public Task GetConfigurationForSetup() + { + var config = new ConfigurationDataBasicLogin(); + return Task.FromResult(config); + } + + public void LoadFromSavedConfiguration(JToken jsonConfig) + { + cookieHeader = (string)jsonConfig["cookies"]; + IsConfigured = true; + } + + public async Task PerformQuery(TorznabQuery query) + { + List releases = new List(); + + var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString(); + var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchString)); + + var response = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = episodeSearchUrl, + Referer = SiteLink.ToString(), + Cookies = cookieHeader + }); + var results = response.Content; + + try + { + CQ dom = results; + var rows = dom["table > tbody > tr"]; + foreach (var row in rows) + { + CQ qRow = row.Cq(); + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + var qLink = row.ChildElements.ElementAt(1).FirstElementChild.Cq(); + release.Title = qLink.Text().Trim(); + release.Comments = new Uri(qLink.Attr("href")); + release.Guid = release.Comments; + + var qDownload = row.ChildElements.ElementAt(3).FirstElementChild.Cq(); + release.Link = new Uri(qDownload.Attr("href")); + + var dateStr = row.ChildElements.ElementAt(5).Cq().Text().Trim(); + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); + + var sizeStr = row.ChildElements.ElementAt(6).Cq().Text().Trim(); + var sizeParts = sizeStr.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); + release.Size = ReleaseInfo.GetBytes(sizeParts[1], ParseUtil.CoerceFloat(sizeParts[0])); + + release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()); + release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(9).Cq().Text()) + release.Seeders; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + return releases.ToArray(); + } + } +} diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 1091c6eb6..f3128a72b 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -155,6 +155,7 @@ + @@ -283,6 +284,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Jackett/Utils/Clients/WebRequest.cs b/src/Jackett/Utils/Clients/WebRequest.cs index b18e6a860..487b844e9 100644 --- a/src/Jackett/Utils/Clients/WebRequest.cs +++ b/src/Jackett/Utils/Clients/WebRequest.cs @@ -19,6 +19,7 @@ namespace Jackett.Utils.Clients public string Cookies { get; set; } public string Referer { get; set; } public RequestType Type { get; set; } + public bool AutoRedirect { get; set; } } public enum RequestType diff --git a/src/Jackett/Utils/Clients/WindowsWebClient.cs b/src/Jackett/Utils/Clients/WindowsWebClient.cs index 1c7ff8be9..7be704154 100644 --- a/src/Jackett/Utils/Clients/WindowsWebClient.cs +++ b/src/Jackett/Utils/Clients/WindowsWebClient.cs @@ -13,16 +13,18 @@ namespace Jackett.Utils.Clients class WindowsWebClient : IWebClient { private Logger logger; + CookieContainer cookies; public WindowsWebClient(Logger l) { logger = l; + cookies = new CookieContainer(); } public async Task GetBytes(WebRequest request) { logger.Debug(string.Format("WindowsWebClient:GetBytes(Url:{0})", request.Url)); - var cookies = new CookieContainer(); + if (!string.IsNullOrEmpty(request.Cookies)) { @@ -45,7 +47,6 @@ namespace Jackett.Utils.Clients CookieContainer = cookies, AllowAutoRedirect = false, UseCookies = true, - }); client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent); @@ -92,9 +93,8 @@ namespace Jackett.Utils.Clients var client = new HttpClient(new HttpClientHandler { CookieContainer = cookies, - AllowAutoRedirect = false, + AllowAutoRedirect = request.AutoRedirect, UseCookies = true, - }); client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent);