sharewood-api: migrate to API (#15628)

This commit is contained in:
Bogdan
2024-10-07 21:08:05 +03:00
committed by GitHub
parent 7a13a5914f
commit 3e8c6aaa0e
5 changed files with 216 additions and 553 deletions

View File

@@ -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 <a href=\"https://www.sharewood.tv/\" target=\"_blank\">Sharewood</a> profile on the <i>My Profile</i> page and scrolling down to the <b>Passkey</b> 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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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<string, string> _apiHeaders = new Dictionary<string, string>
{
{"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<string, string>
{
{"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>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
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<IndexerConfigurationStatus> 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<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
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<string>("id");
var link = new Uri($"{SearchUrl}/{id}/download");
var slug = row.Value<string>("slug");
var details = new Uri($"{SiteLink}torrents/{slug}.{id}");
var cat = row.Value<string>("subcategory_id");
if (Convert.ToInt32(categoryId) != 1000)
{
// USE CATEGORIES OR SUBCATEGORIES
cat = row.Value<string>(Convert.ToInt32(categoryId) < 8 ? "category_id" : "subcategory_id");
}
var dlVolumeFactor = row.Value<bool>("free") ? 0 : 1;
var ulVolumeFactor = row.Value<bool>("doubleup") ? 2 : 1;
var title = row.Value<string>("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<string>("created_at"), CultureInfo.InvariantCulture),
Size = ParseUtil.GetBytes(row.Value<string>("size")),
Grabs = row.Value<long>("times_completed"),
Seeders = row.Value<long>("seeders"),
Peers = row.Value<long>("leechers") + row.Value<long>("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<byte[]> 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;
}
}
}

View File

@@ -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",