From 91095c84b36db50f2cea8ca342574f75cebd03b3 Mon Sep 17 00:00:00 2001 From: Garfield69 Date: Fri, 2 Feb 2024 20:07:26 +1300 Subject: [PATCH] hdspace: C# -> yaml. resolves #15023 --- src/Jackett.Common/Definitions/hdspace.yml | 180 ++++++++++++++++ src/Jackett.Common/Indexers/HDSpace.cs | 231 --------------------- 2 files changed, 180 insertions(+), 231 deletions(-) create mode 100644 src/Jackett.Common/Definitions/hdspace.yml delete mode 100644 src/Jackett.Common/Indexers/HDSpace.cs diff --git a/src/Jackett.Common/Definitions/hdspace.yml b/src/Jackett.Common/Definitions/hdspace.yml new file mode 100644 index 000000000..d87e9f68d --- /dev/null +++ b/src/Jackett.Common/Definitions/hdspace.yml @@ -0,0 +1,180 @@ +--- +id: hdspace +name: HD-Space +description: "HD-Space is a Private Torrent Tracker for MOVIES / TV / GENERAL" +language: en-US +type: private +encoding: UTF-8 +links: + - https://hd-space.org/ + +caps: + categorymappings: + - {id: 15, cat: Movies/BluRay, desc: "Movie / Blu-ray"} + - {id: 40, cat: Movies/HD, desc: "Movie / Remux"} + - {id: 18, cat: Movies/HD, desc: "Movie / 720p"} + - {id: 19, cat: Movies/HD, desc: "Movie / 1080p"} + - {id: 46, cat: Movies/UHD, desc: "Movie / 2160p"} + - {id: 21, cat: TV/HD, desc: "TV Show / 720p HDTV"} + - {id: 22, cat: TV/HD, desc: "TV Show / 1080p HDTV"} + - {id: 45, cat: TV/UHD, desc: "TV Show / 2160p HDTV"} + - {id: 24, cat: TV/Documentary, desc: "Documentary / 720p"} + - {id: 25, cat: TV/Documentary, desc: "Documentary / 1080p"} + - {id: 47, cat: TV/Documentary, desc: "Documentary / 2160p"} + - {id: 27, cat: TV/Anime, desc: "Animation / 720p"} + - {id: 28, cat: TV/Anime, desc: "Animation / 1080p"} + - {id: 48, cat: TV/Anime, desc: "Animation / 2160p"} + - {id: 30, cat: Audio/Lossless, desc: "Music / HQ Audio"} + - {id: 31, cat: Audio/Video, desc: "Music / Videos"} + - {id: 33, cat: XXX, desc: "XXX / 720p"} + - {id: 34, cat: XXX, desc: "XXX / 1080p"} + - {id: 49, cat: XXX, desc: "XXX / 2160p"} + - {id: 36, cat: Movies/Other, desc: "Trailers"} + - {id: 37, cat: PC, desc: "Software"} + - {id: 38, cat: Other, desc: "Others"} + - {id: 41, cat: Movies/UHD, desc: "Movie / 4K UHD"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + music-search: [q] + +settings: + - name: username + type: text + label: Username + - name: password + type: password + label: Password + - name: freeleech + type: checkbox + label: Filter freeleech only + default: false + - name: sort + type: select + label: Sort requested from site + default: 3 + options: + 3: created + 5: seeders + 4: size + 2: title + - name: type + type: select + label: Order requested from site + default: 2 + options: + 2: desc + 1: asc + - name: flaresolverr + type: info + label: FlareSolverr + default: This site may use Cloudflare DDoS Protection, therefore Jackett requires FlareSolverr to access it. + +login: + path: index.php?page=login + method: post + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + logout: "" + error: + - selector: tr td span[style="color:#FF0000;"] + test: + path: index.php + selector: a[href="logout.php"] + +search: + paths: + # https://hd-space.org/index.php?page=torrents&search=&active=0&options=0&category=15;18;19 + - path: index.php + inputs: + page: torrents + search: "{{ if .Query.IMDBID }}{{ .Query.IMDBIDShort }}{{ else }}{{ .Keywords }}{{ end }}" + category: "{{ if .Categories }}{{ range .Categories }}{{.}};{{end}}{{ else }}0{{ end }}" + # 0 default, 1 genre, 2 imdb, 3 uploader + options: "{{ if .Query.IMDBID }}2{{ else }}0{{ end }}" + # 0 all, 1 activeonly, 2 deadonly + active: 0 + order: "{{ .Config.sort }}" + by: "{{ .Config.type }}" + + rows: + selector: "table.lista[width=\"100%\"] > tbody > style ~ tr{{ if .Config.freeleech }}:has(img[src=\"gold/gold.png\"]){{ else }}{{ end }}, table.lista[width=\"100%\"] > tbody > style ~ tr{{ if .Config.freeleech }}:has(img[src=\"images/sf.png\"]){{ else }}{{ end }}" + + fields: + category: + selector: td a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + title: + selector: td a[href^="index.php?page=torrent-details"] + details: + selector: td a[href^="index.php?page=torrent-details"] + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + poster: + selector: td a[href^="index.php?page=torrent-details"] + attribute: onmouseover + filters: + - name: regexp + args: src=\./(.+?)\s + imdbid: + selector: td a[href^="index.php?page=torrent-details"] + attribute: onmouseover + filters: + - name: regexp + args: /(\d{8}).jpg + date_day: + # Today at 09:17:08 + # Yesterday at 17:11:03 + selector: td:nth-child(5):contains("day") + # auto adjusted by site account profile + optional: true + filters: + - name: re_replace + args: ["[ ]at|[//\xa0\\s,]+", " "] + date_year: + # January 30, 2024, 20:23:21 + selector: td:nth-child(5):not(:contains("day")) + # auto adjusted by site account profile + optional: true + filters: + - name: re_replace + args: ["[//\xa0\\s,]+", " "] + - name: dateparse + args: "MMMM dd yyyy HH:mm:ss" + date: + text: "{{ if or .Result.date_day .Result.date_year }}{{ or .Result.date_day .Result.date_year }}{{ else }}now{{ end }}" + size: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + grabs: + selector: td:nth-child(10) + genre: + selector: td:nth-child(2) + remove: a + description: + text: "{{ .Result.genre }}" + downloadvolumefactor: + case: + img[src="images/sf.png"]: 0 # side freeleech + img[src="gold/gold.png"]: 0 + img[src="gold/silver.png"]: 0.5 + "*": 1 + uploadvolumefactor: + text: 1 + minimumratio: + text: 1.0 + minimumseedtime: + # 1 day (as seconds = 1 x 24 x 60 x 60) + text: 86400 +# xbtit diff --git a/src/Jackett.Common/Indexers/HDSpace.cs b/src/Jackett.Common/Indexers/HDSpace.cs deleted file mode 100644 index 93526905c..000000000 --- a/src/Jackett.Common/Indexers/HDSpace.cs +++ /dev/null @@ -1,231 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using AngleSharp.Html.Parser; -using Jackett.Common.Extensions; -using Jackett.Common.Models; -using Jackett.Common.Models.IndexerConfig; -using Jackett.Common.Services.Interfaces; -using Jackett.Common.Utils; -using Newtonsoft.Json.Linq; -using NLog; -using static Jackett.Common.Models.IndexerConfig.ConfigurationData; -using WebClient = Jackett.Common.Utils.Clients.WebClient; - -namespace Jackett.Common.Indexers -{ - [ExcludeFromCodeCoverage] - public class HDSpace : IndexerBase - { - public override string Id => "hdspace"; - public override string Name => "HD-Space"; - public override string Description => "Sharing The Universe"; - public override string SiteLink { get; protected set; } = "https://hd-space.org/"; - public override string Language => "en-US"; - public override string Type => "private"; - - public override TorznabCapabilities TorznabCaps => SetCapabilities(); - - private string LoginUrl => SiteLink + "index.php?page=login"; - private string SearchUrl => SiteLink + "index.php?page=torrents"; - - private new ConfigurationDataBasicLogin configData => (ConfigurationDataBasicLogin)base.configData; - - public HDSpace(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps, - ICacheService cs) - : base(configService: configService, - client: wc, - logger: l, - p: ps, - cacheService: cs, - configData: new ConfigurationDataBasicLogin()) - { - configData.AddDynamic("freeleech", new BoolConfigurationItem("Filter freeleech only") { Value = false }); - configData.AddDynamic("flaresolverr", new DisplayInfoConfigurationItem("FlareSolverr", "This site may use Cloudflare DDoS Protection, therefore Jackett requires FlareSolverr to access it.")); - } - - private TorznabCapabilities SetCapabilities() - { - var 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 - } - }; - - caps.Categories.AddCategoryMapping(15, TorznabCatType.MoviesBluRay, "Movie / Blu-ray"); - caps.Categories.AddCategoryMapping(40, TorznabCatType.MoviesHD, "Movie / Remux"); - caps.Categories.AddCategoryMapping(18, TorznabCatType.MoviesHD, "Movie / 720p"); - caps.Categories.AddCategoryMapping(19, TorznabCatType.MoviesHD, "Movie / 1080p"); - caps.Categories.AddCategoryMapping(46, TorznabCatType.MoviesUHD, "Movie / 2160p"); - caps.Categories.AddCategoryMapping(21, TorznabCatType.TVHD, "TV Show / 720p HDTV"); - caps.Categories.AddCategoryMapping(22, TorznabCatType.TVHD, "TV Show / 1080p HDTV"); - caps.Categories.AddCategoryMapping(45, TorznabCatType.TVUHD, "TV Show / 2160p HDTV"); - caps.Categories.AddCategoryMapping(24, TorznabCatType.TVDocumentary, "Documentary / 720p"); - caps.Categories.AddCategoryMapping(25, TorznabCatType.TVDocumentary, "Documentary / 1080p"); - caps.Categories.AddCategoryMapping(47, TorznabCatType.TVDocumentary, "Documentary / 2160p"); - caps.Categories.AddCategoryMapping(27, TorznabCatType.TVAnime, "Animation / 720p"); - caps.Categories.AddCategoryMapping(28, TorznabCatType.TVAnime, "Animation / 1080p"); - caps.Categories.AddCategoryMapping(48, TorznabCatType.TVAnime, "Animation / 2160p"); - caps.Categories.AddCategoryMapping(30, TorznabCatType.AudioLossless, "Music / HQ Audio"); - caps.Categories.AddCategoryMapping(31, TorznabCatType.AudioVideo, "Music / Videos"); - caps.Categories.AddCategoryMapping(33, TorznabCatType.XXX, "XXX / 720p"); - caps.Categories.AddCategoryMapping(34, TorznabCatType.XXX, "XXX / 1080p"); - caps.Categories.AddCategoryMapping(49, TorznabCatType.XXX, "XXX / 2160p"); - caps.Categories.AddCategoryMapping(36, TorznabCatType.MoviesOther, "Trailers"); - caps.Categories.AddCategoryMapping(37, TorznabCatType.PC, "Software"); - caps.Categories.AddCategoryMapping(38, TorznabCatType.Other, "Others"); - caps.Categories.AddCategoryMapping(41, TorznabCatType.MoviesUHD, "Movie / 4K UHD"); - - return caps; - } - - public override async Task ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - var loginPage = await RequestWithCookiesAsync(LoginUrl, string.Empty); - - var pairs = new Dictionary - { - { "uid", configData.Username.Value }, - { "pwd", configData.Password.Value } - }; - - // Send Post - var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: LoginUrl); - - await ConfigureIfOK(response.Cookies, response.ContentString?.Contains("logout.php") == true || response.ContentString?.Contains("Rank: Parked") == true, () => - { - var parser = new HtmlParser(); - using var dom = parser.ParseDocument(response.ContentString); - var errorMessages = dom - .QuerySelectorAll("table.lista td.lista span[style*=\"#FF0000\"], table.lista td.header:contains(\"login attempts\")") - .Select(r => r.TextContent.Trim()) - .Where(m => m.IsNotNullOrWhiteSpace()) - .ToArray(); - - throw new ExceptionWithConfigData(errorMessages.Any() ? errorMessages.Join(" ") : "Unknown error message, please report.", configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - protected override async Task> PerformQuery(TorznabQuery query) - { - var releases = new List(); - var queryCollection = new NameValueCollection - { - {"active", "0"}, - {"category", string.Join(";", MapTorznabCapsToTrackers(query))} - }; - - if (query.IsImdbQuery) - { - queryCollection.Set("options", "2"); - queryCollection.Set("search", query.ImdbIDShort); - } - else - { - queryCollection.Set("options", "0"); - queryCollection.Set("search", query.GetQueryString().Replace(".", " ")); - } - - var response = await RequestWithCookiesAndRetryAsync($"{SearchUrl}&{queryCollection.GetQueryString()}"); - - try - { - var resultParser = new HtmlParser(); - using var searchResultDocument = resultParser.ParseDocument(response.ContentString); - var rows = searchResultDocument.QuerySelectorAll("table.lista > tbody > tr"); - - foreach (var row in rows) - { - // this tracker has horrible markup, find the result rows by looking for the style tag before each one - var prev = row.PreviousElementSibling; - if (prev == null || !string.Equals(prev.NodeName, "style", StringComparison.OrdinalIgnoreCase)) - continue; - - var release = new ReleaseInfo - { - MinimumRatio = 1, - MinimumSeedTime = 86400 // 24 hours - }; - - if (row.QuerySelector("img[title=\"FreeLeech\"]") != null) - release.DownloadVolumeFactor = 0; - else if (row.QuerySelector("img[src=\"images/sf.png\"]") != null) // side freeleech - release.DownloadVolumeFactor = 0; - else if (row.QuerySelector("img[title=\"Half FreeLeech\"]") != null) - release.DownloadVolumeFactor = 0.5; - else - release.DownloadVolumeFactor = 1; - if (((BoolConfigurationItem)configData.GetDynamic("freeleech")).Value && - release.DownloadVolumeFactor != 0) - continue; - release.UploadVolumeFactor = 1; - - var qLink = row.Children[1].FirstElementChild; - release.Title = qLink.TextContent.Trim(); - release.Details = new Uri(SiteLink + qLink.GetAttribute("href")); - release.Guid = release.Details; - release.Link = new Uri(SiteLink + row.Children[3].FirstElementChild.GetAttribute("href")); - - var torrentTitle = ParseUtil.GetArgumentFromQueryString(release.Link.ToString(), "f")?.Replace(".torrent", "").Trim(); - if (!string.IsNullOrWhiteSpace(torrentTitle)) - release.Title = WebUtility.HtmlDecode(torrentTitle); - - var qGenres = row.QuerySelector("span[style=\"color: #000000 \"]"); - var description = ""; - if (qGenres != null) - description = qGenres.TextContent.Split('\xA0').Last().Replace(" ", ""); - - var imdbLink = row.Children[1].QuerySelector("a[href*=imdb]"); - if (imdbLink != null) - release.Imdb = ParseUtil.GetImdbId(imdbLink.GetAttribute("href").Split('/').Last()); - - var dateStr = row.Children[4].TextContent.Trim(); - //"July 11, 2015, 13:34:09", "Today|Yesterday at 20:04:23" - release.PublishDate = DateTimeUtil.FromUnknown(dateStr); - var sizeStr = row.Children[5].TextContent; - release.Size = ParseUtil.GetBytes(sizeStr); - release.Seeders = ParseUtil.CoerceInt(row.Children[7].TextContent); - release.Peers = ParseUtil.CoerceInt(row.Children[8].TextContent) + release.Seeders; - var grabs = row.QuerySelector("td:nth-child(10)").TextContent; - grabs = grabs.Replace("---", "0"); - release.Grabs = ParseUtil.CoerceInt(grabs); - - var categoryLink = row.QuerySelector("a[href^=\"index.php?page=torrents&category=\"]").GetAttribute("href"); - var cat = ParseUtil.GetArgumentFromQueryString(categoryLink, "category"); - release.Category = MapTrackerCatToNewznab(cat); - - release.Description = description; - if (release.Genres == null) - release.Genres = new List(); - release.Genres = release.Genres.Union(description.Split(',')).ToList(); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(response.ContentString, ex); - } - - return releases; - } - } -}