diff --git a/src/Jackett/Indexers/PiXELHD.cs b/src/Jackett/Indexers/PiXELHD.cs new file mode 100644 index 000000000..e21887611 --- /dev/null +++ b/src/Jackett/Indexers/PiXELHD.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +using AngleSharp.Parser.Html; +using Newtonsoft.Json.Linq; +using NLog; + +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using System.Collections.Specialized; + +namespace Jackett.Indexers +{ + class PiXELHD : BaseIndexer, IIndexer + { + string LoginUrl { get { return SiteLink + "login.php"; } } + string BrowseUrl { get { return SiteLink + "torrents.php"; } } + + new ConfigurationDataCaptchaLogin configData + { + get { return (ConfigurationDataCaptchaLogin)base.configData; } + set { base.configData = value; } + } + + string input_captcha = null; + string input_username = null; + string input_password = null; + + public PiXELHD(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService) + : base(name: "PiXELHD", + description: null, + link: "https://pixelhd.me/", + caps: new TorznabCapabilities(), + manager: indexerManager, + logger: logger, + p: protectionService, + client: webClient, + configData: new ConfigurationDataCaptchaLogin() + ) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping(1, TorznabCatType.MoviesHD); + + } + + public override async Task GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + var LoginParser = new HtmlParser(); + var LoginDocument = LoginParser.Parse(loginPage.Content); + + configData.CaptchaCookie.Value = loginPage.Cookies; + + var catchaImg = LoginDocument.QuerySelector("img[alt=\"FuckOff Image\"]"); + if (catchaImg != null) + { + var catchaInput = LoginDocument.QuerySelector("input[maxlength=\"6\"]"); + input_captcha = catchaInput.GetAttribute("name"); + + var captchaImage = await RequestBytesWithCookies(SiteLink + catchaImg.GetAttribute("src"), loginPage.Cookies, RequestType.GET, LoginUrl); + configData.CaptchaImage.Value = captchaImage.Content; + } + else + { + input_captcha = null; + configData.CaptchaImage.Value = null; + } + + var usernameInput = LoginDocument.QuerySelector("input[maxlength=\"20\"]"); + input_username = usernameInput.GetAttribute("name"); + + var passwordInput = LoginDocument.QuerySelector("input[maxlength=\"40\"]"); + input_password = passwordInput.GetAttribute("name"); + + return configData; + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + var pairs = new Dictionary + { + { input_username, configData.Username.Value }, + { input_password, configData.Password.Value }, + { "keeplogged", "1" } + }; + + if (input_captcha != null) + pairs.Add(input_captcha, configData.CaptchaText.Value); + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, configData.CaptchaCookie.Value, true); + + await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => + { + var LoginParser = new HtmlParser(); + var LoginDocument = LoginParser.Parse(result.Content); + var errorMessage = LoginDocument.QuerySelector("span.warning:has(br)").TextContent; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + var searchString = query.GetQueryString(); + var queryCollection = new NameValueCollection(); + queryCollection.Add("order_by", "time"); + queryCollection.Add("order_way", "desc"); + + if (!string.IsNullOrWhiteSpace(query.ImdbID)) + { + queryCollection.Add("imdbid", query.ImdbID); + } + else if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("groupname", searchString); + } + + queryCollection.Add("groupname", searchString); + + var searchUrl = BrowseUrl + "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookies(searchUrl); + if (results.IsRedirect) + { + // re login + await GetConfigurationForSetup(); + await ApplyConfiguration(null); + results = await RequestStringWithCookies(searchUrl); + } + + Regex IMDBRegEx = new Regex(@"tt(\d+)", RegexOptions.Compiled); + var hParser = new HtmlParser(); + var ResultDocument = hParser.Parse(results.Content); + try + { + var Groups = ResultDocument.QuerySelectorAll("div.browsePoster"); + + foreach (var Group in Groups) + { + var groupPoster = Group.QuerySelector("img.classBrowsePoster"); + var bannerURL = new Uri(SiteLink + groupPoster.GetAttribute("src")); + + long? IMDBId = null; + var imdbLink = Group.QuerySelector("a[href^=\"http://anonym.to/?http://www.imdb.com/title/tt\"]"); + if (imdbLink != null) + { + var IMDBMatch = IMDBRegEx.Match(imdbLink.GetAttribute("href")); + IMDBId = ParseUtil.CoerceLong(IMDBMatch.Groups[1].Value); + } + + var GroupTitle = Group.QuerySelector("strong:has(a[title=\"View Torrent\"])").TextContent.Replace(" ]", "]"); + + var Rows = Group.QuerySelectorAll("tr.group_torrent:has(a[href^=\"torrents.php?id=\"])"); + foreach (var Row in Rows) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 72 * 60 * 60; + + var title = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); + var link = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); + var added = Row.QuerySelector("td:nth-child(3)"); + var Size = Row.QuerySelector("td:nth-child(4)"); + var Grabs = Row.QuerySelector("td:nth-child(6)"); + var Seeders = Row.QuerySelector("td:nth-child(7)"); + var Leechers = Row.QuerySelector("td:nth-child(8)"); + + release.Title = GroupTitle + " " + title.TextContent; + release.Category = TorznabCatType.MoviesHD.ID; + release.Link = new Uri(SiteLink + link.GetAttribute("href")); + release.Comments = new Uri(SiteLink + title.GetAttribute("href")); + release.Guid = release.Link; + release.Size = ReleaseInfo.GetBytes(Size.TextContent); + release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent); + release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; + release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent); + release.PublishDate = DateTimeUtil.FromTimeAgo(added.TextContent); + release.BannerUrl = bannerURL; + release.Imdb = IMDBId; + + releases.Add(release); + } + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + + } +} diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index e5382f821..8a1a6f4ba 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -165,6 +165,7 @@ +