protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var qParams = new NameValueCollection { { "tor[text]", query.GetQueryString() }, { "tor[srchIn][title]", "true" }, { "tor[srchIn][author]", "true" }, { "tor[searchType]", configData.ExcludeVip?.Value == true ? "nVIP" : "all" }, // exclude VIP torrents { "tor[searchIn]", "torrents" }, { "tor[hash]", "" }, { "tor[sortType]", "default" }, { "tor[startNumber]", "0" }, { "thumbnails", "1" }, // gives links for thumbnail sized versions of their posters //{ "posterLink", "1"}, // gives links for a full sized poster //{ "dlLink", "1"}, // include the url to download the torrent { "description", "1" } // include the description //{"bookmarks", "0"} // include if the item is bookmarked or not }; // Exclude VIP torrents var catList = MapTorznabCapsToTrackers(query); if (catList.Any()) { var index = 0; foreach (var cat in catList) { qParams.Add("tor[cat][" + index + "]", cat); index++; } } else { qParams.Add("tor[cat][]", "0"); } var urlSearch = SearchUrl; if (qParams.Count > 0) { urlSearch += $"?{qParams.GetQueryString()}"; } var response = await RequestStringWithCookiesAndRetry(urlSearch); if (response.Content.StartsWith("Error")) { throw new Exception(response.Content); } try { var jsonContent = JObject.Parse(response.Content); var sitelink = new Uri(SiteLink); var error = jsonContent.Value <string>("error"); if (error != null && error == "Nothing returned, out of 0") { return(releases); } foreach (var item in jsonContent.Value <JArray>("data")) { //TODO shift to ReleaseInfo object initializer for consistency var release = new ReleaseInfo(); var id = item.Value <long>("id"); release.Title = item.Value <string>("title"); release.Description = item.Value <string>("description"); var authorInfo = item.Value <string>("author_info"); string author = null; if (!string.IsNullOrWhiteSpace(authorInfo)) { authorInfo = Regex.Unescape(authorInfo); var authorInfoJson = JObject.Parse(authorInfo); author = authorInfoJson.First.Last.Value <string>(); } if (author != null) { release.Title += " by " + author; } var flags = new List <string>(); var langCode = item.Value <string>("lang_code"); if (!string.IsNullOrEmpty(langCode)) { flags.Add(langCode); } var filetype = item.Value <string>("filetype"); if (!string.IsNullOrEmpty(filetype)) { flags.Add(filetype); } if (flags.Count > 0) { release.Title += " [" + string.Join(" / ", flags) + "]"; } if (item.Value <int>("vip") == 1) { release.Title += " [VIP]"; } var category = item.Value <string>("category"); release.Category = MapTrackerCatToNewznab(category); release.Link = new Uri(sitelink, "/tor/download.php?tid=" + id); release.Comments = new Uri(sitelink, "/t/" + id); release.Guid = release.Comments; var dateStr = item.Value <string>("added"); var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime(); release.Grabs = item.Value <long>("times_completed"); release.Files = item.Value <long>("numfiles"); release.Seeders = item.Value <int>("seeders"); release.Peers = item.Value <int>("leechers") + release.Seeders; var size = item.Value <string>("size"); release.Size = ReleaseInfo.GetBytes(size); release.DownloadVolumeFactor = item.Value <int>("free") == 1 ? 0 : 1; release.UploadVolumeFactor = 1; releases.Add(release); } } catch (Exception ex) { OnParseError(response.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchUrl = BrowseUrl; var searchString = query.GetQueryString(); var cats = MapTorznabCapsToTrackers(query); string cat = "0"; if (cats.Count == 1) { cat = cats[0]; } var queryCollection = new NameValueCollection(); if (query.ImdbID != null) { queryCollection.Add("search", query.ImdbID); } else if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("search", searchString); } queryCollection.Add("cat", cat); queryCollection.Add("searchin", "1"); queryCollection.Add("sort", "2"); searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); // Occasionally the cookies become invalid, login again if that happens if (response.IsRedirect) { await ApplyConfiguration(null); response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); } var results = response.Content; try { CQ dom = results; var globalFreeLeech = dom.Find("div.globalFreeLeech").Any(); var rows = dom[".torrentrow"]; foreach (var row in rows) { var release = new ReleaseInfo(); var qRow = row.Cq(); var qTitleLink = qRow.Find(".torrenttable:eq(1) a").First(); release.Title = qRow.Find(".torrenttable:eq(1) b").Text(); var longtitle = qRow.Find(".torrenttable:eq(1) a[title]").Attr("title"); if (!string.IsNullOrEmpty(longtitle) && !longtitle.Contains("<")) // releases with cover image have no full title { release.Title = longtitle; } if (query.ImdbID == null && !query.MatchQueryStringAND(release.Title)) { continue; } release.Description = qRow.Find(".torrenttable:eq(1) > span > font.small").First().Text(); var tooltip = qTitleLink.Attr("title"); if (!string.IsNullOrEmpty(tooltip)) { var ImgRegexp = new Regex("src='(.*?)'"); var ImgRegexpMatch = ImgRegexp.Match(tooltip); if (ImgRegexpMatch.Success) { release.BannerUrl = new Uri(ImgRegexpMatch.Groups[1].Value); } } release.Guid = new Uri(SiteLink + qTitleLink.Attr("href")); release.Comments = release.Guid; //22:05:3716/02/2013 var dateStr = qRow.Find(".torrenttable:eq(5)").Text().Trim() + " +0200"; release.PublishDate = DateTime.ParseExact(dateStr, "H:mm:ssdd/MM/yyyy zzz", CultureInfo.InvariantCulture); var qLink = qRow.Find("a[href^=\"download.php?id=\"]").First(); release.Link = new Uri(SiteLink + qLink.Attr("href").Replace("&usetoken=1", "")); var sizeStr = qRow.Find(".torrenttable:eq(6)").Text().Trim(); release.Size = ReleaseInfo.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(8)").Text().Trim()); release.Peers = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(9)").Text().Trim()) + release.Seeders; var catId = qRow.Find(".torrenttable:eq(0) a").First().Attr("href").Substring(15); release.Category = MapTrackerCatToNewznab(catId); var grabs = qRow.Find(".torrenttable:eq(7)").First().Get(0).FirstChild; release.Grabs = ParseUtil.CoerceLong(catId); if (globalFreeLeech || row.Cq().Find("img[alt=\"FreeLeech\"]").Any()) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; // Skip Romanian releases if (release.Category.Contains(TorznabCatType.MoviesForeign.ID) && !configData.IncludeRomanianReleases.Value) { continue; } releases.Add(release); } } catch (Exception ex) { OnParseError(results, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var trackerCats = MapTorznabCapsToTrackers(query); var cat = (trackerCats.Count == 1 ? trackerCats.ElementAt(0) : "0"); var episodeSearchUrl = string.Format(SearchUrl, cat, WebUtility.UrlEncode(query.GetQueryString())); var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl); if (results.IsRedirect) { throw new ExceptionWithConfigData("Unexpected redirect to " + results.RedirectingTo + ". Check your credentials.", configData); } if (results.Content.Contains("No torrents found")) { return(releases); } try { CQ dom = results.Content; var rows = dom[".ctable_content_no_pad > table > tbody > tr"].ToArray(); DateTime lastDateTime = default(DateTime); for (var i = 0; i < rows.Length; i++) { var rowA = rows[i]; var rAlign = rowA.Attributes["align"]; if (rAlign == "right" || rAlign == "center") { continue; } if (rAlign == "left") { // ex: "Monday, Jun 01, 2015", "Monday, Aug 03, 2015" var dateStr = rowA.Cq().Text().Trim().Replace("Added on ", ""); if (string.IsNullOrWhiteSpace(dateStr) || dateStr == "Sponsored links" || dateStr.StartsWith("!function") || dateStr.StartsWith("atOptions")) { continue; // ignore ads } if (dateStr.ToLowerInvariant().Contains("today")) { lastDateTime = DateTime.Now; } else { lastDateTime = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dddd, MMM dd, yyyy", CultureInfo.InvariantCulture), DateTimeKind.Utc).ToLocalTime(); } continue; } if (rowA.ChildElements.Count() < 2) { continue; } var rowB = rows[++i]; var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; release.PublishDate = lastDateTime; var catUrl = rowA.ChildElements.ElementAt(0).FirstElementChild.GetAttribute("href"); var catId = QueryHelpers.ParseQuery(catUrl)["category"].First(); release.Category = MapTrackerCatToNewznab(catId); var qLink = rowA.ChildElements.ElementAt(1).FirstElementChild.Cq(); release.Title = qLink.Text().Trim(); release.Description = rowB.ChildElements.ElementAt(0).Cq().Text(); if (release.Category != null && release.Category.Contains(TorznabCatType.Audio.ID)) { if (release.Description.Contains("Lossless")) { release.Category = new List <int> { TorznabCatType.AudioLossless.ID } } ; else if (release.Description.Contains("MP3")) { release.Category = new List <int> { TorznabCatType.AudioMP3.ID } } ; else { release.Category = new List <int> { TorznabCatType.AudioOther.ID } }; } release.Comments = new Uri(new Uri(SiteLink), qLink.Attr("href")); release.Guid = release.Comments; release.Link = release.Comments; // indirect download see Download() method var sizeStr = rowB.ChildElements.ElementAt(2).Cq().Text(); release.Size = ReleaseInfo.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(5).Cq().Text()); release.Peers = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()) + release.Seeders; var grabs = rowB.Cq().Find("td:nth-child(5)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); release.DownloadVolumeFactor = 0; // ratioless release.UploadVolumeFactor = 1; releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var pairs = new Dictionary <string, string> { { "do", "search" }, { "search_type", query.IsImdbQuery ? "t_genre" : "t_name" }, { "keywords", query.IsImdbQuery ? query.ImdbID : query.GetQueryString() }, { "category", "0" } // multi cat search not supported }; var results = await RequestWithCookiesAsync(BrowseUrl, method : RequestType.POST, data : pairs); if (results.IsRedirect) { // re-login await ApplyConfiguration(null); results = await RequestWithCookiesAsync(BrowseUrl, method : RequestType.POST, data : pairs); } try { var lastDate = DateTime.Now; var parser = new HtmlParser(); var doc = parser.ParseDocument(results.ContentString); var rows = doc.QuerySelectorAll("table[id='sortabletable'] > tbody > tr"); foreach (var row in rows.Skip(1)) { if (row.Children.Length != 9) { continue; // not a torrent line } var cat = row.Children[0].QuerySelector("a").GetAttribute("href").Split('=')[1]; var title = row.Children[1].QuerySelector("a").TextContent; var qLinks = row.Children[2].QuerySelectorAll("a"); var link = new Uri(configData.TorrentHTTPSMode.Value ? qLinks[1].GetAttribute("href") : qLinks[0].GetAttribute("href")); var comments = new Uri(row.Children[1].QuerySelector("a").GetAttribute("href")); var size = row.Children[4].TextContent; var grabs = row.Children[5].QuerySelector("a").TextContent; var seeders = ParseUtil.CoerceInt(row.Children[6].QuerySelector("a").TextContent); var leechers = ParseUtil.CoerceInt(row.Children[7].QuerySelector("a").TextContent); var qTags = row.Children[1].QuerySelector("div:has(span[style=\"float: right;\"])"); var dlVolumeFactor = 1.0; if (qTags.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null) { dlVolumeFactor = 0.0; } else if (qTags.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null) { dlVolumeFactor = 0.5; } var upVolumeFactor = qTags.QuerySelector("img[alt^=\"TORRENT X2\"]") != null ? 2.0 : 1.0; var release = new ReleaseInfo { MinimumRatio = 1, MinimumSeedTime = 172800, Category = MapTrackerCatToNewznab(cat), Title = title, Link = link, Comments = comments, Size = ReleaseInfo.GetBytes(size), Seeders = seeders, Grabs = ParseUtil.CoerceLong(grabs), DownloadVolumeFactor = dlVolumeFactor, UploadVolumeFactor = upVolumeFactor, Peers = leechers + seeders, Guid = link }; var qTooltip = row.Children[1].QuerySelector("div.tooltip-content"); if (qTooltip != null) { var banner = qTooltip.QuerySelector("img"); if (banner != null) { release.BannerUrl = new Uri(banner.GetAttribute("src")); banner.Remove(); } qTooltip.QuerySelector("div:contains(\"Total Hits\")").Remove(); var qLongTitle = qTooltip.QuerySelector("div"); release.Title = qLongTitle.TextContent; qLongTitle.Remove(); var description = qTooltip.TextContent.Trim(); if (!string.IsNullOrWhiteSpace(description)) { release.Description = description; } } // issue #5064 replace multi keyword if (!string.IsNullOrEmpty(configData.ReplaceMulti.Value)) { var regex = new Regex("(?i)([\\.\\- ])MULTI([\\.\\- ])"); release.Title = regex.Replace(release.Title, "$1" + configData.ReplaceMulti.Value + "$2"); } // issue #6855 Replace VOSTFR with ENGLISH if (configData.Vostfr.Value) { release.Title = release.Title.Replace("VOSTFR", "ENGLISH").Replace("SUBFRENCH", "ENGLISH"); } var qPretime = qTags.QuerySelector("font.mkprettytime"); if (qPretime != null) { if (release.Description == null) { release.Description = qPretime.TextContent; } else { release.Description += "<br>\n" + qPretime.TextContent; } release.PublishDate = lastDate; } else { release.PublishDate = DateTime.ParseExact(qTags.TextContent.Trim(), "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture); lastDate = release.PublishDate; } releases.Add(release); } } catch (Exception ex) { OnParseError(results.ContentString, ex); } return(releases); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 3, 5, DayOfWeek.Sunday); TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 10, 5, DayOfWeek.Sunday); TimeSpan delta = new TimeSpan(1, 0, 0); TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; TimeZoneInfo denmarkTz = TimeZoneInfo.CreateCustomTimeZone("Denmark Time", new TimeSpan(1, 0, 0), "(GMT+01:00) Denmark Time", "Denmark Time", "Denmark DST", adjustments); var releasesPerPage = 100; var releases = new List <ReleaseInfo>(); var page = (query.Offset / releasesPerPage) + 1; string episodeSearchUrl; if (string.IsNullOrEmpty(query.GetQueryString())) { episodeSearchUrl = SearchUrl + "?page=" + page; } else { var cats = MapTorznabCapsToTrackers(query); var catsUrlPart = string.Join("&", cats.Select(c => $"filter_{c}=on")); episodeSearchUrl = $"{SearchUrl}?page={page}&group=0&{catsUrlPart}&search={HttpUtility.UrlEncode(query.GetQueryString())}&pre_type=torrents&type="; } var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl); if (string.IsNullOrEmpty(results.Content)) { CookieHeader = string.Empty; var pairs = new Dictionary <string, string> { { "username", configData.Username.Value }, { "password", configData.Password.Value }, { "langlang", null }, { "login", "login" } }; var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, CookieHeader, true, null, LoginUrl); await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () => { CQ dom = response.Content; var messageEl = dom["#loginform .warning"]; var errorMessage = messageEl.Text().Trim(); throw new ExceptionWithConfigData(errorMessage, configData); }); results = await RequestStringWithCookiesAndRetry(episodeSearchUrl); } try { CQ dom = results.Content; var rows = dom["#torrent_table tr.torrent"]; foreach (var row in rows) { var qRow = row.Cq(); var release = new ReleaseInfo { MinimumRatio = 1, MinimumSeedTime = 172800 }; var catAnchor = row.FirstChild.FirstChild; var catUrl = catAnchor.GetAttribute("href"); var catStr = Regex.Match(catUrl, "filter_(?<catNo>[0-9]+)=on").Groups["catNo"].Value; var catNo = int.Parse(catStr); var moviesCatsDanish = new[] { 2, 3, 10, 28, 29, 31 }; var moviesCatsIntl = new[] { 8, 9, 11, 22, 24 }; var moviesCats = configData.OnlyDanishCategories.Value ? moviesCatsDanish : moviesCatsDanish.Concat(moviesCatsIntl); var seriesCatsDanish = new[] { 1, 4, 30 }; var seriesCatsIntl = new[] { 20, 21 }; var seriesCats = configData.OnlyDanishCategories.Value ? seriesCatsDanish : seriesCatsDanish.Concat(seriesCatsIntl); if (moviesCats.Contains(catNo)) { release.Category = TorznabCatType.Movies.ID; } else if (seriesCats.Contains(catNo)) { release.Category = TorznabCatType.TV.ID; } else if (catNo == 12) { release.Category = TorznabCatType.BooksEbook.ID; } else if (catNo == 6) { release.Category = TorznabCatType.AudioAudiobook.ID; } else { continue; } var titleAnchor = qRow.Find("div.croptorrenttext a").FirstElement(); var title = titleAnchor.GetAttribute("title"); release.Title = title; var dlUrlAnchor = qRow.Find("span.right a[title=\"Direkte download link\"]").FirstElement(); var dlUrl = dlUrlAnchor.GetAttribute("href"); release.Link = new Uri(SiteLink + dlUrl); var torrentLink = titleAnchor.GetAttribute("href"); release.Guid = new Uri(SiteLink + torrentLink); release.Comments = new Uri(SearchUrl + torrentLink); var addedElement = qRow.Find("span.time").FirstElement(); var addedStr = addedElement.GetAttribute("title"); release.PublishDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(addedStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture), denmarkTz).ToLocalTime(); var columns = qRow.Children(); var seedersElement = columns.Reverse().Skip(1).First(); release.Seeders = int.Parse(seedersElement.InnerText); var leechersElement = columns.Last().FirstElement(); release.Peers = release.Seeders + int.Parse(leechersElement.InnerText); var sizeElement = columns.Skip(2).First(); var sizeStr = sizeElement.InnerText; release.Size = ReleaseInfo.GetBytes(sizeStr); var imdbAnchor = qRow.Find(".torrentnotes a") .FirstOrDefault(a => a.GetAttribute("href").Contains("imdb.com")); if (imdbAnchor != null) { var referrerUrl = imdbAnchor.GetAttribute("href"); release.Imdb = long.Parse(Regex.Match(referrerUrl, "tt(?<imdbId>[0-9]+)").Groups["imdbId"].Value); } var Files = qRow.Find("td:nth-child(3) > div"); release.Files = ParseUtil.CoerceLong(Files.Text().Split(' ')[0]); var Grabs = qRow.Find("td:nth-child(6)"); release.Grabs = ParseUtil.CoerceLong(Grabs.Text()); if (qRow.Find("span.freeleech, img[src=\"/static/common/torrents/gratis.png\"]").Length >= 1) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } if (qRow.Find("img[src=\"/static/common/torrents/toxupload.png\"]").Length >= 1) { release.UploadVolumeFactor = 2; } else { release.UploadVolumeFactor = 1; } releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); // if the search string is empty use the "last 24h torrents" view if (string.IsNullOrWhiteSpace(searchString)) { var results = await RequestStringWithCookies(TodayUrl); try { string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); foreach (var Row in Rows) { try { var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 0; var qDetailsLink = Row.QuerySelector("a.BJinfoBox"); var qTitle = qDetailsLink.QuerySelector("font"); release.Title = qTitle.TextContent; var qBJinfoBox = qDetailsLink.QuerySelector("span"); var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); var qSeeders = Row.QuerySelector("td:nth-child(4)"); var qLeechers = Row.QuerySelector("td:nth-child(5)"); var qFreeLeech = Row.QuerySelector("font[color=\"green\"]:contains(Free)"); release.Description = ""; foreach (var Child in qBJinfoBox.ChildNodes) { var type = Child.NodeType; if (type != NodeType.Text) { continue; } var line = Child.TextContent; if (line.StartsWith("Tamanho:")) { string Size = line.Substring("Tamanho: ".Length);; release.Size = ReleaseInfo.GetBytes(Size); } else if (line.StartsWith("Lançado em: ")) { string PublishDateStr = line.Substring("Lançado em: ".Length).Replace("às ", ""); PublishDateStr += " +0"; var PublishDate = DateTime.SpecifyKind(DateTime.ParseExact(PublishDateStr, "dd/MM/yyyy HH:mm z", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); release.PublishDate = PublishDate.ToLocalTime(); } else { release.Description += line + "\n"; } } var catStr = qCatLink.GetAttribute("href").Split('=')[1]; release.Category = MapTrackerCatToNewznab(catStr); release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); release.Guid = release.Link; release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; if (qFreeLeech != null) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; releases.Add(release); } catch (Exception ex) { logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); } } } catch (Exception ex) { OnParseError(results.Content, ex); } } else // use search { var searchUrl = BrowseUrl; var queryCollection = new NameValueCollection(); queryCollection.Add("searchstr", StripSearchString(searchString)); queryCollection.Add("order_by", "time"); queryCollection.Add("order_way", "desc"); queryCollection.Add("group_results", "1"); queryCollection.Add("action", "basic"); queryCollection.Add("searchsubmit", "1"); foreach (var cat in MapTorznabCapsToTrackers(query)) { queryCollection.Add("filter_cat[" + cat + "]", "1"); } searchUrl += "?" + queryCollection.GetQueryString(); var results = await RequestStringWithCookies(searchUrl); try { string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); int GroupCategory = 0; string GroupTitle = null; string GroupYearStr = null; Nullable <DateTime> GroupPublishDate = null; foreach (var Row in Rows) { try { var qDetailsLink = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); string Title = qDetailsLink.TextContent; int Category = 0; string YearStr = null; Nullable <DateTime> YearPublishDate = null; if (Row.ClassList.Contains("group") || Row.ClassList.Contains("torrent")) // group/ungrouped headers { var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); string CategoryStr = qCatLink.GetAttribute("href").Split('=')[1].Split('&')[0]; Category = MapTrackerCatToNewznab(CategoryStr); YearStr = qDetailsLink.NextSibling.TextContent.Trim().TrimStart('[').TrimEnd(']'); YearPublishDate = DateTime.SpecifyKind(DateTime.ParseExact(YearStr, "yyyy", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); if (Row.ClassList.Contains("group")) // group headers { GroupCategory = Category; GroupTitle = Title; GroupYearStr = YearStr; GroupPublishDate = YearPublishDate; continue; } } var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 0; var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); var qSize = Row.QuerySelector("td:nth-last-child(4)"); var qSeeders = Row.QuerySelector("td:nth-last-child(3)"); var qLeechers = Row.QuerySelector("td:nth-last-child(2)"); var qFreeLeech = Row.QuerySelector("strong[title=\"Free\"]"); if (Row.ClassList.Contains("group_torrent")) // torrents belonging to a group { release.Description = qDetailsLink.TextContent; release.Title = GroupTitle + " " + GroupYearStr; release.PublishDate = GroupPublishDate.Value; release.Category = GroupCategory; } else if (Row.ClassList.Contains("torrent")) // standalone/un grouped torrents { var qDescription = Row.QuerySelector("div.torrent_info"); release.Description = qDescription.TextContent; release.Title = Title + " " + YearStr; release.PublishDate = YearPublishDate.Value; release.Category = Category; } release.Description = release.Description.Replace(" / Free", ""); // Remove Free Tag release.Title += " " + release.Description; // add year and Description to the release Title to add some meaning to it // check for previously stripped search terms if (!query.MatchQueryStringAND(release.Title)) { continue; } var Size = qSize.TextContent; release.Size = ReleaseInfo.GetBytes(Size); release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); release.Guid = release.Link; release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; if (qFreeLeech != null) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; releases.Add(release); } catch (Exception ex) { logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); } } } catch (Exception ex) { OnParseError(results.Content, ex); } } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var qc = new List <KeyValuePair <string, string> > // NameValueCollection don't support cat[]=19&cat[]=6 { { "st", "1" } // search in title }; if (query.IsImdbQuery) { qc.Add("search", query.ImdbID); qc.Add("sd", "1"); // search in description } else { qc.Add("search", query.GetQueryString()); } // parse categories and tags var catGroups = new HashSet <string>(); // HashSet instead of List to avoid duplicates var tagGroups = new HashSet <string>(); var cats = MapTorznabCapsToTrackers(query); foreach (var cat in cats) { // "cat[]=7&tags=x264" var cSplit = cat.Split('&'); var gSplit = cSplit[0].Split('='); if (gSplit.Length > 1) { catGroups.Add(gSplit[1]); // category = 7 } if (cSplit.Length > 1) { var tSplit = cSplit[1].Split('='); if (tSplit.Length > 1) { tagGroups.Add(tSplit[1]); // tag = x264 } } } // add categories foreach (var cat in catGroups) { qc.Add("cat[]", cat); } // do not include too many tags as it'll mess with their servers if (tagGroups.Count < 7) { qc.Add("tags", string.Join(",", tagGroups)); // if tags are specified match any // if no tags are specified match all, with any we get random results qc.Add("tf", tagGroups.Any() ? "any" : "all"); } var searchUrl = SearchUrl + "?" + qc.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl); if (response.IsRedirect) // re-login { await ApplyConfiguration(null); response = await RequestStringWithCookiesAndRetry(searchUrl); } try { var parser = new HtmlParser(); var dom = parser.ParseDocument(response.Content); var rows = dom.QuerySelectorAll("table > tbody > tr.browse"); foreach (var row in rows) { var qLink = row.Children[1].QuerySelector("a"); var title = qLink.GetAttribute("title"); if (qLink.QuerySelectorAll("span").Length == 1 && title.StartsWith("NEW! |")) { title = title.Substring(6).Trim(); } if (!query.MatchQueryStringAND(title)) { continue; // we have to skip bad titles due to tags + any word search } var comments = new Uri(SiteLink + qLink.GetAttribute("href")); var link = new Uri(SiteLink + row.Children[2].QuerySelector("a").GetAttribute("href")); var dateStr = Regex.Replace(row.Children[5].InnerHtml, @"\<br[\s]{0,1}[\/]{0,1}\>", " "); var publishDate = DateTimeUtil.FromTimeAgo(dateStr); var files = ParseUtil.CoerceInt(row.Children[3].TextContent); var size = ReleaseInfo.GetBytes(row.Children[7].TextContent); var grabs = ParseUtil.CoerceInt(row.Children[8].TextContent); var seeders = ParseUtil.CoerceInt(row.Children[9].TextContent); var leechers = ParseUtil.CoerceInt(row.Children[10].TextContent); var cat = row.FirstElementChild.FirstElementChild.GetAttribute("href").Replace("browse.php?", string.Empty); var release = new ReleaseInfo { Title = title, Comments = comments, Guid = comments, Link = link, PublishDate = publishDate, Size = size, Category = MapTrackerCatToNewznab(cat), Files = files, Grabs = grabs, Seeders = seeders, Peers = leechers + seeders, MinimumRatio = 1, MinimumSeedTime = 172800, // 48 hours DownloadVolumeFactor = 0, // ratioless UploadVolumeFactor = 1 }; releases.Add(release); } } catch (Exception ex) { OnParseError(response.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); bool configGoldenPopcornOnly = configData.FilterString.Value.ToLowerInvariant().Contains("goldenpopcorn"); bool configSceneOnly = configData.FilterString.Value.ToLowerInvariant().Contains("scene"); bool configCheckedOnly = configData.FilterString.Value.ToLowerInvariant().Contains("checked"); bool configFreeOnly = configData.FilterString.Value.ToLowerInvariant().Contains("free"); string movieListSearchUrl = SearchUrl; var queryCollection = new NameValueCollection(); queryCollection.Add("json", "noredirect"); if (!string.IsNullOrEmpty(query.ImdbID)) { queryCollection.Add("searchstr", query.ImdbID); } else if (!string.IsNullOrEmpty(query.GetQueryString())) { queryCollection.Add("searchstr", query.GetQueryString()); } if (configFreeOnly) { queryCollection.Add("freetorrent", "1"); } if (queryCollection.Count > 0) { movieListSearchUrl += "?" + queryCollection.GetQueryString(); } var results = await RequestStringWithCookiesAndRetry(movieListSearchUrl); if (results.IsRedirect) // untested { // re-login await DoLogin(); results = await RequestStringWithCookiesAndRetry(movieListSearchUrl); } try { //Iterate over the releases for each movie JObject js_results = JObject.Parse(results.Content); foreach (var movie in js_results["Movies"]) { string movie_title = (string)movie["Title"]; string Year = (string)movie["Year"]; var movie_imdbid_str = (string)movie["ImdbId"]; var coverStr = (string)movie["Cover"]; Uri coverUri = null; if (!string.IsNullOrEmpty(coverStr)) { coverUri = new Uri(coverStr); } long?movie_imdbid = null; if (!string.IsNullOrEmpty(movie_imdbid_str)) { movie_imdbid = long.Parse(movie_imdbid_str); } string movie_groupid = (string)movie["GroupId"]; foreach (var torrent in movie["Torrents"]) { var release = new ReleaseInfo(); string release_name = (string)torrent["ReleaseName"]; release.Title = release_name; release.Description = string.Format("Title: {0}", movie_title); release.BannerUrl = coverUri; release.Imdb = movie_imdbid; release.Comments = new Uri(string.Format("{0}?id={1}", SearchUrl, WebUtility.UrlEncode(movie_groupid))); release.Size = long.Parse((string)torrent["Size"]); release.Grabs = long.Parse((string)torrent["Snatched"]); release.Seeders = int.Parse((string)torrent["Seeders"]); release.Peers = release.Seeders + int.Parse((string)torrent["Leechers"]); release.PublishDate = DateTime.ParseExact((string)torrent["UploadTime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); release.Link = new Uri(string.Format("{0}?action=download&id={1}&authkey={2}&torrent_pass={3}", SearchUrl, WebUtility.UrlEncode((string)torrent["Id"]), WebUtility.UrlEncode(AuthKey), WebUtility.UrlEncode(configData.Passkey.Value))); release.Guid = release.Link; release.MinimumRatio = 1; release.MinimumSeedTime = 345600; release.DownloadVolumeFactor = 1; release.UploadVolumeFactor = 1; release.Category = new List <int> { 2000 }; bool golden, scene, check; bool.TryParse((string)torrent["GoldenPopcorn"], out golden); bool.TryParse((string)torrent["Scene"], out scene); bool.TryParse((string)torrent["Checked"], out check); if (configGoldenPopcornOnly && !golden) { continue; //Skip release if user only wants GoldenPopcorn } if (configSceneOnly && !scene) { continue; //Skip release if user only wants Scene } if (configCheckedOnly && !check) { continue; //Skip release if user only wants Checked } var titletags = new List <string>(); string Quality = (string)torrent["Quality"]; string Container = (string)torrent["Container"]; string Codec = (string)torrent["Codec"]; string Resolution = (string)torrent["Resolution"]; string Source = (string)torrent["Source"]; if (Year != null) { release.Description += string.Format("<br>\nYear: {0}", Year); } if (Quality != null) { release.Description += string.Format("<br>\nQuality: {0}", Quality); } if (Resolution != null) { titletags.Add(Resolution); release.Description += string.Format("<br>\nResolution: {0}", Resolution); } if (Source != null) { titletags.Add(Source); release.Description += string.Format("<br>\nSource: {0}", Source); } if (Codec != null) { titletags.Add(Codec); release.Description += string.Format("<br>\nCodec: {0}", Codec); } if (Container != null) { titletags.Add(Container); release.Description += string.Format("<br>\nContainer: {0}", Container); } if (scene) { titletags.Add("Scene"); release.Description += "<br>\nScene"; } if (check) { titletags.Add("Checked"); release.Description += "<br>\nChecked"; } if (golden) { titletags.Add("Golden Popcorn"); release.Description += "<br>\nGolden Popcorn"; } if (titletags.Count() > 0) { release.Title += " [" + string.Join(" / ", titletags) + "]"; } bool freeleech; bool.TryParse((string)torrent["FreeleechType"], out freeleech); if (freeleech) { release.DownloadVolumeFactor = 0; } releases.Add(release); } } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
// hook to adjust the search term protected virtual string GetSearchTerm(TorznabQuery query) { return(query.GetQueryString()); }
// hook to adjust the search term protected virtual string GetSearchTerm(TorznabQuery query) => query.GetQueryString();
public ManualSearchResult Search([FromBody] AdminSearch value) { var results = new List <TrackerCacheResult>(); var query = new TorznabQuery() { SearchTerm = value.Query, Categories = value.Category == 0 ? new int[0] : new int[1] { value.Category } }; query.ExpandCatsToSubCats(); var trackers = indexerService.GetAllIndexers().Where(t => t.IsConfigured).ToList(); if (!string.IsNullOrWhiteSpace(value.Tracker)) { trackers = trackers.Where(t => t.ID == value.Tracker).ToList(); } if (value.Category != 0) { trackers = trackers.Where(t => t.TorznabCaps.Categories.Select(c => c.ID).Contains(value.Category)).ToList(); } Parallel.ForEach(trackers.ToList(), indexer => { try { var searchResults = indexer.PerformQuery(query).Result; searchResults = indexer.CleanLinks(searchResults); cacheService.CacheRssResults(indexer, searchResults); searchResults = indexer.FilterResults(query, searchResults); lock (results) { foreach (var result in searchResults) { var item = Mapper.Map <TrackerCacheResult>(result); item.Tracker = indexer.DisplayName; item.TrackerId = indexer.ID; item.Peers = item.Peers - item.Seeders; // Use peers as leechers results.Add(item); } } } catch (Exception e) { logger.Error(e, "An error occured during manual search on " + indexer.DisplayName + ": " + e.Message); } }); ConfigureCacheResults(results); if (trackers.Count > 1) { results = results.OrderByDescending(d => d.PublishDate).ToList(); } var manualResult = new ManualSearchResult() { Results = results, Indexers = trackers.Select(t => t.DisplayName).ToList() }; if (manualResult.Indexers.Count == 0) { manualResult.Indexers = new List <string>() { "None" } } ; logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", query.GetQueryString(), string.Join(", ", manualResult.Indexers), manualResult.Results.Count)); return(manualResult); } }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var searchUrl = BrowseUrl; var queryCollection = new NameValueCollection(); if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("q", searchString); } foreach (var cat in MapTorznabCapsToTrackers(query)) { queryCollection.Add(cat, string.Empty); } if (queryCollection.Count > 0) { searchUrl += "?" + queryCollection.GetQueryString(); } var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); var results = response.Content; try { CQ dom = results; var rows = dom["table[id='torrents'] > tbody > tr"]; foreach (var row in rows.Skip(1)) { var release = new ReleaseInfo(); var qRow = row.Cq(); var qTitleLink = qRow.Find("a.t_title").First(); release.Title = qTitleLink.Text().Trim(); // If we search an get no results, we still get a table just with no info. if (string.IsNullOrWhiteSpace(release.Title)) { break; } release.Description = release.Title; release.Guid = new Uri(UseLink + qTitleLink.Attr("href").Substring(1)); release.Comments = release.Guid; var descString = qRow.Find(".t_ctime").Text(); var dateString = descString.Split('|').Last().Trim(); dateString = dateString.Split(new string[] { " by " }, StringSplitOptions.None)[0]; release.PublishDate = DateTimeUtil.FromTimeAgo(dateString); var qLink = row.ChildElements.ElementAt(3).Cq().Children("a"); release.Link = new Uri(UseLink + HttpUtility.UrlEncode(qLink.Attr("href").TrimStart('/'))); var sizeStr = row.ChildElements.ElementAt(5).Cq().Text(); release.Size = ReleaseInfo.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(qRow.Find(".t_seeders").Text().Trim()); release.Peers = ParseUtil.CoerceInt(qRow.Find(".t_leechers").Text().Trim()) + release.Seeders; var cat = row.Cq().Find("td:eq(0) a").First().Attr("href").Substring(1); release.Category = MapTrackerCatToNewznab(cat); releases.Add(release); } } catch (Exception ex) { OnParseError(results, ex); } return(releases); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { List <ReleaseInfo> releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var searchUrl = SearchUrl; var queryCollection = new NameValueCollection(); if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("searchstr", searchString); } foreach (var cat in MapTorznabCapsToTrackers(query)) { queryCollection.Add("filter_cat[" + cat + "]", "1"); } searchUrl += queryCollection.GetQueryString(); var results = await RequestStringWithCookiesAndRetry(searchUrl); try { CQ dom = results.Content; var rows = dom["#torrent_table > tbody > tr.torrent"]; foreach (var row in rows) { CQ qRow = row.Cq(); var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; var catStr = row.ChildElements.ElementAt(0).FirstElementChild.GetAttribute("href").Split(new char[] { '[', ']' })[1]; release.Category = MapTrackerCatToNewznab(catStr); var qLink = row.ChildElements.ElementAt(1).Cq().Children("a")[0].Cq(); var linkStr = qLink.Attr("href"); release.Title = qLink.Text(); release.Comments = new Uri(BaseUrl + "/" + linkStr); release.Guid = release.Comments; var qDownload = row.ChildElements.ElementAt(1).Cq().Find("a[title='Download']")[0].Cq(); release.Link = new Uri(BaseUrl + "/" + qDownload.Attr("href")); var dateStr = row.ChildElements.ElementAt(3).Cq().Text().Trim().Replace(" and", ""); release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); var sizeStr = row.ChildElements.ElementAt(4).Cq().Text(); release.Size = ReleaseInfo.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text().Trim()); release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text().Trim()) + release.Seeders; releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
/// <summary> /// Execute our search query /// </summary> /// <param name="query">Query</param> /// <returns>Releases</returns> protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var exactSearchTerm = query.GetQueryString(); var searchUrl = SearchUrl; // Check login before performing a query await CheckLogin(); // Check cache first so we don't query the server (if search term used or not in dev mode) if (!DevMode && !string.IsNullOrEmpty(exactSearchTerm)) { lock (cache) { // Remove old cache items CleanCache(); // Search in cache var cachedResult = cache.FirstOrDefault(i => i.Query == exactSearchTerm); if (cachedResult != null) { return(cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray()); } } } var SearchTerms = new List <string> { exactSearchTerm }; // duplicate search without diacritics var baseSearchTerm = StringUtil.RemoveDiacritics(exactSearchTerm); if (baseSearchTerm != exactSearchTerm) { SearchTerms.Add(baseSearchTerm); } foreach (var searchTerm in SearchTerms) { // Build our query var request = BuildQuery(searchTerm, query, searchUrl); // Getting results & Store content var response = await RequestWithCookiesAndRetryAsync(request, ConfigData.CookieHeader.Value); var parser = new HtmlParser(); var dom = parser.ParseDocument(response.ContentString); try { var firstPageRows = FindTorrentRows(dom); // If pagination available int nbResults; int pageLinkCount; pageLinkCount = 1; // Check if we have a minimum of one result if (firstPageRows?.Length > 1) { // Retrieve total count on our alone page nbResults = firstPageRows.Length; } else { // No result found for this query Output("\nNo result found for your query, please try another search term or change the theme you're currently using on the site as this is an unsupported solution...\n", "info"); break; } Output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !"); Output("\nThere are " + (firstPageRows.Length - 2) + " results on the first page !"); // Loop on results foreach (var row in firstPageRows.Skip(1).Take(firstPageRows.Length - 2)) { Output("Torrent #" + (releases.Count + 1)); // ID var idOrig = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("href").Split('=')[1]; var id = idOrig.Substring(0, idOrig.Length - 4); Output("ID: " + id); // Release Name var name = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").TextContent.Trim(); // Category var categoryId = row.QuerySelector("td:nth-of-type(1) > a:nth-of-type(1)").GetAttribute("href").Split('?').Last(); var newznab = MapTrackerCatToNewznab(categoryId); Output("Category: " + (newznab.Count > 0 ? newznab.First().ToString() : "unknown category") + " (" + categoryId + ")"); // Seeders var seeders = ParseUtil.CoerceInt(Regex.Match(row.QuerySelector("td:nth-of-type(10)").TextContent, @"\d+").Value); Output("Seeders: " + seeders); // Leechers var leechers = ParseUtil.CoerceInt(Regex.Match(row.QuerySelector("td:nth-of-type(11)").TextContent, @"\d+").Value); Output("Leechers: " + leechers); // Files var files = 1; files = ParseUtil.CoerceInt(Regex.Match(row.QuerySelector("td:nth-of-type(5)").TextContent, @"\d+").Value); Output("Files: " + files); // Completed var completed = ParseUtil.CoerceInt(Regex.Match(row.QuerySelector("td:nth-of-type(9)").TextContent, @"\d+").Value); Output("Completed: " + completed); // Size var humanSize = row.QuerySelector("td:nth-of-type(8)").TextContent.ToLowerInvariant(); var size = ReleaseInfo.GetBytes(humanSize); Output("Size: " + humanSize + " (" + size + " bytes)"); // Publish DateToString var dateTimeOrig = row.QuerySelector("td:nth-of-type(7)").TextContent; var datestr = Regex.Replace(dateTimeOrig, @"<[^>]+>| ", "").Trim(); datestr = Regex.Replace(datestr, "Today", DateTime.Now.ToString("MMM dd yyyy"), RegexOptions.IgnoreCase); datestr = Regex.Replace(datestr, "Yesterday", DateTime.Now.Date.AddDays(-1).ToString("MMM dd yyyy"), RegexOptions.IgnoreCase); var date = DateTimeUtil.FromUnknown(datestr, "DK"); Output("Released on: " + date); // Torrent Details URL var detailsLink = new Uri(TorrentDescriptionUrl.Replace("{id}", id.ToString())); Output("Details: " + detailsLink.AbsoluteUri); // Torrent Comments URL var commentsLink = new Uri(TorrentCommentUrl.Replace("{id}", id.ToString())); Output("Comments Link: " + commentsLink.AbsoluteUri); // Torrent Download URL var passkey = row.QuerySelector("td:nth-of-type(3) > a:nth-of-type(1)").GetAttribute("href"); var key = Regex.Match(passkey, "(?<=torrent_pass\\=)([a-zA-z0-9]*)"); var downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{passkey}", key.ToString())); Output("Download Link: " + downloadLink.AbsoluteUri); // Building release infos var release = new ReleaseInfo { Category = newznab, Title = name, Seeders = seeders, Peers = seeders + leechers, PublishDate = date, Size = size, Files = files, Grabs = completed, Guid = detailsLink, Comments = commentsLink, Link = downloadLink, MinimumRatio = 1, MinimumSeedTime = 172800 // 48 hours }; // IMDB var imdbLink = row.QuerySelector("a[href*=\"imdb.com/title/tt\"]")?.GetAttribute("href"); release.Imdb = ParseUtil.GetLongFromString(imdbLink); if (row.QuerySelector("img[title=\"Free Torrent\"]") != null) { release.DownloadVolumeFactor = 0; } else if (row.QuerySelector("img[title=\"Halfleech\"]") != null) { release.DownloadVolumeFactor = 0.5; } else if (row.QuerySelector("img[title=\"90% Freeleech\"]") != null) { release.DownloadVolumeFactor = 0.1; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; releases.Add(release); } } catch (Exception ex) { OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex); } } // Return found releases return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = "--"; var maxPages = 2; // we scrape only 2 pages for recent torrents if (!string.IsNullOrWhiteSpace(query.GetQueryString())) { searchString = Uri.EscapeUriString(query.GetQueryString()); maxPages = MaxSearchPageLimit; } var lastPublishDate = DateTime.Now; for (var page = 0; page < maxPages; page++) { var searchUrl = string.Format(SearchUrl, page * MaxItemsPerPage, searchString); var result = await RequestWithCookiesAsync(searchUrl, headers : _apiHeaders); try { var json = JsonConvert.DeserializeObject <dynamic>(result.ContentString); var parser = new HtmlParser(); var doc = parser.ParseDocument((string)json["contenido"]); var rows = doc.QuerySelectorAll("div.span2"); foreach (var row in rows) { var title = row.QuerySelector("h2").TextContent + " - " + row.QuerySelector("h1").TextContent; if (!CheckTitleMatchWords(query.GetQueryString(), title)) { continue; // skip if it doesn't contain all words } var poster = new Uri(row.QuerySelector("img[id=catalog]").GetAttribute("src")); var qLink = row.QuerySelector("a"); var details = new Uri(qLink.GetAttribute("href")); var qTooltip = parser.ParseDocument(qLink.GetAttribute("data-content")); // we get the language from the last class tag => class="pull-right sprite idioma_5" var languageId = qTooltip.QuerySelector("div.pull-right").GetAttribute("class").Split('_')[1]; title += $" [{_languages[languageId]}] [epub]"; var qDesc = qTooltip.QuerySelectorAll("div.row-fluid > div"); var description = $"Rev: {qDesc[0].TextContent} Páginas: {qDesc[1].TextContent} Puntación: {qDesc[2].TextContent} Likes: {qDesc[3].TextContent}"; // publish date is not available in the torrent list, but we add a relative date so we can sort lastPublishDate = lastPublishDate.AddMinutes(-1); var release = new ReleaseInfo { Title = title, Details = details, Link = details, Guid = details, PublishDate = lastPublishDate, Poster = poster, Description = description, Category = new List <int> { TorznabCatType.BooksEBook.ID }, Size = 5242880, // 5 MB Seeders = 1, Peers = 2, DownloadVolumeFactor = 0, UploadVolumeFactor = 1 }; releases.Add(release); } if (rows.Length < MaxItemsPerPage) { break; // this is the last page } } catch (Exception ex) { OnParseError(result.ContentString, ex); } } return(releases); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var searchUrl = SearchUrl; var queryCollection = new NameValueCollection(); queryCollection.Add("order_by", "time"); queryCollection.Add("order_way", "desc"); if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("searchstr", searchString); } foreach (var cat in MapTorznabCapsToTrackers(query)) { queryCollection.Add("filter_cat[" + cat + "]", "1"); } searchUrl += "?" + queryCollection.GetQueryString(); var results = await RequestStringWithCookiesAndRetry(searchUrl); if (results.Content.Contains("Din søgning gav intet resultat.")) { return(releases); } try { CQ dom = results.Content; var rows = dom["#torrent_table > tbody > tr"].ToArray(); foreach (var row in rows.Skip(1)) { var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; var qCat = row.ChildElements.ElementAt(0).ChildElements.ElementAt(0).Cq(); var catUrl = qCat.Attr("href"); var cat = catUrl.Substring(catUrl.LastIndexOf('[') + 1).Trim(']'); release.Category = MapTrackerCatToNewznab(cat); var qAdded = row.ChildElements.ElementAt(4).ChildElements.ElementAt(0).Cq(); var addedStr = qAdded.Attr("title"); release.PublishDate = DateTime.ParseExact(addedStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture); var qLink = row.ChildElements.ElementAt(1).ChildElements.ElementAt(2).Cq(); release.Title = qLink.Text().Trim(); release.Description = release.Title; release.Comments = new Uri(SiteLink + qLink.Attr("href")); release.Guid = release.Comments; var qDownload = row.ChildElements.ElementAt(1).ChildElements.ElementAt(1).ChildElements.ElementAt(0).Cq(); release.Link = new Uri(SiteLink + qDownload.Attr("href")); var sizeStr = row.ChildElements.ElementAt(5).Cq().Text(); release.Size = ReleaseInfo.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(6).Cq().Text()); release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text()) + release.Seeders; var files = row.Cq().Find("td:nth-child(4)").Text(); release.Files = ParseUtil.CoerceInt(files); if (row.Cq().Find("img[src=\"/static//common/browse/freeleech.png\"]").Any()) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { List <ReleaseInfo> releases = new List <ReleaseInfo>(); List <string> searchStrings = new List <string>(new string[] { query.GetQueryString() }); if (string.IsNullOrEmpty(query.Episode) && (query.Season > 0)) { // Tracker naming rules: If query is for a whole season, "Season #" instead of "S##". searchStrings.Add((query.SanitizedSearchTerm + " " + string.Format("\"Season {0}\"", query.Season)).Trim()); } List <string> categories = MapTorznabCapsToTrackers(query); List <string> request_urls = new List <string>(); foreach (var searchString in searchStrings) { var queryCollection = new NameValueCollection(); queryCollection.Add("action", "basic"); if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("searchstr", searchString); } foreach (var cat in categories) { queryCollection.Add("filter_cat[" + cat + "]", "1"); } request_urls.Add(SearchUrl + queryCollection.GetQueryString()); } IEnumerable <Task <WebClientStringResult> > downloadTasksQuery = from url in request_urls select RequestStringWithCookiesAndRetry(url); WebClientStringResult[] responses = await Task.WhenAll(downloadTasksQuery.ToArray()); for (int i = 0; i < searchStrings.Count(); i++) { var results = responses[i]; // Occasionally the cookies become invalid, login again if that happens if (results.IsRedirect) { await ApplyConfiguration(null); results = await RequestStringWithCookiesAndRetry(request_urls[i]); } try { CQ dom = results.Content; var rows = dom["#torrent_table > tbody > tr.torrent"]; foreach (var row in rows) { CQ qRow = row.Cq(); var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; var catStr = row.ChildElements.ElementAt(0).FirstElementChild.GetAttribute("href").Split(new char[] { '[', ']' })[1]; release.Category = MapTrackerCatToNewznab(catStr); var qLink = row.ChildElements.ElementAt(1).Cq().Children("a")[0].Cq(); var linkStr = qLink.Attr("href"); release.Comments = new Uri(BaseUrl + "/" + linkStr); release.Guid = release.Comments; var qDownload = row.ChildElements.ElementAt(1).Cq().Find("a[title='Download']")[0].Cq(); release.Link = new Uri(BaseUrl + "/" + qDownload.Attr("href")); var dateStr = row.ChildElements.ElementAt(3).Cq().Text().Trim().Replace(" and", ""); release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); var sizeStr = row.ChildElements.ElementAt(4).Cq().Text(); release.Size = ReleaseInfo.GetBytes(sizeStr); release.Files = ParseUtil.CoerceInt(row.ChildElements.ElementAt(2).Cq().Text().Trim()); release.Grabs = ParseUtil.CoerceInt(row.ChildElements.ElementAt(6).Cq().Text().Trim()); release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text().Trim()); release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text().Trim()) + release.Seeders; var grabs = qRow.Find("td:nth-child(6)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); if (qRow.Find("strong:contains(\"Freeleech!\")").Length >= 1) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; var title = qRow.Find("td:nth-child(2)"); title.Find("span, strong, div, br").Remove(); release.Title = ParseUtil.NormalizeMultiSpaces(title.Text().Replace(" - ]", "]")); if (catStr == "10") //change "Season #" to "S##" for TV shows { release.Title = Regex.Replace(release.Title, @"Season (\d+)", m => string.Format("S{0:00}", Int32.Parse(m.Groups[1].Value))); } releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var qc = new List <KeyValuePair <string, string> > // NameValueCollection don't support cat[]=19&cat[]=6 { { "tpage", "1" } }; if (query.IsImdbQuery) { qc.Add("search", query.ImdbID); qc.Add("nfo", "true"); } else if (!string.IsNullOrWhiteSpace(query.GetQueryString())) { qc.Add("search", query.GetQueryString()); } foreach (var cat in MapTorznabCapsToTrackers(query)) { qc.Add("cat[]", cat); } var searchUrl = SearchUrl + "?" + qc.GetQueryString(); var result = await RequestWithCookiesAndRetryAsync(searchUrl, referer : SearchUrl); if (result.IsRedirect) { throw new Exception($"Your cookie did not work. Please, configure the tracker again. Message: {result.ContentString}"); } if (!result.ContentString.StartsWith("{")) // not JSON => error { throw new ExceptionWithConfigData(result.ContentString, configData); } var json = JsonConvert.DeserializeObject <dynamic>(result.ContentString); try { var torrents = json["torrents"]; // latest torrents if (json["hits"] != null) // is search result { torrents = json.SelectTokens("$.hits[?(@._type == 'torrent')]._source"); } foreach (var torrent in torrents) { var torrentId = (long)torrent.id; var details = new Uri(SiteLink + "torrents/" + torrentId); var link = new Uri(SiteLink + "download/" + torrentId); var publishDate = DateTime.Parse(torrent.added.ToString()); var imdbId = ParseUtil.GetImdbID(torrent.imdb_id.ToString()); Uri poster = null; if ((bool)torrent.poster) { if (torrent["imdb_id"] != null) { poster = new Uri(CdnUrl + "images/torrents/poster/imd/l/" + torrent["imdb_id"] + ".jpg"); } else if (torrent["cdu_id"] != null) { poster = new Uri(CdnUrl + "images/torrents/poster/cdu/b/" + torrent["cdu_id"] + "_front.jpg"); } else if (torrent["steam_id"] != null) { poster = new Uri(CdnUrl + "images/torrents/poster/ste/l/" + torrent["steam_id"] + ".jpg"); } } var title = torrent.name.ToString(); var descriptions = new List <string>(); var language = (string)torrent.language; if (!string.IsNullOrEmpty(language)) { descriptions.Add("Language: " + language); } else if ((bool?)torrent.polish == true) { descriptions.Add("Language: pl"); } if (language == "pl" && (((BoolConfigurationItem)configData.GetDynamic("LanguageTitle")).Value)) { title += " POLISH"; } var description = descriptions.Any() ? string.Join("<br />\n", descriptions) : null; var release = new ReleaseInfo { Title = title, Details = details, Guid = details, Link = link, PublishDate = publishDate, Category = MapTrackerCatToNewznab(torrent.category.ToString()), Size = (long)torrent.size, Grabs = (long)torrent.completed, Seeders = (int)torrent.seeders, Peers = (int)torrent.seeders + (int)torrent.leechers, Imdb = imdbId, Poster = poster, Description = description, MinimumRatio = 1, MinimumSeedTime = 259200, // 72 hours (I can't verify this, but this is a safe value in most trackers) UploadVolumeFactor = 1, DownloadVolumeFactor = 1 }; releases.Add(release); } } catch (Exception ex) { OnParseError(result.ToString(), ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); 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 = new List <int> { 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); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var prevCook = CookieHeader + ""; // If we have no query use the RSS Page as their server is slow enough at times! if (query.IsTest || string.IsNullOrWhiteSpace(searchString)) { var rssPage = await RequestStringWithCookiesAndRetry(string.Format(RSSUrl, configData.RSSKey.Value)); try { if (rssPage.Content.EndsWith("\0")) { rssPage.Content = rssPage.Content.Substring(0, rssPage.Content.Length - 1); } rssPage.Content = RemoveInvalidXmlChars(rssPage.Content); var rssDoc = XDocument.Parse(rssPage.Content); foreach (var item in rssDoc.Descendants("item")) { var title = item.Descendants("title").First().Value; var description = item.Descendants("description").First().Value; var link = item.Descendants("link").First().Value; var category = item.Descendants("category").First().Value; var date = item.Descendants("pubDate").First().Value; var torrentIdMatch = Regex.Match(link, "(?<=id=)(\\d)*"); var torrentId = torrentIdMatch.Success ? torrentIdMatch.Value : string.Empty; if (string.IsNullOrWhiteSpace(torrentId)) { throw new Exception("Missing torrent id"); } var infoMatch = Regex.Match(description, @"Category:\W(?<cat>.*)\W\/\WSeeders:\W(?<seeders>[\d\,]*)\W\/\WLeechers:\W(?<leechers>[\d\,]*)\W\/\WSize:\W(?<size>[\d\.]*\W\S*)"); if (!infoMatch.Success) { throw new Exception("Unable to find info"); } var release = new ReleaseInfo { Title = title, Description = title, Guid = new Uri(string.Format(DownloadUrl, torrentId)), Comments = new Uri(string.Format(CommentUrl, torrentId)), PublishDate = DateTime.ParseExact(date, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture), //2015-08-08 21:20:31 Link = new Uri(string.Format(DownloadUrl, torrentId)), Seeders = ParseUtil.CoerceInt(infoMatch.Groups["seeders"].Value), Peers = ParseUtil.CoerceInt(infoMatch.Groups["leechers"].Value), Size = ReleaseInfo.GetBytes(infoMatch.Groups["size"].Value), Category = MapTrackerCatToNewznab(category) }; release.Peers += release.Seeders; releases.Add(release); } } catch (Exception ex) { logger.Error("XSpeeds: Error while parsing the RSS feed:"); logger.Error(rssPage.Content); throw ex; } } if (query.IsTest || !string.IsNullOrWhiteSpace(searchString)) { if (searchString.Length < 3 && !query.IsTest) { OnParseError("", new Exception("Minimum search length is 3")); return(releases); } var searchParams = new Dictionary <string, string> { { "do", "search" }, { "keywords", searchString }, { "search_type", "t_name" }, { "category", "0" }, { "include_dead_torrents", "no" } }; var pairs = new Dictionary <string, string> { { "username", configData.Username.Value }, { "password", configData.Password.Value } }; var searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader); // Occasionally the cookies become invalid, login again if that happens if (searchPage.IsRedirect) { await ApplyConfiguration(null); searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader); } try { CQ dom = searchPage.Content; var rows = dom["table#sortabletable > tbody > tr:has(div > a[href*=\"details.php?id=\"])"]; foreach (var row in rows) { var release = new ReleaseInfo(); var qRow = row.Cq(); var qDetails = qRow.Find("div > a[href*=\"details.php?id=\"]"); // details link, release name get's shortened if it's to long var qTitle = qRow.Find("td:eq(1) .tooltip-content div:eq(0)"); // use Title from tooltip if (!qTitle.Any()) // fallback to Details link if there's no tooltip { qTitle = qDetails; } release.Title = qTitle.Text(); release.Guid = new Uri(qRow.Find("td:eq(2) a").Attr("href")); release.Link = release.Guid; release.Comments = new Uri(qDetails.Attr("href")); release.PublishDate = DateTime.ParseExact(qRow.Find("td:eq(1) div").Last().Text().Trim(), "dd-MM-yyyy H:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); //08-08-2015 12:51 release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:eq(6)").Text()); release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:eq(7)").Text().Trim()); release.Size = ReleaseInfo.GetBytes(qRow.Find("td:eq(4)").Text().Trim()); var cat = row.Cq().Find("td:eq(0) a").First().Attr("href"); var catSplit = cat.LastIndexOf('='); if (catSplit > -1) { cat = cat.Substring(catSplit + 1); } release.Category = MapTrackerCatToNewznab(cat); // If its not apps or audio we can only mark as general TV if (release.Category == 0) { release.Category = 5030; } var grabs = qRow.Find("td:nth-child(6)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); if (qRow.Find("img[alt^=\"Free Torrent\"]").Length >= 1) { release.DownloadVolumeFactor = 0; } else if (qRow.Find("img[alt^=\"Silver Torrent\"]").Length >= 1) { release.DownloadVolumeFactor = 0.5; } else { release.DownloadVolumeFactor = 1; } if (qRow.Find("img[alt^=\"x2 Torrent\"]").Length >= 1) { release.UploadVolumeFactor = 2; } else { release.UploadVolumeFactor = 1; } releases.Add(release); } } catch (Exception ex) { OnParseError(searchPage.Content, ex); } } if (!CookieHeader.Trim().Equals(prevCook.Trim())) { SaveConfig(); } return(releases); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var searchUrl = APIUrl; var queryCollection = new NameValueCollection(); queryCollection.Add("action", "browse"); //queryCollection.Add("group_results", "0"); # results won't include all information queryCollection.Add("order_by", "time"); queryCollection.Add("order_way", "desc"); if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("searchstr", searchString); } foreach (var cat in MapTorznabCapsToTrackers(query)) { queryCollection.Add("filter_cat[" + cat + "]", "1"); } searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl); if (response.IsRedirect || query.IsTest) { // re-login await ApplyConfiguration(null); response = await RequestStringWithCookiesAndRetry(searchUrl); } try { var json = JObject.Parse(response.Content); foreach (JObject r in json["response"]["results"]) { var groupTime = DateTimeUtil.UnixTimestampToDateTime(long.Parse((string)r["groupTime"])); var groupName = HttpUtility.HtmlDecode((string)r["groupName"]); var artist = (string)r["artist"]; var cover = (string)r["cover"]; var tags = r["tags"].ToList(); var groupYear = (string)r["groupYear"]; var releaseType = (string)r["releaseType"]; var release = new ReleaseInfo(); release.PublishDate = groupTime; if (!string.IsNullOrEmpty(cover)) { release.BannerUrl = new Uri(cover); } release.Title = ""; if (!string.IsNullOrEmpty(artist)) { release.Title += artist + " - "; } release.Title += groupName; if (!string.IsNullOrEmpty(groupYear)) { release.Title += " [" + groupYear + "]"; } if (!string.IsNullOrEmpty(releaseType)) { release.Title += " [" + releaseType + "]"; } release.Description = ""; if (tags != null && tags.Count > 0 && (string)tags[0] != "") { release.Description += "Tags: " + string.Join(", ", tags) + "\n"; } if (r["torrents"] is JArray) { foreach (JObject torrent in r["torrents"]) { ReleaseInfo release2 = (ReleaseInfo)release.Clone(); FillReleaseInfoFromJson(release2, torrent); if (ReleaseInfoPostParse(release2, torrent, r)) { releases.Add(release2); } } } else { FillReleaseInfoFromJson(release, r); if (ReleaseInfoPostParse(release, r, r)) { releases.Add(release); } } } } catch (Exception ex) { OnParseError(response.Content, ex); } return(releases); }
private async Task <IEnumerable <ReleaseInfo> > PerformRegularQueryAsync(TorznabQuery query, string hebName = null) { var releases = new List <ReleaseInfo>(); var searchUrl = SearchUrl; var searchString = query.GetQueryString(); if (query.IsImdbQuery) { searchString = query.ImdbID; } if (hebName != null) { searchString = hebName + " - עונה " + query.Season + " פרק " + query.Episode; } searchUrl += "?"; if (!string.IsNullOrWhiteSpace(searchString)) { var strEncoded = WebUtilityHelpers.UrlEncode(searchString, Encoding); searchUrl += "&query=" + strEncoded + "&matchquery=any"; } searchUrl = MapTorznabCapsToTrackers(query).Aggregate(searchUrl, (current, cat) => $"{current}&c[]={cat}"); var data = await RequestWithCookiesAndRetryAsync(searchUrl); try { var parser = new HtmlParser(); var dom = parser.ParseDocument(data.ContentString); var rows = dom.QuerySelectorAll("tr.box_torrent"); foreach (var row in rows) { var release = new ReleaseInfo(); var mainTitleLink = row.QuerySelector("div.main_title > a"); release.Title = mainTitleLink.GetAttribute("longtitle"); if (string.IsNullOrWhiteSpace(release.Title)) { release.Title = mainTitleLink.TextContent; } release.MinimumRatio = 1; release.MinimumSeedTime = 172800; // 48 hours release.Grabs = ParseUtil.CoerceLong(row.QuerySelector("td:nth-child(5)").TextContent.Replace(",", "")); release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent.Replace(",", "")); release.Peers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent.Replace(",", "")) + release.Seeders; var fullSize = row.QuerySelector("td:nth-child(4)").TextContent; release.Size = ReleaseInfo.GetBytes(fullSize); release.Details = new Uri(SiteLink + row.QuerySelector("a.threadlink[href]").GetAttribute("href")); release.Link = new Uri(SiteLink + row.QuerySelector("a:has(div.dlimg)").GetAttribute("href")); release.Guid = release.Details; //some releases have invalid poster URLs, ignore the posters in this case if (Uri.TryCreate(row.QuerySelector("a[imgsrc]").GetAttribute("imgsrc"), UriKind.Absolute, out var poster)) { release.Poster = poster; } var dateStringAll = row.QuerySelector("div.up_info2").ChildNodes.Last().TextContent; var dateParts = dateStringAll.Split(' '); var dateString = dateParts[dateParts.Length - 2] + " " + dateParts[dateParts.Length - 1]; release.PublishDate = DateTime.ParseExact(dateString, "dd/MM/yy HH:mm", CultureInfo.InvariantCulture); var categoryLink = row.QuerySelector("a[href^=\"/browse.php?cat=\"]").GetAttribute("href"); var catid = ParseUtil.GetArgumentFromQueryString(categoryLink, "cat"); release.Category = MapTrackerCatToNewznab(catid); if (row.QuerySelector("a[href^=\"?freeleech=1\"]") != null) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; var subTitle = row.QuerySelector("div.sub_title"); var imdbLink = subTitle.QuerySelector("span.imdb-inline > a"); if (imdbLink != null) { release.Imdb = ParseUtil.GetLongFromString(imdbLink.GetAttribute("href")); } release.Description = subTitle.FirstChild.TextContent; releases.Add(release); } } catch (Exception ex) { OnParseError(data.ContentString, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); // if the search string is empty use the "last 24h torrents" view if (string.IsNullOrWhiteSpace(query.SearchTerm)) { var results = await RequestStringWithCookies(TodayUrl); try { string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); foreach (var Row in Rows) { try { var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 0; var qDetailsLink = Row.QuerySelector("a.BJinfoBox"); var qTitle = qDetailsLink.QuerySelector("font"); release.Title = qTitle.TextContent; var qBJinfoBox = qDetailsLink.QuerySelector("span"); var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); var qSeeders = Row.QuerySelector("td:nth-child(4)"); var qLeechers = Row.QuerySelector("td:nth-child(5)"); var qFreeLeech = Row.QuerySelector("font[color=\"green\"]:contains(Free)"); release.Description = ""; foreach (var Child in qBJinfoBox.ChildNodes) { var type = Child.NodeType; if (type != NodeType.Text) { continue; } var line = Child.TextContent; if (line.StartsWith("Tamanho:")) { string Size = line.Substring("Tamanho: ".Length);; release.Size = ReleaseInfo.GetBytes(Size); } else if (line.StartsWith("Lançado em: ")) { string PublishDateStr = line.Substring("Lançado em: ".Length).Replace("às ", ""); PublishDateStr += " +0"; var PublishDate = DateTime.SpecifyKind(DateTime.ParseExact(PublishDateStr, "dd/MM/yyyy HH:mm z", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); release.PublishDate = PublishDate.ToLocalTime(); } else { release.Description += line + "\n"; } } var catStr = qCatLink.GetAttribute("href").Split('=')[1]; // if result is an anime, convert title from SXXEXX to EXX if (catStr == "14") { release.Title = Regex.Replace(release.Title, @"(Ep[\.]?[ ]?)|([S]\d\d[Ee])", "E"); } release.Category = MapTrackerCatToNewznab(catStr); release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); release.Guid = release.Link; release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; if (qFreeLeech != null) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; releases.Add(release); } catch (Exception ex) { logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); } } } catch (Exception ex) { OnParseError(results.Content, ex); } } else // use search { var searchUrl = BrowseUrl; var isSearchAnime = query.Categories.Any(s => s == TorznabCatType.TVAnime.ID); query.SearchTerm = query.SearchTerm.Replace("Agents of SHIELD", "Agents of S.H.I.E.L.D."); var searchString = query.GetQueryString(); var queryCollection = new NameValueCollection { { "searchstr", StripSearchString(searchString, isSearchAnime) }, { "order_by", "time" }, { "order_way", "desc" }, { "group_results", "1" }, { "action", "basic" }, { "searchsubmit", "1" } }; foreach (var cat in MapTorznabCapsToTrackers(query)) { queryCollection.Add("filter_cat[" + cat + "]", "1"); } searchUrl += "?" + queryCollection.GetQueryString(); var results = await RequestStringWithCookies(searchUrl); try { string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); ICollection <int> GroupCategory = null; string GroupTitle = null; string GroupYearStr = null; Nullable <DateTime> GroupPublishDate = null; foreach (var Row in Rows) { try { var qDetailsLink = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); string Title = qDetailsLink.TextContent; ICollection <int> Category = null; string YearStr = null; Nullable <DateTime> YearPublishDate = null; string CategoryStr = ""; if (Row.ClassList.Contains("group") || Row.ClassList.Contains("torrent")) // group/ungrouped headers { var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); CategoryStr = qCatLink.GetAttribute("href").Split('=')[1].Split('&')[0]; Category = MapTrackerCatToNewznab(CategoryStr); YearStr = qDetailsLink.NextSibling.TextContent.Trim().TrimStart('[').TrimEnd(']'); YearPublishDate = DateTime.SpecifyKind(DateTime.ParseExact(YearStr, "yyyy", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); // if result is an anime, convert title from SXXEXX to EXX if (CategoryStr == "14") { Title = Regex.Replace(Title, @"(Ep[\.]?[ ]?)|([S]\d\d[Ee])", "E"); } if (Row.ClassList.Contains("group")) // group headers { GroupCategory = Category; GroupTitle = Title; GroupYearStr = YearStr; GroupPublishDate = YearPublishDate; continue; } } var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 0; var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); var qSize = Row.QuerySelector("td:nth-last-child(4)"); var qGrabs = Row.QuerySelector("td:nth-last-child(3)"); var qSeeders = Row.QuerySelector("td:nth-last-child(2)"); var qLeechers = Row.QuerySelector("td:nth-last-child(1)"); var qFreeLeech = Row.QuerySelector("strong[title=\"Free\"]"); if (Row.ClassList.Contains("group_torrent")) // torrents belonging to a group { release.Description = qDetailsLink.TextContent; string cleanTitle = Regex.Replace(GroupTitle, @" - S?(?<season>\d{1,2})?E?(?<episode>\d{1,4})?", ""); string seasonEp = Regex.Replace(GroupTitle, @"^(.*?) - (S?(\d{1,2})?E?(\d{1,4})?)?", "$2"); release.Title = CategoryStr == "14" ? GroupTitle : cleanTitle + " " + GroupYearStr + " " + seasonEp; release.PublishDate = GroupPublishDate.Value; release.Category = GroupCategory; } else if (Row.ClassList.Contains("torrent")) // standalone/un grouped torrents { var qDescription = Row.QuerySelector("div.torrent_info"); release.Description = qDescription.TextContent; string cleanTitle = Regex.Replace(Title, @" - ((S(\d{1,2}))?E(\d{1,4}))", ""); string seasonEp = Regex.Replace(Title, @"^(.*?) - ((S(\d{1,2}))?E(\d{1,4}))", "$2"); release.Title = CategoryStr == "14" ? Title : cleanTitle + " " + YearStr + " " + seasonEp; release.PublishDate = YearPublishDate.Value; release.Category = Category; } release.Description = release.Description.Replace(" / Free", ""); // Remove Free Tag release.Description = release.Description.Replace("Full HD", "1080p"); release.Description = release.Description.Replace("/ HD / ", "/ 720p /"); release.Description = release.Description.Replace(" / HD]", " / 720p]"); release.Description = release.Description.Replace("4K", "2160p"); int nBarra = release.Title.IndexOf("["); if (nBarra != -1) { release.Title = release.Title.Substring(nBarra + 1); release.Title = release.Title.Replace("]", ""); } release.Title += " " + release.Description; // add year and Description to the release Title to add some meaning to it // check for previously stripped search terms if (!query.MatchQueryStringAND(release.Title)) { continue; } var Size = qSize.TextContent; release.Size = ReleaseInfo.GetBytes(Size); release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); release.Guid = release.Link; release.Grabs = ParseUtil.CoerceLong(qGrabs.TextContent); release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; if (qFreeLeech != null) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; releases.Add(release); } catch (Exception ex) { logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); } } } catch (Exception ex) { OnParseError(results.Content, ex); } } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var qc = new List <KeyValuePair <string, string> >(); // NameValueCollection don't support c[]=30&c[]=52 if (query.IsImdbQuery) { qc.Add("search", query.ImdbID); qc.Add("d", "on"); } else { qc.Add("search", query.GetQueryString()); } var catList = MapTorznabCapsToTrackers(query); foreach (var cat in catList) { qc.Add("c[]", cat); } var searchUrl = SearchUrl + "?" + qc.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl); if (!response.Content.Contains("/logout.php")) // re-login { await DoLogin(); response = await RequestStringWithCookiesAndRetry(searchUrl); } try { var parser = new HtmlParser(); var dom = parser.ParseDocument(response.Content); var rows = dom.QuerySelectorAll("div.boxContent > table > tbody > tr"); foreach (var row in rows) { var cells = row.QuerySelectorAll("td"); var title = row.QuerySelector("td[class='lft'] > div > a").TextContent.Trim(); var link = new Uri(SiteLink + row.QuerySelector("img[title='Download']").ParentElement.GetAttribute("href").TrimStart('/')); var comments = new Uri(SiteLink + row.QuerySelector("td[class='lft'] > div > a").GetAttribute("href").TrimStart('/')); var size = ReleaseInfo.GetBytes(cells[4].TextContent); var grabs = ParseUtil.CoerceInt(cells[5].TextContent); var seeders = ParseUtil.CoerceInt(cells[6].TextContent); var leechers = ParseUtil.CoerceInt(cells[7].TextContent); var pubDateStr = row.QuerySelector("span[class^='elapsedDate']").GetAttribute("title").Replace(" at", ""); var publishDate = DateTime.ParseExact(pubDateStr, "dddd, MMMM d, yyyy h:mmtt", CultureInfo.InvariantCulture); var cat = row.QuerySelector("a[href^='?c[]=']").GetAttribute("href").Replace("?c[]=", ""); var downloadVolumeFactor = row.QuerySelector("span:contains(\"[Freeleech]\")") != null ? 0 : 1; var release = new ReleaseInfo { Title = title, Link = link, Guid = link, Comments = comments, PublishDate = publishDate, Category = MapTrackerCatToNewznab(cat), Size = size, Grabs = grabs, Seeders = seeders, Peers = seeders + leechers, MinimumRatio = 1, MinimumSeedTime = 172800, // 48 hours DownloadVolumeFactor = downloadVolumeFactor, UploadVolumeFactor = 1 }; releases.Add(release); } } catch (Exception ex) { OnParseError(response.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchurls = new List <string>(); var searchUrl = SearchUrl;// string.Format(SearchUrl, HttpUtility.UrlEncode())); var queryCollection = new NameValueCollection(); var searchString = query.GetQueryString(); foreach (var cat in MapTorznabCapsToTrackers(query)) { searchUrl += "category%5B%5D=" + cat + "&"; } if (query.ImdbID != null) { queryCollection.Add("search", query.ImdbID); } else if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("search", searchString); } queryCollection.Add("active", "0"); queryCollection.Add("options", "0"); searchUrl += queryCollection.GetQueryString().Replace("(", "%28").Replace(")", "%29"); // maually url encode brackets to prevent "hacking" detection var results = await RequestStringWithCookiesAndRetry(searchUrl); try { CQ dom = results.Content; ReleaseInfo release; var rows = dom[".mainblockcontenttt > tbody > tr:has(a[href^=\"details.php?id=\"])"]; foreach (var row in rows) { CQ qRow = row.Cq(); release = new ReleaseInfo(); release.Title = qRow.Find("td.mainblockcontent b a").Text(); release.Description = qRow.Find("td:nth-child(3) > span").Text(); if (0 != qRow.Find("td.mainblockcontent u").Length) { var imdbStr = qRow.Find("td.mainblockcontent u").Parent().First().Attr("href").Replace("http://www.imdb.com/title/tt", "").Replace("/", ""); long imdb; if (ParseUtil.TryCoerceLong(imdbStr, out imdb)) { release.Imdb = imdb; } } release.MinimumRatio = 1; release.MinimumSeedTime = 172800; // Sometimes the uploader column is missing int seeders, peers; if (ParseUtil.TryCoerceInt(qRow.Find("td:nth-last-child(3)").Text(), out seeders)) { release.Seeders = seeders; if (ParseUtil.TryCoerceInt(qRow.Find("td:nth-last-child(2)").Text(), out peers)) { release.Peers = peers + release.Seeders; } } release.Grabs = ParseUtil.CoerceLong(qRow.Find("td:nth-last-child(1)").Text()); string fullSize = qRow.Find("td.mainblockcontent").Get(6).InnerText; release.Size = ReleaseInfo.GetBytes(fullSize); release.Guid = new Uri(SiteLink + qRow.Find("td.mainblockcontent b a").Attr("href")); release.Link = new Uri(SiteLink + qRow.Find("td.mainblockcontent").Get(3).FirstChild.GetAttribute("href")); release.Comments = new Uri(SiteLink + qRow.Find("td.mainblockcontent b a").Attr("href")); string[] dateSplit = qRow.Find("td.mainblockcontent").Get(5).InnerHTML.Split(','); string dateString = dateSplit[1].Substring(0, dateSplit[1].IndexOf('>')).Trim(); release.PublishDate = DateTime.ParseExact(dateString, "dd MMM yyyy HH:mm:ss zz00", CultureInfo.InvariantCulture).ToLocalTime(); string category = qRow.Find("td:eq(0) a").Attr("href").Replace("torrents.php?category=", ""); release.Category = MapTrackerCatToNewznab(category); release.UploadVolumeFactor = 1; if (qRow.Find("img[alt=\"Free Torrent\"]").Length >= 1) { release.DownloadVolumeFactor = 0; release.UploadVolumeFactor = 0; } else if (qRow.Find("img[alt=\"Silver Torrent\"]").Length >= 1) { release.DownloadVolumeFactor = 0.5; } else if (qRow.Find("img[alt=\"Bronze Torrent\"]").Length >= 1) { release.DownloadVolumeFactor = 0.75; } else if (qRow.Find("img[alt=\"Blue Torrent\"]").Length >= 1) { release.DownloadVolumeFactor = 0.25; } else { release.DownloadVolumeFactor = 1; } releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var searchUrl = SearchUrl; var queryCollection = new NameValueCollection(); queryCollection.Add("total", "146"); // Not sure what this is about but its required! var cat = "0"; var queryCats = MapTorznabCapsToTrackers(query); if (queryCats.Count == 1) { cat = queryCats.First().ToString(); } queryCollection.Add("cat", cat); queryCollection.Add("dlable", "1"); queryCollection.Add("searchin", "filename"); queryCollection.Add("search", searchString); queryCollection.Add("page", "1"); searchUrl += "?" + queryCollection.GetQueryString(); var extraHeaders = new Dictionary <string, string>() { { "X-Requested-With", "XMLHttpRequest" } }; var response = await RequestStringWithCookiesAndRetry(searchUrl, null, SearchUrlReferer, extraHeaders); var results = response.Content; if (!string.IsNullOrWhiteSpace(results)) { try { CQ dom = results; var rows = dom["tr"]; foreach (var row in rows.Skip(1)) { var release = new ReleaseInfo(); var qRow = row.Cq(); var qTitleLink = qRow.Find("td:eq(1) a:eq(0)").First(); release.Title = qTitleLink.Find("strong").Text().Trim(); // If we search an get no results, we still get a table just with no info. if (string.IsNullOrWhiteSpace(release.Title)) { break; } release.Description = release.Title; release.Guid = new Uri(qTitleLink.Attr("href")); release.Comments = release.Guid; var dateString = qRow.Find("td:eq(4)").Text(); release.PublishDate = DateTime.ParseExact(dateString, "dd MMM yy", CultureInfo.InvariantCulture); var qLink = qRow.Find("td:eq(2) a"); release.Link = new Uri(qLink.Attr("href")); var sizeStr = qRow.Find("td:eq(5)").Text(); release.Size = ReleaseInfo.GetBytes(sizeStr); var connections = qRow.Find("td:eq(7)").Text().Trim().Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); release.Seeders = ParseUtil.CoerceInt(connections[0].Trim()); release.Peers = ParseUtil.CoerceInt(connections[1].Trim()) + release.Seeders; var rCat = row.Cq().Find("td:eq(0) a").First().Attr("href"); var rCatIdx = rCat.IndexOf("cat="); if (rCatIdx > -1) { rCat = rCat.Substring(rCatIdx + 4); } release.Category = MapTrackerCatToNewznab(rCat); releases.Add(release); } } catch (Exception ex) { OnParseError(results, ex); } } return(releases); }
public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query, int attempts = 0) { await CheckToken(); var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var queryCollection = new NameValueCollection(); queryCollection.Add("token", token); queryCollection.Add("format", "json_extended"); queryCollection.Add("app_id", "jackett_v" + Engine.ConfigService.GetVersion()); queryCollection.Add("limit", "100"); queryCollection.Add("ranked", "0"); if (query.ImdbID != null) { queryCollection.Add("mode", "search"); queryCollection.Add("search_imdb", query.ImdbID); } else if (query.RageID != null) { queryCollection.Add("mode", "search"); queryCollection.Add("search_tvrage", query.RageID.ToString()); } /*else if (query.TvdbID != null) * { * queryCollection.Add("mode", "search"); * queryCollection.Add("search_tvdb", query.TvdbID); * }*/ else if (!string.IsNullOrWhiteSpace(searchString)) { searchString = searchString.Replace("'", ""); // ignore ' (e.g. search for america's Next Top Model) queryCollection.Add("mode", "search"); queryCollection.Add("search_string", searchString); } else { queryCollection.Add("mode", "list"); } var cats = string.Join(";", MapTorznabCapsToTrackers(query)); if (!string.IsNullOrEmpty(cats)) { queryCollection.Add("category", cats); } var searchUrl = ApiEndpoint + "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl, string.Empty); try { var jsonContent = JObject.Parse(response.Content); int errorCode = jsonContent.Value <int>("error_code"); if (errorCode == 20) // no results found { return(releases.ToArray()); } if (errorCode > 0) // too many requests per second { // we use the IwebClient rate limiter now, this shouldn't happen throw new Exception(jsonContent.Value <string>("error")); /*if (attempts < 3) * { * await Task.Delay(TimeSpan.FromSeconds(2)); * return await PerformQuery(query, ++attempts); * } * else * { * throw new Exception(jsonContent.Value<string>("error")); * }*/ } foreach (var item in jsonContent.Value <JArray>("torrent_results")) { var release = new ReleaseInfo(); release.Title = item.Value <string>("title"); release.Category = MapTrackerCatDescToNewznab(item.Value <string>("category")); release.MagnetUri = new Uri(item.Value <string>("download")); release.InfoHash = release.MagnetUri.ToString().Split(':')[3].Split('&')[0]; release.Comments = new Uri(item.Value <string>("info_page")); release.Guid = release.Comments; var episode_info = item.Value <JToken>("episode_info"); if (episode_info.HasValues) { var imdb = episode_info.Value <string>("imdb"); release.Imdb = ParseUtil.GetImdbID(imdb); release.TVDBId = episode_info.Value <long?>("tvdb"); release.RageID = episode_info.Value <long?>("tvrage"); release.TMDb = episode_info.Value <long?>("themoviedb"); } // ex: 2015-08-16 21:25:08 +0000 var dateStr = item.Value <string>("pubdate").Replace(" +0000", ""); var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime(); release.Seeders = item.Value <int>("seeders"); release.Peers = item.Value <int>("leechers") + release.Seeders; release.Size = item.Value <long>("size"); release.DownloadVolumeFactor = 0; release.UploadVolumeFactor = 1; releases.Add(release); } } catch (Exception ex) { OnParseError(response.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var cats = MapTorznabCapsToTrackers(query); if (cats.Count == 0) { cats = GetAllTrackerCategories(); } var catStr = string.Join(";", cats); var searchUrl = SearchUrl + "?" + catStr; if (query.IsImdbQuery) { searchUrl += ";q=" + query.ImdbID; } else { searchUrl += ";q=" + WebUtilityHelpers.UrlEncode(query.GetQueryString(), Encoding); } var results = await RequestStringWithCookiesAndRetry(searchUrl); // Check for being logged out if (results.IsRedirect) { if (results.RedirectingTo.Contains("login.php")) { throw new ExceptionWithConfigData("Login failed, please reconfigure the tracker to update the cookies", configData); } else { throw new ExceptionWithConfigData($"Got a redirect to {results.RedirectingTo}, please adjust your the alternative link", configData); } } try { var rows = JsonConvert.DeserializeObject <dynamic>(results.Content); foreach (var row in rows) { var title = (string)row.name; if ((!query.IsImdbQuery || !TorznabCaps.SupportsImdbMovieSearch) && !query.MatchQueryStringAND(title)) { continue; } var torrentId = (long)row.t; var comments = new Uri(SiteLink + "details.php?id=" + torrentId); var seeders = (int)row.seeders; var imdbId = (string)row["imdb-id"]; var downloadMultiplier = (double?)row["download-multiplier"] ?? 1; var link = new Uri(SiteLink + "download.php/" + torrentId + "/" + torrentId + ".torrent"); var publishDate = DateTimeUtil.UnixTimestampToDateTime((long)row.ctime).ToLocalTime(); var imdb = ParseUtil.GetImdbID(imdbId); var release = new ReleaseInfo { Title = title, Comments = comments, Guid = comments, Link = link, PublishDate = publishDate, Category = MapTrackerCatToNewznab(row.c.ToString()), Size = (long)row.size, Files = (long)row.files, Grabs = (long)row.completed, Seeders = seeders, Peers = seeders + (int)row.leechers, Imdb = imdb, DownloadVolumeFactor = downloadMultiplier, UploadVolumeFactor = 1, MinimumRatio = 1, MinimumSeedTime = 172800 // 48 hours }; releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); // remove dashes at the beginning of keywords as they exclude search strings (see issue #3096) var searchString = query.GetQueryString(); searchString = Regex.Replace(searchString, @"(^|\s)-", " "); var searchUrl = SearchUrl; if (query.IsImdbQuery) { searchUrl += "imdbID/" + query.ImdbID + "/"; } else if (!string.IsNullOrWhiteSpace(searchString)) { searchUrl += "query/" + WebUtility.UrlEncode(searchString) + "/"; } var cats = MapTorznabCapsToTrackers(query); if (cats.Count > 0) { searchUrl += "categories/" + string.Join(",", cats); } else { searchUrl += "newfilter/2"; // include 0day and music } var results = await RequestStringWithCookiesAndRetry(searchUrl); if (results.Content.Contains("/user/account/login")) // re-login { await DoLogin(); results = await RequestStringWithCookiesAndRetry(searchUrl); } try { var rows = (JArray)((JObject)JsonConvert.DeserializeObject(results.Content))["torrentList"]; foreach (var row in rows) { var title = row["name"].ToString(); if (!query.MatchQueryStringAND(title)) { continue; } var torrentId = row["fid"].ToString(); var comments = new Uri(SiteLink + "torrent/" + torrentId); var link = new Uri(SiteLink + "download/" + torrentId + "/" + row["filename"]); var publishDate = DateTime.ParseExact(row["addedTimestamp"].ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); var seeders = (int)row["seeders"]; // freeleech #6579 #6624 #7367 var dlMultiplier = row["download_multiplier"].ToString(); var dlVolumeFactor = string.IsNullOrEmpty(dlMultiplier) ? 1 : ParseUtil.CoerceInt(dlMultiplier); var release = new ReleaseInfo { Title = title, Comments = comments, Guid = comments, Link = link, PublishDate = publishDate, Category = MapTrackerCatToNewznab(row["categoryID"].ToString()), Size = (long)row["size"], Grabs = (int)row["completed"], Seeders = seeders, Peers = seeders + (int)row["leechers"], Imdb = ParseUtil.GetImdbID(row["imdbID"].ToString()), UploadVolumeFactor = 1, DownloadVolumeFactor = dlVolumeFactor, MinimumRatio = 1, MinimumSeedTime = 172800 // 48 hours }; releases.Add(release); } } catch (Exception ex) { OnParseError(results.Content, ex); } return(releases); }
protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var searchString = query.GetQueryString(); var searchUrl = SearchUrl; var queryCollection = new NameValueCollection(); queryCollection.Add("active", "0"); queryCollection.Add("options", "0"); queryCollection.Add("category", string.Join(";", MapTorznabCapsToTrackers(query))); if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("search", searchString); } searchUrl += queryCollection.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl); var results = response.Content; try { CQ dom = results; var rows = dom["table.lista > tbody > tr"]; foreach (var row in rows) { // this tracker has horrible markup, find the result rows by looking for the style tag before each one var prev = row.PreviousElementSibling; if (prev == null || prev.NodeName.ToLowerInvariant() != "style") { continue; } 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(SiteLink + qLink.Attr("href")); release.Guid = release.Comments; var qDownload = row.ChildElements.ElementAt(3).FirstElementChild.Cq(); release.Link = new Uri(SiteLink + qDownload.Attr("href")); //"July 11, 2015, 13:34:09", "Today at 20:04:23" var dateStr = row.ChildElements.ElementAt(4).Cq().Text().Trim(); if (dateStr.StartsWith("Today")) { release.PublishDate = DateTime.Today + TimeSpan.ParseExact(dateStr.Replace("Today at ", ""), "hh\\:mm\\:ss", CultureInfo.InvariantCulture); } else if (dateStr.StartsWith("Yesterday")) { release.PublishDate = DateTime.Today - TimeSpan.FromDays(1) + TimeSpan.ParseExact(dateStr.Replace("Yesterday at ", ""), "hh\\:mm\\:ss", CultureInfo.InvariantCulture); } else { release.PublishDate = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMMM dd, yyyy, HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Local); } var sizeStr = row.ChildElements.ElementAt(5).Cq().Text(); release.Size = ReleaseInfo.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text()); release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()) + release.Seeders; var grabs = qRow.Find("td:nth-child(10)").Text(); grabs = grabs.Replace("---", "0"); release.Grabs = ParseUtil.CoerceInt(grabs); if (qRow.Find("img[title=\"FreeLeech\"]").Length >= 1) { release.DownloadVolumeFactor = 0; } else if (qRow.Find("img[src=\"images/sf.png\"]").Length >= 1) // side freeleech { release.DownloadVolumeFactor = 0; } else if (qRow.Find("img[title=\"Half FreeLeech\"]").Length >= 1) { release.DownloadVolumeFactor = 0.5; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; var qCat = qRow.Find("a[href^=\"index.php?page=torrents&category=\"]"); var cat = qCat.Attr("href").Split('=')[2]; release.Category = MapTrackerCatToNewznab(cat); releases.Add(release); } } catch (Exception ex) { OnParseError(results, ex); } return(releases); }