diff --git a/src/Jackett.Common/Definitions/partis.yml b/src/Jackett.Common/Definitions/partis.yml
new file mode 100644
index 000000000..a9d1ea839
--- /dev/null
+++ b/src/Jackett.Common/Definitions/partis.yml
@@ -0,0 +1,168 @@
+---
+id: partis
+name: Partis
+description: "Partis is a Private SLOVENIAN Torrent Tracker for MOVIES / TV / BOOKS / GENERAL"
+language: sl-SI
+type: private
+encoding: UTF-8
+links:
+ - https://www.partis.si/
+
+caps:
+ categorymappings:
+ # Movies / Filmi
+ - {id: 7, cat: Movies, desc: "Xvid"}
+ - {id: 20, cat: Movies/HD, desc: "HD"}
+ - {id: 55, cat: Movies/UHD, desc: "UHD 4K Remux"}
+ - {id: 32, cat: Movies/UHD, desc: "UHD 4K Disc"}
+ - {id: 40, cat: Movies/BluRay, desc: "Blu-ray 1080p/i"}
+ - {id: 41, cat: Movies/3D, desc: "Blu-ray 3D"}
+ - {id: 42, cat: Movies/BluRay, desc: "Blu-ray 720p/i"}
+ - {id: 43, cat: Movies/BluRay, desc: "Blu-ray B-Disc"}
+ - {id: 44, cat: Movies/BluRay, desc: "Blu-ray Remux"}
+ - {id: 45, cat: Movies/BluRay, desc: "Blu-ray"}
+ - {id: 4, cat: Movies/DVD, desc: "DVD-R"}
+ - {id: 54, cat: Movies/WEB-DL, desc: "WEBRip"}
+ - {id: 59, cat: Movies/WEB-DL, desc: "WEB-DL"}
+ - {id: 30, cat: Movies/Other, desc: "Risanke"}
+ # TV
+ - {id: 17, cat: TV/HD, desc: "HD-TV"}
+ - {id: 31, cat: TV/HD, desc: "HD-TV"}
+ - {id: 38, cat: TV/SD, desc: "SD-TV"}
+ - {id: 51, cat: TV/HD, desc: "TV 1080p/i"}
+ - {id: 52, cat: TV/SD, desc: "TV 720p/i"}
+ - {id: 53, cat: TV/WEB-DL, desc: "TV WEB-DL"}
+ - {id: 5, cat: TV/Sport, desc: "Sport"}
+ - {id: 2, cat: TV/Anime, desc: "Anime"}
+ - {id: 24, cat: TV/Documentary, desc: "Dokumentarci"}
+ # Games / Igre
+ - {id: 10, cat: PC/Games, desc: "PC igre/ISO"}
+ - {id: 11, cat: PC/Games, desc: "PC igre/Rips/Repack"}
+ - {id: 13, cat: Console, desc: "PS2"}
+ - {id: 12, cat: Console/PSP, desc: "PSP"}
+ - {id: 28, cat: Console/PS3, desc: "PS3"}
+ - {id: 63, cat: Console/PS4, desc: "PS4"}
+ - {id: 27, cat: Console/Wii, desc: "Wii"}
+ - {id: 14, cat: Console/XBox, desc: "XboX"}
+ - {id: 49, cat: PC/Games, desc: "Mac Igre"}
+ - {id: 48, cat: PC/Games, desc: "Linux Igre"}
+ - {id: 64, cat: PC/Games, desc: "PC igre/Update & Patch"}
+ # Music / Glasba
+ - {id: 8, cat: Audio, desc: "Glasba/Ostalo"}
+ - {id: 47, cat: Audio/MP3, desc: "Glasba/Mp3"}
+ - {id: 46, cat: Audio/Lossless, desc: "Glasba/Flac"}
+ - {id: 23, cat: Audio/Video, desc: "Videospoti"}
+ - {id: 22, cat: Audio/Video, desc: "Music DVD"}
+ # Programs / Programi
+ - {id: 15, cat: PC, desc: "PC programi/drugo"}
+ - {id: 16, cat: PC/ISO, desc: "PC programi/ISO"}
+ - {id: 58, cat: PC/Mac, desc: "Mac programi"}
+ - {id: 50, cat: PC, desc: "Linux programi"}
+ # XXX
+# only works for exactly categories cat=18,36,35,37,56,39 in this order
+# - {id: 18, cat: XXX, desc: "XXX-HD"}
+# - {id: 36, cat: XXX/XviD, desc: "XXX-XviD"}
+# - {id: 35, cat: XXX, desc: "XXX-Clip"}
+# - {id: 37, cat: XXX, desc: "XXX 37"}
+# - {id: 39, cat: XXX, desc: "XXX 39"}
+# - {id: 56, cat: XXX, desc: "XXX 56"}
+ # Other / Ostalo
+ - {id: 3, cat: Books/EBook, desc: "eKnjige"}
+ - {id: 19, cat: Other, desc: "Slike"}
+ - {id: 21, cat: Audio/Audiobook, desc: "AudioBook"}
+ - {id: 9, cat: PC/Mobile-Other, desc: "GBA"}
+ - {id: 25, cat: PC/Mobile-Other, desc: "GSM/Igre"}
+ - {id: 26, cat: PC/Mobile-Android, desc: "PDA"}
+ - {id: 29, cat: PC/Mobile-iOS, desc: "Ipod"}
+ - {id: 61, cat: PC/Mobile-Other, desc: "GSM/Programi"}
+ - {id: 62, cat: PC/Mobile-Other, desc: "GSM/Ostalo"}
+
+ modes:
+ search: [q]
+ tv-search: [q, season, ep]
+ movie-search: [q]
+ music-search: [q]
+ book-search: [q]
+
+settings:
+ - name: username
+ type: text
+ label: Username
+ - name: password
+ type: password
+ label: Password
+# broken on website
+# - name: freeleech
+# type: checkbox
+# label: Search freeleech only
+# default: false
+ - name: sort
+ type: select
+ label: Sort results
+ default: " "
+ options:
+ " ": "Added descending"
+ "seeders ASC": "Seeders ascending"
+ "seeders DESC": "Seeders descending"
+ "leechers ASC": "Leechers ascending"
+ "leechers DESC": "Leechers descending"
+ "size ASC": "Size ascending"
+ "size DESC": "Size descending"
+
+login:
+ method: post
+ path: user/login
+ inputs:
+ user: "{{ .Config.username }}"
+ pass: "{{ .Config.password }}"
+ test:
+ path: torrent/search
+
+search:
+ paths:
+ - path: /torrent/search
+ inputs:
+ q: "{{ .Keywords }}"
+ cat: "{{ join .Categories \",\" }}"
+ order: "{{ if eq .Config.sort \" \" }}{{ else }}{{ .Config.sort }}{{ end }}"
+ preprocessingfilters:
+ # Extract torrent information from the json array that is part of the response and transform it into html form
+ - name: re_replace
+ args: ["\\[(\\d+),(\\d+),(\\d+),\"([^\"]+?)\",(\\d+),(\\d+),\"([^\"]+?)\",(\\d+),([\\d.]+?),\"([^\"]+?)\",\"([^\"]+?)\",\"([^\"]+?)\".*?\\],?", "$1$2$3$4$5$6$7$8$9$10$11$12"]
+ # Remove javascript and keep only ...
+ - name: re_replace
+ args: ["^.*?(.*<\\\/torrent>).*|.*", "$1"]
+
+ rows:
+ selector: torrent
+
+ fields:
+ category:
+ selector: torrent_category_id
+ title:
+ selector: title
+ _id:
+ selector: fid
+ details:
+ text: "{{ .Config.sitelink }}portal#torrent/{{ .Result._id }}"
+ download:
+ text: "{{ .Config.sitelink }}torrent/download/{{ .Result._id }}"
+ poster:
+ selector: poster
+ date:
+ selector: created_at
+ size:
+ selector: size
+ leechers:
+ selector: leechers
+ seeders:
+ selector: seeders
+ downloadvolumefactor:
+ text: 1
+ uploadvolumefactor:
+ text: 1
+ minimumratio:
+ text: 1.0
+ description:
+ selector: short_description
+# engine n/a
diff --git a/src/Jackett.Common/Indexers/Partis.cs b/src/Jackett.Common/Indexers/Partis.cs
deleted file mode 100644
index dd96e421e..000000000
--- a/src/Jackett.Common/Indexers/Partis.cs
+++ /dev/null
@@ -1,265 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Diagnostics.CodeAnalysis;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-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;
-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/search/";
-
- private new ConfigurationDataBasicLogin configData
- {
- get => (ConfigurationDataBasicLogin)base.configData;
- set => base.configData = value;
- }
-
- public Partis(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps,
- ICacheService cs)
- : base(id: "partis",
- name: "Partis",
- description: "Partis is a SLOVENIAN Private Torrent Tracker",
- link: "https://www.partis.si/",
- caps: new TorznabCapabilities
- {
- TvSearchParams = new List
- {
- TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
- },
- MovieSearchParams = new List
- {
- MovieSearchParam.Q
- },
- MusicSearchParams = new List
- {
- MusicSearchParam.Q
- },
- BookSearchParams = new List
- {
- BookSearchParam.Q
- }
- },
- configService: configService,
- client: wc,
- logger: l,
- p: ps,
- cacheService: cs,
- configData: new ConfigurationDataBasicLogin())
- {
- Encoding = Encoding.UTF8;
- Language = "sl-SL";
- Type = "private";
-
- // Movies
- AddCategoryMapping(40, TorznabCatType.MoviesHD, "Blu-ray 1080p/i");
- AddCategoryMapping(42, TorznabCatType.MoviesHD, "Blu-ray 720p/i");
- AddCategoryMapping(43, TorznabCatType.MoviesBluRay, "Blu-ray B-Disc");
- AddCategoryMapping(41, TorznabCatType.Movies3D, "Blu-ray 3D");
- AddCategoryMapping(44, TorznabCatType.MoviesHD, "Blu-ray Remux");
- AddCategoryMapping(45, TorznabCatType.MoviesBluRay, "Blu-ray Remux/Disc");
- AddCategoryMapping(32, TorznabCatType.MoviesBluRay, "UHD 4K Disc");
- AddCategoryMapping(55, TorznabCatType.MoviesUHD, "UHD 4K Remux");
- AddCategoryMapping(20, TorznabCatType.MoviesHD, "HD");
- AddCategoryMapping(4, TorznabCatType.MoviesDVD, "DVD-R");
- AddCategoryMapping(7, TorznabCatType.MoviesSD, "XviD");
- AddCategoryMapping(30, TorznabCatType.MoviesOther, "Risanke");
- AddCategoryMapping(54, TorznabCatType.MoviesWEBDL, "WEBRip");
- AddCategoryMapping(59, TorznabCatType.MoviesWEBDL, "WEB-DL");
- AddCategoryMapping(24, TorznabCatType.TVDocumentary, "Dokumentarci");
-
- // TV
- AddCategoryMapping(53, TorznabCatType.TVWEBDL, "TV WEB-DL");
- AddCategoryMapping(60, TorznabCatType.TVSD, "TV-XviD");
- AddCategoryMapping(38, TorznabCatType.TVSD, "SD-TV");
- AddCategoryMapping(17, TorznabCatType.TVHD, "HD-TV (1)");
- AddCategoryMapping(31, TorznabCatType.TVHD, "HD-TV (2)");
- AddCategoryMapping(51, TorznabCatType.TVHD, "TV 1080p/i");
- AddCategoryMapping(52, TorznabCatType.TVHD, "TV 720p/i");
- AddCategoryMapping(5, TorznabCatType.TVSport, "Sport");
- AddCategoryMapping(2, TorznabCatType.TVAnime, "Anime");
-
- // Games
- AddCategoryMapping(10, TorznabCatType.PCGames, "PC igre/ISO");
- AddCategoryMapping(11, TorznabCatType.PCGames, "PC igre/Rips/Repack");
- AddCategoryMapping(64, TorznabCatType.PCGames, "PC igre/Update & Patch");
- AddCategoryMapping(13, TorznabCatType.ConsolePSP, "PSP");
- AddCategoryMapping(12, TorznabCatType.ConsoleOther, "PS2");
- AddCategoryMapping(28, TorznabCatType.ConsolePS3, "PS3");
- AddCategoryMapping(63, TorznabCatType.ConsolePS4, "PS4");
- AddCategoryMapping(27, TorznabCatType.ConsoleWii, "Wii");
- AddCategoryMapping(14, TorznabCatType.ConsoleXBox, "XboX");
- AddCategoryMapping(49, TorznabCatType.PCGames, "Mac Igre");
- AddCategoryMapping(48, TorznabCatType.PCGames, "Linux Igre");
-
- // Music
- AddCategoryMapping(46, TorznabCatType.AudioLossless, "Glasba/Flac");
- AddCategoryMapping(8, TorznabCatType.AudioOther, "Glasba/Ostalo");
- AddCategoryMapping(47, TorznabCatType.AudioMP3, "Glasba/Mp3");
- AddCategoryMapping(22, TorznabCatType.AudioVideo, "Music DVD");
- AddCategoryMapping(23, TorznabCatType.AudioVideo, "Videospoti");
-
- // Programs
- AddCategoryMapping(15, TorznabCatType.PC, "PC programi/drugo");
- AddCategoryMapping(58, TorznabCatType.PCMac, "Mac Programi");
- AddCategoryMapping(16, TorznabCatType.PCISO, "PC programi/ISO");
- AddCategoryMapping(50, TorznabCatType.PC, "Linux programi");
-
- // Other
- AddCategoryMapping(21, TorznabCatType.AudioAudiobook, "AudioBook");
- AddCategoryMapping(3, TorznabCatType.BooksEBook, "eKnjige");
- AddCategoryMapping(19, TorznabCatType.Other, "Slike");
- AddCategoryMapping(9, TorznabCatType.ConsoleNDS, "GBA");
- AddCategoryMapping(25, TorznabCatType.PCMobileAndroid, "GSM/Igre");
- AddCategoryMapping(26, TorznabCatType.PCMobileAndroid, "PDA");
- AddCategoryMapping(61, TorznabCatType.PCMobileAndroid, "GSM/Programi");
- AddCategoryMapping(62, TorznabCatType.PCMobileAndroid, "GSM/Ostalo");
- AddCategoryMapping(29, TorznabCatType.PCMobileiOS, "iPOD");
- }
-
- public override async Task ApplyConfiguration(JToken configJson)
- {
- LoadValuesFromJson(configJson);
-
- var pairs = new Dictionary
- {
- { "user", configData.Username.Value },
- { "pass", configData.Password.Value }
- };
-
- var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, false, null, null, true);
- await ConfigureIfOK(result.Cookies, result.ContentString != null && result.Cookies.Contains("udata"), () =>
- {
- var errorMessage = "Login failed. Invalid username or password.";
- 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
-
- WebResult 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
- if (!string.IsNullOrEmpty(searchString))
- queryCollection.Add("q", searchString);
- queryCollection.Add("cat", categ.TrimStart(','));
-
- // concatenate base search url with query
- var searchUrl = $"{SearchUrl}?{queryCollection.GetQueryString()}";
-
- // add necessary headers
- var header = new Dictionary
- {
- { "X-requested-with", "XMLHttpRequest" }
- };
-
- // get results and follow redirect
- results = await RequestWithCookiesAsync(searchUrl, referer: SearchUrl, headers: header);
- if (results.ContentString.Contains("Internal server error"))
- throw new Exception("Partis is offline, returning an Internal server error");
- // parse results
- try
- {
- // successful search returns javascript code containing 'data' variable with actual torrent descriptions.
- // find this variable and extract its value
- var resultDataJson = Regex.Match(results.ContentString, @"data( |=)*(?\{.*\})").Groups["json"];
-
- var resultsData = JsonConvert.DeserializeObject(resultDataJson.Value);
-
- foreach (var torrent in resultsData.sets.torrent_list.data)
- {
- var release = ParseRelease(torrent);
- if (release != null)
- releases.Add(release);
- }
- }
- catch (Exception ex)
- {
- OnParseError(results.ContentString, ex);
- }
-
- return releases;
- }
-
- private ReleaseInfo ParseRelease(dynamic torrent)
- {
- /* Single torrent is represented with array:
- [
- 600934, -- id
- 4571, -- ?
- 1636450141, -- added timestamp
- "No.Time.To.Die.2021.ENGSubs.REPACK.HDRip.", -- title (max 41 chars)
- 677, -- leechers
- 30, -- seeders
- "NI ČAS ZA SMRT/ NOVI JAMES BOND | Akcijski | HDRip...", -- description
- 7, -- category
- 54.9014462385559, -- health? scaled 0-100
- "1.7 GB", -- size
- "/img/ics/xvid.gif", -- icon
- "/torrent/image/600/600934/coverflow/james-bond.jpg" -- thumbnail
- ]
- */
- try
- {
- // initialize ReleaseInfo
- var release = new ReleaseInfo
- {
- MinimumRatio = 1,
- MinimumSeedTime = 0,
- // Get Category
- Category = MapTrackerCatToNewznab(torrent[7].ToString()),
- // Title, description and details link
- Title = torrent[3].ToString(),
- Description = torrent[6].ToString(),
- Details = new Uri($"{SiteLink}index.html#torrent/{torrent[0]}")
- };
- release.Guid = release.Details;
-
- // Date of torrent creation
- release.PublishDate = DateTimeUtil.UnixTimestampToDateTime((long)torrent[2]);
-
- // Download link
- release.Link = new Uri($"{SiteLink}torrent/download/{torrent[0]}");
-
- // Various data - size, seeders, leechers, download count
- release.Size = ReleaseInfo.GetBytes(torrent[9].ToString());
- release.Seeders = ParseUtil.CoerceInt(torrent[4].ToString());
- release.Peers = ParseUtil.CoerceInt(torrent[5].ToString()) + release.Seeders;
-
- // Poster
- release.Poster = new Uri($"{SiteLink}{torrent[11]}");
-
- // // Set download/upload factor
- release.DownloadVolumeFactor = 1; //No way to determine if torrent is freeleech from single request.
- release.UploadVolumeFactor = 1;
-
- return release;
- }
- catch (Exception ex)
- {
- logger.Error(string.Format("{0}: Error while parsing torrent '{1}':\n\n{2}", Id, torrent, ex));
- return null;
- }
- }
- }
-}