diff --git a/src/Jackett.Common/Definitions/sharewood-api.yml b/src/Jackett.Common/Definitions/sharewood-api.yml
new file mode 100644
index 000000000..ff6a499e3
--- /dev/null
+++ b/src/Jackett.Common/Definitions/sharewood-api.yml
@@ -0,0 +1,203 @@
+---
+id: sharewood-api
+replaces:
+ - sharewoodapi
+name: Sharewood (API)
+description: "sharewood is a Semi-Private FRENCH Torrent Tracker for GENERAL"
+language: fr-FR
+type: semi-private
+encoding: UTF-8
+requestDelay: 2.1
+certificates:
+ - 023A091295E81813D040DFA0FA842DF9892BF0F5 # expired 10-March-2024 note: despite a new CA issued this one still pops up occasionally
+links:
+ - https://www.sharewood.tv/
+
+caps:
+ categorymappings:
+ # categories
+# - {id: 1, cat: Movies, desc: "Vidéo"}
+# - {id: 1, cat: TV, desc: "Vidéo"}
+# - {id: 2, cat: Audio, desc: "Audio"}
+# - {id: 3, cat: PC, desc: "Application"}
+# - {id: 4, cat: Books/EBook, desc: "Ebooks"}
+# - {id: 5, cat: PC/Games, desc: "Jeu-Vidéo"}
+# - {id: 6, cat: Other, desc: "Formation"}
+# - {id: 7, cat: XXX, desc: "XXX"}
+
+ # subcategories
+ - {id: 9, cat: Movies, desc: "Films"}
+ - {id: 10, cat: TV, desc: "Séries"}
+ - {id: 11, cat: Movies/Other, desc: "Films Animations"}
+ - {id: 12, cat: TV/Anime, desc: "Séries Animations"}
+ - {id: 13, cat: TV/Documentary, desc: "Documentaires"}
+ - {id: 14, cat: TV/Other, desc: "Emissions TV"}
+ - {id: 15, cat: TV/Other, desc: "Spectacles/Concerts"}
+ - {id: 16, cat: TV/Sport, desc: "Sports"}
+ - {id: 17, cat: Audio/Video, desc: "Karaoké Vidéo"}
+ - {id: 18, cat: Audio/Other, desc: "Karaoké"}
+ - {id: 20, cat: Audio, desc: "Musiques"}
+ - {id: 21, cat: Audio/Other, desc: "Podcasts"}
+ - {id: 22, cat: Audio/Other, desc: "Samples"}
+ - {id: 23, cat: Audio/Audiobook, desc: "Ebooks Audio"}
+ - {id: 24, cat: Books/EBook, desc: "BDs"}
+ - {id: 25, cat: Books/Comics, desc: "Comics"}
+ - {id: 26, cat: Books/Other, desc: "Mangas"}
+ - {id: 27, cat: Books, desc: "Livres"}
+ - {id: 28, cat: Books/Mags, desc: "Presse"}
+ - {id: 29, cat: PC, desc: "Applications Linux"}
+ - {id: 30, cat: PC/0day, desc: "Applications Windows"}
+ - {id: 31, cat: PC/Mac, desc: "Applications Mac"}
+ - {id: 34, cat: PC/Mobile-iOS, desc: "Applications Smartphone/Tablette"}
+ - {id: 34, cat: PC/Mobile-Android, desc: "Applications Smartphone/Tablette"}
+ - {id: 35, cat: PC/Mobile-Other, desc: "GPS"}
+ - {id: 36, cat: PC/Games, desc: "Jeux Linux"}
+ - {id: 37, cat: PC/Games, desc: "Jeux Windows"}
+ - {id: 38, cat: PC/Mac, desc: "Jeux Mac"}
+ - {id: 39, cat: Console/NDS, desc: "Jeux Nintendo"}
+ - {id: 39, cat: Console/Wii, desc: "Jeux Nintendo"}
+ - {id: 39, cat: Console/Wiiware, desc: "Jeux Nintendo"}
+ - {id: 39, cat: Console/3DS, desc: "Jeux Nintendo"}
+ - {id: 39, cat: Console/WiiU, desc: "Jeux Nintendo"}
+ - {id: 40, cat: Console/PS4, desc: "Jeux Sony"}
+ - {id: 41, cat: PC/Mobile-Android, desc: "Jeux Smartphone/Tablette"}
+ - {id: 42, cat: PC/Games, desc: "Jeux Microsoft"}
+ - {id: 43, cat: Other, desc: "Rétrogaming & Emulation"}
+ - {id: 44, cat: XXX, desc: "Films XXX"}
+ - {id: 45, cat: XXX/Other, desc: "XXX Hentai"}
+ - {id: 47, cat: XXX/ImageSet, desc: "XXX Images"}
+ - {id: 48, cat: XXX/Other, desc: "XXX Jeux-Vidéo"}
+ - {id: 49, cat: Other/Misc, desc: "Formations Vidéos"}
+ - {id: 50, cat: Other/Misc, desc: "Formations Logiciels"}
+ - {id: 51, cat: XXX/Other, desc: "XXX Ebooks"}
+ - {id: 52, cat: Audio/Video, desc: "Vidéos-Clips"}
+
+ modes:
+ search: [q]
+ tv-search: [q, season, ep]
+ movie-search: [q]
+ music-search: [q]
+ book-search: [q]
+ allowrawsearch: true
+
+settings:
+ - name: passkey
+ type: text
+ label: Passkey
+ - name: info_passkey
+ type: info
+ label: About your Passkey
+ default: "Find your Passkey by accessing your Sharewood profile on the My Profile page and scrolling down to the Passkey field."
+ - name: freeleech
+ type: checkbox
+ label: Search freeleech only
+ default: false
+ - name: multilang
+ type: checkbox
+ label: Replace MULTi by another language in release name
+ default: false
+ - name: multilanguage
+ type: select
+ label: Replace MULTi by this language
+ default: FRENCH
+ options:
+ FRENCH: FRENCH
+ MULTi FRENCH: MULTi FRENCH
+ ENGLISH: ENGLISH
+ MULTi ENGLISH: MULTi ENGLISH
+ VOSTFR: VOSTFR
+ MULTi VOSTFR: MULTi VOSTFR
+ - name: vostfr
+ type: checkbox
+ label: Replace VOSTFR and SUBFRENCH with ENGLISH
+ default: false
+
+login:
+ path: "api/{{ .Config.passkey }}/last-torrents"
+ method: get
+ error:
+ - selector: ":root:contains(\"Passkey invalide\")"
+ - selector: ":root:contains(\"503 Service Temporarily Unavailable\")"
+
+search:
+ paths:
+ - path: "api/{{ .Config.passkey }}/{{ if .Keywords }}search{{ else }}last-torrents{{ end }}"
+ response:
+ type: json
+
+ inputs:
+ subcategory: "{{ join .Categories \",\" }}"
+ name: "{{ .Keywords }}"
+ limit: 50
+ free: "{{ if .Config.freeleech }}1{{ else }}{{ end }}"
+
+ keywordsfilters:
+ - name: re_replace
+ args: ["[\\:\\-\\/\\|\\(\\)]+", " "]
+
+ rows:
+ selector: $
+
+ fields:
+ _id:
+ selector: id
+ category:
+ selector: subcategory_id
+ title_phase1:
+ selector: name
+ title_vostfr:
+ text: "{{ .Result.title_phase1 }}"
+ filters:
+ - name: re_replace
+ args: ["(?i)\\b(vostfr|subfrench)\\b", "ENGLISH"]
+ title_phase2:
+ text: "{{ if .Config.vostfr }}{{ .Result.title_vostfr }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
+ title_multilang:
+ text: "{{ .Result.title_phase2 }}"
+ filters:
+ - name: re_replace
+ args: ["(?i)\\b(MULTI(?!.*(?:FRENCH|ENGLISH|VOSTFR)))\\b", "{{ .Config.multilanguage }}"]
+ title:
+ text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase2 }}{{ end }}"
+ details:
+ selector: slug
+ filters:
+ - name: prepend
+ args: "/torrents/"
+ - name: append
+ args: ".{{ .Result._id }}"
+ download:
+ selector: download_url
+ size:
+ selector: size
+ seeders:
+ selector: seeders
+ leechers:
+ selector: leechers
+ grabs:
+ selector: times_completed
+ date:
+ selector: created_at
+ filters:
+ - name: append
+ args: " +00:00" # GMT
+ - name: dateparse
+ args: "yyyy-MM-dd HH:mm:ss zzz"
+ downloadvolumefactor:
+ # api returns 0=false, 1=true
+ selector: free
+ case:
+ 0: 1 # not free
+ 1: 0 # freeleech
+ uploadvolumefactor:
+ # api returns 0=false, 1=true
+ selector: doubleup
+ case:
+ 0: 1 # normal
+ 1: 2 # double
+ minimumratio:
+ text: 0.75
+ minimumseedtime:
+ # 3 days (as seconds = 3 x 24 x 60 x 60)
+ text: 259200
+# UNIT3D
diff --git a/src/Jackett.Common/Definitions/sharewood.yml b/src/Jackett.Common/Definitions/sharewood.yml
deleted file mode 100644
index a5de0be49..000000000
--- a/src/Jackett.Common/Definitions/sharewood.yml
+++ /dev/null
@@ -1,218 +0,0 @@
----
-id: sharewood
-name: Sharewood
-description: "sharewood is a Semi-Private FRENCH Torrent Tracker for GENERAL"
-language: fr-FR
-type: semi-private
-encoding: UTF-8
-requestDelay: 4.1
-certificates:
- - 023A091295E81813D040DFA0FA842DF9892BF0F5 # expired 10-March-2024 note: despite a new CA issued this one still pops up occasionally
-links:
- - https://www.sharewood.tv/
-
-caps:
- categorymappings:
- - {id: "Films", cat: Movies, desc: "Films"}
- - {id: "Films_Animations", cat: Movies, desc: "Films Animation"}
- - {id: "Animes", cat: TV/Anime, desc: " Séries Animations"}
- - {id: "Series", cat: TV, desc: "TV Series"}
- - {id: "Documentaires", cat: TV/Documentary, desc: "TV Documentaires"}
- - {id: "Emissions", cat: TV, desc: "TV Emissions"}
- - {id: "Sports", cat: TV/Sport, desc: "TV Sports"}
- - {id: "Spectacles", cat: TV, desc: "TV Spectacles/Concerts"}
- - {id: "Karaoke_Video", cat: Audio/Video, desc: "Karaoké Vidéo"}
- - {id: "Videos_Clips", cat: Audio/Video, desc: "TV Videos Clips"}
- - {id: "Musiques", cat: Audio, desc: "Audio Musiques"}
- - {id: "Karaoke", cat: Audio, desc: "Audio Karaoké"}
- - {id: "Samples", cat: Audio, desc: "Audio Samples"}
- - {id: "Podcasts", cat: Audio, desc: "Audio Podcasts"}
- - {id: "AudioBooks", cat: Audio/Audiobook, desc: "Audio Books"}
- - {id: "Windows", cat: PC/0day, desc: " Applications Windows"}
- - {id: "APK", cat: PC/Mobile-Android, desc: " Applications Android"}
- - {id: "GPS", cat: PC/Mobile-Other, desc: " Applications GPS"}
- - {id: "Ebooks", cat: Books/EBook, desc: "Books Ebooks"}
- - {id: "BDs", cat: Books/EBook, desc: "Books BDs"}
- - {id: "Presse", cat: Books/Mags, desc: "Books Presse"}
- - {id: "Mangas", cat: Books/Comics, desc: "Books Mangas"}
- - {id: "Comics", cat: Books/Comics, desc: "Books Comics"}
- - {id: "Nintendo", cat: Console/NDS, desc: "Jeux Nintendo"}
- - {id: "Microsoft", cat: Console/XBox, desc: "Jeux Microsoft"}
- - {id: "Linux", cat: PC/Games, desc: "Jeux Linux"}
- - {id: "Mac", cat: PC/Games, desc: "Jeux Mac"}
- - {id: "Retro", cat: PC/Games, desc: "Jeux Vidéos"}
- - {id: "Sony", cat: Console/PSP, desc: "Jeux Sony"}
- - {id: "Smartphone_Tablette", cat: Console, desc: "Jeux Smartphone/Tablette"}
- - {id: "Retrogaming_Emulation", cat: Console, desc: "Jeux Rétrogaming & Emulation"}
- - {id: "Formations", cat: Other, desc: "Formations"}
- - {id: "Formations_Video", cat: Other, desc: "Formations Video"}
- - {id: "Formations_Logiciels", cat: Other, desc: "Formations Logiciels"}
- - {id: "Films_X", cat: XXX, desc: "XXX"}
- - {id: "Ebooks_X", cat: XXX, desc: "XXX"}
- - {id: "Hentai", cat: XXX, desc: "Hentai"}
- - {id: "ImagesX", cat: XXX, desc: "ImagesX"}
-
- modes:
- search: [q]
- tv-search: [q, season, ep]
- movie-search: [q]
- music-search: [q]
- book-search: [q]
- allowrawsearch: true
-
-settings:
- - name: username
- type: text
- label: Username
- - name: password
- type: password
- label: Password
- - name: freeleech
- type: checkbox
- label: Search freeleech only
- default: false
- - name: multilang
- type: checkbox
- label: Replace MULTi by another language in release name
- default: false
- - name: multilanguage
- type: select
- label: Replace MULTi by this language
- default: FRENCH
- options:
- FRENCH: FRENCH
- MULTi FRENCH: MULTi FRENCH
- ENGLISH: ENGLISH
- MULTi ENGLISH: MULTi ENGLISH
- VOSTFR: VOSTFR
- MULTi VOSTFR: MULTi VOSTFR
- - name: vostfr
- type: checkbox
- label: Replace VOSTFR and SUBFRENCH with ENGLISH
- default: false
- - name: sort
- type: select
- label: Sort requested from site
- default: created_at
- options:
- created_at: created
- seeders: seeders
- size: size
- name: title
- - name: type
- type: select
- label: Order requested from site
- default: desc
- options:
- desc: desc
- asc: asc
-
-login:
- path: login
- method: form
- form: form[action$="/login"]
- inputs:
- username: "{{ .Config.username }}"
- password: "{{ .Config.password }}"
- remember: on
- selectorinputs:
- _token:
- selector: input[name="_token"]
- attribute: value
- error:
- - selector: form[action$="/login"] .text-red
- - selector: h1:contains("503 Service Temporarily Unavailable")
-# test:
-# path: /
-# selector: a[href$="/logout"]
-
-search:
- paths:
- - path: filterTorrents
- inputs:
- search: "{{ .Keywords }}"
- sorting: "{{ .Config.sort }}"
- direction: "{{ .Config.type }}"
- qty: 100
- freeleech: "{{ if .Config.freeleech }}1{{ else }}{{ end }}"
-
- keywordsfilters:
- - name: re_replace
- args: ["[\\:\\-\\/\\|\\(\\)]+", " "]
-
- rows:
- selector: div.table-responsive-line
-
- fields:
- category:
- selector: img.torrent-icon
- attribute: src
- filters:
- - name: regexp
- args: "/img/NewIcones/(.+?).png"
- title_phase1:
- selector: a.view-torrent
- title_vostfr:
- text: "{{ .Result.title_phase1 }}"
- filters:
- - name: re_replace
- args: ["(?i)\\b(vostfr|subfrench)\\b", "ENGLISH"]
- title_phase2:
- text: "{{ if .Config.vostfr }}{{ .Result.title_vostfr }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
- title_multilang:
- text: "{{ .Result.title_phase2 }}"
- filters:
- - name: re_replace
- args: ["(?i)\\b(MULTI(?!.*(?:FRENCH|ENGLISH|VOSTFR)))\\b", "{{ .Config.multilanguage }}"]
- title:
- text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase2 }}{{ end }}"
- download:
- selector: a.view-torrent
- attribute: href
- filters:
- - name: replace
- args: ["/torrents/", "/download/"]
- details:
- selector: a.view-torrent
- attribute: href
- size:
- selector: div.col-detail div.row div:nth-child(2)
- seeders:
- selector: div.bouton-s
- leechers:
- selector: div.bouton-l
- grabs:
- selector: div.bouton-c
- date:
- selector: div.col-detail div.row div span
- filters:
- - name: replace
- args: ["il y a ", ""]
- - name: replace
- args: ["seconde", "second"]
- - name: replace
- args: ["heure", "hour"]
- - name: replace
- args: ["jour", "day"]
- - name: replace
- args: ["semaine", "week"]
- - name: replace
- args: ["mois", "month"]
- - name: replace
- args: ["an", "year"]
- - name: append
- args: " ago"
- downloadvolumefactor:
- case:
- "span.badge-extra:contains('Freeleech')": 0
- "*": 1
- uploadvolumefactor:
- case:
- "span.badge-extra:contains('Double Upload')": 2
- "*": 1
- minimumratio:
- text: 0.75
- minimumseedtime:
- # 3 days (as seconds = 3 x 24 x 60 x 60)
- text: 259200
-# UNIT3D
diff --git a/src/Jackett.Common/Indexers/BaseIndexer.cs b/src/Jackett.Common/Indexers/BaseIndexer.cs
index 0dbca304d..88597546c 100644
--- a/src/Jackett.Common/Indexers/BaseIndexer.cs
+++ b/src/Jackett.Common/Indexers/BaseIndexer.cs
@@ -316,18 +316,28 @@ namespace Jackett.Common.Indexers
if (query.HasSpecifiedCategories)
{
var supportedCats = TorznabCaps.Categories.SupportedCategories(query.Categories);
+
if (supportedCats.Length == 0)
{
if (!isMetaIndexer)
+ {
logger.Error($"All categories provided are unsupported in {Name}: {string.Join(",", query.Categories)}");
+ }
+
return false;
}
+
if (supportedCats.Length != query.Categories.Length && !isMetaIndexer)
{
- var unsupportedCats = query.Categories.Except(supportedCats);
- logger.Warn($"Some of the categories provided are unsupported in {Name}: {string.Join(",", unsupportedCats)}");
+ var unsupportedCats = query.Categories.Except(supportedCats).ToList();
+
+ if (unsupportedCats.Any())
+ {
+ logger.Warn($"Some of the categories provided are unsupported in {Name}: {string.Join(",", unsupportedCats)}");
+ }
}
}
+
return true;
}
diff --git a/src/Jackett.Common/Indexers/Definitions/Sharewood.cs b/src/Jackett.Common/Indexers/Definitions/Sharewood.cs
deleted file mode 100644
index 852c64b3e..000000000
--- a/src/Jackett.Common/Indexers/Definitions/Sharewood.cs
+++ /dev/null
@@ -1,333 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Linq;
-using System.Net;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-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.Definitions
-{
- [ExcludeFromCodeCoverage]
- public class ShareWood : IndexerBase
- {
- public override string Id => "sharewoodapi";
- public override string Name => "Sharewood API";
- public override string Description => "Sharewood is a Semi-Private FRENCH Torrent Tracker for GENERAL";
- public override string SiteLink { get; protected set; } = "https://www.sharewood.tv/";
- public override string Language => "fr-FR";
- public override string Type => "semi-private";
-
- public override TorznabCapabilities TorznabCaps => SetCapabilities();
-
- private readonly Dictionary _apiHeaders = new Dictionary
- {
- {"Accept", "application/json"},
- {"Content-Type", "application/json"}
- };
- // API DOC: https://github.com/Jackett/Jackett/issues/10269
- private string SearchUrl => SiteLink + "api/" + configData.Passkey.Value;
- private new ConfigurationDataPasskey configData => (ConfigurationDataPasskey)base.configData;
-
- public ShareWood(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps, ICacheService cs)
- : base(configService: configService,
- client: wc,
- logger: l,
- p: ps,
- cacheService: cs,
- configData: new ConfigurationDataPasskey())
- {
- // requestDelay for API Limit (1 request per 4 seconds)
- webclient.requestDelay = 4.1;
-
- var freeLeechOnly = new BoolConfigurationItem("Search freeleech only");
- configData.AddDynamic("freeleechonly", freeLeechOnly);
-
- var replaceMulti = new BoolConfigurationItem("Replace MULTi by another language in release name");
- configData.AddDynamic("replacemulti", replaceMulti);
-
- // Configure the language select option for MULTI
- var languageSelect = new SingleSelectConfigurationItem("Replace MULTi by this language", new Dictionary
- {
- {"FRENCH", "FRENCH"},
- {"MULTi FRENCH", "MULTi FRENCH"},
- {"ENGLISH", "ENGLISH"},
- {"MULTi ENGLISH", "MULTi ENGLISH" },
- {"VOSTFR", "VOSTFR"},
- {"MULTi VOSTFR", "MULTi VOSTFR"}
- })
- { Value = "FRENCH" };
- configData.AddDynamic("languageid", languageSelect);
-
- var replaceVostfr = new BoolConfigurationItem("Replace VOSTFR and SUBFRENCH with ENGLISH");
- configData.AddDynamic("replacevostfr", replaceVostfr);
-
- EnableConfigurableRetryAttempts();
- }
-
- private TorznabCapabilities SetCapabilities()
- {
- var 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
- },
- SupportsRawSearch = true
- };
-
- //CATEGORIES
- //caps.Categories.AddCategoryMapping(1, TorznabCatType.Movies, "Vidéos");
- //caps.Categories.AddCategoryMapping(1, TorznabCatType.TV, "Vidéos");
- //caps.Categories.AddCategoryMapping(2, TorznabCatType.Audio, "Audio");
- //caps.Categories.AddCategoryMapping(3, TorznabCatType.PC, "Application");
- //caps.Categories.AddCategoryMapping(4, TorznabCatType.Books, "Ebooks");
- //caps.Categories.AddCategoryMapping(5, TorznabCatType.PCGames, "Jeu-Vidéo");
- //caps.Categories.AddCategoryMapping(6, TorznabCatType.OtherMisc, "Formation");
- //caps.Categories.AddCategoryMapping(7, TorznabCatType.XXX, "XXX");
-
- //SUBCATEGORIES
- caps.Categories.AddCategoryMapping(9, TorznabCatType.Movies, "Films");
- caps.Categories.AddCategoryMapping(10, TorznabCatType.TV, "Série");
- caps.Categories.AddCategoryMapping(11, TorznabCatType.MoviesOther, "Film Animation");
- caps.Categories.AddCategoryMapping(12, TorznabCatType.TVAnime, "Série Animation");
- caps.Categories.AddCategoryMapping(13, TorznabCatType.TVDocumentary, "Documentaire");
- caps.Categories.AddCategoryMapping(14, TorznabCatType.TVOther, "Emission TV");
- caps.Categories.AddCategoryMapping(15, TorznabCatType.TVOther, "Spectacle/Concert");
- caps.Categories.AddCategoryMapping(16, TorznabCatType.TVSport, "Sport");
- caps.Categories.AddCategoryMapping(17, TorznabCatType.AudioVideo, "Karaoké Vidéo");
- caps.Categories.AddCategoryMapping(18, TorznabCatType.AudioOther, "Karaoké");
- caps.Categories.AddCategoryMapping(20, TorznabCatType.Audio, "Musique");
- caps.Categories.AddCategoryMapping(21, TorznabCatType.AudioOther, "Podcast");
- caps.Categories.AddCategoryMapping(22, TorznabCatType.AudioOther, "Sample");
- caps.Categories.AddCategoryMapping(23, TorznabCatType.AudioAudiobook, "Ebook Audio");
- caps.Categories.AddCategoryMapping(24, TorznabCatType.BooksEBook, "BD");
- caps.Categories.AddCategoryMapping(25, TorznabCatType.BooksComics, "Comic");
- caps.Categories.AddCategoryMapping(26, TorznabCatType.BooksOther, "Manga");
- caps.Categories.AddCategoryMapping(27, TorznabCatType.Books, "Livre");
- caps.Categories.AddCategoryMapping(28, TorznabCatType.BooksMags, "Presse");
- caps.Categories.AddCategoryMapping(29, TorznabCatType.PC, "Application Linux");
- caps.Categories.AddCategoryMapping(30, TorznabCatType.PC0day, "Application Window");
- caps.Categories.AddCategoryMapping(31, TorznabCatType.PCMac, "Application Mac");
- caps.Categories.AddCategoryMapping(34, TorznabCatType.PCMobileiOS, "Application Smartphone/Tablette");
- caps.Categories.AddCategoryMapping(34, TorznabCatType.PCMobileAndroid, "Application Smartphone/Tablette");
- caps.Categories.AddCategoryMapping(35, TorznabCatType.PCMobileOther, "GPS");
- caps.Categories.AddCategoryMapping(36, TorznabCatType.PCGames, "Jeux Linux");
- caps.Categories.AddCategoryMapping(37, TorznabCatType.PCGames, "Jeux Windows");
- caps.Categories.AddCategoryMapping(39, TorznabCatType.ConsoleNDS, "Jeux Nintendo");
- caps.Categories.AddCategoryMapping(39, TorznabCatType.ConsoleWii, "Jeux Nintendo");
- caps.Categories.AddCategoryMapping(39, TorznabCatType.ConsoleWiiware, "Jeux Nintendo");
- caps.Categories.AddCategoryMapping(39, TorznabCatType.Console3DS, "Jeux Nintendo");
- caps.Categories.AddCategoryMapping(39, TorznabCatType.ConsoleWiiU, "Jeux Nintendo");
- caps.Categories.AddCategoryMapping(41, TorznabCatType.PCMobileAndroid, "PC/Mobile-Android");
- caps.Categories.AddCategoryMapping(42, TorznabCatType.PCGames, "Jeux Microsoft");
- caps.Categories.AddCategoryMapping(44, TorznabCatType.XXX, "XXX Films");
- caps.Categories.AddCategoryMapping(45, TorznabCatType.XXXOther, "XXX Hentai");
- caps.Categories.AddCategoryMapping(47, TorznabCatType.XXXImageSet, "XXX Images");
- caps.Categories.AddCategoryMapping(48, TorznabCatType.XXXOther, "XXX Jeu-Vidéo");
- caps.Categories.AddCategoryMapping(49, TorznabCatType.OtherMisc, "Formations Vidéos");
- caps.Categories.AddCategoryMapping(50, TorznabCatType.OtherMisc, "Formation Logiciels");
- caps.Categories.AddCategoryMapping(51, TorznabCatType.XXXOther, "XXX Ebooks");
- caps.Categories.AddCategoryMapping(52, TorznabCatType.AudioVideo, "Vidéos-Clips");
-
- return caps;
- }
-
- private string MultiRename(string term, string replacement)
- {
- replacement = " " + replacement + " ";
- term = Regex.Replace(term, @"(?i)\b(MULTI(?!.*(?:FRENCH|ENGLISH|VOSTFR)))\b", replacement);
- return term;
- }
-
- private string VostfrRename(string term, string replacement)
- {
- term = Regex.Replace(term, @"(?i)\b(vostfr|subfrench)\b", replacement);
- return term;
- }
-
- private bool GetFreeLeech => ((BoolConfigurationItem)configData.GetDynamic("freeleechonly")).Value;
- private bool GetReplaceMulti => ((BoolConfigurationItem)configData.GetDynamic("replacemulti")).Value;
- private string GetLang => ((SingleSelectConfigurationItem)configData.GetDynamic("languageid")).Value;
- private bool GetReplaceVostfr => ((BoolConfigurationItem)configData.GetDynamic("replacevostfr")).Value;
-
- public override async Task ApplyConfiguration(JToken configJson)
- {
- LoadValuesFromJson(configJson);
-
- if (configData.Passkey.Value.Length != 32)
- {
- throw new Exception("Invalid Passkey configured. Expected length: 32");
- }
-
- var releases = await PerformQuery(new TorznabQuery());
-
- await ConfigureIfOK(string.Empty, releases.Any(), () => throw new Exception("Could not find releases."));
-
- return IndexerConfigurationStatus.Completed;
- }
-
- protected override async Task> PerformQuery(TorznabQuery query)
- {
- var releases = new List();
-
- var categoryMapping = MapTorznabCapsToTrackers(query).Distinct().ToList();
-
- if (!categoryMapping.Any())
- {
- // NO CATEGORIES ==> RSS SEARCH
- categoryMapping.Add("1000");
- }
-
- var term = query.GetQueryString().Trim();
- term = Regex.Replace(term, @"[\:\-\/\|\(\)]+", " ");
-
- foreach (var categoryId in categoryMapping)
- {
- var searchUrl = SearchUrl;
-
- var parameters = new NameValueCollection
- {
- { "limit", categoryId != "1000" ? "25" : "100" }
- };
-
- if (categoryId != "1000")
- {
- parameters.Set("subcategory", categoryId);
- }
-
- if (term.IsNotNullOrWhiteSpace())
- {
- parameters.Set("name", term);
- searchUrl += "/search";
- }
- else
- {
- searchUrl += "/last-torrents";
- }
-
- if (parameters.Count > 0)
- {
- searchUrl += $"?{parameters.GetQueryString()}";
- }
-
- var response = await RequestWithCookiesAsync(searchUrl);
- if (response.Status == HttpStatusCode.Unauthorized)
- {
- response = await RequestWithCookiesAsync(searchUrl);
- }
- else if (response.Status != HttpStatusCode.OK)
- {
- throw new Exception($"Unknown error in search: {response.ContentString}");
- }
-
- try
- {
- var rows = JArray.Parse(response.ContentString);
- foreach (var row in rows)
- {
- var id = row.Value("id");
- var link = new Uri($"{SearchUrl}/{id}/download");
- var slug = row.Value("slug");
- var details = new Uri($"{SiteLink}torrents/{slug}.{id}");
-
- var cat = row.Value("subcategory_id");
- if (Convert.ToInt32(categoryId) != 1000)
- {
- // USE CATEGORIES OR SUBCATEGORIES
- cat = row.Value(Convert.ToInt32(categoryId) < 8 ? "category_id" : "subcategory_id");
- }
-
- var dlVolumeFactor = row.Value("free") ? 0 : 1;
- var ulVolumeFactor = row.Value("doubleup") ? 2 : 1;
-
- var title = row.Value("name");
-
- //SPECIAL CASES
- if (GetFreeLeech && dlVolumeFactor == 1)
- {
- continue;
- }
-
- if (GetReplaceMulti)
- {
- title = MultiRename(title, GetLang);
- }
-
- if (GetReplaceVostfr)
- {
- title = VostfrRename(title, "ENGLISH");
- }
-
- var release = new ReleaseInfo
- {
- Guid = details,
- Details = details,
- Link = link,
- Title = title,
- Category = MapTrackerCatToNewznab(cat),
- PublishDate = DateTime.Parse(row.Value("created_at"), CultureInfo.InvariantCulture),
- Size = ParseUtil.GetBytes(row.Value("size")),
- Grabs = row.Value("times_completed"),
- Seeders = row.Value("seeders"),
- Peers = row.Value("leechers") + row.Value("seeders"),
- DownloadVolumeFactor = dlVolumeFactor,
- UploadVolumeFactor = ulVolumeFactor,
- MinimumRatio = 1,
- MinimumSeedTime = 259200 // 72 hours
- };
-
- releases.Add(release);
- }
- }
- catch (Exception ex)
- {
- OnParseError(response.ContentString, ex);
- }
- }
- return releases;
- }
-
- public override async Task Download(Uri link)
- {
- var response = await RequestWithCookiesAsync(link.ToString());
-
- if (response.Status == HttpStatusCode.Unauthorized)
- {
- response = await RequestWithCookiesAsync(link.ToString());
- }
-
- if (response.Status != HttpStatusCode.OK)
- {
- logger.Debug("Unknown error in download: {0}", response.ContentString);
-
- throw new Exception($"Unexpected status code: {(int)response.Status} ({response.Status})");
- }
-
- return response.ContentBytes;
- }
- }
-}
diff --git a/src/Jackett.Updater/Program.cs b/src/Jackett.Updater/Program.cs
index 8b08e5ef1..8b02b32a2 100644
--- a/src/Jackett.Updater/Program.cs
+++ b/src/Jackett.Updater/Program.cs
@@ -622,6 +622,7 @@ namespace Jackett.Updater
"Definitions/shareisland.yml", // switch to *-API #8682
"Definitions/sharespacedb.yml",
"Definitions/shareuniversity.yml",
+ "Definitions/sharewood.yml", // switch to *-API #10269
"Definitions/sharingue.yml",
"Definitions/shellife.yml",
"Definitions/sharkpt.yml",