private static Torrent ParseTorrentFromRowNode( HtmlNode rowNode ) => new Torrent { Seeders = rowNode .SelectSingleNode(XPathSeeders) ?.InnerText ?.TryToInt() ?? 0, Leechers = rowNode .SelectSingleNode(XPathLeechers) ?.InnerText ?.TryToInt() ?? 0, MagnetUri = rowNode .SelectSingleNode(XPathMagnetUri) ?.GetAttributeValue("href", string.Empty) ?? string.Empty, Name = rowNode .SelectNodes(XPathTorrentName) ?.LastOrDefault() ?.InnerText ?.Trim() ?? string.Empty, Size = ParseUtil.GetBytes(rowNode .SelectSingleNode(XPathSize) ?.InnerText), UploadedOn = rowNode .SelectSingleNode(XPathUploadedOn) ?.InnerText ?.TryParseExact(UploadedOnDateFormat) };
private static long GetReleaseSize(AngleSharp.Dom.IElement tabNode) { const string SizeSelector = ".list.down > .red"; var sizeStr = tabNode.QuerySelector(SizeSelector).TextContent; return(ParseUtil.GetBytes(sizeStr)); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.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(); } // TODO: Asses if we should be throwing this out //if (!query.MatchQueryStringAND(title)) //{ // continue; // we have to skip bad titles due to tags + any word search //} var details = _settings.BaseUrl + qLink.GetAttribute("href"); var link = _settings.BaseUrl + 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 = ParseUtil.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 TorrentInfo { Title = title, InfoUrl = details, Guid = details, DownloadUrl = link, PublishDate = publishDate, Size = size, Categories = _categories.MapTrackerCatToNewznab(cat), Files = files, Grabs = grabs, Seeders = seeders, Peers = leechers + seeders, MinimumRatio = 0.75, MinimumSeedTime = 216000, // 60 hours DownloadVolumeFactor = 0, // ratioless UploadVolumeFactor = 1 }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
private static long ParseSize(HtmlNode torrentDetailsDocumentNode) { var textSize = torrentDetailsDocumentNode .SelectSingleNode(XPathTorrentSizeText) ?.InnerText ?? string.Empty; return(ParseUtil.GetBytes(textSize)); }
private async Task <IEnumerable <Torrent> > ParseTorrents(HtmlNode node) { var torrents = node .SelectNodes(@"//table[contains(@class, 'table2')]/tr") .Skip(1) .Select(async torrentRow => { try { var detailsUrl = torrentRow .SelectSingleNode("td[1]/div[1]/a[2]") .GetAttributeValue("href", string.Empty); return(new Torrent { Leechers = torrentRow .SelectSingleNode("td[5]") ?.InnerText ?.Replace(",", null) .TryToInt() ?? 0, MagnetUri = await GetMagnetUri(_settings.BaseUrl, detailsUrl), Name = torrentRow .SelectSingleNode("td[1]") ?.InnerText, Seeders = torrentRow .SelectSingleNode("td[4]") ?.InnerText ?.Replace(",", null) .TryToInt() ?? 0, Size = ParseUtil.GetBytes( torrentRow .SelectSingleNode("td[3]") ?.InnerText ), UploadedOn = ParseUploadedOn( torrentRow .SelectSingleNode("td[2]") ?.InnerText ) }); } catch (Exception ex) { _logService.LogError("Failed to parse torrent entry.", ex); return(null); } }); return(await Task.WhenAll(torrents)); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var releaseInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var doc = parser.ParseDocument(indexerResponse.Content); var rows = doc.QuerySelectorAll("table.xMenuT > tbody > tr").Skip(1); foreach (var row in rows) { var titleElement = row.QuerySelector("td > span.s"); if (titleElement == null) { continue; } var parsedTitle = ParseTitleRegex.Match(titleElement.TextContent); if (!parsedTitle.Success || parsedTitle.Groups["title"].Value.IsNullOrWhiteSpace()) { continue; } var guid = row.QuerySelector("input[type=checkbox]").GetAttribute("name"); var publishDate = DateTimeUtil.FromUnknown(row.QuerySelector("td:nth-child(6)").TextContent); var sizeElement = row.QuerySelector("td > span.d"); var size = ParseSizeRegex.Match(sizeElement.TextContent); var infoUrl = string.Format("{0}{1}", _settings.BaseUrl.TrimEnd('/'), row.QuerySelector("a").GetAttribute("href")); var downloadUrl = string.Format("{0}/?action=nzb&{1}=1", _settings.BaseUrl.TrimEnd('/'), guid); var release = new ReleaseInfo { Guid = guid, Title = parsedTitle.Groups["title"].Value, Size = ParseUtil.GetBytes(string.Format("{0} {1}", size.Groups["size"].Value, size.Groups["unit"].Value)), PublishDate = publishDate, Categories = new List <IndexerCategory> { NewznabStandardCategory.Other }, InfoUrl = infoUrl, DownloadUrl = downloadUrl }; releaseInfos.Add(release); } return(releaseInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.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(_settings.BaseUrl + row.QuerySelector("img[title='Download']").ParentElement.GetAttribute("href").TrimStart('/')); var details = new Uri(_settings.BaseUrl + row.QuerySelector("td[class='lft'] > div > a").GetAttribute("href").TrimStart('/')); var size = ParseUtil.GetBytes(cells[5].TextContent); var grabs = ParseUtil.CoerceInt(cells[6].TextContent); var seeders = ParseUtil.CoerceInt(cells[7].TextContent); var leechers = ParseUtil.CoerceInt(cells[8].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").GetAttribute("href").Split('/').Last(); var downloadVolumeFactor = row.QuerySelector("span:contains(\"[Freeleech]\")") != null ? 0 : 1; var release = new TorrentInfo { Title = title, DownloadUrl = link.AbsoluteUri, Guid = link.AbsoluteUri, InfoUrl = details.AbsoluteUri, PublishDate = publishDate, Categories = _categories.MapTrackerCatToNewznab(cat), Size = size, Grabs = grabs, Seeders = seeders, Peers = seeders + leechers, MinimumRatio = 1, MinimumSeedTime = 259200, // 72 hours DownloadVolumeFactor = downloadVolumeFactor, UploadVolumeFactor = 1 }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <TorrentInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var rows = dom.QuerySelectorAll("table.table-bordered > tbody > tr[class*=\"torrent_row_\"]"); foreach (var row in rows) { var release = new TorrentInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 72 * 60 * 60; var qCatLink = row.QuerySelector("a[href^=\"/browse_elastic.php?cat=\"]"); var catStr = qCatLink.GetAttribute("href").Split('=')[1]; release.Categories = _categories.MapTrackerCatToNewznab(catStr); var qDetailsLink = row.QuerySelector("a[href^=\"/details.php?id=\"]"); var qDetailsTitle = row.QuerySelector("td:has(a[href^=\"/details.php?id=\"]) b"); release.Title = qDetailsTitle.TextContent.Trim(); var qDlLink = row.QuerySelector("a[href^=\"/download.php?torrent=\"]"); release.DownloadUrl = _settings.BaseUrl + qDlLink.GetAttribute("href").TrimStart('/'); release.InfoUrl = _settings.BaseUrl + qDetailsLink.GetAttribute("href").TrimStart('/'); release.Guid = release.InfoUrl; var qColumns = row.QuerySelectorAll("td"); release.Files = ParseUtil.CoerceInt(qColumns[3].TextContent); release.PublishDate = DateTimeUtil.FromUnknown(qColumns[5].TextContent); release.Size = ParseUtil.GetBytes(qColumns[6].TextContent); release.Grabs = ParseUtil.CoerceInt(qColumns[7].TextContent.Replace("Times", "")); release.Seeders = ParseUtil.CoerceInt(qColumns[8].TextContent); release.Peers = ParseUtil.CoerceInt(qColumns[9].TextContent) + release.Seeders; var qImdb = row.QuerySelector("a[href*=\"www.imdb.com\"]"); if (qImdb != null) { var deRefUrl = qImdb.GetAttribute("href"); release.ImdbId = ParseUtil.GetImdbID(WebUtility.UrlDecode(deRefUrl).Split('/').Last()) ?? 0; } release.DownloadVolumeFactor = row.QuerySelector("span.freeleech") != null ? 0 : 1; release.UploadVolumeFactor = 1; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
private static IEnumerable <Torrent> ParseTorrents(HtmlNode rootNode) { var torrentRows = rootNode.SelectNodes(XPathTorrentRow); return(torrentRows ?.Select(torrentRow => new Torrent { Name = torrentRow .SelectSingleNode(XPathTorrentTitle) ?.InnerText ?.Trim(), MagnetUri = torrentRow .SelectSingleNode(XPathMagnetUri) ?.ParentNode ?.GetAttributeValue("href", string.Empty), Size = ParseUtil.GetBytes( torrentRow .SelectSingleNode(XPathSize) ?.InnerText ), Leechers = int.Parse( torrentRow .SelectSingleNode(XPathLeech) ?.InnerText ?? "0" ), Seeders = int.Parse( torrentRow .SelectSingleNode(XPathSeed) ?.InnerText ?? "0" ), UploadedOn = torrentRow .SelectSingleNode(XPathUploadedOn) ?.InnerText ?.TryParseExact(UploadedOnDateFormat) }) ?? new Torrent[0]); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var rowsSelector = "table#tor-tbl > tbody > tr"; var searchResultParser = new HtmlParser(); var searchResultDocument = searchResultParser.ParseDocument(indexerResponse.Content); var rows = searchResultDocument.QuerySelectorAll(rowsSelector); foreach (var row in rows) { try { var qDownloadLink = row.QuerySelector("a.tr-dl"); // Expects moderation if (qDownloadLink == null) { continue; } var qForumLink = row.QuerySelector("a.f"); var qDetailsLink = row.QuerySelector("a.tLink"); var qSize = row.QuerySelector("td:nth-child(6) u"); var link = new Uri(_settings.BaseUrl + "forum/" + qDetailsLink.GetAttribute("href")); var seederString = row.QuerySelector("td:nth-child(7) b").TextContent; var seeders = string.IsNullOrWhiteSpace(seederString) ? 0 : ParseUtil.CoerceInt(seederString); var timestr = row.QuerySelector("td:nth-child(11) u").TextContent; var forum = qForumLink; var forumid = forum.GetAttribute("href").Split('=')[1]; var title = _settings.StripRussianLetters ? StripRussianRegex.Replace(qDetailsLink.TextContent, "") : qDetailsLink.TextContent; var size = ParseUtil.GetBytes(qSize.TextContent); var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent); var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(9)").TextContent); var publishDate = DateTimeUtil.UnixTimestampToDateTime(long.Parse(timestr)); var release = new TorrentInfo { MinimumRatio = 1, MinimumSeedTime = 0, Title = title, InfoUrl = link.AbsoluteUri, Description = qForumLink.TextContent, DownloadUrl = link.AbsoluteUri, Guid = link.AbsoluteUri, Size = size, Seeders = seeders, Peers = leechers + seeders, Grabs = grabs, PublishDate = publishDate, Categories = _categories.MapTrackerCatToNewznab(forumid), DownloadVolumeFactor = 1, UploadVolumeFactor = 1 }; torrentInfos.Add(release); } catch (Exception ex) { _logger.Error(string.Format("Pornolab: Error while parsing row '{0}':\n\n{1}", row.OuterHtml, ex)); } } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <TorrentInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var rows = dom.QuerySelectorAll(".torrents tr.torrent, .torrents tr.torrent_alt"); var currentCategories = new List <IndexerCategory> { NewznabStandardCategory.TVAnime }; foreach (var row in rows) { var qTitleLink = row.QuerySelector("a.title, a.alt_title"); if (qTitleLink == null) { continue; } var title = qTitleLink.TextContent.Trim(); // Insert before the release info var taidx = title.IndexOf('('); var tbidx = title.IndexOf('['); if (taidx == -1) { taidx = title.Length; } if (tbidx == -1) { tbidx = title.Length; } var titleSplit = Math.Min(taidx, tbidx); var titleSeries = title.Substring(0, titleSplit); var releaseInfo = title.Substring(titleSplit); currentCategories = GetNextCategory(row, currentCategories).ToList(); var stringSeparator = new[] { " | " }; var titles = titleSeries.Split(stringSeparator, StringSplitOptions.RemoveEmptyEntries); if (titles.Count() > 1 && !_settings.AddRomajiTitle) { titles = titles.Skip(1).ToArray(); } foreach (var name in titles) { var release = new TorrentInfo(); release.Title = (name + releaseInfo).Trim(); // Ensure the season is defined as this tracker only deals with full seasons if (release.Title.IndexOf("Season") == -1 && _settings.AppendSeason) { // Insert before the release info var aidx = release.Title.IndexOf('('); var bidx = release.Title.IndexOf('['); if (aidx == -1) { aidx = release.Title.Length; } if (bidx == -1) { bidx = release.Title.Length; } var insertPoint = Math.Min(aidx, bidx); release.Title = release.Title.Substring(0, insertPoint) + " Season 1 " + release.Title.Substring(insertPoint); } release.Categories = currentCategories; release.Description = row.QuerySelector("span.tags")?.TextContent; release.Guid = _settings.BaseUrl + qTitleLink.GetAttribute("href"); release.InfoUrl = release.Guid; release.DownloadUrl = _settings.BaseUrl + row.QuerySelector(".peers a").GetAttribute("href"); var grabs = row.QuerySelectorAll(".peers")[0].FirstChild.NodeValue.TrimEnd().TrimEnd('/').TrimEnd(); grabs = grabs.Replace("k", "000"); release.Grabs = int.Parse(grabs); release.Seeders = int.Parse(row.QuerySelectorAll(".peers a")[0].TextContent); release.Peers = release.Seeders + int.Parse(row.QuerySelectorAll(".peers a")[1].TextContent); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; // 48 hours var size = row.QuerySelector(".size").TextContent; release.Size = ParseUtil.GetBytes(size); //22 Jul 15 var dateStr = row.QuerySelector(".added").TextContent.Replace("'", string.Empty); if (dateStr.Split(' ')[0].Length == 1) { dateStr = "0" + dateStr; } if (string.Equals(dateStr, "yesterday", StringComparison.InvariantCultureIgnoreCase)) { release.PublishDate = DateTime.Now.AddDays(-1); } else if (string.Equals(dateStr, "today", StringComparison.InvariantCultureIgnoreCase)) { release.PublishDate = DateTime.Now; } else { release.PublishDate = DateTime.ParseExact(dateStr, "dd MMM yy", CultureInfo.InvariantCulture); } release.DownloadVolumeFactor = row.QuerySelector("span.freeleech") != null ? 0 : 1; release.UploadVolumeFactor = 1; torrentInfos.Add(release); } } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var doc = parser.ParseDocument(indexerResponse.Content); var rows = doc.QuerySelectorAll("table.torrent_table > tbody > tr.torrent"); foreach (var row in rows) { var qDetailsLink = row.QuerySelector("a.torrent_name"); var year = qDetailsLink.NextSibling.TextContent.Replace("[", "").Replace("]", "").Trim(); var tags = row.QuerySelector("div.torrent_info").FirstChild.TextContent.Replace(" / ", " ").Trim(); var title = $"{qDetailsLink.TextContent} {year} {tags}"; var description = row.QuerySelector("div.tags").TextContent.Trim(); var details = _settings.BaseUrl + qDetailsLink.GetAttribute("href"); var torrentId = qDetailsLink.GetAttribute("href").Split('=').Last(); var link = _settings.BaseUrl + "torrents.php?action=download&id=" + torrentId; var posterStr = qDetailsLink.GetAttribute("data-cover"); var poster = !string.IsNullOrWhiteSpace(posterStr) ? posterStr : null; var files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(3)").TextContent); var publishDate = DateTimeUtil.FromTimeAgo(row.QuerySelector("td:nth-child(4)").TextContent); var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(5)").FirstChild.TextContent); var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent); var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent); var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent); var dlVolumeFactor = row.QuerySelector("strong.tl_free") != null ? 0 : 1; var cat = row.QuerySelector("td.cats_col > div").GetAttribute("class").Replace("tooltip cats_", ""); var category = new List <IndexerCategory> { cat switch { "featurefilm" => NewznabStandardCategory.Movies, "shortfilm" => NewznabStandardCategory.Movies, "miniseries" => NewznabStandardCategory.TV, "other" => NewznabStandardCategory.Other, _ => throw new Exception($"Unknown category: {cat}") } }; // TODO: TMDb is also available var qImdb = row.QuerySelector("a[href^=\"https://www.imdb.com\"]"); var imdb = qImdb != null?ParseUtil.GetImdbID(qImdb.GetAttribute("href").Split('/').Last()) : null; var release = new TorrentInfo { MinimumRatio = 1, MinimumSeedTime = 259200, Description = description, Title = title, PublishDate = publishDate, Categories = category, DownloadUrl = link, InfoUrl = details, PosterUrl = poster, Guid = link, ImdbId = imdb.GetValueOrDefault(), Seeders = seeders, Peers = leechers + seeders, Size = size, Grabs = grabs, Files = files, DownloadVolumeFactor = dlVolumeFactor, UploadVolumeFactor = 1 }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); foreach (var child in dom.QuerySelectorAll("#needseed")) { child.Remove(); } var table = dom.QuerySelector("table[align=center] + br + table > tbody"); // No results, so skip this search if (table == null) { return(torrentInfos); } foreach (var row in table.Children.Skip(1)) { var release = new TorrentInfo(); var qLink = row.Children[2].QuerySelector("a"); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; // 48 hours release.Title = qLink.GetAttribute("title"); var detailsLink = new Uri(qLink.GetAttribute("href")); //Skip irrelevant and duplicate entries if (torrentInfos.Any(r => r.Guid == detailsLink.AbsoluteUri)) { continue; } release.Files = ParseUtil.CoerceInt(row.Children[3].TextContent); release.Grabs = ParseUtil.CoerceInt(row.Children[7].TextContent); release.Guid = detailsLink.AbsoluteUri; release.InfoUrl = release.Guid; release.DownloadUrl = new Uri(_settings.BaseUrl + row.QuerySelector("a[href^=\"download.php\"]").GetAttribute("href")).AbsoluteUri; var catUrl = new Uri(_settings.BaseUrl + row.Children[1].FirstElementChild.GetAttribute("href")); var catQuery = HttpUtility.ParseQueryString(catUrl.Query); var catNum = catQuery["cat"]; release.Categories = _categories.MapTrackerCatToNewznab(catNum); var dateString = row.Children[5].TextContent.Trim(); var pubDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); release.PublishDate = DateTime.SpecifyKind(pubDate, DateTimeKind.Local); var sizeStr = row.Children[6].TextContent; release.Size = ParseUtil.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.Children[8].TextContent.Trim()); release.Peers = ParseUtil.CoerceInt(row.Children[9].TextContent.Trim()) + release.Seeders; switch (row.GetAttribute("bgcolor")) { case "#DDDDDD": release.DownloadVolumeFactor = 1; release.UploadVolumeFactor = 2; break; case "#FFFF99": release.DownloadVolumeFactor = 0; release.UploadVolumeFactor = 1; break; case "#CCFF99": release.DownloadVolumeFactor = 0; release.UploadVolumeFactor = 2; break; default: release.DownloadVolumeFactor = 1; release.UploadVolumeFactor = 1; break; } torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
private long getReleaseSize(AngleSharp.Dom.IElement tr) { var sizeStr = tr.QuerySelector("div.tracker_info_left").TextContent; return(ParseUtil.GetBytes(SizeInfoQueryRegex.Match(sizeStr).Groups[1].Value.Trim())); }
private string ParseFields(string value, string fieldName, TorrentInfo release, List <string> fieldModifiers, Uri searchUrlUri) { switch (fieldName) { case "download": if (string.IsNullOrEmpty(value)) { value = null; release.DownloadUrl = null; break; } if (value.StartsWith("magnet:")) { release.MagnetUrl = value; value = release.MagnetUrl; } else { release.DownloadUrl = ResolvePath(value, searchUrlUri).AbsoluteUri; value = release.DownloadUrl; } release.Guid = value; break; case "magnet": var magnetUri = value; release.MagnetUrl = magnetUri; value = magnetUri.ToString(); break; case "infohash": release.InfoHash = value; break; case "details": var url = ResolvePath(value, searchUrlUri)?.AbsoluteUri; release.InfoUrl = url; value = url.ToString(); break; case "comments": var commentsUrl = ResolvePath(value, searchUrlUri); if (release.CommentUrl == null) { release.CommentUrl = commentsUrl.AbsoluteUri; } value = commentsUrl.ToString(); break; case "title": if (fieldModifiers.Contains("append")) { release.Title += value; } else { release.Title = value; } value = release.Title; break; case "description": if (fieldModifiers.Contains("append")) { release.Description += value; } else { release.Description = value; } value = release.Description; break; case "category": var cats = MapTrackerCatToNewznab(value); if (cats.Any()) { if (release.Categories == null || fieldModifiers.Contains("noappend")) { release.Categories = cats; } else { release.Categories = release.Categories.Union(cats).ToList(); } } value = release.Categories.ToString(); break; case "categorydesc": var catsDesc = MapTrackerCatDescToNewznab(value); if (catsDesc.Any()) { if (release.Categories == null || fieldModifiers.Contains("noappend")) { release.Categories = catsDesc; } else { release.Categories = release.Categories.Union(catsDesc).ToList(); } } value = release.Categories.ToString(); break; case "size": release.Size = ParseUtil.GetBytes(value); value = release.Size.ToString(); break; case "leechers": var leechers = ParseUtil.CoerceLong(value); leechers = leechers < 5000000L ? leechers : 0; // to fix #6558 if (release.Peers == null) { release.Peers = (int)leechers; } else { release.Peers += (int)leechers; } value = leechers.ToString(); break; case "seeders": release.Seeders = ParseUtil.CoerceInt(value); release.Seeders = release.Seeders < 5000000L ? release.Seeders : 0; // to fix #6558 if (release.Peers == null) { release.Peers = release.Seeders; } else { release.Peers += release.Seeders; } value = release.Seeders.ToString(); break; case "date": release.PublishDate = DateTimeUtil.FromUnknown(value); value = release.PublishDate.ToString(DateTimeUtil.Rfc1123ZPattern); break; case "files": release.Files = ParseUtil.CoerceInt(value); value = release.Files.ToString(); break; case "grabs": release.Grabs = ParseUtil.CoerceInt(value); value = release.Grabs.ToString(); break; case "downloadvolumefactor": release.DownloadVolumeFactor = ParseUtil.CoerceDouble(value); value = release.DownloadVolumeFactor.ToString(); break; case "uploadvolumefactor": release.UploadVolumeFactor = ParseUtil.CoerceDouble(value); value = release.UploadVolumeFactor.ToString(); break; case "minimumratio": release.MinimumRatio = ParseUtil.CoerceDouble(value); value = release.MinimumRatio.ToString(); break; case "minimumseedtime": release.MinimumSeedTime = ParseUtil.CoerceLong(value); value = release.MinimumSeedTime.ToString(); break; case "imdb": case "imdbid": release.ImdbId = (int)ParseUtil.GetLongFromString(value); value = release.ImdbId.ToString(); break; case "tmdbid": var tmdbIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); var tmdbIDMatch = tmdbIDRegEx.Match(value); var tmdbID = tmdbIDMatch.Groups[1].Value; release.TmdbId = (int)ParseUtil.CoerceLong(tmdbID); value = release.TmdbId.ToString(); break; case "rageid": var rageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); var rageIDMatch = rageIDRegEx.Match(value); var rageID = rageIDMatch.Groups[1].Value; release.TvRageId = (int)ParseUtil.CoerceLong(rageID); value = release.TvRageId.ToString(); break; case "traktid": var traktIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); var traktIDMatch = traktIDRegEx.Match(value); var traktID = traktIDMatch.Groups[1].Value; release.TraktId = (int)ParseUtil.CoerceLong(traktID); value = release.TraktId.ToString(); break; case "tvdbid": var tvdbIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); var tvdbIdMatch = tvdbIdRegEx.Match(value); var tvdbId = tvdbIdMatch.Groups[1].Value; release.TvdbId = (int)ParseUtil.CoerceLong(tvdbId); value = release.TvdbId.ToString(); break; case "poster": if (!string.IsNullOrWhiteSpace(value)) { var poster = ResolvePath(value, searchUrlUri); release.PosterUrl = poster.AbsoluteUri; } value = release.PosterUrl; break; case "genre": release.Genres = release.Genres.Union(value.Split(',')).ToList(); value = release.Genres.ToString(); break; case "year": release.Year = ParseUtil.CoerceInt(value); value = release.Year.ToString(); break; case "author": release.Author = value; break; case "booktitle": release.BookTitle = value; break; case "artist": release.Artist = value; break; case "album": release.Album = value; break; default: break; } return(value); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var rowsSelector = ".torrent_table > tbody > tr"; var searchResultParser = new HtmlParser(); var searchResultDocument = searchResultParser.ParseDocument(indexerResponse.Content); var rows = searchResultDocument.QuerySelectorAll(rowsSelector); var stickyGroup = false; string categoryStr; ICollection <IndexerCategory> groupCategory = null; string groupTitle = null; foreach (var row in rows) { if (row.ClassList.Contains("torrent")) { // garbage rows continue; } else if (row.ClassList.Contains("group")) { stickyGroup = row.ClassList.Contains("sticky"); var dispalyname = row.QuerySelector("#displayname"); var qCat = row.QuerySelector("td.cats_col > div"); categoryStr = qCat.GetAttribute("title"); var qArtistLink = dispalyname.QuerySelector("#groupplatform > a"); if (qArtistLink != null) { categoryStr = ParseUtil.GetArgumentFromQueryString(qArtistLink.GetAttribute("href"), "artistname"); } groupCategory = _categories.MapTrackerCatToNewznab(categoryStr); var qDetailsLink = dispalyname.QuerySelector("#groupname > a"); groupTitle = qDetailsLink.TextContent; } else if (row.ClassList.Contains("group_torrent")) { if (row.QuerySelector("td.edition_info") != null) { continue; } var sizeString = row.QuerySelector("td:nth-child(4)").TextContent; if (string.IsNullOrEmpty(sizeString)) { continue; } var qDetailsLink = row.QuerySelector("a[href^=\"torrents.php?id=\"]"); var title = qDetailsLink.TextContent.Replace(", Freeleech!", "").Replace(", Neutral Leech!", ""); //if (stickyGroup && (query.ImdbID == null || !NewznabStandardCategory.MovieSearchImdbAvailable) && !query.MatchQueryStringAND(title)) // AND match for sticky releases //{ // continue; //} var qDescription = qDetailsLink.QuerySelector("span.torrent_info_tags"); var qDLLink = row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); var qTime = row.QuerySelector("span.time"); var qGrabs = row.QuerySelector("td:nth-child(5)"); var qSeeders = row.QuerySelector("td:nth-child(6)"); var qLeechers = row.QuerySelector("td:nth-child(7)"); var qFreeLeech = row.QuerySelector("strong.freeleech_label"); var qNeutralLeech = row.QuerySelector("strong.neutralleech_label"); var time = qTime.GetAttribute("title"); var link = _settings.BaseUrl + qDLLink.GetAttribute("href"); var seeders = ParseUtil.CoerceInt(qSeeders.TextContent); var publishDate = DateTime.SpecifyKind( DateTime.ParseExact(time, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified).ToLocalTime(); var details = _settings.BaseUrl + qDetailsLink.GetAttribute("href"); var grabs = ParseUtil.CoerceInt(qGrabs.TextContent); var leechers = ParseUtil.CoerceInt(qLeechers.TextContent); var size = ParseUtil.GetBytes(sizeString); var release = new TorrentInfo { MinimumRatio = 1, MinimumSeedTime = 288000, //80 hours Categories = groupCategory, PublishDate = publishDate, Size = size, InfoUrl = details, DownloadUrl = link, Guid = link, Grabs = grabs, Seeders = seeders, Peers = leechers + seeders, Title = title, Description = qDescription?.TextContent, UploadVolumeFactor = qNeutralLeech is null ? 1 : 0, DownloadVolumeFactor = qFreeLeech != null || qNeutralLeech != null ? 0 : 1 }; torrentInfos.Add(release); } } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <TorrentInfo>(); var parser = new HtmlParser(); var doc = parser.ParseDocument(indexerResponse.Content); var rows = doc.QuerySelectorAll("table[id='torrents'] > tbody > tr"); foreach (var row in rows) { var qTitleLink = row.QuerySelector("a.hv"); //no results if (qTitleLink == null) { continue; } // drop invalid char that seems to have cropped up in some titles. #6582 var title = qTitleLink.TextContent.Trim().Replace("\u000f", ""); var details = new Uri(_settings.BaseUrl + qTitleLink.GetAttribute("href").TrimStart('/')); var qLink = row.QuerySelector("a[href^=\"/download.php/\"]"); var link = new Uri(_settings.BaseUrl + qLink.GetAttribute("href").TrimStart('/')); var descrSplit = row.QuerySelector("div.sub").TextContent.Split('|'); var dateSplit = descrSplit.Last().Split(new[] { " by " }, StringSplitOptions.None); var publishDate = DateTimeUtil.FromTimeAgo(dateSplit.First()); var description = descrSplit.Length > 1 ? "Tags: " + descrSplit.First().Trim() : ""; description += dateSplit.Length > 1 ? " Uploaded by: " + dateSplit.Last().Trim() : ""; var catIcon = row.QuerySelector("td:nth-of-type(1) a"); if (catIcon == null) { // Torrents - Category column == Text or Code // release.Category = MapTrackerCatDescToNewznab(row.Cq().Find("td:eq(0)").Text()); // Works for "Text" but only contains the parent category throw new Exception("Please, change the 'Torrents - Category column' option to 'Icons' in the website Settings. Wait a minute (cache) and then try again."); } // Torrents - Category column == Icons var cat = _categories.MapTrackerCatToNewznab(catIcon.GetAttribute("href").Substring(1)); var size = ParseUtil.GetBytes(row.Children[5].TextContent); var colIndex = 6; int?files = null; if (row.Children.Length == 10) { files = ParseUtil.CoerceInt(row.Children[colIndex].TextContent.Replace("Go to files", "")); colIndex++; } var grabs = ParseUtil.CoerceInt(row.Children[colIndex++].TextContent); var seeders = ParseUtil.CoerceInt(row.Children[colIndex++].TextContent); var leechers = ParseUtil.CoerceInt(row.Children[colIndex].TextContent); var dlVolumeFactor = row.QuerySelector("span.free") != null ? 0 : 1; var release = new TorrentInfo { Title = title, Guid = details.AbsoluteUri, DownloadUrl = link.AbsoluteUri, InfoUrl = details.AbsoluteUri, PublishDate = publishDate, Categories = cat, Size = size, Files = files, Grabs = grabs, Seeders = seeders, Peers = seeders + leechers, DownloadVolumeFactor = dlVolumeFactor, UploadVolumeFactor = 1, MinimumRatio = 1, MinimumSeedTime = 1209600 // 336 hours }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <TorrentInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var rows = dom.QuerySelectorAll("tr"); foreach (var row in rows.Skip(1)) { var release = new TorrentInfo(); var qTitleLink = row.QuerySelector("td:nth-of-type(2) a:nth-of-type(1)"); release.Title = qTitleLink.TextContent.Trim(); // If we search an get no results, we still get a table just with no info. if (string.IsNullOrWhiteSpace(release.Title)) { break; } release.Guid = qTitleLink.GetAttribute("href"); release.InfoUrl = release.Guid; var dateString = row.QuerySelector("td:nth-of-type(5)").TextContent; release.PublishDate = DateTime.ParseExact(dateString, "dd MMM yy", CultureInfo.InvariantCulture); // newbie users don't see DL links var qLink = row.QuerySelector("td:nth-of-type(3) a"); if (qLink != null) { release.DownloadUrl = qLink.GetAttribute("href"); } else { // use details link as placeholder // null causes errors during export to torznab // skipping the release prevents newbie users from adding the tracker (empty result) release.DownloadUrl = release.InfoUrl; } var sizeStr = row.QuerySelector("td:nth-of-type(6)").TextContent; release.Size = ParseUtil.GetBytes(sizeStr); var connections = row.QuerySelector("td:nth-of-type(8)").TextContent.Trim().Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); release.Seeders = ParseUtil.CoerceInt(connections[0].Trim()); release.Peers = ParseUtil.CoerceInt(connections[1].Trim()) + release.Seeders; release.Grabs = ParseUtil.CoerceInt(connections[2].Trim()); var rCat = row.QuerySelector("td:nth-of-type(1) a").GetAttribute("href"); var rCatIdx = rCat.IndexOf("cat="); if (rCatIdx > -1) { rCat = rCat.Substring(rCatIdx + 4); } release.Categories = _categories.MapTrackerCatToNewznab(rCat); if (row.QuerySelector("img[alt=\"Gold Torrent\"]") != null) { release.DownloadVolumeFactor = 0; } else if (row.QuerySelector("img[alt=\"Silver Torrent\"]") != null) { release.DownloadVolumeFactor = 0.5; } else { release.DownloadVolumeFactor = 1; } var uLFactorImg = row.QuerySelector("img[alt*=\"x Multiplier Torrent\"]"); if (uLFactorImg != null) { release.UploadVolumeFactor = ParseUtil.CoerceDouble(uLFactorImg.GetAttribute("alt").Split('x')[0]); } else { release.UploadVolumeFactor = 1; } qTitleLink.Remove(); //release.Description = row.QuerySelector("td:nth-of-type(2)").TextContent; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <TorrentInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var rows = dom.QuerySelectorAll("#torrents-table > tbody > tr"); foreach (var row in rows.Skip(1)) { var qDetails = row.QuerySelector(".br_right > a"); var details = _settings.BaseUrl + qDetails.GetAttribute("href"); var title = qDetails.QuerySelector("b").TextContent; // Remove auto-generated [REQ] tag from fulfilled requests if (title.StartsWith("[REQ] ")) { title = title.Substring(6); } var qLink = row.QuerySelector("td:nth-child(4) > a"); if (qLink == null) { continue; // support/donation banner } var link = _settings.BaseUrl + qLink.GetAttribute("href"); // dateString format "yyyy-MMM-dd hh:mm:ss" => eg "2015-04-25 23:38:12" var dateString = row.QuerySelector("td:nth-child(6) nobr").TextContent.Trim(); var publishDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(7)").InnerHtml.Split('<').First().Trim()); var files = ParseUtil.GetLongFromString(row.QuerySelector("td:nth-child(7) > a").TextContent); var grabs = ParseUtil.GetLongFromString(row.QuerySelector("td:nth-child(8)").TextContent); var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(9)").TextContent); var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(10)").TextContent); var category = row.QuerySelector(".br_type > a").GetAttribute("href").Replace("browse.php?cat=", string.Empty); var qImdb = row.QuerySelector("a[href*=\"www.imdb.com/\"]"); var imdb = qImdb != null?ParseUtil.GetImdbID(qImdb.GetAttribute("href").Split('/').Last()) : null; var release = new TorrentInfo { InfoUrl = details, Guid = details, Title = title, DownloadUrl = link, PublishDate = publishDate, Size = size, Seeders = seeders, Peers = seeders + leechers, Grabs = (int)grabs, Files = (int)files, Categories = _categories.MapTrackerCatToNewznab(category), ImdbId = imdb ?? 0, MinimumRatio = 1, MinimumSeedTime = 172800, // 48 hours UploadVolumeFactor = 1, DownloadVolumeFactor = 1 }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var rows = dom.QuerySelectorAll("#torrent_table > tbody > tr.torrent"); foreach (var row in rows) { var release = new TorrentInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; // 48 hours var catStr = row.Children[0].FirstElementChild.GetAttribute("href").Split(new[] { '[', ']' })[1]; release.Categories = _categories.MapTrackerCatToNewznab(catStr); var qDetails = row.Children[1].QuerySelector("a[title='View Torrent']"); release.InfoUrl = _settings.BaseUrl + qDetails.GetAttribute("href"); release.Guid = release.InfoUrl; var qDownload = row.Children[1].QuerySelector("a[title='Download']"); release.DownloadUrl = _settings.BaseUrl + qDownload.GetAttribute("href"); var dateStr = row.Children[3].TextContent.Trim().Replace(" and", ""); release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); var sizeStr = row.Children[4].TextContent; release.Size = ParseUtil.GetBytes(sizeStr); release.Files = ParseUtil.CoerceInt(row.Children[2].TextContent.Trim()); release.Seeders = ParseUtil.CoerceInt(row.Children[7].TextContent.Trim()); release.Peers = ParseUtil.CoerceInt(row.Children[8].TextContent.Trim()) + release.Seeders; var grabs = row.QuerySelector("td:nth-child(6)").TextContent; release.Grabs = ParseUtil.CoerceInt(grabs); if (row.QuerySelector("strong:contains(\"Freeleech!\")") != null) { release.DownloadVolumeFactor = 0; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; var title = row.QuerySelector("td:nth-child(2)"); foreach (var element in title.QuerySelectorAll("span, strong, div, br")) { element.Remove(); } release.Title = ParseUtil.NormalizeMultiSpaces(title.TextContent.Replace(" - ]", "]")); //change "Season #" to "S##" for TV shows if (catStr == "10") { release.Title = Regex.Replace(release.Title, @"Season (\d+)", m => string.Format("S{0:00}", int.Parse(m.Groups[1].Value))); } torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public void should_parse_size(string stringSize, long size) { ParseUtil.GetBytes(stringSize).Should().Be(size); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var document = parser.ParseDocument(indexerResponse.Content); var rows = document.QuerySelectorAll(".torrent_table > tbody > tr[class^='torrent row']"); foreach (var row in rows) { var title = row.QuerySelector("a[data-src]").GetAttribute("data-src"); if (string.IsNullOrEmpty(title) || title == "0") { title = row.QuerySelector("a[data-src]").TextContent; title = Regex.Replace(title, @"[\[\]\/]", ""); } else { if (title.Length > 5 && title.Substring(title.Length - 5).Contains(".")) { title = title.Remove(title.LastIndexOf(".", StringComparison.Ordinal)); } } var posterStr = row.QuerySelector("img")?.GetAttribute("src"); Uri.TryCreate(posterStr, UriKind.Absolute, out var poster); var details = _settings.BaseUrl + row.QuerySelector("a[data-src]").GetAttribute("href"); var link = _settings.BaseUrl + row.QuerySelector("a[href*='action=download']").GetAttribute("href"); var qColSize = row.QuerySelector("td:nth-child(3)"); var size = ParseUtil.GetBytes(qColSize.Children[0].TextContent); var files = ParseUtil.CoerceInt(qColSize.Children[1].TextContent.Split(':')[1].Trim()); var qPublishdate = row.QuerySelector("td:nth-child(4) span"); var publishDateStr = qPublishdate.GetAttribute("title"); var publishDate = !string.IsNullOrEmpty(publishDateStr) && publishDateStr.Contains(",") ? DateTime.ParseExact(publishDateStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture) : DateTime.ParseExact(qPublishdate.TextContent.Trim(), "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture); var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(5)").TextContent); var seeds = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent); var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent); var release = new TorrentInfo { Title = title, Guid = details, InfoUrl = details, PosterUrl = poster?.AbsoluteUri ?? null, DownloadUrl = link, Categories = new List <IndexerCategory> { TvCategoryFromQualityParser.ParseTvShowQuality(title) }, Size = size, Files = files, PublishDate = publishDate, Grabs = grabs, Seeders = seeds, Peers = seeds + leechers, MinimumRatio = 0, // ratioless MinimumSeedTime = 86400, // 24 hours DownloadVolumeFactor = 0, // ratioless tracker UploadVolumeFactor = 1 }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var resultParser = new HtmlParser(); var searchResultDocument = resultParser.ParseDocument(indexerResponse.Content); var rows = searchResultDocument.QuerySelectorAll("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 || !string.Equals(prev.NodeName, "style", StringComparison.OrdinalIgnoreCase)) { continue; } var release = new TorrentInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 86400; // 24 hours var qLink = row.Children[1].FirstElementChild; release.Title = qLink.TextContent.Trim(); release.InfoUrl = _settings.BaseUrl + qLink.GetAttribute("href"); release.Guid = release.InfoUrl; var imdbLink = row.Children[1].QuerySelector("a[href*=imdb]"); if (imdbLink != null) { release.ImdbId = ParseUtil.GetImdbID(imdbLink.GetAttribute("href").Split('/').Last()).GetValueOrDefault(); } var qDownload = row.Children[3].FirstElementChild; release.DownloadUrl = _settings.BaseUrl + qDownload.GetAttribute("href"); var dateStr = row.Children[4].TextContent.Trim(); //"July 11, 2015, 13:34:09", "Today|Yesterday at 20:04:23" release.PublishDate = DateTimeUtil.FromUnknown(dateStr); var sizeStr = row.Children[5].TextContent; release.Size = ParseUtil.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.Children[7].TextContent); release.Peers = ParseUtil.CoerceInt(row.Children[8].TextContent) + release.Seeders; var grabs = row.QuerySelector("td:nth-child(10)").TextContent; grabs = grabs.Replace("---", "0"); release.Grabs = ParseUtil.CoerceInt(grabs); if (row.QuerySelector("img[title=\"FreeLeech\"]") != null) { release.DownloadVolumeFactor = 0; } else if (row.QuerySelector("img[src=\"images/sf.png\"]") != null) { release.DownloadVolumeFactor = 0; } else if (row.QuerySelector("img[title=\"Half FreeLeech\"]") != null) { release.DownloadVolumeFactor = 0.5; } else { release.DownloadVolumeFactor = 1; } release.UploadVolumeFactor = 1; var qCat = row.QuerySelector("a[href^=\"index.php?page=torrents&category=\"]"); var cat = qCat.GetAttribute("href").Split('=')[2]; release.Categories = _categories.MapTrackerCatToNewznab(cat); torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <TorrentInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var rows = dom.QuerySelectorAll("#sortabletable tr:has(a[href*=\"details.php?id=\"])"); foreach (var row in rows) { var release = new TorrentInfo(); var qDetails = row.QuerySelector("div > a[href*=\"details.php?id=\"]"); // details link, release name get's shortened if it's to long // use Title from tooltip or fallback to Details link if there's no tooltip var qTitle = row.QuerySelector(".tooltip-content > div:nth-of-type(1)") ?? qDetails; release.Title = qTitle.TextContent; var qDesciption = row.QuerySelectorAll(".tooltip-content > div"); if (qDesciption.Any()) { release.Description = qDesciption[1].TextContent.Trim(); } var qLink = row.QuerySelector("a[href*=\"download.php\"]"); release.DownloadUrl = qLink.GetAttribute("href"); release.Guid = release.DownloadUrl; release.InfoUrl = qDetails.GetAttribute("href"); // 2021-03-17 03:39 AM var dateString = row.QuerySelectorAll("td:nth-of-type(2) div").Last().LastChild.TextContent.Trim(); release.PublishDate = DateTime.ParseExact(dateString, "yyyy-MM-dd hh:mm tt", CultureInfo.InvariantCulture); var sizeStr = row.QuerySelector("td:nth-of-type(5)").TextContent.Trim(); release.Size = ParseUtil.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(7)").TextContent.Trim()); release.Peers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(8)").TextContent.Trim()) + release.Seeders; var catLink = row.QuerySelector("td:nth-of-type(1) a").GetAttribute("href"); var catSplit = catLink.IndexOf("category="); if (catSplit > -1) { catLink = catLink.Substring(catSplit + 9); } release.Categories = _categories.MapTrackerCatToNewznab(catLink); var grabs = row.QuerySelector("td:nth-child(6)").TextContent; release.Grabs = ParseUtil.CoerceInt(grabs); if (row.QuerySelector("img[title^=\"Free Torrent\"]") != null) { release.DownloadVolumeFactor = 0; } else if (row.QuerySelector("img[title^=\"Silver Torrent\"]") != null) { release.DownloadVolumeFactor = 0.5; } else { release.DownloadVolumeFactor = 1; } if (row.QuerySelector("img[title^=\"x2 Torrent\"]") != null) { release.UploadVolumeFactor = 2; } else { release.UploadVolumeFactor = 1; } torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { // Throw auth errors here before we try to parse if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.Forbidden) { throw new IndexerAuthException("[403 Forbidden] - mam_session_id expired or invalid"); } // Throw common http errors here before we try to parse if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { // Remove cookie cache CookiesUpdater(null, null); throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); } if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) { // Remove cookie cache CookiesUpdater(null, null); throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); } var torrentInfos = new List <TorrentInfo>(); var jsonResponse = JsonConvert.DeserializeObject <MyAnonamouseResponse>(indexerResponse.Content); var error = jsonResponse.Error; if (error != null && error == "Nothing returned, out of 0") { return(torrentInfos.ToArray()); } foreach (var item in jsonResponse.Data) { //TODO shift to ReleaseInfo object initializer for consistency var release = new TorrentInfo(); var id = item.Id; release.Title = item.Title; // release.Description = item.Value<string>("description"); var author = string.Empty; if (item.AuthorInfo != null) { var authorInfo = JsonConvert.DeserializeObject <Dictionary <string, string> >(item.AuthorInfo); author = authorInfo?.First().Value; } if (author != null) { release.Title += " by " + author; } var flags = new List <string>(); var langCode = item.LangCode; if (!string.IsNullOrEmpty(langCode)) { flags.Add(langCode); } var filetype = item.Filetype; if (!string.IsNullOrEmpty(filetype)) { flags.Add(filetype); } if (flags.Count > 0) { release.Title += " [" + string.Join(" / ", flags) + "]"; } if (item.Vip) { release.Title += " [VIP]"; } var category = item.Category; release.Categories = _categories.MapTrackerCatToNewznab(category); release.DownloadUrl = _settings.BaseUrl + "/tor/download.php?tid=" + id; release.InfoUrl = _settings.BaseUrl + "/t/" + id; release.Guid = release.InfoUrl; var dateStr = item.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.Grabs; release.Files = item.NumFiles; release.Seeders = item.Seeders; release.Peers = item.Leechers + release.Seeders; var size = item.Size; release.Size = ParseUtil.GetBytes(size); release.DownloadVolumeFactor = item.Free ? 0 : 1; release.UploadVolumeFactor = 1; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <TorrentInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var userInfo = dom.QuerySelector("table.navus tr"); var userRank = userInfo.Children[1].TextContent.Replace("Rank:", string.Empty).Trim(); var hasFreeleech = _freeleechRanks.Contains(userRank); var rows = dom.QuerySelectorAll("table.mainblockcontenttt tr:has(td.mainblockcontent)"); foreach (var row in rows.Skip(1)) { var mainLink = row.Children[2].QuerySelector("a"); var title = mainLink.TextContent; var details = new Uri(_settings.BaseUrl + mainLink.GetAttribute("href")); var posterMatch = _posterRegex.Match(mainLink.GetAttribute("onmouseover")); var poster = posterMatch.Success ? _settings.BaseUrl + posterMatch.Groups[1].Value.Replace("\\", "/") : null; var link = new Uri(_settings.BaseUrl + row.Children[4].FirstElementChild.GetAttribute("href")); var description = row.Children[2].QuerySelector("span").TextContent; var size = ParseUtil.GetBytes(row.Children[7].TextContent); var dateTag = row.Children[6].FirstElementChild; var dateString = string.Join(" ", dateTag.Attributes.Select(attr => attr.Name)); var publishDate = DateTime.ParseExact(dateString, "dd MMM yyyy HH:mm:ss zz00", CultureInfo.InvariantCulture).ToLocalTime(); var catStr = row.FirstElementChild.FirstElementChild.GetAttribute("href").Split('=')[1]; var cat = _categories.MapTrackerCatToNewznab(catStr); // Sometimes the uploader column is missing, so seeders, leechers, and grabs may be at a different index. // There's room for improvement, but this works for now. var endIndex = row.Children.Length; if (row.Children[endIndex - 1].TextContent == "Edit") { //Maybe use row.Children.Index(Node) after searching for an element instead? endIndex -= 1; } else if (row.Children[endIndex - 4].TextContent == "Edit") { // moderators get additional delete, recommend and like links endIndex -= 4; } int?seeders = null; int?peers = null; if (ParseUtil.TryCoerceInt(row.Children[endIndex - 3].TextContent, out var rSeeders)) { seeders = rSeeders; if (ParseUtil.TryCoerceInt(row.Children[endIndex - 2].TextContent, out var rLeechers)) { peers = rLeechers + rSeeders; } } var grabs = ParseUtil.TryCoerceInt(row.Children[endIndex - 1].TextContent, out var rGrabs) ? (int?)rGrabs : null; var dlVolumeFactor = 1.0; var upVolumeFactor = 1.0; if (row.QuerySelector("img[src$=\"no_ratio.png\"]") != null) { dlVolumeFactor = 0; upVolumeFactor = 0; } else if (hasFreeleech || row.QuerySelector("img[src$=\"free.png\"]") != null) { dlVolumeFactor = 0; } else if (row.QuerySelector("img[src$=\"50.png\"]") != null) { dlVolumeFactor = 0.5; } else if (row.QuerySelector("img[src$=\"25.png\"]") != null) { dlVolumeFactor = 0.75; } else if (row.QuerySelector("img[src$=\"75.png\"]") != null) { dlVolumeFactor = 0.25; } var imdbLink = row.QuerySelector("a[href*=\"www.imdb.com/title/\"]")?.GetAttribute("href"); var imdb = !string.IsNullOrWhiteSpace(imdbLink) ? ParseUtil.GetImdbID(imdbLink) : null; var release = new TorrentInfo { Title = title, Guid = details.AbsoluteUri, DownloadUrl = link.AbsoluteUri, InfoUrl = details.AbsoluteUri, PosterUrl = poster, PublishDate = publishDate, Categories = cat, ImdbId = imdb ?? 0, Size = size, Grabs = grabs, Seeders = seeders, Peers = peers, DownloadVolumeFactor = dlVolumeFactor, UploadVolumeFactor = upVolumeFactor, MinimumRatio = 1, MinimumSeedTime = 172800 // 48 hours }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var doc = parser.ParseDocument(indexerResponse.Content); // get params to build download link (user could be banned without those params) var rssFeedUri = new Uri(_settings.BaseUrl + doc.QuerySelector("link[href^=\"/feeds.php?feed=\"]") .GetAttribute("href")); var rssFeedQuery = HttpUtility.ParseQueryString(rssFeedUri.Query); var downloadLinkExtraParams = "&authkey=" + rssFeedQuery["authkey"] + "&torrent_pass="******"passkey"]; var rows = doc.QuerySelectorAll("table.torrent_table > tbody > tr.torrent"); foreach (var row in rows) { var qDetailsLink = row.QuerySelector("a[href^=\"torrents.php?id=\"]"); var title = qDetailsLink.TextContent; var description = qDetailsLink.NextSibling.TextContent.Trim(); title += " " + description; var details = _settings.BaseUrl + qDetailsLink.GetAttribute("href"); var torrentId = qDetailsLink.GetAttribute("href").Split('=').Last(); var link = _settings.BaseUrl + "torrents.php?action=download&id=" + torrentId + downloadLinkExtraParams; var files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(3)").TextContent); var publishDate = DateTimeUtil.FromTimeAgo(row.QuerySelector("td:nth-child(4)").TextContent); var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(5)").FirstChild.TextContent); var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent); var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent); var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent); var dlVolumeFactor = row.QuerySelector("strong.freeleech_normal") != null ? 0 : 1; var category = new List <IndexerCategory> { TvCategoryFromQualityParser.ParseTvShowQuality(description) }; var release = new TorrentInfo { MinimumRatio = 1, MinimumSeedTime = 0, Description = description, Title = title, PublishDate = publishDate, Categories = category, DownloadUrl = link, InfoUrl = details, Guid = link, Seeders = seeders, Peers = leechers + seeders, Size = size, Grabs = grabs, Files = files, DownloadVolumeFactor = dlVolumeFactor, UploadVolumeFactor = 1 }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var table = dom.QuerySelector("table.movehere"); if (table == null) { return(torrentInfos); // no results } var headerColumns = table.QuerySelectorAll("tbody > tr > td.cat_Head") .Select(x => x.TextContent).ToList(); var categoryIndex = headerColumns.FindIndex(x => x.Equals("Type")); var nameIndex = headerColumns.FindIndex(x => x.Equals("Name")); var sizeIndex = headerColumns.FindIndex(x => x.Equals("Size")); var seedersIndex = headerColumns.FindIndex(x => x.Equals("Seeders")); var leechersIndex = headerColumns.FindIndex(x => x.Equals("Leechers")); var rows = dom.QuerySelectorAll("tr.browse"); foreach (var row in rows) { // TODO convert to initializer var qDescCol = row.Children[nameIndex]; var qLink = qDescCol.QuerySelector("a"); var details = _settings.BaseUrl + "/" + qLink.GetAttribute("href"); var torrentId = qLink.GetAttribute("href").Split('=')[1]; var sizeStr = row.Children[sizeIndex].TextContent; var seeders = ParseUtil.CoerceInt(row.Children[seedersIndex].TextContent.Trim()); var catId = "82"; // default var qCatLink = row.Children[categoryIndex].QuerySelector("a"); if (qCatLink != null) { catId = new Regex(@"\?cat=(\d*)").Match(qCatLink.GetAttribute("href")).Groups[1].ToString().Trim(); } var release = new TorrentInfo { Title = qLink.TextContent, InfoUrl = details, Categories = _categories.MapTrackerCatToNewznab(catId), DownloadUrl = string.Format("{0}/download.php/{1}/download.torrent", _settings.BaseUrl, torrentId), Guid = details, PublishDate = DateTimeUtil.FromTimeAgo(qDescCol.ChildNodes.Last().TextContent), Size = ParseUtil.GetBytes(sizeStr), Seeders = seeders, Peers = ParseUtil.CoerceInt(row.Children[leechersIndex].TextContent.Trim()) + seeders, DownloadVolumeFactor = row.QuerySelector("font > b:contains(Freeleech)") != null ? 0 : 1, UploadVolumeFactor = 1, MinimumRatio = 1, MinimumSeedTime = 259200 // 72 hours }; release.Categories = _categories.MapTrackerCatToNewznab(catId); //TODO Do something with this filtering //if (!query.MatchQueryStringAND(release.Title)) // continue; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var dom = parser.ParseDocument(indexerResponse.Content); var firstPageRows = dom.QuerySelectorAll("#torrentTable > tbody > tr").Skip(1).ToCollection(); // If pagination available int nbResults; // Check if we have a minimum of one result if (firstPageRows?.Length >= 1) { // Retrieve total count on our alone page nbResults = firstPageRows.Count(); } else { // No result found for this query return(torrentInfos); } var torrentDetailsUrl = _settings.BaseUrl + "details.php?id={id}"; var torrentDownloadUrl = _settings.BaseUrl + "download.php?id={id}&passkey={passkey}"; // Loop on results foreach (var row in firstPageRows) { var id = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("href").Split('=').Last(); // ID var name = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("title"); // Release Name var categoryName = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("title"); // Category var mainCat = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("href").Split('?').Last(); var qSubCat2 = row.QuerySelector("td:nth-of-type(1) > div > a[href^=\"/browse.php?sub2_cat[]=\"]"); var cat = mainCat; if (qSubCat2 != null) { cat += '&' + qSubCat2.GetAttribute("href").Split('?').Last(); } var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent); // Seeders var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent); // Leechers var regexObj = new Regex(@"[^\d]"); // Completed var completed2 = row.QuerySelector("td:nth-of-type(8)").TextContent; var completed = ParseUtil.CoerceInt(regexObj.Replace(completed2, "")); var qFiles = row.QuerySelector("td:nth-of-type(3) > a"); // Files var files = qFiles != null?ParseUtil.CoerceInt(Regex.Match(qFiles.TextContent, @"\d+").Value) : 1; var humanSize = row.QuerySelector("td:nth-of-type(7)").TextContent.ToLowerInvariant(); // Size var size = ParseUtil.GetBytes(humanSize); // Date var dateTimeOrig = row.QuerySelector("td:nth-of-type(5)").TextContent; var dateTime = Regex.Replace(dateTimeOrig, @"<[^>]+>| ", "").Trim(); var date = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); var details = new Uri(torrentDetailsUrl.Replace("{id}", id.ToString())); // Description Link var passkey = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(2)").GetAttribute("href"); // Download Link var key = Regex.Match(passkey, "(?<=passkey\\=)([a-zA-z0-9]*)"); var downloadLink = new Uri(torrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{passkey}", key.ToString())); // Building release infos var release = new TorrentInfo { Categories = _categories.MapTrackerCatToNewznab(cat), Title = name, Seeders = seeders, Peers = seeders + leechers, PublishDate = date, Size = size, Files = files, Grabs = completed, Guid = details.AbsoluteUri, InfoUrl = details.AbsoluteUri, DownloadUrl = downloadLink.AbsoluteUri, MinimumRatio = 1, MinimumSeedTime = 172800 // 48 hours }; var genres = row.QuerySelector("span.genres")?.TextContent; if (!string.IsNullOrEmpty(genres)) { release.Description = genres; } // IMDB var imdbLink = row.QuerySelector("a[href*=\"imdb.com/title/tt\"]")?.GetAttribute("href"); release.ImdbId = ParseUtil.GetImdbID(imdbLink) ?? 0; if (row.QuerySelector("img[title=\"100% freeleech\"]") != 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; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }
public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List <ReleaseInfo>(); var parser = new HtmlParser(); var doc = parser.ParseDocument(indexerResponse.Content); var rows = doc.QuerySelectorAll("table.torrent_list > tbody > tr"); foreach (var row in rows.Skip(1)) { var qTitleLink = row.QuerySelector("a[href*=\"?page=torrent-details\"]"); // no results if (qTitleLink == null) { continue; } var title = qTitleLink.TextContent.Trim(); title += " SPANiSH"; // fix for Radarr title = Regex.Replace(title, "4k", "2160p", RegexOptions.IgnoreCase); var detailsStr = qTitleLink.GetAttribute("href"); var details = new Uri(detailsStr); var link = new Uri(detailsStr.Replace("/index.php?page=torrent-details&", "/download.php?")); var qPoster = qTitleLink.GetAttribute("title"); var poster = qPoster != null ? new Uri(qPoster) : null; var publishDateStr = row.Children[4].InnerHtml.Split('>').Last(); var publishDate = DateTime.ParseExact(publishDateStr, "dd/MM/yyyy", CultureInfo.InvariantCulture); var size = ParseUtil.GetBytes(row.Children[5].TextContent.Replace(".", "").Replace(",", ".")); var seeders = ParseUtil.CoerceInt(row.Children[6].TextContent); var leechers = ParseUtil.CoerceInt(row.Children[7].TextContent); var grabs = ParseUtil.CoerceInt(row.Children[8].TextContent); var cat1 = row.Children[0].FirstElementChild.GetAttribute("href").Split('=').Last(); var cat2 = row.Children[1].FirstElementChild.GetAttribute("href").Split('=').Last(); var cat = _categories.MapTrackerCatToNewznab($"cat[]={cat1}&subcat[]={cat2}"); var dlVolumeFactor = row.QuerySelector("img[src*=\"/gold.png\"]") != null ? 0 : row.QuerySelector("img[src*=\"/silver.png\"]") != null ? 0.5 : 1; var ulVolumeFactor = row.QuerySelector("img[src*=\"/por3.gif\"]") != null ? 3 : row.QuerySelector("img[src*=\"/por2.gif\"]") != null ? 2 : 1; var release = new TorrentInfo { Title = title, InfoUrl = details.AbsoluteUri, Guid = details.AbsoluteUri, DownloadUrl = link.AbsoluteUri, PosterUrl = poster.AbsoluteUri, PublishDate = publishDate, Categories = cat, Size = size, Grabs = grabs, Seeders = seeders, Peers = seeders + leechers, DownloadVolumeFactor = dlVolumeFactor, UploadVolumeFactor = ulVolumeFactor, MinimumRatio = 1, MinimumSeedTime = 259200 // 72 hours }; torrentInfos.Add(release); } return(torrentInfos.ToArray()); }