diff --git a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs index 763861a27..bd850f27a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs @@ -20,399 +20,391 @@ using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.Indexers.Definitions +namespace NzbDrone.Core.Indexers.Definitions; + +public class PreToMe : TorrentIndexerBase { - public class PreToMe : TorrentIndexerBase + public override string Name => "PreToMe"; + public override string[] IndexerUrls => new[] { "https://pretome.info/" }; + public override string Description => "PreToMe is a ratioless 0Day/General tracker."; + public override string Language => "en-US"; + 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 PreToMe(IIndexerHttpClient httpClient, + IEventAggregator eventAggregator, + IIndexerStatusService indexerStatusService, + IConfigService configService, + Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { - public override string Name => "PreToMe"; - public override string[] IndexerUrls => new string[] { "https://pretome.info/" }; - public override string Description => "PreToMe is a ratioless 0Day/General tracker."; - private string LoginUrl => Settings.BaseUrl + "takelogin.php"; - public override string Language => "en-US"; - 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 PreToMe(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } + } - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new PreToMeRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new PreToMeRequestGenerator(Settings, Capabilities); + } - public override IParseIndexerResponse GetParser() + public override IParseIndexerResponse GetParser() + { + return new PreToMeParser(Settings, Capabilities.Categories); + } + + protected override async Task DoLogin() + { + UpdateCookies(null, null); + + var loginPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl + "login.php")); + + var loginUrl = Settings.BaseUrl + "takelogin.php"; + var requestBuilder = new HttpRequestBuilder(loginUrl) { - return new PreToMeParser(Settings, Capabilities.Categories); + LogResponseContent = true, + AllowAutoRedirect = true, + Method = HttpMethod.Post + }; + requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); + + var authLoginRequest = requestBuilder + .SetCookies(loginPage.GetCookies()) + .AddFormParameter("username", Settings.Username) + .AddFormParameter("password", Settings.Password) + .AddFormParameter("login_pin", Settings.Pin) + .AddFormParameter("returnto", "%2F") + .AddFormParameter("login", "Login") + .SetHeader("Content-Type", "application/x-www-form-urlencoded") + .Build(); + + var response = await ExecuteAuth(authLoginRequest); + + if (response.Content == null) + { + throw new IndexerAuthException("Authentication failed. Reason: empty response."); } - protected override async Task DoLogin() + if (CheckIfLoginNeeded(response)) { - UpdateCookies(null, null); - - var requestBuilder = new HttpRequestBuilder(LoginUrl) - { - LogResponseContent = true, - AllowAutoRedirect = true - }; + var parser = new HtmlParser(); + var dom = parser.ParseDocument(response.Content); + var errorMessage = dom.QuerySelector("table.body_table font[color~=\"red\"]")?.TextContent.Trim(); - var loginPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl + "login.php")); + throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report."); + } - requestBuilder.Method = HttpMethod.Post; - requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); - requestBuilder.SetCookies(loginPage.GetCookies()); + UpdateCookies(response.GetCookies(), DateTime.Now + TimeSpan.FromDays(30)); - var authLoginRequest = requestBuilder - .AddFormParameter("returnto", "%2F") - .AddFormParameter("login_pin", Settings.Pin) - .AddFormParameter("login", "Login") - .AddFormParameter("username", Settings.Username) - .AddFormParameter("password", Settings.Password) - .SetHeader("Content-Type", "multipart/form-data") - .Build(); + _logger.Debug("Authentication succeeded"); + } - var response = await ExecuteAuth(authLoginRequest); + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + return httpResponse.HasHttpRedirect || !httpResponse.Content.Contains("logout.php"); + } - if (response.Content != null && response.Content.Contains("logout.php")) + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List { - UpdateCookies(response.GetCookies(), DateTime.Now + TimeSpan.FromDays(30)); - _logger.Debug("PreToMe authentication succeeded"); - } - else + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + }, + MovieSearchParams = new List { - throw new IndexerAuthException("PreToMe authentication failed"); - } - } - - protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) - { - if (httpResponse.HasHttpRedirect || !httpResponse.Content.Contains("logout.php")) + MovieSearchParam.Q, MovieSearchParam.ImdbId + }, + MusicSearchParams = new List + { + MusicSearchParam.Q + }, + BookSearchParams = new List { - return true; + BookSearchParam.Q } + }; + + caps.Categories.AddCategoryMapping("cat[]=22", NewznabStandardCategory.PC, "Applications"); + caps.Categories.AddCategoryMapping("cat[]=22&tags=Windows", NewznabStandardCategory.PC0day, "Applications/Windows"); + caps.Categories.AddCategoryMapping("cat[]=22&tags=MAC", NewznabStandardCategory.PCMac, "Applications/MAC"); + caps.Categories.AddCategoryMapping("cat[]=22&tags=Linux", NewznabStandardCategory.PC, "Applications/Linux"); + + caps.Categories.AddCategoryMapping("cat[]=27", NewznabStandardCategory.BooksEBook, "Ebooks"); + + caps.Categories.AddCategoryMapping("cat[]=4", NewznabStandardCategory.Console, "Games"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=PC", NewznabStandardCategory.PCGames, "Games/PC"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=RIP", NewznabStandardCategory.PCGames, "Games/RIP"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=ISO", NewznabStandardCategory.PCGames, "Games/ISO"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=XBOX360", NewznabStandardCategory.ConsoleXBox360, "Games/XBOX360"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=PS3", NewznabStandardCategory.ConsolePS3, "Games/PS3"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=Wii", NewznabStandardCategory.ConsoleWii, "Games/Wii"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=PSP", NewznabStandardCategory.ConsolePSP, "Games/PSP"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=GAMES-NSW", NewznabStandardCategory.ConsoleOther, "Games/NSW"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=NDS", NewznabStandardCategory.ConsoleNDS, "Games/NDS"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=Xbox", NewznabStandardCategory.ConsoleXBox, "Games/Xbox"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=NSW", NewznabStandardCategory.ConsoleOther, "Games/NSW"); + caps.Categories.AddCategoryMapping("cat[]=4&tags=PS2", NewznabStandardCategory.ConsoleOther, "Games/PS2"); + + caps.Categories.AddCategoryMapping("cat[]=31", NewznabStandardCategory.Other, "Miscellaneous"); + caps.Categories.AddCategoryMapping("cat[]=31&tags=Ebook", NewznabStandardCategory.BooksEBook, "Miscellaneous/Ebook"); + caps.Categories.AddCategoryMapping("cat[]=31&tags=RARFiX", NewznabStandardCategory.Other, "Miscellaneous/RARFiX"); + + caps.Categories.AddCategoryMapping("cat[]=19", NewznabStandardCategory.Movies, "Movies"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=x264", NewznabStandardCategory.Movies, "Movies/x264"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=720p", NewznabStandardCategory.MoviesHD, "Movies/720p"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=XviD", NewznabStandardCategory.MoviesSD, "Movies/XviD"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=BluRay", NewznabStandardCategory.MoviesHD, "Movies/BluRay"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=DVDRiP", NewznabStandardCategory.MoviesSD, "Movies/DVDRiP"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=1080p", NewznabStandardCategory.MoviesHD, "Movies/1080p"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=DVD", NewznabStandardCategory.MoviesSD, "Movies/DVD"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=DVDR", NewznabStandardCategory.MoviesSD, "Movies/DVDR"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=WMV", NewznabStandardCategory.Movies, "Movies/WMV"); + caps.Categories.AddCategoryMapping("cat[]=19&tags=CAM", NewznabStandardCategory.Movies, "Movies/CAM"); + + caps.Categories.AddCategoryMapping("cat[]=6", NewznabStandardCategory.Audio, "Music"); + caps.Categories.AddCategoryMapping("cat[]=6&tags=MP3", NewznabStandardCategory.AudioMP3, "Music/MP3"); + caps.Categories.AddCategoryMapping("cat[]=6&tags=V2", NewznabStandardCategory.AudioMP3, "Music/V2"); + caps.Categories.AddCategoryMapping("cat[]=6&tags=FLAC", NewznabStandardCategory.AudioLossless, "Music/FLAC"); + caps.Categories.AddCategoryMapping("cat[]=6&tags=320kbps", NewznabStandardCategory.AudioMP3, "Music/320kbps"); + + caps.Categories.AddCategoryMapping("cat[]=7", NewznabStandardCategory.TV, "TV"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=x264", NewznabStandardCategory.TVHD, "TV/x264"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=720p", NewznabStandardCategory.TVHD, "TV/720p"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=HDTV", NewznabStandardCategory.TVHD, "TV/HDTV"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=XviD", NewznabStandardCategory.TVSD, "TV/XviD"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=BluRay", NewznabStandardCategory.TVHD, "TV/BluRay"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=DVDRiP", NewznabStandardCategory.TVSD, "TV/DVDRiP"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=DVD", NewznabStandardCategory.TVSD, "TV/DVD"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=Documentary", NewznabStandardCategory.TVDocumentary, "TV/Documentary"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=PDTV", NewznabStandardCategory.TVSD, "TV/PDTV"); + caps.Categories.AddCategoryMapping("cat[]=7&tags=HD-DVD", NewznabStandardCategory.TVSD, "TV/HD-DVD"); + + caps.Categories.AddCategoryMapping("cat[]=51", NewznabStandardCategory.XXX, "XXX"); + caps.Categories.AddCategoryMapping("cat[]=51&tags=XviD", NewznabStandardCategory.XXXXviD, "XXX/XviD"); + caps.Categories.AddCategoryMapping("cat[]=51&tags=DVDRiP", NewznabStandardCategory.XXXDVD, "XXX/DVDRiP"); + + return caps; + } +} - return false; - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId - }, - MovieSearchParams = new List - { - MovieSearchParam.Q, MovieSearchParam.ImdbId - }, - MusicSearchParams = new List - { - MusicSearchParam.Q - }, - BookSearchParams = new List - { - BookSearchParam.Q - } - }; +public class PreToMeRequestGenerator : IIndexerRequestGenerator +{ + private readonly PreToMeSettings _settings; + private readonly IndexerCapabilities _capabilities; - caps.Categories.AddCategoryMapping("cat[]=22", NewznabStandardCategory.PC, "Applications"); - caps.Categories.AddCategoryMapping("cat[]=22&tags=Windows", NewznabStandardCategory.PC0day, "Applications/Windows"); - caps.Categories.AddCategoryMapping("cat[]=22&tags=MAC", NewznabStandardCategory.PCMac, "Applications/MAC"); - caps.Categories.AddCategoryMapping("cat[]=22&tags=Linux", NewznabStandardCategory.PC, "Applications/Linux"); - - caps.Categories.AddCategoryMapping("cat[]=27", NewznabStandardCategory.BooksEBook, "Ebooks"); - - caps.Categories.AddCategoryMapping("cat[]=4", NewznabStandardCategory.Console, "Games"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=PC", NewznabStandardCategory.PCGames, "Games/PC"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=RIP", NewznabStandardCategory.PCGames, "Games/RIP"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=ISO", NewznabStandardCategory.PCGames, "Games/ISO"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=XBOX360", NewznabStandardCategory.ConsoleXBox360, "Games/XBOX360"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=PS3", NewznabStandardCategory.ConsolePS3, "Games/PS3"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=Wii", NewznabStandardCategory.ConsoleWii, "Games/Wii"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=PSP", NewznabStandardCategory.ConsolePSP, "Games/PSP"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=GAMES-NSW", NewznabStandardCategory.ConsoleOther, "Games/NSW"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=NDS", NewznabStandardCategory.ConsoleNDS, "Games/NDS"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=Xbox", NewznabStandardCategory.ConsoleXBox, "Games/Xbox"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=NSW", NewznabStandardCategory.ConsoleOther, "Games/NSW"); - caps.Categories.AddCategoryMapping("cat[]=4&tags=PS2", NewznabStandardCategory.ConsoleOther, "Games/PS2"); - - caps.Categories.AddCategoryMapping("cat[]=31", NewznabStandardCategory.Other, "Miscellaneous"); - caps.Categories.AddCategoryMapping("cat[]=31&tags=Ebook", NewznabStandardCategory.BooksEBook, "Miscellaneous/Ebook"); - caps.Categories.AddCategoryMapping("cat[]=31&tags=RARFiX", NewznabStandardCategory.Other, "Miscellaneous/RARFiX"); - - caps.Categories.AddCategoryMapping("cat[]=19", NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=x264", NewznabStandardCategory.Movies, "Movies/x264"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=720p", NewznabStandardCategory.MoviesHD, "Movies/720p"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=XviD", NewznabStandardCategory.MoviesSD, "Movies/XviD"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=BluRay", NewznabStandardCategory.MoviesHD, "Movies/BluRay"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=DVDRiP", NewznabStandardCategory.MoviesSD, "Movies/DVDRiP"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=1080p", NewznabStandardCategory.MoviesHD, "Movies/1080p"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=DVD", NewznabStandardCategory.MoviesSD, "Movies/DVD"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=DVDR", NewznabStandardCategory.MoviesSD, "Movies/DVDR"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=WMV", NewznabStandardCategory.Movies, "Movies/WMV"); - caps.Categories.AddCategoryMapping("cat[]=19&tags=CAM", NewznabStandardCategory.Movies, "Movies/CAM"); - - caps.Categories.AddCategoryMapping("cat[]=6", NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping("cat[]=6&tags=MP3", NewznabStandardCategory.AudioMP3, "Music/MP3"); - caps.Categories.AddCategoryMapping("cat[]=6&tags=V2", NewznabStandardCategory.AudioMP3, "Music/V2"); - caps.Categories.AddCategoryMapping("cat[]=6&tags=FLAC", NewznabStandardCategory.AudioLossless, "Music/FLAC"); - caps.Categories.AddCategoryMapping("cat[]=6&tags=320kbps", NewznabStandardCategory.AudioMP3, "Music/320kbps"); - - caps.Categories.AddCategoryMapping("cat[]=7", NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=x264", NewznabStandardCategory.TVHD, "TV/x264"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=720p", NewznabStandardCategory.TVHD, "TV/720p"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=HDTV", NewznabStandardCategory.TVHD, "TV/HDTV"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=XviD", NewznabStandardCategory.TVSD, "TV/XviD"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=BluRay", NewznabStandardCategory.TVHD, "TV/BluRay"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=DVDRiP", NewznabStandardCategory.TVSD, "TV/DVDRiP"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=DVD", NewznabStandardCategory.TVSD, "TV/DVD"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=Documentary", NewznabStandardCategory.TVDocumentary, "TV/Documentary"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=PDTV", NewznabStandardCategory.TVSD, "TV/PDTV"); - caps.Categories.AddCategoryMapping("cat[]=7&tags=HD-DVD", NewznabStandardCategory.TVSD, "TV/HD-DVD"); - - caps.Categories.AddCategoryMapping("cat[]=51", NewznabStandardCategory.XXX, "XXX"); - caps.Categories.AddCategoryMapping("cat[]=51&tags=XviD", NewznabStandardCategory.XXXXviD, "XXX/XviD"); - caps.Categories.AddCategoryMapping("cat[]=51&tags=DVDRiP", NewznabStandardCategory.XXXDVD, "XXX/DVDRiP"); - - return caps; - } + public PreToMeRequestGenerator(PreToMeSettings settings, IndexerCapabilities capabilities) + { + _settings = settings; + _capabilities = capabilities; } - public class PreToMeRequestGenerator : IIndexerRequestGenerator + private IEnumerable GetPagedRequests(string term, int[] categories, string imdbId = null) { - public PreToMeSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } + // NameValueCollection don't support cat[]=19&cat[]=6 + var parameters = new List> + { + { "st", "1" } // search in title + }; - public PreToMeRequestGenerator() + if (imdbId.IsNotNullOrWhiteSpace()) { + parameters.Add("search", imdbId); + parameters.Add("sd", "1"); // search in description } - - private IEnumerable GetPagedRequests(string term, int[] categories, string imdbId = null) + else { - var searchUrl = string.Format("{0}/browse.php", Settings.BaseUrl.TrimEnd('/')); + parameters.Add("search", term); + } - var qc = new List> // NameValueCollection don't support cat[]=19&cat[]=6 - { - { "st", "1" } // search in title - }; + // parse categories and tags + var catGroups = new HashSet(); + var tagGroups = new HashSet(); - if (imdbId.IsNotNullOrWhiteSpace()) - { - qc.Add("search", imdbId); - qc.Add("sd", "1"); // search in description - } - else + var cats = _capabilities.Categories.MapTorznabCapsToTrackers(categories); + foreach (var cat in cats) + { + // "cat[]=7&tags=x264" + var cSplit = cat.Split('&'); + + var gSplit = cSplit[0].Split('='); + if (gSplit.Length > 1) { - qc.Add("search", term); + catGroups.Add(gSplit[1]); // category = 7 } - // parse categories and tags - var catGroups = new HashSet(); // HashSet instead of List to avoid duplicates - var tagGroups = new HashSet(); - var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories); - foreach (var cat in cats) + if (cSplit.Length > 1) { - // "cat[]=7&tags=x264" - var cSplit = cat.Split('&'); - - var gSplit = cSplit[0].Split('='); - if (gSplit.Length > 1) + var tSplit = cSplit[1].Split('='); + if (tSplit.Length > 1) { - catGroups.Add(gSplit[1]); // category = 7 - } - - if (cSplit.Length > 1) - { - var tSplit = cSplit[1].Split('='); - if (tSplit.Length > 1) - { - tagGroups.Add(tSplit[1]); // tag = x264 - } + tagGroups.Add(tSplit[1]); // tag = x264 } } - - // add categories - foreach (var cat in catGroups) - { - qc.Add("cat[]", cat); - } - - // do not include too many tags as it'll mess with their servers - if (tagGroups.Count < 7) - { - qc.Add("tags", string.Join(",", tagGroups)); - - // if tags are specified match any - // if no tags are specified match all, with any we get random results - qc.Add("tf", tagGroups.Any() ? "any" : "all"); - } - - searchUrl = searchUrl + "?" + qc.GetQueryString(); - - var request = new IndexerRequest(searchUrl, HttpAccept.Html); - - request.HttpRequest.AllowAutoRedirect = false; - - yield return request; } - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + // add categories + foreach (var cat in catGroups) { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; + parameters.Add("cat[]", cat); } - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + // do not include too many tags as it'll mess with their servers + if (tagGroups.Count < 7) { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + parameters.Add("tags", string.Join(",", tagGroups)); - return pageableRequests; + // if tags are specified match any + // if no tags are specified match all, with any we get random results + parameters.Add("tf", tagGroups.Any() ? "any" : "all"); } - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + var searchUrl = $"{_settings.BaseUrl}browse.php"; - return pageableRequests; + if (parameters.Count > 0) + { + searchUrl += $"?{parameters.GetQueryString()}"; } - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + var request = new IndexerRequest(searchUrl, HttpAccept.Html) { - var pageableRequests = new IndexerPageableRequestChain(); + HttpRequest = + { + AllowAutoRedirect = false + } + }; - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + yield return request; + } - return pageableRequests; - } + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, searchCriteria.FullImdbId)); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + return pageableRequests; + } - return pageableRequests; - } + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - public Func> GetCookies { get; set; } - public Action, DateTime?> CookiesUpdater { get; set; } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories)); + + return pageableRequests; } - public class PreToMeParser : IParseIndexerResponse + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) { - private readonly PreToMeSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; + var pageableRequests = new IndexerPageableRequestChain(); - public PreToMeParser(PreToMeSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedTvSearchString}", searchCriteria.Categories, searchCriteria.FullImdbId)); - public IList ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List(); + return pageableRequests; + } - var parser = new HtmlParser(); - var dom = parser.ParseDocument(indexerResponse.Content); - var rows = dom.QuerySelectorAll("table > tbody > tr.browse"); - foreach (var row in rows) - { - var qLink = row.Children[1].QuerySelector("a"); - var title = qLink.GetAttribute("title"); - if (qLink.QuerySelectorAll("span").Length == 1 && title.StartsWith("NEW! |")) - { - title = title.Substring(6).Trim(); - } + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); - // TODO: Asses if we should be throwing this out - //if (!query.MatchQueryStringAND(title)) - //{ - // continue; // we have to skip bad titles due to tags + any word search - //} - var details = _settings.BaseUrl + qLink.GetAttribute("href"); - var link = _settings.BaseUrl + row.Children[2].QuerySelector("a").GetAttribute("href"); - var dateStr = Regex.Replace(row.Children[5].InnerHtml, @"\", " "); - var publishDate = DateTimeUtil.FromTimeAgo(dateStr); - var files = ParseUtil.CoerceInt(row.Children[3].TextContent); - var size = ParseUtil.GetBytes(row.Children[7].TextContent); - var grabs = ParseUtil.CoerceInt(row.Children[8].TextContent); - var seeders = ParseUtil.CoerceInt(row.Children[9].TextContent); - var leechers = ParseUtil.CoerceInt(row.Children[10].TextContent); - var cat = row.FirstElementChild.FirstElementChild.GetAttribute("href").Replace("browse.php?", string.Empty); - - var release = new TorrentInfo - { - Title = title, - InfoUrl = details, - Guid = details, - DownloadUrl = link, - PublishDate = publishDate, - Size = size, - Categories = _categories.MapTrackerCatToNewznab(cat), - Files = files, - Grabs = grabs, - Seeders = seeders, - Peers = leechers + seeders, - MinimumRatio = 0.75, - MinimumSeedTime = 216000, // 60 hours - DownloadVolumeFactor = 0, // ratioless - UploadVolumeFactor = 1 - }; - - torrentInfos.Add(release); - } + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories)); - return torrentInfos.ToArray(); - } + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories)); - public Action, DateTime?> CookiesUpdater { get; set; } + return pageableRequests; } - public class PreToMeSettingsValidator : NoAuthSettingsValidator + public Func> GetCookies { get; set; } + public Action, DateTime?> CookiesUpdater { get; set; } +} + +public class PreToMeParser : IParseIndexerResponse +{ + private readonly PreToMeSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public PreToMeParser(PreToMeSettings settings, IndexerCapabilitiesCategories categories) { - public PreToMeSettingsValidator() - { - RuleFor(c => c.Pin).NotEmpty(); - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } + _settings = settings; + _categories = categories; } - public class PreToMeSettings : NoAuthTorrentBaseSettings + public IList ParseResponse(IndexerResponse indexerResponse) { - private static readonly PreToMeSettingsValidator Validator = new (); + var releaseInfos = new List(); - public PreToMeSettings() + var parser = new HtmlParser(); + var dom = parser.ParseDocument(indexerResponse.Content); + + var rows = dom.QuerySelectorAll("table > tbody > tr.browse"); + foreach (var row in rows) { - Pin = ""; - Username = ""; - Password = ""; - } + var qDetails = row.QuerySelector("a[href^=\"details.php?id=\"]"); + var title = qDetails?.GetAttribute("title"); - [FieldDefinition(2, Label = "Pin", HelpText = "Site Pin", Privacy = PrivacyLevel.Password)] - public string Pin { get; set; } + var infoUrl = _settings.BaseUrl + qDetails.GetAttribute("href"); + var downloadUrl = _settings.BaseUrl + row.QuerySelector("a[href^=\"download.php\"]")?.GetAttribute("href"); - [FieldDefinition(3, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } + var dateAdded = Regex.Replace(row.QuerySelector("td:nth-of-type(6)").InnerHtml, @"\", " ").Trim(); - [FieldDefinition(4, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } + var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)")?.TextContent); + var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(11)")?.TextContent); - public override NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); + var cat = row.QuerySelector("td:nth-of-type(1) a[href^=\"browse.php\"]")?.GetAttribute("href")?.Split('?').Last(); + + var release = new TorrentInfo + { + Guid = infoUrl, + InfoUrl = infoUrl, + DownloadUrl = downloadUrl, + Title = title, + Categories = _categories.MapTrackerCatToNewznab(cat), + PublishDate = DateTimeUtil.FromTimeAgo(dateAdded), + Size = ParseUtil.GetBytes(row.QuerySelector("td:nth-of-type(8)")?.TextContent), + Files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(4)")?.TextContent), + Grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)")?.TextContent), + Seeders = seeders, + Peers = leechers + seeders, + DownloadVolumeFactor = 0, // ratioless + UploadVolumeFactor = 1, + MinimumRatio = 0.75, + MinimumSeedTime = 216000 // 60 hours + }; + + releaseInfos.Add(release); } + + return releaseInfos.ToArray(); + } + + public Action, DateTime?> CookiesUpdater { get; set; } +} + +public class PreToMeSettingsValidator : UserPassBaseSettingsValidator +{ + public PreToMeSettingsValidator() + { + RuleFor(c => c.Pin).NotEmpty(); + } +} + +public class PreToMeSettings : UserPassTorrentBaseSettings +{ + private static readonly PreToMeSettingsValidator Validator = new (); + + [FieldDefinition(4, Label = "Pin", HelpText = "Site Pin", Privacy = PrivacyLevel.Password)] + public string Pin { get; set; } + + public override NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); } }