diff --git a/src/Jackett.Common/Definitions/torrentleech.yml b/src/Jackett.Common/Definitions/torrentleech.yml
new file mode 100644
index 000000000..231b7bed2
--- /dev/null
+++ b/src/Jackett.Common/Definitions/torrentleech.yml
@@ -0,0 +1,178 @@
+---
+id: torrentleech
+name: TorrentLeech
+description: "not here _ not scene"
+language: en-US
+type: private
+encoding: UTF-8
+links:
+ - https://www.torrentleech.org/
+legacylinks:
+ - https://v4.torrentleech.org/
+
+caps:
+ categorymappings:
+ - {id: 1, cat: Movies, desc: "Movies"}
+ - {id: 8, cat: Movies/SD, desc: "Movies Cam"}
+ - {id: 9, cat: Movies/SD, desc: "Movies TS/TC"}
+ - {id: 11, cat: Movies/SD, desc: "Movies DVDRip/DVDScreener"}
+ - {id: 12, cat: Movies/DVD, desc: "Movies DVD-R"}
+ - {id: 13, cat: Movies/BluRay, desc: "Movies Bluray"}
+ - {id: 14, cat: Movies/HD, desc: "Movies BlurayRip"}
+ - {id: 15, cat: Movies, desc: "Movies Boxsets"}
+ - {id: 29, cat: TV/Documentary, desc: "Documentaries"}
+ - {id: 47, cat: Movies/UHD, desc: "Movies 4K"}
+ - {id: 36, cat: Movies/Foreign, desc: "Movies Foreign"}
+ - {id: 37, cat: Movies/WEB-DL, desc: "Movies WEBRip"}
+ - {id: 43, cat: Movies/HD, desc: "Movies HDRip"}
+
+ - {id: 2, cat: TV, desc: "TV"}
+ - {id: 26, cat: TV/SD, desc: "TV Episodes"}
+ - {id: 27, cat: TV, desc: "TV Boxsets"}
+ - {id: 32, cat: TV/HD, desc: "TV Episodes HD"}
+ - {id: 44, cat: TV/Foreign, desc: "TV Foreign"}
+
+ - {id: 3, cat: PC/Games, desc: "Games"}
+ - {id: 17, cat: PC/Games, desc: "Games PC"}
+ - {id: 18, cat: Console/XBox, desc: "Games XBOX"}
+ - {id: 19, cat: Console/XBox 360, desc: "Games XBOX360"}
+ - {id: 40, cat: Console/XBox One, desc: "Games XBOXONE"}
+ - {id: 20, cat: Console/PS3, desc: "Games PS2"}
+ - {id: 21, cat: Console/PS3, desc: "Games Mac"}
+ - {id: 22, cat: Console/PSP, desc: "Games PSP"}
+ - {id: 28, cat: Console/Wii, desc: "Games Wii"}
+ - {id: 30, cat: Console/NDS, desc: "Games Nintendo DS"}
+ - {id: 39, cat: Console/PS4, desc: "Games PS4"}
+ - {id: 42, cat: PC/Mac, desc: "Games Mac"}
+ - {id: 48, cat: Console/Other, desc: "Games Nintendo Switch"}
+
+ - {id: 4, cat: Audio, desc: "Music"}
+ - {id: 16, cat: Audio/Video, desc: "Music videos"}
+ - {id: 31, cat: Audio, desc: "Audio"}
+
+ - {id: 7, cat: TV, desc: "Animation"}
+ - {id: 34, cat: TV/Anime, desc: "TV Anime"}
+ - {id: 35, cat: TV, desc: "TV Cartoons"}
+
+ - {id: 5, cat: Books, desc: "Books"}
+ - {id: 45, cat: Books/EBook, desc: "Books EBooks"}
+ - {id: 46, cat: Books/Comics, desc: "Books Comics"}
+
+ - {id: 6, cat: PC, desc: "Apps"}
+ - {id: 23, cat: PC/ISO, desc: "PC ISO"}
+ - {id: 24, cat: PC/Mac, desc: "PC Mac"}
+ - {id: 25, cat: PC/Mobile-Other, desc: "PC Mobile"}
+ - {id: 33, cat: PC/0day, desc: "PC 0-day"}
+ - {id: 38, cat: Other, desc: "Education"}
+
+ modes:
+ search: [q]
+ tv-search: [q, season, ep, imdbid]
+ movie-search: [q, imdbid]
+ music-search: [q]
+ book-search: [q]
+
+settings:
+ - name: username
+ type: text
+ label: Username
+ - name: password
+ type: password
+ label: Password
+ - name: freeleech
+ type: checkbox
+ label: Search freeleech only
+ default: false
+ - name: sort
+ type: select
+ label: Sort requested from site
+ default: added
+ options:
+ added: created
+ seeders: seeders
+ size: size
+ nameSort: title
+ - name: type
+ type: select
+ label: Order requested from site
+ default: desc
+ options:
+ desc: desc
+ asc: asc
+ - name: info_tpp
+ type: info
+ label: Results Per Page
+ default: For best results, change the Torrents per page: setting to 100 on your account profile.
+
+login:
+ path: user/account/login/
+ method: post
+ inputs:
+ username: "{{ .Config.username }}"
+ password: "{{ .Config.password }}"
+ error:
+ - selector: p.text-danger
+ test:
+ path: /
+ selector: a[href="/user/account/logout"]
+
+search:
+ paths:
+ # "newfilter/2" include 0day and music
+ - path: "torrents/browse/list/{{ if .Config.freeleech }}facets/tags:FREELEECH/{{ else }}{{ end }}{{ if .Query.IMDBID }}imdbID/{{ .Query.IMDBID }}/{{ else }}exact/1/query/{{ .Keywords }}/{{ end }}{{ if .Keywords }}{{ else }}newfilter/2/{{ end }}{{ if .Categories }}categories/{{ join .Categories \",\" }}/{{ else }}{{ end }}orderby/{{ .Config.sort }}/order/{{ .Config.type }}"
+ response:
+ type: json
+
+ keywordsfilters:
+ # remove dashes at the beginning of keywords as they exclude search strings (see issue #3096)
+ - name: re_replace
+ args: ["(^|\\s)-", " "]
+ rows:
+ selector: torrentList
+ count:
+ selector: $.numFound
+
+ fields:
+ category:
+ selector: categoryID
+ title:
+ selector: name
+ id:
+ selector: fid
+ filename:
+ selector: filename
+ details:
+ text: "{{ .Config.sitelink }}torrent/{{ .Result.id }}"
+ download:
+ text: "{{ .Config.sitelink }}download/{{ .Result.id }}/{{ .Result.filename }}"
+ imdbid:
+ selector: imdbID
+ seeders:
+ selector: seeders
+ leechers:
+ selector: leechers
+ grabs:
+ selector: completed
+ date:
+ # 2021-10-25 02:18:31 (auto adjusted by site account profile)
+ selector: addedTimestamp
+ filters:
+ - name: dateparse
+ args: "2006-01-02 15:04:05"
+ size:
+ selector: size
+ downloadvolumefactor:
+ # freeleech #6579 #6624 #7367
+ selector: download_multiplier
+ case:
+ 0: 0 # freeleech
+ "*": 1 # not free
+ uploadvolumefactor:
+ text: 1
+ minimumratio:
+ text: 1.0
+ minimumseedtime:
+ # 10 days for registered users, less for upgraded users
+ # 10 day (as seconds = 7 x 24 x 60 x 60)
+ text: 864000
+# json enigine n/a
diff --git a/src/Jackett.Common/Indexers/TorrentLeech.cs b/src/Jackett.Common/Indexers/TorrentLeech.cs
deleted file mode 100644
index 9d233fa8f..000000000
--- a/src/Jackett.Common/Indexers/TorrentLeech.cs
+++ /dev/null
@@ -1,231 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Net;
-using System.Text;
-using System.Text.RegularExpressions;
-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 Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using NLog;
-using static Jackett.Common.Models.IndexerConfig.ConfigurationData;
-
-namespace Jackett.Common.Indexers
-{
- [ExcludeFromCodeCoverage]
- public class TorrentLeech : BaseWebIndexer
- {
- private string LoginUrl => SiteLink + "user/account/login/";
- private string SearchUrl => SiteLink + "torrents/browse/list/";
- private new ConfigurationDataBasicLogin configData => (ConfigurationDataBasicLogin)base.configData;
-
- public override string[] LegacySiteLinks { get; protected set; } =
- {
- "https://v4.torrentleech.org/"
- };
-
- public TorrentLeech(IIndexerConfigurationService configService, Utils.Clients.WebClient wc, Logger l,
- IProtectionService ps, ICacheService cs)
- : base(id: "torrentleech",
- name: "TorrentLeech",
- description: "This is what happens when you seed",
- link: "https://www.torrentleech.org/",
- 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,
- client: wc,
- logger: l,
- p: ps,
- cacheService: cs,
- configData: new ConfigurationDataBasicLogin(
- "For best results, change the 'Default Number of Torrents per Page' setting to 100 in your Profile."))
- {
- Encoding = Encoding.UTF8;
- Language = "en-US";
- Type = "private";
-
- configData.AddDynamic("freeleech", new BoolConfigurationItem("Search freeleech only") { Value = false });
-
- AddCategoryMapping(1, TorznabCatType.Movies, "Movies");
- AddCategoryMapping(8, TorznabCatType.MoviesSD, "Movies Cam");
- AddCategoryMapping(9, TorznabCatType.MoviesSD, "Movies TS/TC");
- AddCategoryMapping(11, TorznabCatType.MoviesSD, "Movies DVDRip/DVDScreener");
- AddCategoryMapping(12, TorznabCatType.MoviesDVD, "Movies DVD-R");
- AddCategoryMapping(13, TorznabCatType.MoviesBluRay, "Movies Bluray");
- AddCategoryMapping(14, TorznabCatType.MoviesHD, "Movies BlurayRip");
- AddCategoryMapping(15, TorznabCatType.Movies, "Movies Boxsets");
- AddCategoryMapping(29, TorznabCatType.TVDocumentary, "Documentaries");
- AddCategoryMapping(47, TorznabCatType.MoviesUHD, "Movies 4K");
- AddCategoryMapping(36, TorznabCatType.MoviesForeign, "Movies Foreign");
- AddCategoryMapping(37, TorznabCatType.MoviesWEBDL, "Movies WEBRip");
- AddCategoryMapping(43, TorznabCatType.MoviesHD, "Movies HDRip");
-
- AddCategoryMapping(2, TorznabCatType.TV, "TV");
- AddCategoryMapping(26, TorznabCatType.TVSD, "TV Episodes");
- AddCategoryMapping(27, TorznabCatType.TV, "TV Boxsets");
- AddCategoryMapping(32, TorznabCatType.TVHD, "TV Episodes HD");
- AddCategoryMapping(44, TorznabCatType.TVForeign, "TV Foreign");
-
- AddCategoryMapping(3, TorznabCatType.PCGames, "Games");
- AddCategoryMapping(17, TorznabCatType.PCGames, "Games PC");
- AddCategoryMapping(18, TorznabCatType.ConsoleXBox, "Games XBOX");
- AddCategoryMapping(19, TorznabCatType.ConsoleXBox360, "Games XBOX360");
- AddCategoryMapping(40, TorznabCatType.ConsoleXBoxOne, "Games XBOXONE");
- AddCategoryMapping(20, TorznabCatType.ConsolePS3, "Games PS2");
- AddCategoryMapping(21, TorznabCatType.ConsolePS3, "Games Mac");
- AddCategoryMapping(22, TorznabCatType.ConsolePSP, "Games PSP");
- AddCategoryMapping(28, TorznabCatType.ConsoleWii, "Games Wii");
- AddCategoryMapping(30, TorznabCatType.ConsoleNDS, "Games Nintendo DS");
- AddCategoryMapping(39, TorznabCatType.ConsolePS4, "Games PS4");
- AddCategoryMapping(42, TorznabCatType.PCMac, "Games Mac");
- AddCategoryMapping(48, TorznabCatType.ConsoleOther, "Games Nintendo Switch");
-
- AddCategoryMapping(4, TorznabCatType.Audio, "Music");
- AddCategoryMapping(16, TorznabCatType.AudioVideo, "Music videos");
- AddCategoryMapping(31, TorznabCatType.Audio, "Audio");
-
- AddCategoryMapping(7, TorznabCatType.TV, "Animation");
- AddCategoryMapping(34, TorznabCatType.TVAnime, "TV Anime");
- AddCategoryMapping(35, TorznabCatType.TV, "TV Cartoons");
-
- AddCategoryMapping(5, TorznabCatType.Books, "Books");
- AddCategoryMapping(45, TorznabCatType.BooksEBook, "Books EBooks");
- AddCategoryMapping(46, TorznabCatType.BooksComics, "Books Comics");
-
- AddCategoryMapping(6, TorznabCatType.PC, "Apps");
- AddCategoryMapping(23, TorznabCatType.PCISO, "PC ISO");
- AddCategoryMapping(24, TorznabCatType.PCMac, "PC Mac");
- AddCategoryMapping(25, TorznabCatType.PCMobileOther, "PC Mobile");
- AddCategoryMapping(33, TorznabCatType.PC0day, "PC 0-day");
- AddCategoryMapping(38, TorznabCatType.Other, "Education");
- }
-
- public override async Task ApplyConfiguration(JToken configJson)
- {
- LoadValuesFromJson(configJson);
- await DoLogin();
- return IndexerConfigurationStatus.RequiresTesting;
- }
-
- private async Task DoLogin()
- {
- var pairs = new Dictionary {
- { "username", configData.Username.Value },
- { "password", configData.Password.Value }
- };
-
- var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
- await ConfigureIfOK(result.Cookies, result.ContentString != null && result.ContentString.Contains("/user/account/logout"), () =>
- {
- var parser = new HtmlParser();
- var dom = parser.ParseDocument(result.ContentString);
- var errorMessage = dom.QuerySelector("p.text-danger:contains(\"Error:\")").TextContent.Trim();
- throw new ExceptionWithConfigData(errorMessage, configData);
- });
- }
-
- protected override async Task> PerformQuery(TorznabQuery query)
- {
- var releases = new List();
-
- // remove dashes at the beginning of keywords as they exclude search strings (see issue #3096)
- var searchString = query.GetQueryString();
- searchString = Regex.Replace(searchString, @"(^|\s)-", " ");
-
- var searchUrl = SearchUrl;
-
- if (((BoolConfigurationItem)configData.GetDynamic("freeleech")).Value)
- searchUrl += "facets/tags%3AFREELEECH/";
-
- if (query.IsImdbQuery)
- searchUrl += "imdbID/" + query.ImdbID + "/";
- else if (!string.IsNullOrWhiteSpace(searchString))
- searchUrl += "exact/1/query/" + WebUtility.UrlEncode(searchString) + "/";
-
- var cats = MapTorznabCapsToTrackers(query);
- if (cats.Count > 0)
- searchUrl += "categories/" + string.Join(",", cats);
- else
- searchUrl += "newfilter/2"; // include 0day and music
-
- var results = await RequestWithCookiesAndRetryAsync(searchUrl);
-
- if (results.ContentString.Contains("/user/account/login")) // re-login
- {
- await DoLogin();
- results = await RequestWithCookiesAndRetryAsync(searchUrl);
- }
-
- try
- {
- var rows = (JArray)((JObject)JsonConvert.DeserializeObject(results.ContentString))["torrentList"];
- foreach (var row in rows)
- {
- var title = row["name"].ToString();
- if (!query.MatchQueryStringAND(title))
- continue;
-
- var torrentId = row["fid"].ToString();
- var details = new Uri(SiteLink + "torrent/" + torrentId);
- var link = new Uri(SiteLink + "download/" + torrentId + "/" + row["filename"]);
- var publishDate = DateTime.ParseExact(row["addedTimestamp"].ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
- var seeders = (int)row["seeders"];
-
- // freeleech #6579 #6624 #7367
- var dlMultiplier = row["download_multiplier"].ToString();
- var dlVolumeFactor = string.IsNullOrEmpty(dlMultiplier) ? 1 : ParseUtil.CoerceInt(dlMultiplier);
-
- var release = new ReleaseInfo
- {
- Title = title,
- Details = details,
- Guid = details,
- Link = link,
- PublishDate = publishDate,
- Category = MapTrackerCatToNewznab(row["categoryID"].ToString()),
- Size = (long)row["size"],
- Grabs = (int)row["completed"],
- Seeders = seeders,
- Peers = seeders + (int)row["leechers"],
- Imdb = ParseUtil.GetImdbID(row["imdbID"].ToString()),
- UploadVolumeFactor = 1,
- DownloadVolumeFactor = dlVolumeFactor,
- MinimumRatio = 1,
- MinimumSeedTime = 864000 // 10 days for registered users, less for upgraded users
- };
-
- releases.Add(release);
- }
- }
- catch (Exception ex)
- {
- OnParseError(results.ContentString, ex);
- }
-
- return releases;
- }
- }
-}