diff --git a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs index d80e3b032..7d3111527 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs @@ -5,11 +5,9 @@ using System.Globalization; using System.Linq; using System.Net.Http; using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; using AngleSharp.Dom; using AngleSharp.Html.Parser; -using FluentValidation; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; @@ -21,386 +19,331 @@ using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.ThingiProvider; -using NzbDrone.Core.Validation; -namespace NzbDrone.Core.Indexers.Definitions +namespace NzbDrone.Core.Indexers.Definitions; + +public class NorBits : TorrentIndexerBase { - public class NorBits : TorrentIndexerBase + public override string Name => "NorBits"; + public override string[] IndexerUrls => new[] { "https://norbits.net/" }; + public override string Description => "NorBits is a Norwegian Private site for MOVIES / TV / GENERAL"; + public override string Language => "nb-NO"; + public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1"); + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public NorBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { - public override string Name => "NorBits"; - public override string[] IndexerUrls => new string[] { "https://norbits.net/" }; - public override string Description => "NorBits is a Norwegian Private site for MOVIES / TV / GENERAL"; - public override string Language => "nb-NO"; - public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1"); - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public NorBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } + } - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new NorBitsRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new NorBitsRequestGenerator(Settings, Capabilities); + } - public override IParseIndexerResponse GetParser() - { - return new NorBitsParser(Settings, Capabilities.Categories); - } + public override IParseIndexerResponse GetParser() + { + return new NorBitsParser(Settings, Capabilities.Categories); + } - protected override async Task DoLogin() + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl) { - var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl) - { - LogResponseContent = true, - AllowAutoRedirect = true - }; + LogResponseContent = true, + AllowAutoRedirect = true + }; - var indexPage = await ExecuteAuth(requestBuilder.Build()); + var indexPage = await ExecuteAuth(requestBuilder.Build()); - var loginUrl = string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "login.php"); + var loginUrl = $"{Settings.BaseUrl.TrimEnd('/')}/login.php"; - var requestBuilder2 = new HttpRequestBuilder(loginUrl) - { - LogResponseContent = true, - AllowAutoRedirect = true - }; + var requestBuilder2 = new HttpRequestBuilder(loginUrl) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; - var authLoginRequest = requestBuilder2 - .SetCookies(indexPage.GetCookies()) - .Build(); + var authLoginRequest = requestBuilder2 + .SetCookies(indexPage.GetCookies()) + .Build(); - // Get login page -- (not used, but simulation needed by tracker security's checks) - await ExecuteAuth(authLoginRequest); + // Get login page -- (not used, but simulation needed by tracker security's checks) + await ExecuteAuth(authLoginRequest); - var requestBuilder3 = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "takelogin.php")) - { - LogResponseContent = true, - AllowAutoRedirect = true, - Method = HttpMethod.Post - }; - - var authLoginCheckRequest = requestBuilder3 - .AddFormParameter("username", Settings.Username) - .AddFormParameter("password", Settings.Password) - .SetCookies(indexPage.GetCookies()) - .SetHeader("Referer", loginUrl) - .Build(); + var requestBuilder3 = new HttpRequestBuilder($"{Settings.BaseUrl.TrimEnd('/')}/takelogin.php") + { + LogResponseContent = true, + AllowAutoRedirect = true, + Method = HttpMethod.Post + }; - var loginResponse = await ExecuteAuth(authLoginCheckRequest); + var authLoginCheckRequest = requestBuilder3 + .AddFormParameter("username", Settings.Username) + .AddFormParameter("password", Settings.Password) + .SetCookies(indexPage.GetCookies()) + .SetHeader("Referer", loginUrl) + .Build(); - if (!loginResponse.GetCookies().ContainsKey("uid")) - { - // Default error message - var message = "Error during attempt !"; + var loginResponse = await ExecuteAuth(authLoginCheckRequest); - // Oops, unable to login - _logger.Info("NorBits - Login failed: " + message, "error"); + if (!loginResponse.GetCookies().ContainsKey("uid")) + { + throw new IndexerAuthException("Login failed"); + } - throw new IndexerAuthException(message); - } + var cookies = loginResponse.GetCookies(); + UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); - var cookies = loginResponse.GetCookies(); - UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); + _logger.Debug("Authentication succeeded."); + } - _logger.Debug("NorBits authentication succeeded."); - } + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + return !httpResponse.Content.Contains("logout.php"); + } - protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities { - if (!httpResponse.Content.Contains("logout.php")) + TvSearchParams = new List + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + }, + MusicSearchParams = new List { - return true; + MusicSearchParam.Q + }, + BookSearchParams = new List + { + BookSearchParam.Q } + }; + + caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=49", NewznabStandardCategory.MoviesUHD, "Filmer - UHD-2160p"); + caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=19", NewznabStandardCategory.MoviesHD, "Filmer - HD-1080p/i"); + caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=20", NewznabStandardCategory.MoviesHD, "Filmer - HD-720p"); + caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=22", NewznabStandardCategory.MoviesSD, "Filmer - SD"); + caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=49", NewznabStandardCategory.TVUHD, "TV - UHD-2160p"); + caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=19", NewznabStandardCategory.TVHD, "TV - HD-1080p/i"); + caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=20", NewznabStandardCategory.TVHD, "TV - HD-720p"); + caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=22", NewznabStandardCategory.TVSD, "TV - SD"); + caps.Categories.AddCategoryMapping("main_cat[]=3", NewznabStandardCategory.PC, "Programmer"); + caps.Categories.AddCategoryMapping("main_cat[]=4", NewznabStandardCategory.Console, "Spill"); + caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=42", NewznabStandardCategory.AudioMP3, "Musikk - 192"); + caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=43", NewznabStandardCategory.AudioMP3, "Musikk - 256"); + caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=44", NewznabStandardCategory.AudioMP3, "Musikk - 320"); + caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=45", NewznabStandardCategory.AudioMP3, "Musikk - VBR"); + caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=46", NewznabStandardCategory.AudioLossless, "Musikk - Lossless"); + caps.Categories.AddCategoryMapping("main_cat[]=6", NewznabStandardCategory.Books, "Tidsskrift"); + caps.Categories.AddCategoryMapping("main_cat[]=7", NewznabStandardCategory.AudioAudiobook, "Lydbøker"); + caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=19", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-1080p/i"); + caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=20", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-720p"); + caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=22", NewznabStandardCategory.AudioVideo, "Musikkvideoer - SD"); + caps.Categories.AddCategoryMapping("main_cat[]=40", NewznabStandardCategory.AudioOther, "Podcasts"); + + return caps; + } +} - return false; - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List - { - MovieSearchParam.Q, MovieSearchParam.ImdbId - }, - MusicSearchParams = new List - { - MusicSearchParam.Q - }, - BookSearchParams = new List - { - BookSearchParam.Q - } - }; +public class NorBitsRequestGenerator : IIndexerRequestGenerator +{ + private readonly NorBitsSettings _settings; + private readonly IndexerCapabilities _capabilities; - caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=49", NewznabStandardCategory.MoviesUHD, "Filmer - UHD-2160p"); - caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=19", NewznabStandardCategory.MoviesHD, "Filmer - HD-1080p/i"); - caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=20", NewznabStandardCategory.MoviesHD, "Filmer - HD-720p"); - caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=22", NewznabStandardCategory.MoviesSD, "Filmer - SD"); - caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=49", NewznabStandardCategory.TVUHD, "TV - UHD-2160p"); - caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=19", NewznabStandardCategory.TVHD, "TV - HD-1080p/i"); - caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=20", NewznabStandardCategory.TVHD, "TV - HD-720p"); - caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=22", NewznabStandardCategory.TVSD, "TV - SD"); - caps.Categories.AddCategoryMapping("main_cat[]=3", NewznabStandardCategory.PC, "Programmer"); - caps.Categories.AddCategoryMapping("main_cat[]=4", NewznabStandardCategory.Console, "Spill"); - caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=42", NewznabStandardCategory.AudioMP3, "Musikk - 192"); - caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=43", NewznabStandardCategory.AudioMP3, "Musikk - 256"); - caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=44", NewznabStandardCategory.AudioMP3, "Musikk - 320"); - caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=45", NewznabStandardCategory.AudioMP3, "Musikk - VBR"); - caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=46", NewznabStandardCategory.AudioLossless, "Musikk - Lossless"); - caps.Categories.AddCategoryMapping("main_cat[]=6", NewznabStandardCategory.Books, "Tidsskrift"); - caps.Categories.AddCategoryMapping("main_cat[]=7", NewznabStandardCategory.AudioAudiobook, "Lydbøker"); - caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=19", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-1080p/i"); - caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=20", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-720p"); - caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=22", NewznabStandardCategory.AudioVideo, "Musikkvideoer - SD"); - caps.Categories.AddCategoryMapping("main_cat[]=40", NewznabStandardCategory.AudioOther, "Podcasts"); - - return caps; - } + public NorBitsRequestGenerator(NorBitsSettings settings, IndexerCapabilities capabilities) + { + _settings = settings; + _capabilities = capabilities; } - public class NorBitsRequestGenerator : IIndexerRequestGenerator + private IEnumerable GetPagedRequests(string term, int[] categories, string imdbId = null) { - public NorBitsSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } + var searchUrl = $"{_settings.BaseUrl.TrimEnd('/')}/browse.php"; - public NorBitsRequestGenerator() + var parameters = new NameValueCollection { - } + { "incldead", "1" }, + { "fullsearch", _settings.UseFullSearch ? "1" : "0" }, + { "scenerelease", "0" } + }; - private IEnumerable GetPagedRequests(string term, int[] categories, string imdbId = null) - { - var searchUrl = string.Format("{0}/browse.php", Settings.BaseUrl.TrimEnd('/')); + var searchTerm = "search="; - var parameters = new NameValueCollection(); - var categoriesList = Capabilities.Categories.MapTorznabCapsToTrackers(categories); - var searchterm = term; - - // Building our tracker query - parameters.Add("incldead", "1"); - parameters.Add("fullsearch", Settings.UseFullSearch ? "1" : "0"); - parameters.Add("scenerelease", "0"); + if (!string.IsNullOrWhiteSpace(imdbId)) + { + searchTerm = "imdbsearch=" + imdbId; + } + else if (!string.IsNullOrWhiteSpace(term)) + { + searchTerm = "search=" + term.UrlEncode(Encoding.GetEncoding(28591)); + } - // If search term provided - if (!string.IsNullOrWhiteSpace(imdbId)) - { - searchterm = "imdbsearch=" + imdbId; - } - else if (!string.IsNullOrWhiteSpace(term)) - { - searchterm = "search=" + term.UrlEncode(Encoding.GetEncoding(28591)); - } - else - { - // Showing all torrents (just for output function) - searchterm = "search="; - } + searchUrl += "?" + searchTerm + "&" + parameters.GetQueryString(); - var catQryStr = ""; + var categoriesList = _capabilities.Categories.MapTorznabCapsToTrackers(categories); + if (categoriesList.Any()) + { + searchUrl += "&" + string.Join("&", categoriesList); + } - foreach (var cat in categoriesList) - { - catQryStr += "&" + cat; - } + var request = new IndexerRequest(searchUrl, HttpAccept.Html); - // Building our query - searchUrl += "?" + searchterm + "&" + parameters.GetQueryString() + "&" + catQryStr; + yield return request; + } - var request = new IndexerRequest(searchUrl, HttpAccept.Html); + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - yield return request; - } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, searchCriteria.FullImdbId)); - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); + return pageableRequests; + } - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - return pageableRequests; - } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories)); - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); + return pageableRequests; + } - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - return pageableRequests; - } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedTvSearchString}", searchCriteria.Categories, searchCriteria.FullImdbId)); - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); + return pageableRequests; + } - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - return pageableRequests; - } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories)); - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); + return pageableRequests; + } - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - return pageableRequests; - } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories)); - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); + return pageableRequests; + } - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + public Func> GetCookies { get; set; } + public Action, DateTime?> CookiesUpdater { get; set; } +} - return pageableRequests; - } +public class NorBitsParser : IParseIndexerResponse +{ + private readonly NorBitsSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; - public Func> GetCookies { get; set; } - public Action, DateTime?> CookiesUpdater { get; set; } + public NorBitsParser(NorBitsSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; } - public class NorBitsParser : IParseIndexerResponse + public IList ParseResponse(IndexerResponse indexerResponse) { - private readonly NorBitsSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; + var releaseInfos = new List(); - public NorBitsParser(NorBitsSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } + var parser = new HtmlParser(); + var dom = parser.ParseDocument(indexerResponse.Content); - public IList ParseResponse(IndexerResponse indexerResponse) + var rows = dom.QuerySelectorAll("#torrentTable > tbody > tr").Skip(1).ToCollection(); + + foreach (var row in rows) { - var torrentInfos = new List(); + var link = _settings.BaseUrl + row.QuerySelector("td:nth-of-type(2) > a[href*=\"download.php?id=\"]")?.GetAttribute("href").TrimStart('/'); + var qDetails = row.QuerySelector("td:nth-of-type(2) > a[href*=\"details.php?id=\"]"); + + var title = qDetails?.GetAttribute("title").Trim(); + var details = _settings.BaseUrl + qDetails?.GetAttribute("href").TrimStart('/'); - var parser = new HtmlParser(); - var dom = parser.ParseDocument(indexerResponse.Content); + var mainCategory = row.QuerySelector("td:nth-of-type(1) > div > a[href*=\"main_cat[]\"]")?.GetAttribute("href")?.Split('?').Last(); + var secondCategory = row.QuerySelector("td:nth-of-type(1) > div > a[href*=\"sub2_cat[]\"]")?.GetAttribute("href")?.Split('?').Last(); - var firstPageRows = dom.QuerySelectorAll("#torrentTable > tbody > tr").Skip(1).ToCollection(); + var categoryList = new[] { mainCategory, secondCategory }; + var cat = string.Join("&", categoryList.Where(c => !string.IsNullOrWhiteSpace(c))); - // If pagination available - int nbResults; + var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent); + var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent); - // Check if we have a minimum of one result - if (firstPageRows?.Length >= 1) + var release = new TorrentInfo { - // Retrieve total count on our alone page - nbResults = firstPageRows.Count(); - } - else + Guid = details, + InfoUrl = details, + DownloadUrl = link, + Title = title, + Categories = _categories.MapTrackerCatToNewznab(cat), + Size = ParseUtil.GetBytes(row.QuerySelector("td:nth-of-type(7)")?.TextContent), + Files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(3) > a")?.TextContent.Trim()), + Grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(8)")?.FirstChild?.TextContent.Trim()), + Seeders = seeders, + Peers = seeders + leechers, + PublishDate = DateTime.ParseExact(row.QuerySelector("td:nth-of-type(5)")?.TextContent.Trim(), "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture), + DownloadVolumeFactor = 1, + UploadVolumeFactor = 1, + MinimumRatio = 1, + MinimumSeedTime = 172800 // 48 hours + }; + + var genres = row.QuerySelector("span.genres")?.TextContent; + if (!string.IsNullOrEmpty(genres)) { - // No result found for this query - return torrentInfos; + genres = genres.Trim().Replace("\xA0", " ").Replace("(", "").Replace(")", "").Replace(" | ", ","); + release.Description = genres; + release.Genres = genres.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(); } - var torrentDetailsUrl = _settings.BaseUrl + "details.php?id={id}"; - var torrentDownloadUrl = _settings.BaseUrl + "download.php?id={id}&passkey={passkey}"; + var imdbLink = row.QuerySelector("a[href*=\"imdb.com/title/tt\"]")?.GetAttribute("href"); + release.ImdbId = ParseUtil.GetImdbID(imdbLink) ?? 0; - // Loop on results - foreach (var row in firstPageRows) + if (row.QuerySelector("img[title=\"100% freeleech\"]") != null) + { + release.DownloadVolumeFactor = 0; + } + else if (row.QuerySelector("img[title=\"Halfleech\"]") != null) { - var id = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("href").Split('=').Last(); // ID - var name = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("title"); // Release Name - var categoryName = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("title"); // Category - var mainCat = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("href").Split('?').Last(); - var qSubCat2 = row.QuerySelector("td:nth-of-type(1) > div > a[href^=\"/browse.php?sub2_cat[]=\"]"); - var cat = mainCat; - if (qSubCat2 != null) - { - cat += '&' + qSubCat2.GetAttribute("href").Split('?').Last(); - } - - var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent); // Seeders - var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent); // Leechers - var regexObj = new Regex(@"[^\d]"); // Completed - var completed2 = row.QuerySelector("td:nth-of-type(8)").TextContent; - var completed = ParseUtil.CoerceInt(regexObj.Replace(completed2, "")); - var qFiles = row.QuerySelector("td:nth-of-type(3) > a"); // Files - var files = qFiles != null ? ParseUtil.CoerceInt(Regex.Match(qFiles.TextContent, @"\d+").Value) : 1; - var humanSize = row.QuerySelector("td:nth-of-type(7)").TextContent.ToLowerInvariant(); // Size - var size = ParseUtil.GetBytes(humanSize); // Date - var dateTimeOrig = row.QuerySelector("td:nth-of-type(5)").TextContent; - var dateTime = Regex.Replace(dateTimeOrig, @"<[^>]+>| ", "").Trim(); - var date = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); - var details = new Uri(torrentDetailsUrl.Replace("{id}", id.ToString())); // Description Link - var passkey = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(2)").GetAttribute("href"); // Download Link - var key = Regex.Match(passkey, "(?<=passkey\\=)([a-zA-z0-9]*)"); - var downloadLink = new Uri(torrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{passkey}", key.ToString())); - - // Building release infos - var release = new TorrentInfo - { - Categories = _categories.MapTrackerCatToNewznab(cat), - Title = name, - Seeders = seeders, - Peers = seeders + leechers, - PublishDate = date, - Size = size, - Files = files, - Grabs = completed, - Guid = details.AbsoluteUri, - InfoUrl = details.AbsoluteUri, - DownloadUrl = downloadLink.AbsoluteUri, - MinimumRatio = 1, - MinimumSeedTime = 172800 // 48 hours - }; - - var genres = row.QuerySelector("span.genres")?.TextContent; - if (!string.IsNullOrEmpty(genres)) - { - release.Description = genres; - } - - // IMDB - var imdbLink = row.QuerySelector("a[href*=\"imdb.com/title/tt\"]")?.GetAttribute("href"); - release.ImdbId = ParseUtil.GetImdbID(imdbLink) ?? 0; - - if (row.QuerySelector("img[title=\"100% freeleech\"]") != null) - { - release.DownloadVolumeFactor = 0; - } - else if (row.QuerySelector("img[title=\"Halfleech\"]") != null) - { - release.DownloadVolumeFactor = 0.5; - } - else if (row.QuerySelector("img[title=\"90% Freeleech\"]") != null) - { - release.DownloadVolumeFactor = 0.1; - } - else - { - release.DownloadVolumeFactor = 1; - } - - release.UploadVolumeFactor = 1; - - torrentInfos.Add(release); + release.DownloadVolumeFactor = 0.5; + } + else if (row.QuerySelector("img[title=\"90% Freeleech\"]") != null) + { + release.DownloadVolumeFactor = 0.1; } - return torrentInfos.ToArray(); + releaseInfos.Add(release); } - public Action, DateTime?> CookiesUpdater { get; set; } + return releaseInfos.ToArray(); } - public class NorBitsSettings : UserPassTorrentBaseSettings - { - public NorBitsSettings() - { - } + public Action, DateTime?> CookiesUpdater { get; set; } +} - [FieldDefinition(4, Label = "Use Full Search", HelpText = "Use Full Search from Site", Type = FieldType.Checkbox)] - public bool UseFullSearch { get; set; } +public class NorBitsSettings : UserPassTorrentBaseSettings +{ + public NorBitsSettings() + { + UseFullSearch = false; } + + [FieldDefinition(4, Label = "Use Full Search", HelpText = "Use Full Search from Site", Type = FieldType.Checkbox)] + public bool UseFullSearch { get; set; } }