mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-17 17:34:09 +02:00
sharewood-api: migrate to API (#15628)
This commit is contained in:
203
src/Jackett.Common/Definitions/sharewood-api.yml
Normal file
203
src/Jackett.Common/Definitions/sharewood-api.yml
Normal 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
|
@@ -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
|
|
@@ -316,18 +316,28 @@ namespace Jackett.Common.Indexers
|
|||||||
if (query.HasSpecifiedCategories)
|
if (query.HasSpecifiedCategories)
|
||||||
{
|
{
|
||||||
var supportedCats = TorznabCaps.Categories.SupportedCategories(query.Categories);
|
var supportedCats = TorznabCaps.Categories.SupportedCategories(query.Categories);
|
||||||
|
|
||||||
if (supportedCats.Length == 0)
|
if (supportedCats.Length == 0)
|
||||||
{
|
{
|
||||||
if (!isMetaIndexer)
|
if (!isMetaIndexer)
|
||||||
|
{
|
||||||
logger.Error($"All categories provided are unsupported in {Name}: {string.Join(",", query.Categories)}");
|
logger.Error($"All categories provided are unsupported in {Name}: {string.Join(",", query.Categories)}");
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supportedCats.Length != query.Categories.Length && !isMetaIndexer)
|
if (supportedCats.Length != query.Categories.Length && !isMetaIndexer)
|
||||||
{
|
{
|
||||||
var unsupportedCats = query.Categories.Except(supportedCats);
|
var unsupportedCats = query.Categories.Except(supportedCats).ToList();
|
||||||
logger.Warn($"Some of the categories provided are unsupported in {Name}: {string.Join(",", unsupportedCats)}");
|
|
||||||
|
if (unsupportedCats.Any())
|
||||||
|
{
|
||||||
|
logger.Warn($"Some of the categories provided are unsupported in {Name}: {string.Join(",", unsupportedCats)}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -622,6 +622,7 @@ namespace Jackett.Updater
|
|||||||
"Definitions/shareisland.yml", // switch to *-API #8682
|
"Definitions/shareisland.yml", // switch to *-API #8682
|
||||||
"Definitions/sharespacedb.yml",
|
"Definitions/sharespacedb.yml",
|
||||||
"Definitions/shareuniversity.yml",
|
"Definitions/shareuniversity.yml",
|
||||||
|
"Definitions/sharewood.yml", // switch to *-API #10269
|
||||||
"Definitions/sharingue.yml",
|
"Definitions/sharingue.yml",
|
||||||
"Definitions/shellife.yml",
|
"Definitions/shellife.yml",
|
||||||
"Definitions/sharkpt.yml",
|
"Definitions/sharkpt.yml",
|
||||||
|
Reference in New Issue
Block a user