/// <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 searchTerm = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString(); if (EnhancedAnimeSearch && query.HasSpecifiedCategories && (query.Categories.Contains(TorznabCatType.TVAnime.ID) || query.Categories.Contains(100032) || query.Categories.Contains(100101) || query.Categories.Contains(100110))) { var regex = new Regex(" ([0-9]+)"); searchTerm = regex.Replace(searchTerm, " E$1"); } searchTerm = searchTerm.Trim(); searchTerm = searchTerm.ToLower(); searchTerm = searchTerm.Replace(" ", "."); // Multiple page support var nextPage = 1; var followingPages = true; do { // Build our query var request = BuildQuery(searchTerm, query, SearchUrl, nextPage); // Getting results logger.Info("\nAbnormal - Querying API page " + nextPage); var dom = new HtmlParser().ParseDocument(await QueryExecAsync(request)); var results = dom.QuerySelectorAll(".table-rows > tbody > tr:not(.mvc-grid-empty-row)"); // Torrents Result Count var torrentsCount = results.Length; try { // If contains torrents if (torrentsCount > 0) { logger.Info("\nAbnormal - Found " + torrentsCount + " torrents on current page."); // Adding each torrent row to releases releases.AddRange(results.Select(torrent => { // Selectors var id = torrent.QuerySelector("td.grid-release-column > a").GetAttribute("href"); // ID var name = torrent.QuerySelector("td.grid-release-column > a").TextContent; // Release Name var categoryId = torrent.QuerySelector("td.grid-cat-column > a").GetAttribute("href"); // Category var completed = torrent.QuerySelector("td:nth-of-type(3)").TextContent; // Completed var seeders = torrent.QuerySelector("td.text-green").TextContent; // Seeders var leechers = torrent.QuerySelector("td.text-red").TextContent; // Leechers var size = torrent.QuerySelector("td:nth-of-type(5)").TextContent; // Size var release = new ReleaseInfo { // Mapping data Category = MapTrackerCatToNewznab(Regex.Match(categoryId, @"\d+").Value), Title = name, Seeders = int.Parse(Regex.Match(seeders, @"\d+").Value), Peers = int.Parse(Regex.Match(seeders, @"\d+").Value) + int.Parse(Regex.Match(leechers, @"\d+").Value), Grabs = int.Parse(Regex.Match(completed, @"\d+").Value) + int.Parse(Regex.Match(leechers, @"\d+").Value), MinimumRatio = 1, MinimumSeedTime = 172800, Size = ReleaseInfo.GetBytes(size.Replace("Go", "gb").Replace("Mo", "mb").Replace("Ko", "kb")), UploadVolumeFactor = 1, DownloadVolumeFactor = 1, PublishDate = DateTime.Now, Guid = new Uri(TorrentDetailsUrl.Replace("{id}", Regex.Match(id, @"\d+").Value)), Details = new Uri(TorrentDetailsUrl.Replace("{id}", Regex.Match(id, @"\d+").Value)), Link = new Uri(TorrentDownloadUrl.Replace("{id}", Regex.Match(id, @"\d+").Value)) }; // Multi Replacement if (!string.IsNullOrEmpty(MultiReplacement)) { var regex = new Regex("(?i)([\\.\\- ])MULTI([\\.\\- ])"); release.Title = regex.Replace(release.Title, "$1" + MultiReplacement + "$2"); } // Sub Replacement if (SubReplacement) { release.Title = release.Title.Replace("VOSTFR", "ENGLISH").Replace("SUBFRENCH", "ENGLISH"); } // Freeleech if (torrent.QuerySelector("img[alt=\"Freeleech\"]") != null) { release.DownloadVolumeFactor = 0; } return(release); })); if (torrentsCount == 50) { // Is there more pages to follow ? var morePages = dom.QuerySelectorAll("div.mvc-grid-pager > button").Last().GetAttribute("tabindex"); if (morePages == "-1") { followingPages = false; } } nextPage++; } else { logger.Info("\nAbnormal - No results found on page " + nextPage + ", stopping follow of next page."); // No results or no more results available followingPages = false; break; } } catch (Exception ex) { OnParseError("Unable to parse result \n" + ex.StackTrace, ex); } // Stop ? if (torrentsCount < int.Parse(dom.QuerySelector(".mvc-grid-pager-rows").GetAttribute("value"))) { logger.Info("\nAbnormal - Stopping follow of next page " + nextPage + " due max available results reached."); break; } else if (nextPage > MaxPages) { logger.Info("\nAbnormal - Stopping follow of next page " + nextPage + " due to page limit reached."); break; } else if (query.IsTest) { logger.Info("\nAbnormal - Stopping follow of next page " + nextPage + " due to index test query."); break; } } while (followingPages); // Return found releases return(releases); }
/// <summary> /// Execute our search query /// </summary> /// <param name="query">Query</param> /// <returns>Releases</returns> public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query) { var releases = new List <ReleaseInfo>(); var torrentRowList = new List <CQ>(); var searchTerm = query.GetQueryString(); var searchUrl = SearchUrl; int nbResults = 0; int pageLinkCount = 0; // Check cache first so we don't query the server (if search term used or not in dev mode) if (!DevMode && !string.IsNullOrEmpty(searchTerm)) { lock (cache) { // Remove old cache items CleanCache(); // Search in cache var cachedResult = cache.Where(i => i.Query == searchTerm).FirstOrDefault(); if (cachedResult != null) { return(cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray()); } } } // Build our query var request = buildQuery(searchTerm, query, searchUrl); // Getting results & Store content WebClientStringResult results = await queryExec(request); fDom = results.Content; try { // Find torrent rows var firstPageRows = findTorrentRows(); // Add them to torrents list torrentRowList.AddRange(firstPageRows.Select(fRow => fRow.Cq())); // Check if there are pagination links at bottom Boolean pagination = (fDom[".linkbox > a"].Length != 0); // If pagination available if (pagination) { // Calculate numbers of pages available for this search query (Based on number results and number of torrents on first page) pageLinkCount = ParseUtil.CoerceInt(Regex.Match(fDom[".linkbox > a"].Last().Attr("href").ToString(), @"\d+").Value); // Calculate average number of results (based on torrents rows lenght on first page) nbResults = firstPageRows.Count() * pageLinkCount; } else { // Check if we have a minimum of one result if (firstPageRows.Length >= 1) { // Retrieve total count on our alone page nbResults = firstPageRows.Count(); pageLinkCount = 1; } else { output("\nNo result found for your query, please try another search term ...\n", "info"); // No result found for this query return(releases); } } output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !"); output("\nThere are " + firstPageRows.Length + " results on the first page !"); // If we have a term used for search and pagination result superior to one if (!string.IsNullOrWhiteSpace(query.GetQueryString()) && pageLinkCount > 1) { // Starting with page #2 for (int i = 2; i <= Math.Min(Int32.Parse(ConfigData.Pages.Value), pageLinkCount); i++) { output("\nProcessing page #" + i); // Request our page latencyNow(); // Build our query var pageRequest = buildQuery(searchTerm, query, searchUrl, i); // Getting results & Store content WebClientStringResult pageResults = await queryExec(pageRequest); // Assign response fDom = pageResults.Content; // Process page results var additionalPageRows = findTorrentRows(); // Add them to torrents list torrentRowList.AddRange(additionalPageRows.Select(fRow => fRow.Cq())); } } else { // No search term, maybe testing... so registring autkey and torrentpass for future uses string infosData = firstPageRows.First().Find("td:eq(3) > a").Attr("href"); IList <string> infosList = infosData.Split('&').Select(s => s.Trim()).Where(s => s != String.Empty).ToList(); IList <string> infosTracker = infosList.Select(s => s.Split(new[] { '=' }, 2)[1].Trim()).ToList(); output("\nStoring Authkey for future uses..."); ConfigData.AuthKey.Value = infosTracker[2]; output("\nStoring TorrentPass for future uses..."); ConfigData.TorrentPass.Value = infosTracker[3]; } // Loop on results foreach (CQ tRow in torrentRowList) { output("\n=>> Torrent #" + (releases.Count + 1)); // ID int id = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(1) > a").Attr("href").ToString(), @"\d+").Value); output("ID: " + id); // Release Name string name = tRow.Find("td:eq(1) > a").Text().ToString(); output("Release: " + name); // Category string categoryID = tRow.Find("td:eq(0) > a").Attr("href").Replace("torrents.php?cat[]=", String.Empty); output("Category: " + MapTrackerCatToNewznab(categoryID) + " (" + categoryID + ")"); // Seeders int seeders = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5)").Text(), @"\d+").Value); output("Seeders: " + seeders); // Leechers int leechers = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(6)").Text(), @"\d+").Value); output("Leechers: " + leechers); // Completed int completed = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5)").Text(), @"\d+").Value); output("Completed: " + completed); // Size string sizeStr = tRow.Find("td:eq(4)").Text().Replace("Go", "gb").Replace("Mo", "mb").Replace("Ko", "kb"); long size = ReleaseInfo.GetBytes(sizeStr); output("Size: " + sizeStr + " (" + size + " bytes)"); // Publish DateToString IList <string> clockList = tRow.Find("td:eq(2) > span").Text().Replace("Il y a", "").Split(',').Select(s => s.Trim()).Where(s => s != String.Empty).ToList(); var date = agoToDate(clockList); output("Released on: " + date.ToLocalTime()); // Torrent Details URL Uri detailsLink = new Uri(TorrentDescriptionUrl + id); output("Details: " + detailsLink.AbsoluteUri); // Torrent Comments URL Uri commentsLink = new Uri(TorrentCommentUrl + id); output("Comments Link: " + commentsLink.AbsoluteUri); // Torrent Download URL Uri downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{auth_key}", ConfigData.AuthKey.Value).Replace("{torrent_pass}", ConfigData.TorrentPass.Value)); output("Download Link: " + downloadLink.AbsoluteUri); // Building release infos var release = new ReleaseInfo(); release.Category = MapTrackerCatToNewznab(categoryID.ToString()); release.Title = name; release.Seeders = seeders; release.Peers = seeders + leechers; release.MinimumRatio = 1; release.MinimumSeedTime = 172800; release.PublishDate = date; release.Size = size; release.Guid = detailsLink; release.Comments = commentsLink; release.Link = downloadLink; releases.Add(release); } } catch (Exception ex) { OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex); } // Return found releases return(releases); }