Beispiel #1
0
        /// <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;
                    var pageLinkCount = 1;

                    // 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
                        Output("\nNo result found for your query, please try another search term ...\n", "info");
                        break;
                    }

                    Output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !");
                    Output("\nThere are " + firstPageRows.Length + " results on the first page !");

                    // Loop on results

                    foreach (var row in firstPageRows)
                    {
                        Output("Torrent #" + (releases.Count + 1));

                        // ID
                        var id = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("href").Split('=').Last();
                        Output("ID: " + id);

                        // Release Name
                        var name = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("title");

                        // Category
                        var categoryName = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("title");
                        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();
                        }

                        Output("Category: " + cat + " - " + categoryName);

                        // Seeders
                        var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent);
                        Output("Seeders: " + seeders);

                        // Leechers
                        var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent);
                        Output("Leechers: " + leechers);

                        // Completed
                        var regexObj   = new Regex(@"[^\d]");
                        var completed2 = row.QuerySelector("td:nth-of-type(8)").TextContent;
                        var completed  = ParseUtil.CoerceLong(regexObj.Replace(completed2, ""));
                        Output("Completed: " + completed);

                        // Files
                        var qFiles = row.QuerySelector("td:nth-of-type(3) > a");
                        var files  = qFiles != null?ParseUtil.CoerceInt(Regex.Match(qFiles.TextContent, @"\d+").Value) : 1;

                        Output("Files: " + files);

                        // Size
                        var humanSize = row.QuerySelector("td:nth-of-type(7)").TextContent.ToLowerInvariant();
                        var size      = ReleaseInfo.GetBytes(humanSize);
                        Output("Size: " + humanSize + " (" + size + " bytes)");

                        // --> Date
                        var dateTimeOrig = row.QuerySelector("td:nth-of-type(5)").TextContent;
                        var dateTime     = Regex.Replace(dateTimeOrig, @"<[^>]+>|&nbsp;", "").Trim();
                        var date         = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime();
                        Output("Released on: " + date);

                        // Torrent Details URL
                        var details = new Uri(TorrentDetailsUrl.Replace("{id}", id.ToString()));
                        Output("Details: " + details.AbsoluteUri);

                        // Torrent Download URL
                        var passkey      = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(2)").GetAttribute("href");
                        var key          = Regex.Match(passkey, "(?<=passkey\\=)([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        = MapTrackerCatToNewznab(cat),
                            Title           = name,
                            Seeders         = seeders,
                            Peers           = seeders + leechers,
                            PublishDate     = date,
                            Size            = size,
                            Files           = files,
                            Grabs           = completed,
                            Guid            = details,
                            Details         = details,
                            Link            = downloadLink,
                            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.Imdb = ParseUtil.GetLongFromString(imdbLink);

                        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;

                        releases.Add(release);
                    }
                }
                catch (Exception ex)
                {
                    OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex);
                }
            }
            // Return found releases
            return(releases);
        }
Beispiel #2
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases        = new List <ReleaseInfo>();
            var searchString    = query.GetQueryString();
            var queryCollection = new NameValueCollection();

            if (!string.IsNullOrWhiteSpace(searchString))
            {
                queryCollection.Add("search", searchString);
            }

            queryCollection.Add("incldead", "1");

            var searchUrl = SearchUrl + queryCollection.GetQueryString();

            var trackerCats = MapTorznabCapsToTrackers(query, mapChildrenCatsToParent: true);

            var results = await RequestStringWithCookiesAndRetry(searchUrl);

            try
            {
                CQ dom = results.Content;
                dom["#needseed"].Remove();
                foreach (var table in dom["table[align=center] + br + table > tbody"])
                {
                    var rows = table.Cq().Children();
                    foreach (var row in rows.Skip(1))
                    {
                        var release = new ReleaseInfo();

                        var qRow  = row.Cq();
                        var qLink = qRow.Children().ElementAt(2).Cq().Children("a").First();

                        release.MinimumRatio    = 1;
                        release.MinimumSeedTime = 172800;
                        release.Title           = qLink.Attr("title");
                        if (!query.MatchQueryStringAND(release.Title))
                        {
                            continue;
                        }
                        release.Files    = ParseUtil.CoerceLong(qRow.Find("td:nth-child(4)").Text());
                        release.Grabs    = ParseUtil.CoerceLong(qRow.Find("td:nth-child(8)").Text());
                        release.Guid     = new Uri(qLink.Attr("href"));
                        release.Comments = release.Guid;
                        release.Link     = new Uri(string.Format(DownloadUrl, qLink.Attr("href").Split('=')[1]));

                        var catUrl = qRow.Children().ElementAt(1).FirstElementChild.Cq().Attr("href");
                        var catNum = catUrl.Split(new char[] { '=', '&' })[1];
                        release.Category = MapTrackerCatToNewznab(catNum);

                        // This tracker cannot search multiple cats at a time, so search all cats then filter out results from different cats
                        if (trackerCats.Count > 0 && !trackerCats.Contains(catNum))
                        {
                            continue;
                        }

                        var dateString = qRow.Children().ElementAt(5).Cq().Text().Trim();
                        var pubDate    = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture);
                        release.PublishDate = DateTime.SpecifyKind(pubDate, DateTimeKind.Local);

                        var sizeStr = qRow.Children().ElementAt(6).Cq().Text();
                        release.Size = ReleaseInfo.GetBytes(sizeStr);

                        release.Seeders = ParseUtil.CoerceInt(qRow.Children().ElementAt(8).Cq().Text().Trim());
                        release.Peers   = ParseUtil.CoerceInt(qRow.Children().ElementAt(9).Cq().Text().Trim()) + release.Seeders;

                        var bgcolor = qRow.Attr("bgcolor");
                        if (bgcolor == "#DDDDDD")
                        {
                            release.DownloadVolumeFactor = 1;
                            release.UploadVolumeFactor   = 2;
                        }
                        else if (bgcolor == "#FFFF99")
                        {
                            release.DownloadVolumeFactor = 0;
                            release.UploadVolumeFactor   = 1;
                        }
                        else if (bgcolor == "#CCFF99")
                        {
                            release.DownloadVolumeFactor = 0;
                            release.UploadVolumeFactor   = 2;
                        }
                        else
                        {
                            release.DownloadVolumeFactor = 1;
                            release.UploadVolumeFactor   = 1;
                        }
                        releases.Add(release);
                    }
                }
            }
            catch (Exception ex)
            {
                OnParseError(results.Content, ex);
            }

            return(releases);
        }
Beispiel #3
0
        public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();

            NameValueCollection qParams = new NameValueCollection();

            qParams.Add("tor[text]", query.GetQueryString());
            qParams.Add("tor[srchIn][title]", "true");
            qParams.Add("tor[srchIn][author]", "true");
            qParams.Add("tor[searchType]", "all");
            qParams.Add("tor[searchIn]", "torrents");
            qParams.Add("tor[hash]", "");
            qParams.Add("tor[sortType]", "default");
            qParams.Add("tor[startNumber]", "0");

            List <string> catList = MapTorznabCapsToTrackers(query);

            if (catList.Any())
            {
                foreach (string cat in catList)
                {
                    qParams.Add("tor[cat][]", cat);
                }
            }
            else
            {
                qParams.Add("tor[cat][]", "0");
            }

            string urlSearch = SearchUrl;

            if (qParams.Count > 0)
            {
                urlSearch += $"?{qParams.GetQueryString()}";
            }

            var response = await RequestStringWithCookiesAndRetry(urlSearch);

            try
            {
                CQ  dom  = response.Content;
                var rows = dom["table[class='newTorTable'] > tbody > tr[id^=\"tdr\"]"];

                foreach (IDomObject row in rows)
                {
                    CQ torrentData = row.OuterHTML;
                    CQ cells       = row.Cq().Find("td");

                    string tid       = torrentData.Attr("id").Substring(4);
                    var    qTitle    = torrentData.Find("a[class='title']").First();
                    string title     = qTitle.Text().Trim();
                    var    details   = new Uri(SiteLink + qTitle.Attr("href"));
                    string author    = torrentData.Find("a[class='author']").First().Text().Trim();
                    Uri    link      = new Uri(SiteLink + "tor/download.php?tid=" + tid); // DL Link is no long available directly, build it ourself
                    long   files     = ParseUtil.CoerceLong(cells.Elements.ElementAt(4).Cq().Find("a").Text());
                    long   size      = ReleaseInfo.GetBytes(cells.Elements.ElementAt(4).Cq().Text().Split('[')[1].TrimEnd(']'));
                    int    seeders   = ParseUtil.CoerceInt(cells.Elements.ElementAt(6).Cq().Find("p").ElementAt(0).Cq().Text());
                    int    leechers  = ParseUtil.CoerceInt(cells.Elements.ElementAt(6).Cq().Find("p").ElementAt(1).Cq().Text());
                    long   grabs     = ParseUtil.CoerceLong(cells.Elements.ElementAt(6).Cq().Find("p").ElementAt(2).Cq().Text());
                    bool   freeleech = torrentData.Find("img[alt=\"freeleech\"]").Any();

                    string   pubDateStr  = cells.Elements.ElementAt(5).Cq().Text().Split('[')[0];
                    DateTime publishDate = DateTime.Parse(pubDateStr).ToLocalTime();

                    long   category = 0;
                    string cat      = torrentData.Find("a[class='newCatLink']").First().Attr("href").Remove(0, "/tor/browse.php?tor[cat][]]=".Length);
                    long.TryParse(cat, out category);


                    var release = new ReleaseInfo();

                    release.Title           = String.IsNullOrEmpty(author) ? title : String.Format("{0} by {1}", title, author);
                    release.Guid            = link;
                    release.Link            = link;
                    release.PublishDate     = publishDate;
                    release.Files           = files;
                    release.Size            = size;
                    release.Description     = release.Title;
                    release.Seeders         = seeders;
                    release.Peers           = seeders + leechers;
                    release.Grabs           = grabs;
                    release.MinimumRatio    = 1;
                    release.MinimumSeedTime = 172800;
                    release.Category        = MapTrackerCatToNewznab(category.ToString());
                    release.Comments        = details;

                    if (freeleech)
                    {
                        release.DownloadVolumeFactor = 0;
                    }
                    else
                    {
                        release.DownloadVolumeFactor = 1;
                    }

                    release.UploadVolumeFactor = 1;

                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(response.Content, ex);
            }

            return(releases);
        }
Beispiel #4
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases     = new List <ReleaseInfo>();
            var searchString = query.GetQueryString();

            WebClientStringResult results = null;
            var queryCollection           = new NameValueCollection();

            queryCollection.Add("st", "0");
            queryCollection.Add("sd", "d");
            queryCollection.Add("sk", "t");
            queryCollection.Add("tracker_search", "torrent");
            queryCollection.Add("t", "0");
            queryCollection.Add("submit", "Search");
            queryCollection.Add("sr", "topics");
            //queryCollection.Add("sr", "posts");
            //queryCollection.Add("ch", "99999");

            // if the search string is empty use the getnew view
            if (string.IsNullOrWhiteSpace(searchString))
            {
                queryCollection.Add("search_id", "active_topics");
                queryCollection.Add("ot", "1");
            }
            else // use the normal search
            {
                searchString = searchString.Replace("-", " ");
                queryCollection.Add("keywords", searchString);
                queryCollection.Add("sf", "titleonly");
                queryCollection.Add("sr", "topics");
                queryCollection.Add("pt", "t");
                queryCollection.Add("ot", "1");
            }

            var searchUrl = SearchUrl + "?" + queryCollection.GetQueryString();

            results = await RequestStringWithCookies(searchUrl);

            if (!results.Content.Contains("ucp.php?mode=logout"))
            {
                await ApplyConfiguration(null);

                results = await RequestStringWithCookies(searchUrl);
            }
            try
            {
                string RowsSelector = "ul.topics > li.row";

                var ResultParser         = new HtmlParser();
                var SearchResultDocument = ResultParser.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.topictitle");

                        release.Title    = qDetailsLink.TextContent;
                        release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href"));
                        release.Guid     = release.Comments;

                        var detailsResult = await RequestStringWithCookies(SiteLink + qDetailsLink.GetAttribute("href"));

                        var DetailsResultDocument = ResultParser.Parse(detailsResult.Content);
                        var qDownloadLink         = DetailsResultDocument.QuerySelector("table.table2 > tbody > tr > td > a[href^=\"/download/torrent.php?id\"]");

                        release.Link = new Uri(SiteLink + qDownloadLink.GetAttribute("href").TrimStart('/'));

                        release.Seeders = ParseUtil.CoerceInt(Row.QuerySelector("span.seed").TextContent);
                        release.Peers   = ParseUtil.CoerceInt(Row.QuerySelector("span.leech").TextContent) + release.Seeders;
                        release.Grabs   = ParseUtil.CoerceLong(Row.QuerySelector("span.complet").TextContent);

                        var author  = Row.QuerySelector("dd.lastpost > span");
                        var timestr = author.TextContent.Split('\n')[4].Trim();

                        release.PublishDate = DateTimeUtil.FromUnknown(timestr, "UK");

                        var forum   = Row.QuerySelector("a[href^=\"./viewforum.php?f=\"]");
                        var forumid = forum.GetAttribute("href").Split('=')[1];

                        release.Category = MapTrackerCatToNewznab(forumid);

                        var size = Row.QuerySelector("dl.row-item > dt > div.list-inner > div[style^=\"float:right\"]").TextContent;
                        size = size.Replace("GiB", "GB");
                        size = size.Replace("MiB", "MB");
                        size = size.Replace("KiB", "KB");

                        size = size.Replace("ГБ", "GB");
                        size = size.Replace("МБ", "MB");
                        size = size.Replace("КБ", "KB");

                        release.Size = ReleaseInfo.GetBytes(size);

                        release.DownloadVolumeFactor = 1;
                        release.UploadVolumeFactor   = 1;

                        releases.Add(release);
                    }
                    catch (Exception ex)
                    {
                        logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex));
                    }
                }
            }
            catch (Exception ex)
            {
                OnParseError(results.Content, ex);
            }

            return(releases);
        }
Beispiel #5
0
        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 PostDataWithCookies(BrowseUrl, pairs);

            if (results.IsRedirect)
            {
                // re-login
                await ApplyConfiguration(null);

                results = await PostDataWithCookies(BrowseUrl, pairs);
            }

            try
            {
                var lastDate = DateTime.Now;

                var parser = new HtmlParser();
                var doc    = parser.ParseDocument(results.Content);
                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      = 0,
                        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");
                    }

                    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.Content, ex);
            }

            return(releases);
        }
Beispiel #6
0
        private async Task <List <ReleaseInfo> > ParseUserSearchAsync(TorznabQuery query)
        {
            var releases        = new List <ReleaseInfo>();
            var searchUrl       = BrowseUrl;
            var isSearchAnime   = query.Categories.Any(s => s == TorznabCatType.TVAnime.ID);
            var searchTerm      = FixSearchTerm(query);
            var queryCollection = new NameValueCollection
            {
                { "searchstr", StripSearchString(searchTerm, 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 RequestWithCookiesAsync(searchUrl);

            if (IsSessionIsClosed(results))
            {
                // re-login
                await ApplyConfiguration(null);

                results = await RequestWithCookiesAsync(searchUrl);
            }

            try
            {
                const string      rowsSelector         = "table.torrent_table > tbody > tr:not(tr.colhead)";
                var               searchResultParser   = new HtmlParser();
                var               searchResultDocument = searchResultParser.ParseDocument(results.ContentString);
                var               rows          = searchResultDocument.QuerySelectorAll(rowsSelector);
                ICollection <int> groupCategory = null;
                string            groupTitle    = null;
                string            groupYearStr  = null;
                var               categoryStr   = "";
                foreach (var row in rows)
                {
                    try
                    {
                        // ignore sub groups info row, it's just an row with an info about the next section, something like "Dual Áudio" or "Legendado"
                        if (row.QuerySelector(".edition_info") != null)
                        {
                            continue;
                        }

                        // some torrents has more than one link, and the one with .tooltip is the wrong one in that case,
                        // so let's try to pick up first without the .tooltip class,
                        // if nothing is found, then we try again without that filter
                        var qDetailsLink = row.QuerySelector("a[href^=\"torrents.php?id=\"]:not(.tooltip)");
                        if (qDetailsLink == null)
                        {
                            qDetailsLink = row.QuerySelector("a[href^=\"torrents.php?id=\"]");
                            // if still can't find the right link, skip it
                            if (qDetailsLink == null)
                            {
                                logger.Error($"{Id}: Error while parsing row '{row.OuterHtml}': Can't find the right details link");
                                continue;
                            }
                        }
                        var title = StripSearchString(qDetailsLink.TextContent, false);

                        var    seasonEl = row.QuerySelector("a[href^=\"torrents.php?torrentid=\"]");
                        string seasonEp = null;
                        if (seasonEl != null)
                        {
                            var seasonMatch = _EpisodeRegex.Match(seasonEl.TextContent);
                            seasonEp = seasonMatch.Success ? seasonMatch.Value : null;
                        }
                        seasonEp ??= _EpisodeRegex.Match(qDetailsLink.TextContent).Value;

                        ICollection <int> category = null;
                        string            yearStr  = null;
                        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);

                            var torrentInfoEl = row.QuerySelector("div.torrent_info");
                            if (torrentInfoEl != null)
                            {
                                // valid for torrent grouped but that has only 1 episode yet
                                yearStr = torrentInfoEl.GetAttribute("data-year");
                            }
                            yearStr ??= qDetailsLink.NextSibling.TextContent.Trim().TrimStart('[').TrimEnd(']');

                            if (row.ClassList.Contains("group")) // group headers
                            {
                                groupCategory = category;
                                groupTitle    = title;
                                groupYearStr  = yearStr;
                                continue;
                            }
                        }

                        var release = new ReleaseInfo
                        {
                            MinimumRatio    = 1,
                            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 = Regex.Match(qDetailsLink.TextContent, @"\[.*?\]").Value;
                            release.Title       = ParseTitle(groupTitle, seasonEp, groupYearStr, categoryStr);
                            release.Category    = groupCategory;
                        }
                        else if (row.ClassList.Contains("torrent")) // standalone/un grouped torrents
                        {
                            release.Description = row.QuerySelector("div.torrent_info").TextContent;
                            release.Title       = ParseTitle(title, seasonEp, yearStr, categoryStr);
                            release.Category    = category;
                        }

                        release.Description = release.Description.Replace(" / Free", "");         // Remove Free Tag
                        release.Description = release.Description.Replace("/ WEB ", "/ WEB-DL "); // Fix web/web-dl
                        release.Description = release.Description.Replace("Full HD", "1080p");
                        // Handles HDR conflict
                        release.Description = release.Description.Replace("/ HD /", "/ 720p /");
                        release.Description = release.Description.Replace("/ HD]", "/ 720p]");
                        release.Description = release.Description.Replace("4K", "2160p");
                        release.Description = release.Description.Replace("SD", "480p");
                        release.Description = release.Description.Replace("Dual Áudio", "Dual");

                        // Adjust the description in order to can be read by Radarr and Sonarr
                        var      cleanDescription = release.Description.Trim().TrimStart('[').TrimEnd(']');
                        string[] titleElements;

                        //Formats the title so it can be parsed later
                        var stringSeparators = new[]
                        {
                            " / "
                        };
                        titleElements = cleanDescription.Split(stringSeparators, StringSplitOptions.None);
                        // release.Title += string.Join(" ", titleElements);
                        release.Title = release.Title.Trim();
                        if (titleElements.Length < 6)
                        {
                            // Usually non movies / series could have less than 6 elements, eg: Books.
                            release.Title += " " + string.Join(" ", titleElements);
                        }
                        else
                        {
                            release.Title += " " + titleElements[5] + " " + titleElements[3] + " " + titleElements[1] + " " +
                                             titleElements[2] + " " + titleElements[4] + " " + string.Join(
                                " ", titleElements.Skip(6));
                        }

                        // This tracker does not provide an publish date to search terms (only on last 24h page)
                        release.PublishDate = DateTime.Today;

                        // check for previously stripped search terms
                        if (!query.IsImdbQuery && !query.MatchQueryStringAND(release.Title, null, searchTerm))
                        {
                            continue;
                        }
                        var size = qSize.TextContent;
                        release.Size    = ReleaseInfo.GetBytes(size);
                        release.Link    = new Uri(SiteLink + qDlLink.GetAttribute("href"));
                        release.Details = 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;
                        release.DownloadVolumeFactor = qFreeLeech != null ? 0 : 1;
                        release.UploadVolumeFactor   = 1;
                        releases.Add(release);
                    }
                    catch (Exception ex)
                    {
                        logger.Error($"{Id}: Error while parsing row '{row.OuterHtml}': {ex.Message}");
                    }
                }
            }
            catch (Exception ex)
            {
                OnParseError(results.ContentString, ex);
            }

            return(releases);
        }
Beispiel #7
0
        public 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 (!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;



                    int seeders, peers;
                    if (ParseUtil.TryCoerceInt(qRow.Find("td").Get(9).FirstChild.FirstChild.InnerText, out seeders))
                    {
                        release.Seeders = seeders;
                        if (ParseUtil.TryCoerceInt(qRow.Find("td").Get(10).FirstChild.FirstChild.InnerText, out peers))
                        {
                            release.Peers = peers + release.Seeders;
                        }
                    }

                    release.Grabs = ParseUtil.CoerceLong(qRow.Find("td:nth-child(12)").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('>'));
                    release.PublishDate = DateTime.Parse(dateString, CultureInfo.InvariantCulture);

                    string category = qRow.Find("td:eq(0) a").Attr("href").Replace("torrents.php?category=", "");
                    release.Category = MapTrackerCatToNewznab(category);

                    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;
                    }

                    release.UploadVolumeFactor = 1;

                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(results.Content, ex);
            }

            return(releases);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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").FirstElement();
                    var dlUrl       = dlUrlAnchor.GetAttribute("href");
                    var authkey     = Regex.Match(dlUrl, "authkey=(?<authkey>[0-9a-zA-Z]+)").Groups["authkey"].Value;
                    var torrentPass = Regex.Match(dlUrl, "torrent_pass=(?<torrent_pass>[0-9a-zA-Z]+)").Groups["torrent_pass"].Value;
                    var torrentId   = Regex.Match(dlUrl, "id=(?<id>[0-9]+)").Groups["id"].Value;
                    release.Link = new Uri($"{SearchUrl}/{title}.torrent/?action=download&authkey={authkey}&torrent_pass={torrentPass}&id={torrentId}");

                    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("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);
        }