diff --git a/src/Jackett.Common/Indexers/BitHdtv.cs b/src/Jackett.Common/Indexers/BitHdtv.cs index 7521280cd..5cff88c2d 100644 --- a/src/Jackett.Common/Indexers/BitHdtv.cs +++ b/src/Jackett.Common/Indexers/BitHdtv.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Web; using AngleSharp.Html.Parser; using Jackett.Common.Models; using Jackett.Common.Models.IndexerConfig; @@ -20,8 +21,7 @@ namespace Jackett.Common.Indexers { private string LoginUrl => SiteLink + "login.php"; private string TakeLoginUrl => SiteLink + "takelogin.php"; - private string SearchUrl => SiteLink + "torrents.php?"; - private string DownloadUrl => SiteLink + "download.php?id={0}"; + private string SearchUrl => SiteLink + "torrents.php"; private new ConfigurationDataRecaptchaLogin configData { @@ -29,8 +29,9 @@ namespace Jackett.Common.Indexers set => base.configData = value; } - public BitHdtv(IIndexerConfigurationService configService, WebClient w, Logger l, IProtectionService ps) - : base(name: "BIT-HDTV", + public BitHdtv(IIndexerConfigurationService configService, WebClient w, Logger l, IProtectionService ps) : + base( + name: "BIT-HDTV", description: "BIT-HDTV - Home of High Definition", link: "https://www.bit-hdtv.com/", caps: new TorznabCapabilities(), @@ -43,9 +44,7 @@ namespace Jackett.Common.Indexers Encoding = Encoding.GetEncoding("iso-8859-1"); Language = "en-us"; Type = "private"; - TorznabCaps.SupportsImdbMovieSearch = true; - AddCategoryMapping(1, TorznabCatType.TVAnime); // Anime AddCategoryMapping(2, TorznabCatType.MoviesBluRay); // Blu-ray AddCategoryMapping(4, TorznabCatType.TVDocumentary); // Documentaries @@ -76,13 +75,12 @@ namespace Jackett.Common.Indexers public override async Task ApplyConfiguration(JToken configJson) { LoadValuesFromJson(configJson); - - var pairs = new Dictionary { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "g-recaptcha-response", configData.Captcha.Value }, + var pairs = new Dictionary + { + {"username", configData.Username.Value}, + {"password", configData.Password.Value}, + {"g-recaptcha-response", configData.Captcha.Value} }; - if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) { // Cookie was manually supplied @@ -92,7 +90,6 @@ namespace Jackett.Common.Indexers var results = await PerformQuery(new TorznabQuery()); if (!results.Any()) throw new Exception("Your cookie did not work"); - IsConfigured = true; SaveConfig(); return IndexerConfigurationStatus.Completed; @@ -104,17 +101,12 @@ namespace Jackett.Common.Indexers } } - var response = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs, null, true, null, SiteLink); - await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () => + var response = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs, null, true, referer: SiteLink); + await ConfigureIfOK(response.Cookies, response.Content?.Contains("logout.php") == true, () => { var parser = new HtmlParser(); var dom = parser.ParseDocument(response.Content); - var messageEl = dom.QuerySelectorAll("table.detail td.text").Last(); - foreach (var child in messageEl.QuerySelectorAll("a")) - child.Remove(); - foreach (var child in messageEl.QuerySelectorAll("style")) - child.Remove(); - var errorMessage = messageEl.TextContent.Trim(); + var errorMessage = dom.QuerySelector("table.detail td.text").FirstChild.TextContent.Trim(); throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; @@ -123,95 +115,96 @@ namespace Jackett.Common.Indexers protected override async Task> PerformQuery(TorznabQuery query) { var releases = new List(); - var qc = new NameValueCollection(); - if (!string.IsNullOrWhiteSpace(query.ImdbID)) + var results = new List(); + var search = new UriBuilder(SearchUrl); + if (query.IsImdbQuery) { qc.Add("search", query.ImdbID); - qc.Add("options", "4"); + qc.Add("options", "4"); //Search URL field for IMDB link + search.Query = qc.GetQueryString(); + results.Add(await RequestStringWithCookiesAndRetry(search.ToString())); + qc["Options"] = "1"; //Search Title and Description + search.Query = qc.GetQueryString(); + results.Add(await RequestStringWithCookiesAndRetry(search.ToString())); } - else if (!string.IsNullOrWhiteSpace(query.GetQueryString())) + else { + //Site handles empty string on search param. No need to check for IsNullOrEmpty() qc.Add("search", query.GetQueryString()); - qc.Add("options", "0"); + qc.Add("options", "0"); //Search Title Only + search.Query = qc.GetQueryString(); + results.Add(await RequestStringWithCookiesAndRetry(search.ToString())); } - var searchUrl = SearchUrl + qc.GetQueryString(); - var trackerCats = MapTorznabCapsToTrackers(query, mapChildrenCatsToParent: true); - - var results = await RequestStringWithCookiesAndRetry(searchUrl); - try - { - var parser = new HtmlParser(); - var dom = parser.ParseDocument(results.Content); - foreach (var child in dom.QuerySelectorAll("#needseed")) - child.Remove(); - foreach (var table in dom.QuerySelectorAll("table[align=center] + br + table > tbody")) + var trackerCats = MapTorznabCapsToTrackers(query, true); + var parser = new HtmlParser(); + foreach (var result in results) + try { - var rows = table.Children; - foreach (var row in rows.Skip(1)) + var dom = parser.ParseDocument(result.Content); + foreach (var child in dom.QuerySelectorAll("#needseed")) + child.Remove(); + var table = dom.QuerySelector("table[align=center] + br + table > tbody"); + foreach (var row in table.Children.Skip(1)) { var release = new ReleaseInfo(); var qLink = row.Children[2].QuerySelector("a"); - release.MinimumRatio = 1; release.MinimumSeedTime = 172800; // 48 hours release.Title = qLink.GetAttribute("title"); - if (!query.MatchQueryStringAND(release.Title)) + var detailsLink = new Uri(qLink.GetAttribute("href")); + //Skip irrelevant and duplicate entries + if (!query.MatchQueryStringAND(release.Title) || releases.Any(r => r.Guid == detailsLink)) continue; - release.Files = ParseUtil.CoerceLong(row.QuerySelector("td:nth-child(4)").TextContent); - release.Grabs = ParseUtil.CoerceLong(row.QuerySelector("td:nth-child(8)").TextContent); - release.Guid = new Uri(qLink.GetAttribute("href")); + release.Files = ParseUtil.CoerceLong(row.Children[3].TextContent); + release.Grabs = ParseUtil.CoerceLong(row.Children[7].TextContent); + release.Guid = detailsLink; release.Comments = release.Guid; - release.Link = new Uri(string.Format(DownloadUrl, qLink.GetAttribute("href").Split('=')[1])); - - var catUrl = row.Children[1].FirstElementChild.GetAttribute("href"); - var catNum = catUrl.Split('=', '&')[1]; + release.Link = new Uri(SiteLink + row.QuerySelector("a[href^=\"download.php\"]").GetAttribute("href")); + var catUrl = new Uri(SiteLink + row.Children[1].FirstElementChild.GetAttribute("href")); + var catQuery = HttpUtility.ParseQueryString(catUrl.Query); + var catNum = catQuery["cat"]; release.Category = MapTrackerCatToNewznab(catNum); - // This tracker cannot search multiple cats at a time, so search all cats then filter out results from different cats - if (trackerCats.Count > 0 && !trackerCats.Contains(catNum)) + // This tracker cannot search multiple cats at a time + // so search all cats then filter out results from different cats + if (trackerCats.Any() && !trackerCats.Contains(catNum)) continue; - var dateString = row.Children[5].TextContent.Trim(); var pubDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); release.PublishDate = DateTime.SpecifyKind(pubDate, DateTimeKind.Local); - var sizeStr = row.Children[6].TextContent; release.Size = ReleaseInfo.GetBytes(sizeStr); - release.Seeders = ParseUtil.CoerceInt(row.Children[8].TextContent.Trim()); release.Peers = ParseUtil.CoerceInt(row.Children[9].TextContent.Trim()) + release.Seeders; + switch (row.GetAttribute("bgcolor")) + { + case "#DDDDDD": + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 2; + break; + case "#FFFF99": + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + break; + case "#CCFF99": + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 2; + break; + default: + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + break; + } - var bgcolor = row.GetAttribute("bgcolor"); - if (bgcolor == "#DDDDDD") - { - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 2; - } - else if (bgcolor == "#FFFF99") - { - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 1; - } - else if (bgcolor == "#CCFF99") - { - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 2; - } - else - { - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - } releases.Add(release); } } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } + catch (Exception ex) + { + OnParseError(result.Content, ex); + } return releases; }