using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; using System.Threading.Tasks; using AngleSharp.Html.Parser; using Jackett.Common.Models; using Jackett.Common.Models.IndexerConfig; 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] public class Partis : BaseWebIndexer { private string LoginUrl => SiteLink + "user/login/"; private string SearchUrl => SiteLink + "torrent/show/"; private new ConfigurationDataBasicLogin configData { get => (ConfigurationDataBasicLogin)base.configData; set => base.configData = value; } public Partis(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps) : base(name: "Partis", description: "Partis is a SLOVENIAN Private Torrent Tracker", link: "https://www.partis.si/", caps: TorznabUtil.CreateDefaultTorznabTVCaps(), configService: configService, client: wc, logger: l, p: ps, configData: new ConfigurationDataBasicLogin()) { Encoding = Encoding.UTF8; Language = "sl-sl"; Type = "private"; // Blu Ray AddCategoryMapping(40, TorznabCatType.MoviesBluRay, "Blu-Ray 1080p/i"); AddCategoryMapping(42, TorznabCatType.MoviesBluRay, "Blu-Ray 720p/i"); AddCategoryMapping(43, TorznabCatType.MoviesBluRay, "Blu-Ray B-Disc"); AddCategoryMapping(41, TorznabCatType.MoviesBluRay, "Blu-Ray 3D"); AddCategoryMapping(44, TorznabCatType.MoviesBluRay, "Blu-Ray Remux"); AddCategoryMapping(45, TorznabCatType.MoviesBluRay, "Blu-Ray Remux/Disc"); // UHD AddCategoryMapping(32, TorznabCatType.MoviesUHD, "UHD 4K Disc"); AddCategoryMapping(55, TorznabCatType.MoviesUHD, "UHD 4K Remux"); // HD AddCategoryMapping(20, TorznabCatType.MoviesHD, "HD"); AddCategoryMapping(4, TorznabCatType.MoviesSD, "DVD-R"); AddCategoryMapping(7, TorznabCatType.MoviesSD, "XviD"); AddCategoryMapping(12, TorznabCatType.MoviesSD, "Anime"); AddCategoryMapping(30, TorznabCatType.MoviesSD, "Risanke"); AddCategoryMapping(15, TorznabCatType.MoviesSD, "Sport"); // TV Show AddCategoryMapping(53, TorznabCatType.TVWEBDL, "TV WEB-DL"); AddCategoryMapping(60, TorznabCatType.TVSD, "TV-XviD"); AddCategoryMapping(38, TorznabCatType.TVSD, "SD-TV"); AddCategoryMapping(51, TorznabCatType.TVHD, "TV 1080p/i"); AddCategoryMapping(52, TorznabCatType.TVHD, "TV 720p/i"); AddCategoryMapping(54, TorznabCatType.MoviesSD, "WEBRip"); AddCategoryMapping(59, TorznabCatType.MoviesWEBDL, "WEB-DL"); AddCategoryMapping(24, TorznabCatType.TVDocumentary, "Dokumentarci"); // Games AddCategoryMapping(10, TorznabCatType.PCGames, "PC igre/ISO"); AddCategoryMapping(11, TorznabCatType.PCGames, "PC igre/Rips/Repack"); AddCategoryMapping(64, TorznabCatType.PCGames, "PC igre/Update & Patch"); // Music AddCategoryMapping(46, TorznabCatType.AudioLossless, "Glasba/Flac"); AddCategoryMapping(8, TorznabCatType.AudioOther, "Glasba/Ostalo"); AddCategoryMapping(47, TorznabCatType.AudioMP3, "Glasba/Mp3"); AddCategoryMapping(8, TorznabCatType.AudioVideo, "Music DVD"); AddCategoryMapping(8, TorznabCatType.AudioVideo, "Videospoti"); AddCategoryMapping(21, TorznabCatType.AudioAudiobook, "AudioBook"); AddCategoryMapping(3, TorznabCatType.BooksEbook, "eKnjige"); } public override async Task ApplyConfiguration(JToken configJson) { LoadValuesFromJson(configJson); var pairs = new Dictionary { { "user[username]", configData.Username.Value }, { "user[password]", configData.Password.Value } }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, false, null, null, true); await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("/odjava"), () => { var parser = new HtmlParser(); var dom = parser.ParseDocument(result.Content); var errorMessage = dom.QuerySelector("div.obvet > span.najvecji").TextContent.Trim(); // Prijava ni uspela! obvestilo throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } protected override async Task> PerformQuery(TorznabQuery query) { var releases = new List(); //List of releases initialization var searchString = query.GetQueryString(); //get search string from query WebClientStringResult results = null; var queryCollection = new NameValueCollection(); var catList = MapTorznabCapsToTrackers(query); // map categories from query to indexer specific var categ = string.Join(",", catList); //create GET request - search URI queryCollection.Add("offset", "0"); queryCollection.Add("keyword", searchString); queryCollection.Add("category", categ.TrimStart(',')); queryCollection.Add("option", ""); queryCollection.Add("ns", "true"); //concatenate base search url with query var searchUrl = SearchUrl + "?" + queryCollection.GetQueryString(); // log search URL logger.Info(string.Format("Searh URL Partis_: {0}", searchUrl)); // add necessary headers var heder = new Dictionary { { "X-requested-with", "XMLHttpRequest" } }; //get results and follow redirect results = await RequestStringWithCookies(searchUrl, null, SearchUrl, heder); await FollowIfRedirect(results, null, null, null, true); // are we logged in? if (!results.Content.Contains("/odjava")) { await ApplyConfiguration(null); } // another request with specific query - NEEDED for succesful response - return data results = await RequestStringWithCookies(SiteLink + "brskaj/?rs=false&offset=0", null, SearchUrl, heder); await FollowIfRedirect(results, null, null, null, true); // parse results try { var RowsSelector = "div.list > div[name=\"torrrow\"]"; var ResultParser = new HtmlParser(); var SearchResultDocument = ResultParser.ParseDocument(results.Content); var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); foreach (var Row in Rows) { try { // initialize REleaseInfo var release = new ReleaseInfo { MinimumRatio = 1, MinimumSeedTime = 0 }; // Get Category var catega = Row.QuerySelector("div.likona div").GetAttribute("alt"); release.Category = MapTrackerCatDescToNewznab(catega); var qDetailsLink = Row.QuerySelector("div.listeklink a"); // Title and torrent link release.Title = qDetailsLink.TextContent; release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href").TrimStart('/')); release.Guid = release.Comments; // Date of torrent creation var liopis = Row.QuerySelector("div.listeklink div span.middle"); var ind = liopis.TextContent.IndexOf("Naloženo:"); var reldate = liopis.TextContent.Substring(ind + 10, 22); release.PublishDate = DateTime.ParseExact(reldate, "dd.MM.yyyy ob HH:mm:ss", CultureInfo.InvariantCulture); // Is freeleech? var checkIfFree = (Row.QuerySelector("div.listeklink div.liopisl img[title=\"freeleech\"]") != null) ? true : false; // Download link var qDownloadLink = Row.QuerySelector("div.data3t a").GetAttribute("href"); release.Link = new Uri(SiteLink + qDownloadLink.TrimStart('/')); // Various data - size, seeders, leechers, download count var sel = Row.QuerySelectorAll("div.datat"); var size = sel[0].TextContent; release.Size = ReleaseInfo.GetBytes(size); release.Seeders = ParseUtil.CoerceInt(sel[1].TextContent); release.Peers = ParseUtil.CoerceInt(sel[2].TextContent) + release.Seeders; release.Grabs = ParseUtil.CoerceLong(sel[3].TextContent); // Set download/upload factor release.DownloadVolumeFactor = checkIfFree ? 0 : 1; release.UploadVolumeFactor = 1; // Add current release to List releases.Add(release); } catch (Exception ex) { logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex)); } } } catch (Exception ex) { OnParseError(results.Content, ex); } return releases; } } }