using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using AngleSharp.Html.Parser; using Jackett.Common.Models; using Jackett.Common.Models.IndexerConfig.Bespoke; using Jackett.Common.Services.Interfaces; using Jackett.Common.Utils; using Jackett.Common.Utils.Clients; using Newtonsoft.Json.Linq; using NLog; namespace Jackett.Common.Indexers { [ExcludeFromCodeCoverage] internal class EliteTracker : BaseWebIndexer { private string LoginUrl => SiteLink + "takelogin.php"; private string BrowseUrl => SiteLink + "browse.php"; private new ConfigurationDataEliteTracker configData => (ConfigurationDataEliteTracker)base.configData; public EliteTracker(IIndexerConfigurationService configService, WebClient webClient, Logger logger, IProtectionService ps, ICacheService cs) : base(id: "elitetracker", name: "Elite-Tracker", description: "French Torrent Tracker", link: "https://elite-tracker.net/", caps: new TorznabCapabilities { 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 } }, configService: configService, logger: logger, p: ps, cacheService: cs, client: webClient, configData: new ConfigurationDataEliteTracker() ) { Encoding = Encoding.UTF8; Language = "fr-fr"; Type = "private"; AddCategoryMapping(27, TorznabCatType.TVAnime, "Animation/Animes"); AddCategoryMapping(90, TorznabCatType.TVAnime, "Animes - 3D"); AddCategoryMapping(99, TorznabCatType.TVAnime, "Animes - 4K"); AddCategoryMapping(63, TorznabCatType.TVAnime, "Animes - DVD"); AddCategoryMapping(56, TorznabCatType.TVAnime, "Animes - HD"); AddCategoryMapping(89, TorznabCatType.TVAnime, "Animes - HDRip"); AddCategoryMapping(87, TorznabCatType.TVAnime, "Animes - Pack"); AddCategoryMapping(88, TorznabCatType.TVAnime, "Animes - SD"); AddCategoryMapping(59, TorznabCatType.TVAnime, "Animes - Serie"); AddCategoryMapping(3, TorznabCatType.PC0day, "APPLICATION"); AddCategoryMapping(74, TorznabCatType.PCMobileAndroid, "APPLICATION - ANDROID"); AddCategoryMapping(57, TorznabCatType.PCMobileiOS, "APPLICATION - IPHONE"); AddCategoryMapping(6, TorznabCatType.PC0day, "APPLICATION - LINUX"); AddCategoryMapping(5, TorznabCatType.PCMac, "APPLICATION - MAC"); AddCategoryMapping(4, TorznabCatType.PC0day, "APPLICATION - WINDOWS"); AddCategoryMapping(38, TorznabCatType.TVDocumentary, "DOCUMENTAIRES"); AddCategoryMapping(97, TorznabCatType.TVDocumentary, "DOCUMENTAIRES - PACK"); AddCategoryMapping(34, TorznabCatType.Books, "EBOOKS"); AddCategoryMapping(86, TorznabCatType.Books, "EBOOKS - ABOOKS"); AddCategoryMapping(48, TorznabCatType.MoviesHD, "FiLMS HD"); AddCategoryMapping(51, TorznabCatType.MoviesHD, "FiLMS HD - 1080p"); AddCategoryMapping(98, TorznabCatType.MoviesUHD, "FiLMS HD - 2160p"); AddCategoryMapping(70, TorznabCatType.Movies3D, "FiLMS HD - 3D"); AddCategoryMapping(84, TorznabCatType.MoviesUHD, "FiLMS HD - 4K"); AddCategoryMapping(50, TorznabCatType.MoviesHD, "FiLMS HD - 720P"); AddCategoryMapping(49, TorznabCatType.MoviesBluRay, "FiLMS HD - BluRay"); AddCategoryMapping(78, TorznabCatType.MoviesHD, "FiLMS HD - HDRip"); AddCategoryMapping(105, TorznabCatType.MoviesUHD, "FiLMS HD - VOSTFR 4k"); AddCategoryMapping(95, TorznabCatType.MoviesHD, "FiLMS HD - VOSTFR HD"); AddCategoryMapping(85, TorznabCatType.MoviesHD, "FiLMS HD - x265"); AddCategoryMapping(7, TorznabCatType.Movies, "FiLMS SD"); AddCategoryMapping(91, TorznabCatType.Movies3D, "FiLMS SD - 3D"); AddCategoryMapping(11, TorznabCatType.MoviesDVD, "FiLMS SD - DVD"); AddCategoryMapping(53, TorznabCatType.MoviesSD, "FiLMS SD - DVD-SCREENER"); AddCategoryMapping(9, TorznabCatType.MoviesDVD, "FiLMS SD - R5"); AddCategoryMapping(8, TorznabCatType.MoviesSD, "FiLMS SD - SCREENER"); AddCategoryMapping(10, TorznabCatType.MoviesSD, "FiLMS SD - SDRip"); AddCategoryMapping(40, TorznabCatType.Movies, "FiLMS SD - VO"); AddCategoryMapping(39, TorznabCatType.Movies, "FiLMS SD - VOSTFR"); AddCategoryMapping(15, TorznabCatType.Console, "JEUX VIDEO"); AddCategoryMapping(76, TorznabCatType.Console3DS, "JEUX VIDEO - 3DS"); AddCategoryMapping(18, TorznabCatType.ConsoleNDS, "JEUX VIDEO - DS"); AddCategoryMapping(55, TorznabCatType.PCMobileiOS, "JEUX VIDEO - IPHONE"); AddCategoryMapping(80, TorznabCatType.PCGames, "JEUX VIDEO - LINUX"); AddCategoryMapping(96, TorznabCatType.ConsoleOther, "JEUX VIDEO - NSW"); AddCategoryMapping(79, TorznabCatType.PCMac, "JEUX VIDEO - OSX"); AddCategoryMapping(22, TorznabCatType.PCGames, "JEUX VIDEO - PC"); AddCategoryMapping(66, TorznabCatType.ConsolePS3, "JEUX VIDEO - PS2"); AddCategoryMapping(58, TorznabCatType.ConsolePS3, "JEUX VIDEO - PS3"); AddCategoryMapping(81, TorznabCatType.ConsolePS4, "JEUX VIDEO - PS4"); AddCategoryMapping(20, TorznabCatType.ConsolePSP, "JEUX VIDEO - PSP"); AddCategoryMapping(75, TorznabCatType.ConsolePS3, "JEUX VIDEO - PSX"); AddCategoryMapping(19, TorznabCatType.ConsoleWii, "JEUX VIDEO - WII"); AddCategoryMapping(83, TorznabCatType.ConsoleWiiU, "JEUX VIDEO - WiiU"); AddCategoryMapping(16, TorznabCatType.ConsoleXBox, "JEUX VIDEO - XBOX"); AddCategoryMapping(82, TorznabCatType.ConsoleXBoxOne, "JEUX VIDEO - XBOX ONE"); AddCategoryMapping(17, TorznabCatType.ConsoleXBox360, "JEUX VIDEO - XBOX360"); AddCategoryMapping(23, TorznabCatType.Audio, "MUSIQUES"); AddCategoryMapping(26, TorznabCatType.Audio, "MUSIQUES - CLIP/CONCERT"); AddCategoryMapping(61, TorznabCatType.AudioLossless, "MUSIQUES - FLAC"); AddCategoryMapping(60, TorznabCatType.AudioMP3, "MUSIQUES - MP3"); AddCategoryMapping(30, TorznabCatType.TV, "SERIES"); AddCategoryMapping(77, TorznabCatType.TVSD, "SERIES - DVD"); AddCategoryMapping(100, TorznabCatType.TVUHD, "SERIES - 4k"); AddCategoryMapping(67, TorznabCatType.TVHD, "SERIES - FR HD"); AddCategoryMapping(31, TorznabCatType.TVSD, "SERIES - FR SD"); AddCategoryMapping(102, TorznabCatType.TVUHD, "SERIES - Pack 4k"); AddCategoryMapping(92, TorznabCatType.TVHD, "SERIES - Pack FR HD"); AddCategoryMapping(73, TorznabCatType.TVSD, "SERIES - Pack FR SD"); AddCategoryMapping(94, TorznabCatType.TVHD, "SERIES - Pack VOSTFR HD"); AddCategoryMapping(93, TorznabCatType.TVSD, "SERIES - Pack VOSTFR SD"); AddCategoryMapping(68, TorznabCatType.TVHD, "SERIES - VO HD"); AddCategoryMapping(32, TorznabCatType.TVSD, "SERIES - VO SD"); AddCategoryMapping(101, TorznabCatType.TVUHD, "SERIES - 4k"); AddCategoryMapping(69, TorznabCatType.TVHD, "SERIES - VOSTFR HD"); AddCategoryMapping(33, TorznabCatType.TVSD, "SERIES - VOSTFR SD"); AddCategoryMapping(47, TorznabCatType.TV, "SPECTACLES/EMISSIONS"); AddCategoryMapping(71, TorznabCatType.TV, "SPECTACLES/EMISSIONS - Emissions"); AddCategoryMapping(103, TorznabCatType.TV, "SPECTACLES/EMISSIONS - Emissions Pack"); AddCategoryMapping(72, TorznabCatType.TV, "SPECTACLES/EMISSIONS - Spectacles"); AddCategoryMapping(35, TorznabCatType.TVSport, "SPORT"); AddCategoryMapping(36, TorznabCatType.TVSport, "SPORT - CATCH"); AddCategoryMapping(65, TorznabCatType.TVSport, "SPORT - UFC"); AddCategoryMapping(37, TorznabCatType.XXX, "XXX"); } public override async Task ApplyConfiguration(JToken configJson) { LoadValuesFromJson(configJson); var pairs = new Dictionary { { "username", configData.Username.Value }, { "password", configData.Password.Value } }; var result = await RequestWithCookiesAsync(LoginUrl, "", RequestType.POST, data: pairs); await ConfigureIfOK(result.Cookies, result.Cookies != null, () => { var errorMessage = result.ContentString; throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } protected override async Task> PerformQuery(TorznabQuery query) { var releases = new List(); var pairs = new Dictionary { {"do", "search"}, {"search_type", query.IsImdbQuery ? "t_genre" : "t_name"}, {"keywords", query.IsImdbQuery ? query.ImdbID : query.GetQueryString()}, {"category", "0"} // multi cat search not supported }; var results = await RequestWithCookiesAsync(BrowseUrl, method: RequestType.POST, data: pairs); if (results.IsRedirect) { // re-login await ApplyConfiguration(null); results = await RequestWithCookiesAsync(BrowseUrl, method: RequestType.POST, data: pairs); } try { var lastDate = DateTime.Now; var parser = new HtmlParser(); var doc = parser.ParseDocument(results.ContentString); var rows = doc.QuerySelectorAll("table[id='sortabletable'] > tbody > tr"); foreach (var row in rows.Skip(1)) { if (row.Children.Length != 9) continue; // not a torrent line var cat = row.Children[0].QuerySelector("a").GetAttribute("href").Split('=')[1]; var title = row.Children[1].QuerySelector("a").TextContent; var qLinks = row.Children[2].QuerySelectorAll("a"); var link = new Uri(configData.TorrentHTTPSMode.Value ? qLinks[1].GetAttribute("href") : qLinks[0].GetAttribute("href")); var details = new Uri(row.Children[1].QuerySelector("a").GetAttribute("href")); var size = row.Children[4].TextContent; var grabs = row.Children[5].QuerySelector("a").TextContent; var seeders = ParseUtil.CoerceInt(row.Children[6].QuerySelector("a").TextContent); var leechers = ParseUtil.CoerceInt(row.Children[7].QuerySelector("a").TextContent); var qTags = row.Children[1].QuerySelector("div:has(span[style=\"float: right;\"])"); var dlVolumeFactor = 1.0; if (qTags.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null) dlVolumeFactor = 0.0; else if (qTags.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null) dlVolumeFactor = 0.5; var upVolumeFactor = qTags.QuerySelector("img[alt^=\"TORRENT X2\"]") != null ? 2.0 : 1.0; var release = new ReleaseInfo { MinimumRatio = 1, MinimumSeedTime = 172800, Category = MapTrackerCatToNewznab(cat), Title = title, Link = link, Details = details, Size = ReleaseInfo.GetBytes(size), Seeders = seeders, Grabs = ParseUtil.CoerceLong(grabs), DownloadVolumeFactor = dlVolumeFactor, UploadVolumeFactor = upVolumeFactor, Peers = leechers + seeders, Guid = link }; var qTooltip = row.Children[1].QuerySelector("div.tooltip-content"); if (qTooltip != null) { var qPoster = qTooltip.QuerySelector("img"); if (qPoster != null) { release.Poster = new Uri(qPoster.GetAttribute("src")); qPoster.Remove(); } qTooltip.QuerySelector("div:contains(\"Total Hits\")").Remove(); var qLongTitle = qTooltip.QuerySelector("div"); release.Title = qLongTitle.TextContent; qLongTitle.Remove(); var description = qTooltip.TextContent.Trim(); if (!string.IsNullOrWhiteSpace(description)) release.Description = description; } // issue #5064 replace multi keyword if (!string.IsNullOrEmpty(configData.ReplaceMulti.Value)) { var regex = new Regex("(?i)([\\.\\- ])MULTI([\\.\\- ])"); release.Title = regex.Replace(release.Title, "$1" + configData.ReplaceMulti.Value + "$2"); } // issue #6855 Replace VOSTFR with ENGLISH if (configData.Vostfr.Value) release.Title = release.Title.Replace("VOSTFR", "ENGLISH").Replace("SUBFRENCH", "ENGLISH"); var qPretime = qTags.QuerySelector("font.mkprettytime"); if (qPretime != null) { if (release.Description == null) release.Description = qPretime.TextContent; else release.Description += "
\n" + qPretime.TextContent; release.PublishDate = lastDate; } else { release.PublishDate = DateTime.ParseExact(qTags.TextContent.Trim(), "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture); lastDate = release.PublishDate; } releases.Add(release); } } catch (Exception ex) { OnParseError(results.ContentString, ex); } return releases; } } }