public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
        {
            var pageableRequests = new IndexerPageableRequestChain();
            var query            = new TorrentQuery();
            var tvdbId           = searchCriteria.TvdbId.GetValueOrDefault(0);
            var imdbId           = ParseUtil.GetImdbID(searchCriteria.ImdbId).GetValueOrDefault(0);

            if (searchCriteria.Categories?.Length > 0)
            {
                query.Category = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories).Select(int.Parse).ToArray();
            }

            if (tvdbId == 0 && imdbId == 0 && searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
            {
                query.Search = searchCriteria.SanitizedTvSearchString;
            }

            if (tvdbId != 0)
            {
                query.TvdbInfo         = query.TvdbInfo ?? new TvdbInfo();
                query.TvdbInfo.Id      = tvdbId;
                query.TvdbInfo.Season  = searchCriteria.Season;
                query.TvdbInfo.Episode = searchCriteria.Episode;
            }

            if (imdbId != 0)
            {
                query.ImdbInfo    = query.ImdbInfo ?? new ImdbInfo();
                query.ImdbInfo.Id = imdbId;
            }

            pageableRequests.Add(GetRequest(query));

            return(pageableRequests);
        }
Пример #2
0
        private ReleaseInfo CreateReleaseInfo(QueryResponseItem item)
        {
            var magnetUri = new Uri(_MagnetUri.Replace(KeyInfoHash, item.InfoHash));

            return(new ReleaseInfo
            {
                Title = item.Name,
                Category = MapTrackerCatToNewznab(item.Category.ToString()),
                Comments = item.Id == 0
                    ? null
                    : new Uri($"{SiteLink}description.php?id={item.Id}"),
                MagnetUri = magnetUri,
                InfoHash = item.InfoHash,
                PublishDate = DateTimeUtil.UnixTimestampToDateTime(item.Added),
                Guid = magnetUri,
                Seeders = item.Seeders,
                Peers = item.Seeders + item.Leechers,
                Size = item.Size,
                Files = item.NumFiles,
                DownloadVolumeFactor = 0,
                UploadVolumeFactor = 1,
                Imdb = string.IsNullOrEmpty(item.Imdb)
                    ? null
                    : ParseUtil.GetImdbID(item.Imdb)
            });
        }
Пример #3
0
        public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
        {
            var torrentInfos        = new List <TorrentInfo>();
            var indexerHttpResponse = indexerResponse.HttpResponse;

            if (indexerHttpResponse.StatusCode != HttpStatusCode.OK)
            {
                throw new IndexerException(indexerResponse, $"Unexpected response status {indexerHttpResponse.StatusCode} code from API request");
            }

            if (!indexerHttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
            {
                throw new IndexerException(indexerResponse, $"Unexpected response header {indexerHttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
            }

            if (indexerResponse.Content.ContainsIgnoreCase("Invalid API Key"))
            {
                throw new IndexerAuthException("API Key invalid or not authorized");
            }

            var jsonResponse = new HttpResponse <BeyondHDResponse>(indexerHttpResponse);

            foreach (var row in jsonResponse.Resource.Results)
            {
                var details = row.InfoUrl;
                var link    = row.DownloadLink;

                // BHD can return crazy values for tmdb
                var tmdbId = row.TmdbId.IsNullOrWhiteSpace() ? 0 : ParseUtil.TryCoerceInt(row.TmdbId.Split("/")[1], out var tmdbResult) ? tmdbResult : 0;
                var imdbId = ParseUtil.GetImdbID(row.ImdbId).GetValueOrDefault();

                var release = new TorrentInfo
                {
                    Title                = row.Name,
                    DownloadUrl          = link,
                    InfoHash             = row.InfoHash,
                    InfoUrl              = details,
                    Guid                 = details,
                    Categories           = _categories.MapTrackerCatDescToNewznab(row.Category),
                    PublishDate          = DateTime.Parse(row.CreatedAt, CultureInfo.InvariantCulture),
                    Size                 = row.Size,
                    Grabs                = row.Grabs,
                    Seeders              = row.Seeders,
                    ImdbId               = imdbId,
                    TmdbId               = tmdbId,
                    Peers                = row.Leechers + row.Seeders,
                    DownloadVolumeFactor = row.Freeleech || row.Limited ? 0 : row.Promo75 ? 0.25 : row.Promo50 ? 0.5 : row.Promo25 ? 0.75 : 1,
                    UploadVolumeFactor   = 1,
                    MinimumRatio         = 1,
                    MinimumSeedTime      = 172800, // 120 hours
                };

                torrentInfos.Add(release);
            }

            // order by date
            return(torrentInfos.OrderByDescending(o => o.PublishDate).ToArray());
        }
Пример #4
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();
            var response = await CallProviderAsync(query);

            if (response.StartsWith("{\"error\""))
            {
                throw new ExceptionWithConfigData(response, configData);
            }

            try
            {
                var json = JArray.Parse(response);
                foreach (var row in json)
                {
                    var detailsUri           = new Uri(DetailsUrl + "?id=" + (string)row["id"]);
                    var seeders              = (int)row["seeders"];
                    var peers                = seeders + (int)row["leechers"];
                    var publishDate          = DateTimeUtil.FromFuzzyTime((string)row["upload_date"] + " +0200");
                    var downloadVolumeFactor = (int)row["freeleech"] == 1 ? 0 : 1;
                    var uploadVolumeFactor   = (int)row["doubleup"] == 1 ? 2 : 1;
                    var imdbId               = ((JObject)row).ContainsKey("imdb") ? ParseUtil.GetImdbID((string)row["imdb"]) : null;
                    var link = new Uri((string)row["download_link"]);

                    var release = new ReleaseInfo
                    {
                        Title                = (string)row["name"],
                        Details              = detailsUri,
                        Link                 = link,
                        Category             = MapTrackerCatDescToNewznab((string)row["category"]),
                        Size                 = (long)row["size"],
                        Files                = (long)row["files"],
                        Grabs                = (long)row["times_completed"],
                        Seeders              = seeders,
                        Peers                = peers,
                        MinimumRatio         = 1,
                        MinimumSeedTime      = 172800, //48 hours
                        PublishDate          = publishDate,
                        DownloadVolumeFactor = downloadVolumeFactor,
                        UploadVolumeFactor   = uploadVolumeFactor,
                        Guid                 = detailsUri,
                        Imdb                 = imdbId
                    };

                    releases.Add(release);
                }

                return(releases);
            }
            catch (Exception ex)
            {
                OnParseError(response, ex);
            }

            return(releases);
        }
Пример #5
0
        private List <ReleaseInfo> ParseMultiResult(WebResult response)
        {
            var releases = new List <ReleaseInfo>();
            var results  = response.ContentString;

            try
            {
                var parser = new HtmlParser();
                var dom    = parser.ParseDocument(results);
                var rows   = dom.QuerySelectorAll("table.table-bordered > tbody > tr[class*=\"torrent_row_\"]");
                foreach (var row in rows)
                {
                    var release = new ReleaseInfo();
                    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.Category = 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.Link    = new Uri(SiteLink + qDlLink.GetAttribute("href").TrimStart('/'));
                    release.Details = new Uri(SiteLink + qDetailsLink.GetAttribute("href").TrimStart('/'));
                    release.Guid    = release.Details;

                    var qColumns = row.QuerySelectorAll("td");
                    release.Files       = ParseUtil.CoerceInt(qColumns[3].TextContent);
                    release.PublishDate = DateTimeUtil.FromUnknown(qColumns[5].TextContent);
                    release.Size        = ReleaseInfo.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.Imdb = ParseUtil.GetImdbID(WebUtility.UrlDecode(deRefUrl).Split('/').Last());
                    }

                    release.DownloadVolumeFactor = row.QuerySelector("span.freeleech") != null ? 0 : 1;
                    release.UploadVolumeFactor   = 1;
                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(results, ex);
            }

            return(releases);
        }
Пример #6
0
        public virtual IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
        {
            var torrentInfos = new List <TorrentInfo>();

            if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
            {
                throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
            }

            if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
            {
                throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
            }

            var jsonResponse = new HttpResponse <Unit3dResponse>(indexerResponse.HttpResponse);

            foreach (var row in jsonResponse.Resource.Data)
            {
                var details = row.Attributes.DetailsLink;
                var link    = row.Attributes.DownloadLink;

                var release = new TorrentInfo
                {
                    Title                = row.Attributes.Name,
                    DownloadUrl          = link,
                    InfoHash             = row.Id,
                    InfoUrl              = details,
                    Guid                 = details,
                    Categories           = _categories.MapTrackerCatDescToNewznab(row.Attributes.Category),
                    PublishDate          = DateTime.Parse(row.Attributes.CreatedAt, CultureInfo.InvariantCulture),
                    Size                 = row.Attributes.Size,
                    Files                = row.Attributes.Files,
                    Grabs                = row.Attributes.Grabs,
                    Seeders              = row.Attributes.Seeders,
                    ImdbId               = ParseUtil.GetImdbID(row.Attributes.ImdbId).GetValueOrDefault(),
                    TmdbId               = row.Attributes.TmdbId.IsNullOrWhiteSpace() ? 0 : ParseUtil.CoerceInt(row.Attributes.TmdbId),
                    TvdbId               = row.Attributes.TvdbId.IsNullOrWhiteSpace() ? 0 : ParseUtil.CoerceInt(row.Attributes.TvdbId),
                    Peers                = row.Attributes.Leechers + row.Attributes.Seeders,
                    DownloadVolumeFactor = row.Attributes.Freeleech ? 0 : 1,
                    UploadVolumeFactor   = row.Attributes.DoubleUpload ? 2 : 1,
                    MinimumRatio         = 1,
                    MinimumSeedTime      = 172800, // 48 hours
                };

                torrentInfos.Add(release);
            }

            // order by date
            return(torrentInfos.OrderByDescending(o => o.PublishDate).ToArray());
        }
Пример #7
0
        public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
        {
            var torrentInfos = new List <ReleaseInfo>();

            var detailsUrl  = _settings.BaseUrl + "details.php?";
            var downloadUrl = _settings.BaseUrl + "download.php?";

            if (indexerResponse.Content?.Contains("User not found or passkey not set") == true)
            {
                throw new IndexerAuthException("The passkey is invalid. Check the indexer configuration.");
            }

            var jsonContent = JArray.Parse(indexerResponse.Content);

            foreach (var item in jsonContent)
            {
                var title = item.Value <string>("name");

                var id             = item.Value <long>("id");
                var details        = new Uri(detailsUrl + "id=" + id).AbsoluteUri;
                var link           = new Uri(downloadUrl + "id=" + id + "&passkey=" + _settings.Passkey).AbsoluteUri;
                var publishDate    = DateTime.ParseExact(item.Value <string>("added"), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
                var dlVolumeFactor = item.Value <int>("is_freeleech") == 1 ? 0 : 1;

                var release = new TorrentInfo
                {
                    Title                = title,
                    DownloadUrl          = link,
                    InfoUrl              = details,
                    Guid                 = details,
                    Categories           = _categories.MapTrackerCatToNewznab(item.Value <string>("category")),
                    PublishDate          = publishDate,
                    Size                 = item.Value <long>("size"),
                    Grabs                = item.Value <int>("times_completed"),
                    Files                = item.Value <int>("numfiles"),
                    Seeders              = item.Value <int>("seeders"),
                    Peers                = item.Value <int>("leechers") + item.Value <int>("seeders"),
                    ImdbId               = ParseUtil.GetImdbID(item.Value <string>("imdbid")) ?? 0,
                    MinimumRatio         = 1,
                    MinimumSeedTime      = 0,
                    DownloadVolumeFactor = dlVolumeFactor,
                    UploadVolumeFactor   = 1
                };

                torrentInfos.Add(release);
            }

            return(torrentInfos.ToArray());
        }
Пример #8
0
        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());
        }
Пример #9
0
        private ReleaseInfo getMovieBasicInformation(JToken jsonData)
        {
            var release = new ReleaseInfo();

            release.Title       = jsonData.Value <string>("title");
            release.Description = jsonData.Value <string>("description_full");
            release.Comments    = new Uri(jsonData.Value <string>("url"));
            string imdbId = jsonData.Value <string>("imdb_code");

            if (!String.IsNullOrEmpty(imdbId))
            {
                release.Imdb = ParseUtil.GetImdbID(imdbId);
            }

            ;
            return(release);
        }
Пример #10
0
        public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
        {
            var torrentInfos = new List <TorrentInfo>();

            var rows = JsonConvert.DeserializeObject <dynamic>(indexerResponse.Content);

            foreach (var row in rows)
            {
                var title = (string)row.name;

                var torrentId          = (long)row.t;
                var details            = new Uri(_settings.BaseUrl + "details.php?id=" + torrentId);
                var seeders            = (int)row.seeders;
                var imdbId             = (string)row["imdb-id"];
                var downloadMultiplier = (double?)row["download-multiplier"] ?? 1;
                var link        = new Uri(_settings.BaseUrl + "download.php/" + torrentId + "/" + torrentId + ".torrent");
                var publishDate = DateTimeUtil.UnixTimestampToDateTime((long)row.ctime).ToLocalTime();
                var imdb        = ParseUtil.GetImdbID(imdbId) ?? 0;

                var release = new TorrentInfo
                {
                    Title                = title,
                    Guid                 = details.AbsoluteUri,
                    DownloadUrl          = link.AbsoluteUri,
                    InfoUrl              = details.AbsoluteUri,
                    PublishDate          = publishDate,
                    Categories           = _categories.MapTrackerCatToNewznab(row.c.ToString()),
                    Size                 = (long)row.size,
                    Files                = (int)row.files,
                    Grabs                = (int)row.completed,
                    Seeders              = seeders,
                    Peers                = seeders + (int)row.leechers,
                    ImdbId               = imdb,
                    DownloadVolumeFactor = downloadMultiplier,
                    UploadVolumeFactor   = 1,
                    MinimumRatio         = 1,
                    MinimumSeedTime      = 172800 // 48 hours
                };

                torrentInfos.Add(release);
            }

            return(torrentInfos.ToArray());
        }
Пример #11
0
        public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
        {
            var torrentInfos = new List <ReleaseInfo>();

            var queryResponseItems = JsonConvert.DeserializeObject <List <ThePirateBayTorrent> >(indexerResponse.Content);

            // The API returns a single item to represent a state of no results. Avoid returning this result.
            if (queryResponseItems.Count == 1 && queryResponseItems.First().Id == 0)
            {
                return(torrentInfos);
            }

            foreach (var item in queryResponseItems)
            {
                var details     = item.Id == 0 ? null : $"{_settings.BaseUrl}description.php?id={item.Id}";
                var imdbId      = string.IsNullOrEmpty(item.Imdb) ? null : ParseUtil.GetImdbID(item.Imdb);
                var torrentItem = new TorrentInfo
                {
                    Title                = item.Name,
                    Categories           = _categories.MapTrackerCatToNewznab(item.Category.ToString()),
                    Guid                 = details,
                    InfoUrl              = details,
                    InfoHash             = item.InfoHash, // magnet link is auto generated from infohash
                    PublishDate          = DateTimeUtil.UnixTimestampToDateTime(item.Added),
                    Seeders              = item.Seeders,
                    Peers                = item.Seeders + item.Leechers,
                    Size                 = item.Size,
                    Files                = item.NumFiles,
                    DownloadVolumeFactor = 0,
                    UploadVolumeFactor   = 1,
                    ImdbId               = imdbId.GetValueOrDefault()
                };

                if (item.InfoHash != null)
                {
                    torrentItem.MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(item.InfoHash, item.Name);
                }

                torrentInfos.Add(torrentItem);
            }

            return(torrentInfos.ToArray());
        }
Пример #12
0
        private ReleaseInfo CreateReleaseInfo(QueryResponseItem item)
        {
            var details = item.Id == 0 ? null : new Uri($"{SiteLink}description.php?id={item.Id}");
            var imdbId  = string.IsNullOrEmpty(item.Imdb) ? null : ParseUtil.GetImdbID(item.Imdb);

            return(new ReleaseInfo
            {
                Title = item.Name,
                Category = MapTrackerCatToNewznab(item.Category.ToString()),
                Guid = details,
                Details = details,
                InfoHash = item.InfoHash, // magnet link is auto generated from infohash
                PublishDate = DateTimeUtil.UnixTimestampToDateTime(item.Added),
                Seeders = item.Seeders,
                Peers = item.Seeders + item.Leechers,
                Size = item.Size,
                Files = item.NumFiles,
                DownloadVolumeFactor = 0,
                UploadVolumeFactor = 1,
                Imdb = imdbId
            });
        }
Пример #13
0
        public IList <ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
        {
            if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
            {
                throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
            }

            if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
            {
                throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
            }

            var jsonResponse = new HttpResponse <List <SpeedAppTorrent> >(indexerResponse.HttpResponse);

            return(jsonResponse.Resource.Select(torrent => new TorrentInfo
            {
                Guid = torrent.Id.ToString(),
                Title = torrent.Name,
                Description = torrent.ShortDescription,
                Size = torrent.Size,
                ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(),
                DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download",
                PosterUrl = torrent.Poster,
                InfoUrl = torrent.Url,
                Grabs = torrent.TimesCompleted,
                PublishDate = torrent.CreatedAt,
                Categories = _categories.MapTrackerCatToNewznab(torrent.Category.Id.ToString()),
                InfoHash = null,
                Seeders = torrent.Seeders,
                Peers = torrent.Leechers + torrent.Seeders,
                MinimumRatio = 1,
                MinimumSeedTime = 172800,
                DownloadVolumeFactor = torrent.DownloadVolumeFactor,
                UploadVolumeFactor = torrent.UploadVolumeFactor,
            }).ToArray());
        }
Пример #14
0
        private async Task <IEnumerable <ReleaseInfo> > PerformQueryWithRetry(TorznabQuery query, bool retry)
        {
            var releases = new List <ReleaseInfo>();

            // check the token and renewal if necessary
            await RenewalTokenAsync();

            var response = await RequestWithCookiesAndRetryAsync(BuildSearchUrl(query));

            var jsonContent = JObject.Parse(response.ContentString);
            var errorCode   = jsonContent.Value <int>("error_code");

            switch (errorCode)
            {
            case 0:     // valid response with results
                break;

            case 2:
            case 4:                            // invalid token
                await RenewalTokenAsync(true); // force renewal token

                response = await RequestWithCookiesAndRetryAsync(BuildSearchUrl(query));

                jsonContent = JObject.Parse(response.ContentString);
                break;

            case 10:     // imdb not found, see issue #1486
            case 20:     // no results found
                // the api returns "no results" in some valid queries. we do one retry on this case but we can't do more
                // because we can't distinguish between search without results and api malfunction
                return(retry ? await PerformQueryWithRetry(query, false) : releases);

            default:
                throw new Exception("Unknown error code: " + errorCode + " response: " + response.ContentString);
            }

            try
            {
                foreach (var item in jsonContent.Value <JArray>("torrent_results"))
                {
                    var title = WebUtility.HtmlDecode(item.Value <string>("title"));

                    var magnetStr = item.Value <string>("download");
                    var magnetUri = new Uri(magnetStr);
                    var infoHash  = magnetStr.Split(':')[3].Split('&')[0];

                    // append app_id to prevent api server returning 403 forbidden
                    var details = new Uri(item.Value <string>("info_page") + "&app_id=" + _appId);

                    // ex: 2015-08-16 21:25:08 +0000
                    var dateStr     = item.Value <string>("pubdate").Replace(" +0000", "");
                    var dateTime    = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
                    var publishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime();

                    var size     = item.Value <long>("size");
                    var seeders  = item.Value <int>("seeders");
                    var leechers = item.Value <int>("leechers");

                    var release = new ReleaseInfo
                    {
                        Title                = title,
                        Category             = MapTrackerCatDescToNewznab(item.Value <string>("category")),
                        MagnetUri            = magnetUri,
                        InfoHash             = infoHash,
                        Details              = details,
                        PublishDate          = publishDate,
                        Guid                 = magnetUri,
                        Seeders              = seeders,
                        Peers                = leechers + seeders,
                        Size                 = size,
                        DownloadVolumeFactor = 0,
                        UploadVolumeFactor   = 1
                    };

                    var episodeInfo = item.Value <JToken>("episode_info");
                    if (episodeInfo.HasValues)
                    {
                        release.Imdb   = ParseUtil.GetImdbID(episodeInfo.Value <string>("imdb"));
                        release.TVDBId = episodeInfo.Value <long?>("tvdb");
                        release.RageID = episodeInfo.Value <long?>("tvrage");
                        release.TMDb   = episodeInfo.Value <long?>("themoviedb");
                    }

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

            return(releases);
        }
Пример #15
0
        public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query, int attempts)
        {
            await CheckToken();

            var releases     = new List <ReleaseInfo>();
            var searchString = query.GetQueryString();

            var queryCollection = new NameValueCollection();

            queryCollection.Add("token", token);
            queryCollection.Add("format", "json_extended");
            queryCollection.Add("app_id", app_id);
            queryCollection.Add("limit", "100");
            queryCollection.Add("ranked", "0");

            if (query.ImdbID != null)
            {
                queryCollection.Add("mode", "search");
                queryCollection.Add("search_imdb", query.ImdbID);
            }
            else if (query.RageID != null)
            {
                queryCollection.Add("mode", "search");
                queryCollection.Add("search_tvrage", query.RageID.ToString());
            }

            /*else if (query.TvdbID != null)
             * {
             *  queryCollection.Add("mode", "search");
             *  queryCollection.Add("search_tvdb", query.TvdbID);
             * }*/
            else if (!string.IsNullOrWhiteSpace(searchString))
            {
                searchString = searchString.Replace("'", ""); // ignore ' (e.g. search for america's Next Top Model)
                queryCollection.Add("mode", "search");
                queryCollection.Add("search_string", searchString);
            }
            else
            {
                queryCollection.Add("mode", "list");
            }

            var cats = string.Join(";", MapTorznabCapsToTrackers(query));

            if (!string.IsNullOrEmpty(cats))
            {
                queryCollection.Add("category", cats);
            }

            var searchUrl = ApiEndpoint + "?" + queryCollection.GetQueryString();
            var response  = await RequestStringWithCookiesAndRetry(searchUrl, string.Empty);

            try
            {
                var jsonContent = JObject.Parse(response.Content);

                int errorCode = jsonContent.Value <int>("error_code");
                if (errorCode == 20) // no results found
                {
                    return(releases.ToArray());
                }

                // return empty results in case of invalid imdb ID, see issue #1486
                if (errorCode == 10) // Cant find imdb in database. Are you sure this imdb exists?
                {
                    return(releases);
                }

                if (errorCode == 2 || // Invalid token set!
                    errorCode == 4)    // Invalid token. Use get_token for a new one!
                {
                    token = null;
                    if (attempts < 3)
                    {
                        return(await PerformQuery(query, ++attempts));
                    }
                    else
                    {
                        throw new Exception("error " + errorCode.ToString() + " after " + attempts.ToString() + " attempts: " + jsonContent.Value <string>("error"));
                    }
                }

                if (errorCode > 0) // too many requests per seconds ???
                {
                    // we use the IwebClient rate limiter now, this shouldn't happen
                    throw new Exception("error " + errorCode.ToString() + ": " + jsonContent.Value <string>("error"));
                }

                foreach (var item in jsonContent.Value <JArray>("torrent_results"))
                {
                    var release = new ReleaseInfo();
                    release.Title    = item.Value <string>("title");
                    release.Category = MapTrackerCatDescToNewznab(item.Value <string>("category"));

                    release.MagnetUri = new Uri(item.Value <string>("download"));
                    release.InfoHash  = release.MagnetUri.ToString().Split(':')[3].Split('&')[0];

                    release.Comments = new Uri(item.Value <string>("info_page"));
                    release.Link     = release.Comments; // in case of a torrent download we grab the link from the details page in Download()
                    release.Guid     = release.MagnetUri;

                    var episode_info = item.Value <JToken>("episode_info");

                    if (episode_info.HasValues)
                    {
                        var imdb = episode_info.Value <string>("imdb");
                        release.Imdb   = ParseUtil.GetImdbID(imdb);
                        release.TVDBId = episode_info.Value <long?>("tvdb");
                        release.RageID = episode_info.Value <long?>("tvrage");
                        release.TMDb   = episode_info.Value <long?>("themoviedb");
                    }

                    // ex: 2015-08-16 21:25:08 +0000
                    var dateStr  = item.Value <string>("pubdate").Replace(" +0000", "");
                    var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
                    release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime();

                    release.Seeders = item.Value <int>("seeders");
                    release.Peers   = item.Value <int>("leechers") + release.Seeders;
                    release.Size    = item.Value <long>("size");
                    release.DownloadVolumeFactor = 0;
                    release.UploadVolumeFactor   = 1;

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

            return(releases);
        }
Пример #16
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases                = new List <ReleaseInfo>();
            var searchString            = query.GetQueryString();
            var prevCook                = CookieHeader + "";
            var searchStringIsImdbQuery = (ParseUtil.GetImdbID(searchString) != null);

            // If we have no query use the RSS Page as their server is slow enough at times!
            // ~15.01.2019 they removed the description tag making the RSS feed almost useless, we don't use it for now. See #4458
            // if (false && query.IsTest || string.IsNullOrWhiteSpace(searchString))

            /*
             * if (false)
             * {
             *  var rssPage = await RequestStringWithCookiesAndRetry(string.Format(RSSUrl, configData.RSSKey.Value));
             *  try
             *  {
             *      if (rssPage.Content.EndsWith("\0"))
             *      {
             *          rssPage.Content = rssPage.Content.Substring(0, rssPage.Content.Length - 1);
             *      }
             *      rssPage.Content = RemoveInvalidXmlChars(rssPage.Content);
             *      var rssDoc = XDocument.Parse(rssPage.Content);
             *
             *      foreach (var item in rssDoc.Descendants("item"))
             *      {
             *          var title = item.Descendants("title").First().Value;
             *          var description = item.Descendants("description").First().Value;
             *          var link = item.Descendants("link").First().Value;
             *          var category = item.Descendants("category").First().Value;
             *          var date = item.Descendants("pubDate").First().Value;
             *
             *          var torrentIdMatch = Regex.Match(link, "(?<=id=)(\\d)*");
             *          var torrentId = torrentIdMatch.Success ? torrentIdMatch.Value : string.Empty;
             *          if (string.IsNullOrWhiteSpace(torrentId))
             *              throw new Exception("Missing torrent id");
             *
             *          var infoMatch = Regex.Match(description, @"Category:\W(?<cat>.*)\W\/\WSeeders:\W(?<seeders>[\d\,]*)\W\/\WLeechers:\W(?<leechers>[\d\,]*)\W\/\WSize:\W(?<size>[\d\.]*\W\S*)");
             *          if (!infoMatch.Success)
             *              throw new Exception("Unable to find info");
             *
             *          var release = new ReleaseInfo
             *          {
             *              Title = title,
             *              Description = title,
             *              Guid = new Uri(string.Format(DownloadUrl, torrentId)),
             *              Comments = new Uri(string.Format(CommentUrl, torrentId)),
             *              PublishDate = DateTime.ParseExact(date, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture), //2015-08-08 21:20:31
             *              Link = new Uri(string.Format(DownloadUrl, torrentId)),
             *              Seeders = ParseUtil.CoerceInt(infoMatch.Groups["seeders"].Value),
             *              Peers = ParseUtil.CoerceInt(infoMatch.Groups["leechers"].Value),
             *              Size = ReleaseInfo.GetBytes(infoMatch.Groups["size"].Value),
             *              Category = MapTrackerCatToNewznab(category)
             *          };
             *
             *          release.Peers += release.Seeders;
             *          releases.Add(release);
             *      }
             *  }
             *  catch (Exception ex)
             *  {
             *      logger.Error("XSpeeds: Error while parsing the RSS feed:");
             *      logger.Error(rssPage.Content);
             *      throw ex;
             *  }
             * }
             */
            //if (query.IsTest || !string.IsNullOrWhiteSpace(searchString))

            /*
             * if (searchString.Length < 3 && !query.IsTest)
             * {
             *  OnParseError("", new Exception("Minimum search length is 3"));
             *  return releases;
             * }
             */
            var searchParams = new Dictionary <string, string> {
                { "do", "search" },
                { "category", "0" },
                { "include_dead_torrents", "no" }
            };

            if (query.IsImdbQuery)
            {
                searchParams.Add("keywords", query.ImdbID);
                searchParams.Add("search_type", "t_both");
            }
            else
            {
                searchParams.Add("keywords", searchString);
                if (searchStringIsImdbQuery)
                {
                    searchParams.Add("search_type", "t_both");
                }
                else
                {
                    searchParams.Add("search_type", "t_name");
                }
            }

            var searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader);

            // Occasionally the cookies become invalid, login again if that happens
            if (searchPage.IsRedirect)
            {
                await ApplyConfiguration(null);

                searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader);
            }

            try
            {
                CQ  dom  = searchPage.Content;
                var rows = dom["table#sortabletable > tbody > tr:has(div > a[href*=\"details.php?id=\"])"];
                foreach (var row in rows)
                {
                    var release = new ReleaseInfo();
                    var qRow    = row.Cq();

                    var qDetails = qRow.Find("div > a[href*=\"details.php?id=\"]");  // details link, release name get's shortened if it's to long
                    var qTitle   = qRow.Find("td:eq(1) .tooltip-content div:eq(0)"); // use Title from tooltip
                    if (!qTitle.Any())                                               // fallback to Details link if there's no tooltip
                    {
                        qTitle = qDetails;
                    }
                    release.Title = qTitle.Text();

                    release.Guid        = new Uri(qRow.Find("td:eq(2) a").Attr("href"));
                    release.Link        = release.Guid;
                    release.Comments    = new Uri(qDetails.Attr("href"));
                    release.PublishDate = DateTime.ParseExact(qRow.Find("td:eq(1) div").Last().Text().Trim(), "dd-MM-yyyy H:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); //08-08-2015 12:51
                    release.Seeders     = ParseUtil.CoerceInt(qRow.Find("td:eq(6)").Text());
                    release.Peers       = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:eq(7)").Text().Trim());
                    release.Size        = ReleaseInfo.GetBytes(qRow.Find("td:eq(4)").Text().Trim());

                    var qBanner = qRow.Find("td:eq(1) .tooltip-content img").First();
                    if (qBanner.Length > 0)
                    {
                        release.BannerUrl = new Uri(qBanner.Attr("src"));
                    }

                    var cat      = row.Cq().Find("td:eq(0) a").First().Attr("href");
                    var catSplit = cat.LastIndexOf('=');
                    if (catSplit > -1)
                    {
                        cat = cat.Substring(catSplit + 1);
                    }
                    release.Category = MapTrackerCatToNewznab(cat);

                    var grabs = qRow.Find("td:nth-child(6)").Text();
                    release.Grabs = ParseUtil.CoerceInt(grabs);

                    if (qRow.Find("img[alt^=\"Free Torrent\"]").Length >= 1)
                    {
                        release.DownloadVolumeFactor = 0;
                    }
                    else if (qRow.Find("img[alt^=\"Silver Torrent\"]").Length >= 1)
                    {
                        release.DownloadVolumeFactor = 0.5;
                    }
                    else
                    {
                        release.DownloadVolumeFactor = 1;
                    }

                    if (qRow.Find("img[alt^=\"x2 Torrent\"]").Length >= 1)
                    {
                        release.UploadVolumeFactor = 2;
                    }
                    else
                    {
                        release.UploadVolumeFactor = 1;
                    }

                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(searchPage.Content, ex);
            }
            if (!CookieHeader.Trim().Equals(prevCook.Trim()))
            {
                SaveConfig();
            }
            return(releases);
        }
Пример #17
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();

            var qc = new NameValueCollection
            {
                { "incldead", "1" }
            };

            if (query.IsImdbQuery)
            {
                qc.Add("titleonly", "0");
                qc.Add("search", query.ImdbID);
            }
            else
            {
                qc.Add("titleonly", "1");
                qc.Add("search", query.GetQueryString());
            }

            var cats = MapTorznabCapsToTrackers(query);

            if (cats.Count > 0)
            {
                foreach (var cat in cats)
                {
                    qc.Add($"c{cat}", "1");
                }
            }

            var searchUrl = SearchUrl + "?" + qc.GetQueryString();
            var results   = await RequestWithCookiesAndRetryAsync(searchUrl);

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

                results = await RequestWithCookiesAndRetryAsync(searchUrl);
            }

            try
            {
                var parser = new HtmlParser();
                var dom    = parser.ParseDocument(results.ContentString);
                var rows   = dom.QuerySelectorAll("#torrents-table > tbody > tr");

                foreach (var row in rows.Skip(1))
                {
                    var qDetails = row.QuerySelector(".br_right > a");
                    var details  = new Uri(SiteLink + qDetails.GetAttribute("href"));
                    var title    = qDetails.QuerySelector("b").TextContent;

                    var qLink = row.QuerySelector("td:nth-child(4) > a");
                    if (qLink == null)
                    {
                        continue; // support/donation banner
                    }
                    var link = new Uri(SiteLink + 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     = ReleaseInfo.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 ReleaseInfo
                    {
                        Details              = details,
                        Guid                 = details,
                        Title                = title,
                        Link                 = link,
                        PublishDate          = publishDate,
                        Size                 = size,
                        Seeders              = seeders,
                        Peers                = seeders + leechers,
                        Grabs                = grabs,
                        Files                = files,
                        Category             = MapTrackerCatToNewznab(category),
                        Imdb                 = imdb,
                        MinimumRatio         = 1,
                        MinimumSeedTime      = 172800, // 48 hours
                        UploadVolumeFactor   = 1,
                        DownloadVolumeFactor = 1
                    };
                    releases.Add(release);
                }
            }
            catch (Exception e)
            {
                OnParseError(results.ContentString, e);
            }

            return(releases);
        }
Пример #18
0
        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, @"<[^>]+>|&nbsp;", "").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());
        }
Пример #19
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();

            // remove operator characters
            var cleanSearchString = Regex.Replace(query.GetQueryString().Trim(), "[ _.+-]+", " ", RegexOptions.Compiled);

            var searchUrl       = SearchUrl;
            var queryCollection = new NameValueCollection
            {
                { "search_in", "name" },
                { "search_mode", "all" },
                { "order_by", "added" },
                { "order_way", "desc" }
            };

            if (!string.IsNullOrWhiteSpace(cleanSearchString))
            {
                queryCollection.Add("query", cleanSearchString);
            }
            foreach (var cat in MapTorznabCapsToTrackers(query))
            {
                queryCollection.Add($"cat[{cat}]", "1");
            }
            searchUrl += "?" + queryCollection.GetQueryString();
            var response = await RequestWithCookiesAndRetryAsync(searchUrl);

            var results = response.ContentString;

            if (!results.Contains("/logout.php?"))
            {
                await ApplyConfiguration(null);

                response = await RequestWithCookiesAndRetryAsync(searchUrl);

                results = response.ContentString;
            }

            try
            {
                var parser = new HtmlParser();
                var dom    = parser.ParseDocument(results);
                var rows   = dom.QuerySelectorAll("table.table-bordered > tbody > tr[class*=\"torrent_row_\"]");
                foreach (var row in rows)
                {
                    var release = new ReleaseInfo();
                    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.Category = 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.Link     = new Uri(SiteLink + qDlLink.GetAttribute("href").TrimStart('/'));
                    release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href").TrimStart('/'));
                    release.Guid     = release.Comments;

                    var qColumns = row.QuerySelectorAll("td");
                    release.Files       = ParseUtil.CoerceInt(qColumns[3].TextContent);
                    release.PublishDate = DateTimeUtil.FromUnknown(qColumns[5].TextContent);
                    release.Size        = ReleaseInfo.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.Imdb = ParseUtil.GetImdbID(WebUtility.UrlDecode(deRefUrl).Split('/').Last());
                    }

                    release.DownloadVolumeFactor = row.QuerySelector("span.freeleech") != null ? 0 : 1;
                    release.UploadVolumeFactor   = 1;
                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(results, ex);
            }

            return(releases);
        }
Пример #20
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();

            // remove dashes at the beginning of keywords as they exclude search strings (see issue #3096)
            var searchString = query.GetQueryString();

            searchString = Regex.Replace(searchString, @"(^|\s)-", " ");

            var searchUrl = SearchUrl;

            if (((BoolConfigurationItem)configData.GetDynamic("freeleech")).Value)
            {
                searchUrl += "facets/tags%3AFREELEECH/";
            }

            if (query.IsImdbQuery)
            {
                searchUrl += "imdbID/" + query.ImdbID + "/";
            }
            else if (!string.IsNullOrWhiteSpace(searchString))
            {
                searchUrl += "exact/1/query/" + WebUtility.UrlEncode(searchString) + "/";
            }

            var cats = MapTorznabCapsToTrackers(query);

            if (cats.Count > 0)
            {
                searchUrl += "categories/" + string.Join(",", cats);
            }
            else
            {
                searchUrl += "newfilter/2"; // include 0day and music
            }
            var results = await RequestWithCookiesAndRetryAsync(searchUrl);

            if (results.ContentString.Contains("/user/account/login")) // re-login
            {
                await DoLogin();

                results = await RequestWithCookiesAndRetryAsync(searchUrl);
            }

            try
            {
                var rows = (JArray)((JObject)JsonConvert.DeserializeObject(results.ContentString))["torrentList"];
                foreach (var row in rows)
                {
                    var title = row["name"].ToString();
                    if (!query.MatchQueryStringAND(title))
                    {
                        continue;
                    }

                    var torrentId   = row["fid"].ToString();
                    var details     = new Uri(SiteLink + "torrent/" + torrentId);
                    var link        = new Uri(SiteLink + "download/" + torrentId + "/" + row["filename"]);
                    var publishDate = DateTime.ParseExact(row["addedTimestamp"].ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
                    var seeders     = (int)row["seeders"];

                    // freeleech #6579 #6624 #7367
                    var dlMultiplier   = row["download_multiplier"].ToString();
                    var dlVolumeFactor = string.IsNullOrEmpty(dlMultiplier) ? 1 : ParseUtil.CoerceInt(dlMultiplier);

                    var release = new ReleaseInfo
                    {
                        Title                = title,
                        Details              = details,
                        Guid                 = details,
                        Link                 = link,
                        PublishDate          = publishDate,
                        Category             = MapTrackerCatToNewznab(row["categoryID"].ToString()),
                        Size                 = (long)row["size"],
                        Grabs                = (int)row["completed"],
                        Seeders              = seeders,
                        Peers                = seeders + (int)row["leechers"],
                        Imdb                 = ParseUtil.GetImdbID(row["imdbID"].ToString()),
                        UploadVolumeFactor   = 1,
                        DownloadVolumeFactor = dlVolumeFactor,
                        MinimumRatio         = 1,
                        MinimumSeedTime      = 864000 // 10 days for registered users, less for upgraded users
                    };

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

            return(releases);
        }
Пример #21
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();

            var cats = MapTorznabCapsToTrackers(query);

            if (cats.Count == 0)
            {
                cats = GetAllTrackerCategories();
            }
            var catStr    = string.Join(";", cats);
            var searchUrl = SearchUrl + "?" + catStr;

            if (query.IsImdbQuery)
            {
                searchUrl += ";q=" + query.ImdbID;
            }
            else
            {
                searchUrl += ";q=" + WebUtilityHelpers.UrlEncode(query.GetQueryString(), Encoding);
            }

            if (((BoolConfigurationItem)configData.GetDynamic("freeleech")).Value)
            {
                searchUrl += ";free=on";
            }

            var results = await RequestWithCookiesAndRetryAsync(searchUrl);

            // Check for being logged out
            if (results.IsRedirect)
            {
                if (results.RedirectingTo.Contains("login.php"))
                {
                    throw new Exception("The user is not logged in. It is possible that the cookie has expired or you made a mistake when copying it. Please check the settings.");
                }
                else
                {
                    throw new Exception($"Got a redirect to {results.RedirectingTo}, please adjust your the alternative link");
                }
            }

            try
            {
                var rows = JsonConvert.DeserializeObject <dynamic>(results.ContentString);

                foreach (var row in rows)
                {
                    var title = (string)row.name;
                    if ((!query.IsImdbQuery || !TorznabCaps.MovieSearchImdbAvailable) && !query.MatchQueryStringAND(title))
                    {
                        continue;
                    }
                    var torrentId          = (long)row.t;
                    var details            = new Uri(SiteLink + "details.php?id=" + torrentId);
                    var seeders            = (int)row.seeders;
                    var imdbId             = (string)row["imdb-id"];
                    var downloadMultiplier = (double?)row["download-multiplier"] ?? 1;
                    var link        = new Uri(SiteLink + "download.php/" + torrentId + "/" + torrentId + ".torrent");
                    var publishDate = DateTimeUtil.UnixTimestampToDateTime((long)row.ctime).ToLocalTime();
                    var imdb        = ParseUtil.GetImdbID(imdbId);

                    var release = new ReleaseInfo
                    {
                        Title                = title,
                        Details              = details,
                        Guid                 = details,
                        Link                 = link,
                        PublishDate          = publishDate,
                        Category             = MapTrackerCatToNewznab(row.c.ToString()),
                        Size                 = (long)row.size,
                        Files                = (long)row.files,
                        Grabs                = (long)row.completed,
                        Seeders              = seeders,
                        Peers                = seeders + (int)row.leechers,
                        Imdb                 = imdb,
                        DownloadVolumeFactor = downloadMultiplier,
                        UploadVolumeFactor   = 1,
                        MinimumRatio         = 1,
                        MinimumSeedTime      = 172800 // 48 hours
                    };

                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(results.ContentString, ex);
            }
            return(releases);
        }
Пример #22
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases     = new List <ReleaseInfo>();
            var searchString = GetSearchTerm(query);

            var searchUrl       = APIUrl;
            var queryCollection = new NameValueCollection
            {
                { "action", "browse" },
                //{"group_results", "0"}, # results won't include all information
                { "order_by", "time" },
                { "order_way", "desc" }
            };

            if (!string.IsNullOrWhiteSpace(query.ImdbID))
            {
                if (imdbInTags)
                {
                    queryCollection.Add("taglist", query.ImdbID);
                }
                else
                {
                    queryCollection.Add("cataloguenumber", query.ImdbID);
                }
            }
            else if (!string.IsNullOrWhiteSpace(searchString))
            {
                queryCollection.Add("searchstr", searchString);
            }

            if (query.Artist != null)
            {
                queryCollection.Add("artistname", query.Artist);
            }

            if (query.Label != null)
            {
                queryCollection.Add("recordlabel", query.Label);
            }

            if (query.Year != null)
            {
                queryCollection.Add("year", query.Year.ToString());
            }

            if (query.Album != null)
            {
                queryCollection.Add("groupname", query.Album);
            }

            foreach (var cat in MapTorznabCapsToTrackers(query))
            {
                queryCollection.Add("filter_cat[" + cat + "]", "1");
            }

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

            var apiKey  = configData.ApiKey;
            var headers = apiKey != null ? new Dictionary <string, string> {
                ["Authorization"] = String.Format(AuthorizationFormat, apiKey.Value)
            } : null;

            var response = await RequestWithCookiesAndRetryAsync(searchUrl, headers : headers);

            // we get a redirect in html pages and an error message in json response (api)
            if (response.IsRedirect || (response.ContentString != null && response.ContentString.Contains("\"bad credentials\"")))
            {
                // re-login
                await ApplyConfiguration(null);

                response = await RequestWithCookiesAndRetryAsync(searchUrl);
            }

            try
            {
                var json = JObject.Parse(response.ContentString);
                foreach (JObject r in json["response"]["results"])
                {
                    var groupTime   = DateTimeUtil.UnixTimestampToDateTime(long.Parse((string)r["groupTime"]));
                    var groupName   = WebUtility.HtmlDecode((string)r["groupName"]);
                    var artist      = WebUtility.HtmlDecode((string)r["artist"]);
                    var cover       = (string)r["cover"];
                    var tags        = r["tags"].ToList();
                    var groupYear   = (string)r["groupYear"];
                    var releaseType = (string)r["releaseType"];
                    var title       = new StringBuilder();
                    if (!string.IsNullOrEmpty(artist))
                    {
                        title.Append(artist + " - ");
                    }
                    title.Append(groupName);
                    if (!string.IsNullOrEmpty(groupYear) && groupYear != "0")
                    {
                        title.Append(" [" + groupYear + "]");
                    }
                    if (!string.IsNullOrEmpty(releaseType) && releaseType != "Unknown")
                    {
                        title.Append(" [" + releaseType + "]");
                    }
                    var description = tags?.Any() == true && !string.IsNullOrEmpty(tags[0].ToString())
                        ? "Tags: " + string.Join(", ", tags) + "\n"
                        : null;
                    Uri poster = null;
                    if (!string.IsNullOrEmpty(cover))
                    {
                        poster = new Uri(cover);
                    }
                    var release = new ReleaseInfo
                    {
                        PublishDate = groupTime,
                        Title       = title.ToString(),
                        Description = description,
                        Poster      = poster
                    };


                    if (imdbInTags)
                    {
                        release.Imdb = tags
                                       .Select(tag => ParseUtil.GetImdbID((string)tag))
                                       .Where(tag => tag != null).FirstIfSingleOrDefault();
                    }

                    if (r["torrents"] is JArray)
                    {
                        foreach (JObject torrent in r["torrents"])
                        {
                            var release2 = (ReleaseInfo)release.Clone();
                            FillReleaseInfoFromJson(release2, torrent);
                            if (ReleaseInfoPostParse(release2, torrent, r))
                            {
                                releases.Add(release2);
                            }
                        }
                    }
                    else
                    {
                        FillReleaseInfoFromJson(release, r);
                        if (ReleaseInfoPostParse(release, r, r))
                        {
                            releases.Add(release);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                OnParseError(response.ContentString, ex);
            }

            return(releases);
        }
Пример #23
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();
            var passkey  = configData.Passkey.Value;

            var qc = new NameValueCollection
            {
                { "passkey", passkey }
            };

            if (query.IsImdbQuery)
            {
                qc.Add("action", "imdbsearch");
                qc.Add("imdb", query.ImdbID);
            }
            else if (!string.IsNullOrWhiteSpace(query.GetQueryString()))
            {
                // not use query.GetQueryString(), because it includes the season
                var searchTerm = query.SearchTerm;
                // search for tv series
                if (query.Season > 0)
                {
                    searchTerm += $": Season {query.Season:D2}";
                }
                // remove the year, it's not supported in the api
                searchTerm = _removeYearRegex.Replace(searchTerm, "");
                qc.Add("action", "titlesearch");
                qc.Add("title", searchTerm);
            }
            else
            {
                qc.Add("action", "latestmovies");
                // the endpoint 'latestmovies' only returns movies, this hack overwrites categories to get movies even if
                // you are searching for tv series. this allows to configure the tracker in Sonarr
                query.Categories = new int[] { };
            }

            var searchUrl = SearchUrl + "?" + qc.GetQueryString();
            var results   = await RequestStringWithCookies(searchUrl);

            if (string.IsNullOrWhiteSpace(results.Content))
            {
                throw new Exception("Empty response. Please, check the Passkey.");
            }

            try
            {
                var doc = XDocument.Parse(results.Content);

                var errorMsg = doc.Descendants("error").FirstOrDefault()?.Value;
                if (errorMsg?.Contains("No Results") == true)
                {
                    return(releases); // no results
                }
                if (errorMsg != null)
                {
                    throw new Exception(errorMsg);
                }

                var authkey  = doc.Descendants("authkey").First().Value;
                var torrents = doc.Descendants("torrent");
                foreach (var torrent in torrents)
                {
                    var torrentName = torrent.FirstValue("name").Trim();

                    // the field <type> is always Movie, so we have to guess if it's a tv series
                    var isSerie = torrentName.Contains(": Season ");
                    if (isSerie)
                    {
                        torrentName = torrentName.Replace(": Season ", " S");
                    }

                    // we have to guess if it's an audio track too
                    var isAudio = string.IsNullOrWhiteSpace((string)torrent.Element("resolution"));
                    var cat     = new List <int>
                    {
                        isSerie?TorznabCatType.TVHD.ID:
                        isAudio ? TorznabCatType.Audio.ID :
                        TorznabCatType.MoviesHD.ID
                    };

                    // if the category is not in the search categories, skip
                    if (query.Categories.Any() && !query.Categories.Intersect(cat).Any())
                    {
                        continue;
                    }

                    var title = new StringBuilder(torrentName);
                    if (!isSerie && torrent.Element("year") != null) // only for movies
                    {
                        title.Append($" {torrent.FirstValue("year")}");
                    }
                    if (torrent.Element("internal")?.Value == "1")
                    {
                        title.Append(" iNTERNAL");
                    }
                    if (torrent.Element("resolution") != null)
                    {
                        title.Append($" {torrent.FirstValue("resolution")}");
                    }
                    if (torrent.Element("media") != null)
                    {
                        title.Append($" {torrent.FirstValue("media")}");
                    }
                    if (torrent.Element("encoding") != null)
                    {
                        title.Append($" {torrent.FirstValue("encoding")}");
                    }
                    if (torrent.Element("audioformat") != null)
                    {
                        title.Append($" {torrent.FirstValue("audioformat")}");
                    }
                    if (torrent.Element("releasegroup") != null)
                    {
                        title.Append($"-{torrent.FirstValue("releasegroup")}");
                    }

                    var torrentId = torrent.FirstValue("id");
                    var groupId   = torrent.FirstValue("groupid");
                    var comments  = new Uri($"{TorrentUrl}?id={groupId}&torrentid={torrentId}");
                    var link      = new Uri($"{TorrentUrl}?action=download&id={torrentId}&authkey={authkey}&torrent_pass={passkey}");

                    var publishDate = DateTime.Parse(torrent.FirstValue("time"));
                    var size        = long.Parse(torrent.FirstValue("size"));
                    var grabs       = int.Parse(torrent.FirstValue("snatched"));
                    var seeders     = int.Parse(torrent.FirstValue("seeders"));
                    var peers       = seeders + int.Parse(torrent.FirstValue("leechers"));
                    var freeleech   = double.Parse(torrent.FirstValue("freeleech"));

                    Uri    banner      = null;
                    string description = null;
                    if (!isAudio) // audio tracks don't have banner either description
                    {
                        // small cover only for movies
                        if (!isSerie && !string.IsNullOrWhiteSpace(torrent.Element("smallcover")?.Value))
                        {
                            banner = new Uri(torrent.FirstValue("smallcover"));
                        }
                        else if (!string.IsNullOrWhiteSpace(torrent.Element("cover")?.Value))
                        {
                            banner = new Uri(torrent.FirstValue("cover"));
                        }

                        description = torrent.Element("encodestatus") != null ?
                                      $"Encode status: {torrent.FirstValue("encodestatus")}" : null;
                    }

                    var imdb = ParseUtil.GetImdbID(torrent.Element("imdb")?.Value);

                    var release = new ReleaseInfo
                    {
                        Title                = title.ToString(),
                        Comments             = comments,
                        Link                 = link,
                        Guid                 = link,
                        PublishDate          = publishDate,
                        Category             = cat,
                        BannerUrl            = banner,
                        Description          = description,
                        Imdb                 = imdb,
                        Size                 = size,
                        Grabs                = grabs,
                        Seeders              = seeders,
                        Peers                = peers,
                        MinimumRatio         = 1,
                        MinimumSeedTime      = 259200, // 72 hours
                        DownloadVolumeFactor = freeleech,
                        UploadVolumeFactor   = 1
                    };

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

            return(releases);
        }
Пример #24
0
        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());
        }
Пример #25
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases = new List <ReleaseInfo>();

            var qc = new List <KeyValuePair <string, string> > // NameValueCollection don't support cat[]=19&cat[]=6
            {
                { "tpage", "1" }
            };

            if (query.IsImdbQuery)
            {
                qc.Add("search", query.ImdbID);
                qc.Add("nfo", "true");
            }
            else if (!string.IsNullOrWhiteSpace(query.GetQueryString()))
            {
                qc.Add("search", query.GetQueryString());
            }

            foreach (var cat in MapTorznabCapsToTrackers(query))
            {
                qc.Add("cat[]", cat);
            }

            var searchUrl = SearchUrl + "?" + qc.GetQueryString();
            var result    = await RequestWithCookiesAndRetryAsync(searchUrl, referer : SearchUrl);

            if (result.IsRedirect)
            {
                throw new Exception($"Your cookie did not work. Please, configure the tracker again. Message: {result.ContentString}");
            }

            if (!result.ContentString.StartsWith("{")) // not JSON => error
            {
                throw new ExceptionWithConfigData(result.ContentString, configData);
            }

            var json = JsonConvert.DeserializeObject <dynamic>(result.ContentString);

            try
            {
                var torrents = json["torrents"]; // latest torrents
                if (json["hits"] != null)        // is search result
                {
                    torrents = json.SelectTokens("$.hits[?(@._type == 'torrent')]._source");
                }
                foreach (var torrent in torrents)
                {
                    var torrentId   = (long)torrent.id;
                    var comments    = new Uri(SiteLink + "torrents/" + torrentId);
                    var link        = new Uri(SiteLink + "download/" + torrentId);
                    var publishDate = DateTime.Parse(torrent.added.ToString());
                    var imdbId      = ParseUtil.GetImdbID(torrent.imdb_id.ToString());

                    Uri banner = null;
                    if ((bool)torrent.poster)
                    {
                        if (torrent["imdb_id"] != null)
                        {
                            banner = new Uri(CdnUrl + "images/torrents/poster/imd/l/" + torrent["imdb_id"] + ".jpg");
                        }
                        else if (torrent["cdu_id"] != null)
                        {
                            banner = new Uri(CdnUrl + "images/torrents/poster/cdu/b/" + torrent["cdu_id"] + "_front.jpg");
                        }
                        else if (torrent["steam_id"] != null)
                        {
                            banner = new Uri(CdnUrl + "images/torrents/poster/ste/l/" + torrent["steam_id"] + ".jpg");
                        }
                    }

                    var descriptions = new List <string>();
                    var language     = (string)torrent.language;
                    if (!string.IsNullOrEmpty(language))
                    {
                        descriptions.Add("Language: " + language);
                    }
                    else if ((bool?)torrent.polish == true)
                    {
                        descriptions.Add("Language: pl");
                    }
                    var description = descriptions.Any() ? string.Join("<br />\n", descriptions) : null;

                    var release = new ReleaseInfo
                    {
                        Title                = torrent.name.ToString(),
                        Comments             = comments,
                        Guid                 = comments,
                        Link                 = link,
                        PublishDate          = publishDate,
                        Category             = MapTrackerCatToNewznab(torrent.category.ToString()),
                        Size                 = (long)torrent.size,
                        Grabs                = (long)torrent.completed,
                        Seeders              = (int)torrent.seeders,
                        Peers                = (int)torrent.seeders + (int)torrent.leechers,
                        Imdb                 = imdbId,
                        BannerUrl            = banner,
                        Description          = description,
                        MinimumRatio         = 1,
                        MinimumSeedTime      = 259200, // 72 hours (I can't verify this, but this is a safe value in most trackers)
                        UploadVolumeFactor   = 1,
                        DownloadVolumeFactor = 1
                    };

                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(result.ToString(), ex);
            }

            return(releases);
        }
Пример #26
0
        public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query, int attempts)
        {
            var releases     = new List <ReleaseInfo>();
            var searchString = query.GetQueryString();

            var queryCollection = new NameValueCollection();

            // without this the API sometimes returns nothing
            queryCollection.Add("sort", "date_added");
            queryCollection.Add("limit", "50");

            if (query.ImdbID != null)
            {
                queryCollection.Add("query_term", query.ImdbID);
            }
            else if (!string.IsNullOrWhiteSpace(searchString))
            {
                searchString = searchString.Replace("'", ""); // ignore ' (e.g. search for america's Next Top Model)
                queryCollection.Add("query_term", searchString);
            }

            var searchUrl = ApiEndpoint + "?" + queryCollection.GetQueryString();
            var response  = await RequestStringWithCookiesAndRetry(searchUrl, string.Empty);

            try
            {
                // returned content might start with an html error message, remove it first
                var jsonStart      = response.Content.IndexOf('{');
                var jsonContentStr = response.Content.Remove(0, jsonStart);

                var jsonContent = JObject.Parse(jsonContentStr);

                string result = jsonContent.Value <string>("status");
                if (result != "ok") // query was not successful
                {
                    return(releases.ToArray());
                }

                var data_items  = jsonContent.Value <JToken>("data");
                int movie_count = data_items.Value <int>("movie_count");
                if (movie_count < 1) // no results found in query
                {
                    return(releases.ToArray());
                }

                var movies = data_items.Value <JToken>("movies");
                if (movies == null)
                {
                    throw new Exception("API error, movies missing");
                }

                foreach (var movie_item in movies)
                {
                    var torrents = movie_item.Value <JArray>("torrents");
                    if (torrents == null)
                    {
                        continue;
                    }
                    foreach (var torrent_info in torrents)
                    {
                        var release = new ReleaseInfo();

                        // append type: BRRip or WEBRip, resolves #3558 via #4577
                        var type = torrent_info.Value <string>("type");
                        switch (type)
                        {
                        case "web":
                            type = " WEBRip";
                            break;

                        default:
                            type = " BRRip";
                            break;
                        }
                        var quality = torrent_info.Value <string>("quality");
                        release.Title = "[YTS] " + movie_item.Value <string>("title_long") + " " + quality + type;
                        var imdb = movie_item.Value <string>("imdb_code");
                        release.Imdb = ParseUtil.GetImdbID(imdb);

                        // API does not provide magnet link, so, construct it
                        string magnet_uri = "magnet:?xt=urn:btih:" + torrent_info.Value <string>("hash") +
                                            "&dn=" + movie_item.Value <string>("slug") +
                                            "&tr=udp://open.demonii.com:1337/announce" +
                                            "&tr=udp://tracker.openbittorrent.com:80" +
                                            "&tr=udp://tracker.coppersurfer.tk:6969" +
                                            "&tr=udp://glotorrents.pw:6969/announce" +
                                            "&tr=udp://tracker.opentrackr.org:1337/announce" +
                                            "&tr=udp://torrent.gresille.org:80/announce" +
                                            "&tr=udp://p4p.arenabg.com:1337" +
                                            "&tr=udp://tracker.leechers-paradise.org:6969";

                        release.MagnetUri = new Uri(magnet_uri);
                        release.InfoHash  = torrent_info.Value <string>("hash");

                        // ex: 2015-08-16 21:25:08 +0000
                        var dateStr  = torrent_info.Value <string>("date_uploaded");
                        var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
                        release.PublishDate          = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime();
                        release.Link                 = new Uri(torrent_info.Value <string>("url"));
                        release.Seeders              = torrent_info.Value <int>("seeds");
                        release.Peers                = torrent_info.Value <int>("peers") + release.Seeders;
                        release.Size                 = torrent_info.Value <long>("size_bytes");
                        release.MinimumRatio         = 1;
                        release.MinimumSeedTime      = 172800; // 48 hours
                        release.DownloadVolumeFactor = 0;
                        release.UploadVolumeFactor   = 1;

                        release.Comments  = new Uri(movie_item.Value <string>("url"));
                        release.BannerUrl = new Uri(movie_item.Value <string>("large_cover_image"));
                        release.Guid      = release.Link;

                        // map the quality to a newznab category for torznab compatibility (for Radarr, etc)
                        switch (quality)
                        {
                        case "720p":
                            release.Category = MapTrackerCatToNewznab("45");
                            break;

                        case "1080p":
                            release.Category = MapTrackerCatToNewznab("44");
                            break;

                        case "2160p":
                            release.Category = MapTrackerCatToNewznab("46");
                            break;

                        case "3D":
                            release.Category = MapTrackerCatToNewznab("47");
                            break;

                        default:
                            release.Category = MapTrackerCatToNewznab("45");
                            break;
                        }
                        releases.Add(release);
                    }
                }
            }
            catch (Exception ex)
            {
                OnParseError(response.Content, ex);
            }

            return(releases);
        }
Пример #27
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases        = new List <ReleaseInfo>();
            var queryCollection = new NameValueCollection
            {
                { "active", "0" },
                { "category", string.Join(";", MapTorznabCapsToTrackers(query)) }
            };

            if (query.IsImdbQuery)
            {
                queryCollection.Add("options", "2");
                queryCollection.Add("search", query.ImdbIDShort);
            }
            else
            {
                queryCollection.Add("options", "0");
                queryCollection.Add("search", query.GetQueryString());
            }

            var response = await RequestWithCookiesAndRetryAsync(SearchUrl + queryCollection.GetQueryString());

            try
            {
                var resultParser         = new HtmlParser();
                var searchResultDocument = resultParser.ParseDocument(response.ContentString);
                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 ReleaseInfo();
                    release.MinimumRatio    = 1;
                    release.MinimumSeedTime = 86400; // 24 hours

                    var qLink = row.Children[1].FirstElementChild;
                    release.Title   = qLink.TextContent.Trim();
                    release.Details = new Uri(SiteLink + qLink.GetAttribute("href"));
                    release.Guid    = release.Details;

                    var imdbLink = row.Children[1].QuerySelector("a[href*=imdb]");
                    if (imdbLink != null)
                    {
                        release.Imdb = ParseUtil.GetImdbID(imdbLink.GetAttribute("href").Split('/').Last());
                    }

                    var qDownload = row.Children[3].FirstElementChild;
                    release.Link = new Uri(SiteLink + 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    = ReleaseInfo.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) // side freeleech
                    {
                        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.Category = MapTrackerCatToNewznab(cat);
                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(response.ContentString, ex);
            }

            return(releases);
        }
Пример #28
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases     = new List <ReleaseInfo>();
            var searchString = query.GetQueryString();
            var queryUrl     = SearchUrl;

            var cats = MapTorznabCapsToTrackers(query);

            if (cats.Count == 0)
            {
                cats = GetAllTrackerCategories();
            }

            var catStr = string.Join(";", cats);

            queryUrl += "?" + catStr;

            if (!string.IsNullOrWhiteSpace(query.ImdbID))
            {
                queryUrl += ";q=" + query.ImdbID;
            }
            else
            {
                queryUrl += ";q=" + WebUtilityHelpers.UrlEncode(searchString, Encoding);
            }

            var results = await RequestStringWithCookiesAndRetry(queryUrl);

            // Check for being logged out
            if (results.IsRedirect)
            {
                if (results.RedirectingTo.Contains("login.php"))
                {
                    throw new ExceptionWithConfigData("Login failed, please reconfigure the tracker to update the cookies", configData);
                }
                else
                {
                    throw new ExceptionWithConfigData(string.Format("Got a redirect to {0}, please adjust your the alternative link", results.RedirectingTo), configData);
                }
            }

            try
            {
                dynamic json = JsonConvert.DeserializeObject <dynamic>(results.Content);

                foreach (var torrent in json)
                {
                    var release = new ReleaseInfo();

                    release.Title = torrent.name;
                    if ((query.ImdbID == null || !TorznabCaps.SupportsImdbMovieSearch) && !query.MatchQueryStringAND(release.Title))
                    {
                        continue;
                    }

                    release.MinimumRatio    = 1;
                    release.MinimumSeedTime = 172800; // 48 hours
                    release.Category        = MapTrackerCatToNewznab(torrent.c.ToString());

                    var torrentID = (long)torrent.t;
                    release.Comments    = new Uri(SiteLink + "details.php?id=" + torrentID);
                    release.Guid        = release.Comments;
                    release.Link        = new Uri(SiteLink + "download.php/" + torrentID + "/" + torrentID + ".torrent");
                    release.PublishDate = DateTimeUtil.UnixTimestampToDateTime((long)torrent.ctime).ToLocalTime();

                    release.Size    = (long)torrent.size;
                    release.Seeders = (int)torrent.seeders;
                    release.Peers   = release.Seeders + (int)torrent.leechers;
                    release.Files   = (long)torrent.files;
                    release.Grabs   = (long)torrent.completed;
                    var imdbId = (string)torrent["imdb-id"];
                    release.Imdb = ParseUtil.GetImdbID(imdbId);
                    var downloadMultiplier = (double?)torrent["download-multiplier"];
                    release.DownloadVolumeFactor = downloadMultiplier ?? 1;
                    release.UploadVolumeFactor   = 1;

                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(results.Content, ex);
            }
            return(releases);
        }
Пример #29
0
        public async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query, int attempts)
        {
            var releases     = new List <ReleaseInfo>();
            var searchString = query.GetQueryString();

            var queryCollection = new NameValueCollection();

            if (query.ImdbID != null)
            {
                queryCollection.Add("query_term", query.ImdbID);
            }
            else if (!string.IsNullOrWhiteSpace(searchString))
            {
                searchString = searchString.Replace("'", ""); // ignore ' (e.g. search for america's Next Top Model)
                queryCollection.Add("query_term", searchString);
            }

            var searchUrl = ApiEndpoint + "?" + queryCollection.GetQueryString();
            var response  = await RequestStringWithCookiesAndRetry(searchUrl, string.Empty);

            try
            {
                var jsonContent = JObject.Parse(response.Content);

                string result = jsonContent.Value <string>("status");
                if (result != "ok") // query was not successful
                {
                    return(releases.ToArray());
                }

                var data_items  = jsonContent.Value <JToken>("data");
                int movie_count = data_items.Value <int>("movie_count");
                if (movie_count < 1) // no results found in query
                {
                    return(releases.ToArray());
                }

                foreach (var movie_item in data_items.Value <JToken>("movies"))
                {
                    var torrents = movie_item.Value <JArray>("torrents");
                    if (torrents == null)
                    {
                        continue;
                    }
                    foreach (var torrent_info in torrents)
                    {
                        var release = new ReleaseInfo();

                        // Append the quality to the title because thats how radarr seems to be determining the quality?
                        // All releases are BRRips, see issue #2200
                        release.Title = movie_item.Value <string>("title_long") + " " + torrent_info.Value <string>("quality") + " BRRip";
                        var imdb = movie_item.Value <string>("imdb_code");
                        release.Imdb = ParseUtil.GetImdbID(imdb);

                        // API does not provide magnet link, so, construct it
                        string magnet_uri = "magnet:?xt=urn:btih:" + torrent_info.Value <string>("hash") +
                                            "&dn=" + movie_item.Value <string>("slug") +
                                            "&tr=udp://open.demonii.com:1337/announce" +
                                            "&tr=udp://tracker.openbittorrent.com:80" +
                                            "&tr=udp://tracker.coppersurfer.tk:6969" +
                                            "&tr=udp://glotorrents.pw:6969/announce" +
                                            "&tr=udp://tracker.opentrackr.org:1337/announce" +
                                            "&tr=udp://torrent.gresille.org:80/announce" +
                                            "&tr=udp://p4p.arenabg.com:1337" +
                                            "&tr=udp://tracker.leechers-paradise.org:6969";

                        release.MagnetUri = new Uri(magnet_uri);
                        release.InfoHash  = torrent_info.Value <string>("hash");

                        var dateStr  = torrent_info.Value <long>("date_uploaded_unix");
                        var dateTime = DateTimeUtil.UnixTimestampToDateTime(dateStr);
                        release.PublishDate          = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime();
                        release.Link                 = new Uri(torrent_info.Value <string>("url"));
                        release.Seeders              = torrent_info.Value <int>("seeds");
                        release.Peers                = torrent_info.Value <int>("peers") + release.Seeders;
                        release.Size                 = torrent_info.Value <long>("size_bytes");
                        release.DownloadVolumeFactor = 0;
                        release.UploadVolumeFactor   = 1;

                        release.Comments  = new Uri(movie_item.Value <string>("url"));
                        release.BannerUrl = new Uri(movie_item.Value <string>("medium_cover_image"));
                        release.Guid      = release.Link;

                        // API doesn't provide Categories, resolve via quality
                        release.Category = MapTrackerCatToNewznab("1"); // default
                        if (torrent_info.Value <string>("quality") == "720p")
                        {
                            release.Category = MapTrackerCatToNewznab("1");
                        }
                        if (torrent_info.Value <string>("quality") == "1080p")
                        {
                            release.Category = MapTrackerCatToNewznab("2");
                        }
                        if (torrent_info.Value <string>("quality") == "2160p")
                        {
                            release.Category = MapTrackerCatToNewznab("3");
                        }
                        if (torrent_info.Value <string>("quality") == "3D")
                        {
                            release.Category = MapTrackerCatToNewznab("4");
                        }
                        releases.Add(release);
                    }
                }
            }
            catch (Exception ex)
            {
                OnParseError(response.Content, ex);
            }

            return(releases);
        }
Пример #30
0
        protected override async Task <IEnumerable <ReleaseInfo> > PerformQuery(TorznabQuery query)
        {
            var releases     = new List <ReleaseInfo>();
            var searchString = GetSearchString(query);

            var searchUrl       = APIUrl;
            var queryCollection = new NameValueCollection();

            if (!string.IsNullOrEmpty(query.ImdbID))
            {
                queryCollection.Add("imdbid", query.ImdbID);
            }
            if (searchString != null)
            {
                queryCollection.Add("search", searchString);
            }
            queryCollection.Add("passkey", configData.Passkey.Value);
            queryCollection.Add("user", configData.Username.Value);

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

            var response = await RequestStringWithCookiesAndRetry(searchUrl);

            JObject json = null;

            try
            {
                json = JObject.Parse(response.Content);
            }
            catch (Exception ex)
            {
                throw new Exception("Error while parsing json: " + response.Content, ex);
            }
            var error = (string)json["error"];

            if (error != null)
            {
                throw new Exception(error);
            }

            if ((int)json["total_results"] == 0)
            {
                return(releases);
            }

            try
            {
                foreach (JObject r in json["results"])
                {
                    var release = new ReleaseInfo();
                    release.Title    = (string)r["release_name"];
                    release.Comments = new Uri((string)r["details_url"]);
                    release.Link     = new Uri((string)r["download_url"]);
                    release.Guid     = release.Link;
                    release.Imdb     = ParseUtil.GetImdbID((string)r["imdb_id"]);
                    var freeleech = (bool)r["freeleech"];
                    if (freeleech)
                    {
                        release.DownloadVolumeFactor = 0;
                    }
                    else
                    {
                        release.DownloadVolumeFactor = 1;
                    }
                    release.UploadVolumeFactor = 1;
                    var type = (string)r["type"];
                    release.Category    = MapTrackerCatToNewznab(type);
                    release.Size        = (long?)r["size"] * 1024 * 1024;
                    release.Seeders     = (int?)r["seeders"];
                    release.Peers       = release.Seeders + (int?)r["leechers"];
                    release.PublishDate = DateTimeUtil.FromUnknown((string)r["publish_date"]);
                    releases.Add(release);
                }
            }
            catch (Exception ex)
            {
                OnParseError(response.Content, ex);
            }

            return(releases);
        }