Compare commits

...

60 Commits

Author SHA1 Message Date
Garfield69
a80a42b46f revolutiontt: update cats resolves #16311 2025-11-29 19:00:01 +13:00
Garfield69
b8283d0982 magnetcat: bump alt domains 2025-11-29 18:33:40 +13:00
ilike2burnthing
f07af5dc54 mteamtp: update cats & info (#16313) 2025-11-29 05:31:17 +00:00
Garfield69
8bf22fb3c3 revolutiontt: add new cat. #16311 2025-11-29 16:06:51 +13:00
Garfield69
05c6991783 revolutiontt: add net cat. #16311 2025-11-29 14:57:13 +13:00
jackettbot[bot]
2402ef6c6f Update rudub 2025-11-29 01:29:00 +00:00
Garfield69
d5f1f63486 hdgalaktik: new layout, no cats. resolves #13186 2025-11-29 06:49:26 +13:00
Garfield69
c357a9f4a7 zetorrents: new domain 2025-11-28 18:32:32 +13:00
jackettbot[bot]
0097d823e6 Update rudub 2025-11-28 01:29:07 +00:00
Garfield69
798a4b160f torrentqq: bump domains 2025-11-28 05:07:47 +13:00
jackettbot[bot]
b0dbd475dc Update rudub 2025-11-27 01:29:09 +00:00
Garfield69
14b132e4f3 torrenttip: bump domain 2025-11-26 18:35:37 +13:00
Garfield69
5e78223cdc torrentsome: bump domain 2025-11-26 18:35:26 +13:00
jackettbot[bot]
4cd883d432 Update rudub 2025-11-26 01:29:05 +00:00
ilike2burnthing
a1a98f9836 theoldschool-api: add setting to disable imdbid & tvdbid search
https://github.com/Prowlarr/Indexers/issues/691
2025-11-25 22:46:44 +00:00
Garfield69
0c9c144e5a extremebits: CA expired. 2025-11-26 05:26:58 +13:00
Garfield69
a2da916252 zktorrent: new domain 2025-11-25 18:34:09 +13:00
Garfield69
8d85708721 assorted nexus: bump engine tag 2025-11-25 17:03:30 +13:00
Garfield69
a00ff4703e rudub workflow part 2 of 2 previous domain pics -> world 2025-11-25 16:08:38 +13:00
jackettbot[bot]
fcf7694ae7 Update rudub 2025-11-25 01:29:25 +00:00
Garfield69
503030045f torrentkitty: prevent "could not select database" 2025-11-25 09:11:34 +13:00
Garfield69
5f53bea74a sosulki: new domain + change row selector. resolves #7559 2025-11-25 06:12:49 +13:00
Garfield69
855d89296a nicept: bump engine tag and add cookie comment. completes 7800813aee 2025-11-25 05:11:51 +13:00
ilike2burnthing
7800813aee nicept: change to cookie login
`response` JS input
2025-11-24 15:14:42 +00:00
ilike2burnthing
2151dba5d1 rudub workflow part 1 of 2 current domain pics -> world 2025-11-24 14:27:09 +00:00
ilike2burnthing
8e1887a133 Revert "matrix: update cat 26 detection"
This reverts commit aa0ae46fd9.
2025-11-24 14:13:24 +00:00
Garfield69
587bef69d4 nortorrent: new domain 2025-11-24 18:34:15 +13:00
ilike2burnthing
32863c2aa9 matrix: add cat 2025-11-24 04:53:08 +00:00
jackettbot[bot]
6e0a3ea759 Update rudub 2025-11-24 01:29:27 +00:00
Garfield69
7de44d8c9e ArabicSource: add magnet. resolves #15996 2025-11-24 08:45:38 +13:00
Garfield69
53646c28de arabicsource: grabs/seed/leech are long not int 2025-11-24 07:36:20 +13:00
Garfield69
aa0ae46fd9 matrix: update cat 26 detection 2025-11-24 07:15:23 +13:00
Bogdan
535f199e84 anilibria: use TryParse in season and episode parsing 2025-11-23 15:05:12 +02:00
Bogdan
64dd9c6897 anilibria: fix roman to arabic regex
Fixes #16303
2025-11-23 14:58:12 +02:00
jackettbot[bot]
eb3898a961 Update rudub 2025-11-23 01:29:45 +00:00
dependabot[bot]
75bf8d7078 build(deps): bump actions/checkout from 5 to 6 (#16305)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ilike2burnthing <59480337+ilike2burnthing@users.noreply.github.com>
(skip definitions update job for dependabot)
2025-11-22 02:46:28 +00:00
jackettbot[bot]
390b1714f4 Update rudub 2025-11-22 01:28:49 +00:00
Garfield69
6254d62c23 torrentqq: bump domain 2025-11-21 18:32:28 +13:00
jackettbot[bot]
08773ae3c9 Update rudub 2025-11-21 01:28:59 +00:00
jackettbot[bot]
7b7f77e06f Update rudub 2025-11-20 01:29:17 +00:00
Bogdan
64fc61f777 core: refactor remaining obsolete calls (#16301) 2025-11-19 19:41:26 +02:00
Garfield69
dee082ead3 torrenttip: bump domain 2025-11-20 05:39:38 +13:00
Garfield69
6347fdff66 torrentsome: bump domain 2025-11-20 05:39:28 +13:00
Garfield69
cdeac3c0ef kickasstorrents-to: new cat 2025-11-20 05:39:13 +13:00
Bogdan
6d568a4059 yts: update links
Closes #16297
2025-11-19 17:50:18 +02:00
jackettbot[bot]
3dd5b1e5f0 Update rudub 2025-11-19 01:29:18 +00:00
Garfield69
fb9845d1e3 magnetz: q -> query 2025-11-19 13:03:56 +13:00
Garfield69
70b0aa1f67 linuxtracker: new cat 2025-11-19 06:10:10 +13:00
Garfield69
368afcfc5a hdgalaktik: new size selector. resolves dd11b7e6cd 2025-11-18 16:42:57 +13:00
jackettbot[bot]
29d28e2607 Update rudub 2025-11-18 01:29:11 +00:00
Garfield69
b023e8fe6d clearjav: -> 9.1.7 drop info_hash 2025-11-18 06:56:48 +13:00
Garfield69
d51752f682 kickasstorrents-to: new cat 2025-11-18 06:36:40 +13:00
Garfield69
ec40699cdc hdgalaktik: restore previous size selector. reverts dd11b7e6cd 2025-11-18 06:36:24 +13:00
jackettbot[bot]
3c798127c5 Update rudub 2025-11-17 01:29:17 +00:00
Bogdan
61b263dd98 core: refactor obsolete calls (#16290)
* core: refactor obsolete hashing calls

* core: delete cert callback validation removal in update service

* core: remove deprecated ServicePointManager calls

- Avoid harcoding SSL protocols.
- Lowering DefaultConnectionLimit 1000 to MaxConnectionsPerServer 20

* core: avoid is only supported on windows warnings
2025-11-16 22:05:22 +02:00
ilike2burnthing
dd11b7e6cd hdgalaktik: update size selector & remove cert exception 2025-11-16 19:05:54 +00:00
jackettbot[bot]
bec42c4ac0 Update rudub 2025-11-16 01:29:39 +00:00
Garfield69
9b08d7ad46 hdgalaktik: new layout resolves #13186
necessitates switching to categorydesc
plus new selectors
2025-11-16 13:10:06 +13:00
Garfield69
9311af24b5 uztracker: update cats 2025-11-16 06:01:56 +13:00
jackettbot[bot]
9e5d79d2a4 Update rudub 2025-11-15 01:29:11 +00:00
55 changed files with 418 additions and 545 deletions

View File

@@ -57,7 +57,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL

View File

@@ -15,7 +15,7 @@ concurrency:
jobs: jobs:
update-rudub: update-rudub:
name: Update rudub name: Update rudub
if: github.repository == 'Jackett/Jackett' if: (github.repository == 'Jackett/Jackett' && github.actor != 'dependabot[bot]')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
@@ -34,14 +34,14 @@ jobs:
GH_TOKEN: ${{ steps.app-token.outputs.token }} GH_TOKEN: ${{ steps.app-token.outputs.token }}
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v6
with: with:
token: ${{ steps.app-token.outputs.token }} token: ${{ steps.app-token.outputs.token }}
- name: Setup Environment Variables - name: Setup Environment Variables
run: | run: |
echo "CURRENT_RUDUB_DOMAIN=$(date +'%b%d' | tr '[:upper:]' '[:lower:]').rudub.pics" >> $GITHUB_ENV echo "CURRENT_RUDUB_DOMAIN=$(date +'%b%d' | tr '[:upper:]' '[:lower:]').rudub.world" >> $GITHUB_ENV
echo "PREVIOUS_RUDUB_DOMAIN=$(date --date='yesterday' +'%b%d' | tr '[:upper:]' '[:lower:]').rudub.pics" >> $GITHUB_ENV echo "PREVIOUS_RUDUB_DOMAIN=$(date --date='yesterday' +'%b%d' | tr '[:upper:]' '[:lower:]').rudub.world" >> $GITHUB_ENV
- name: Update rudub definition - name: Update rudub definition
uses: mikefarah/yq@master uses: mikefarah/yq@master

View File

@@ -20,7 +20,7 @@ jobs:
steps: steps:
# This workflow will run a script that is stored in the repository. This step checks out the repository contents so that the workflow can access the script. # This workflow will run a script that is stored in the repository. This step checks out the repository contents so that the workflow can access the script.
- name: Check out repo content - name: Check out repo content
uses: actions/checkout@v5 uses: actions/checkout@v6
# This step sets up Node.js. The script that this workflow will run uses Node.js. # This step sets up Node.js. The script that this workflow will run uses Node.js.
- name: Setup Node.js - name: Setup Node.js

View File

@@ -431,7 +431,7 @@ Prior versions of Jackett are no longer supported.
* LosslessClub [![(invite needed)][inviteneeded]](#) * LosslessClub [![(invite needed)][inviteneeded]](#)
* LST * LST
* LuckPT [![(invite needed)][inviteneeded]](#) * LuckPT [![(invite needed)][inviteneeded]](#)
* M-Team TP (MTTP) [![(invite needed)][inviteneeded]](#) * M-Team - TP (MTTP)
* MaDs Revolution * MaDs Revolution
* Majomparádé (TurkDepo) * Majomparádé (TurkDepo)
* Making Off * Making Off

View File

@@ -182,4 +182,4 @@ search:
description: description:
selector: td.rowfollow:nth-child(2) selector: td.rowfollow:nth-child(2)
remove: a, b, font, img, span remove: a, b, font, img, span
# NexusPHP v1.9.10 2025-10-30 # NexusPHP v1.9.11 2025-11-02

View File

@@ -94,8 +94,6 @@ search:
selector: details_link selector: details_link
download: download:
selector: download_link selector: download_link
infohash:
selector: info_hash
files: files:
selector: num_file selector: num_file
seeders: seeders:
@@ -145,4 +143,4 @@ search:
minimumseedtime: minimumseedtime:
# 7 days (as seconds = 7 x 24 x 60 x 60) # 7 days (as seconds = 7 x 24 x 60 x 60)
text: 604800 text: 604800
# json UNIT3D 9.1.5 (custom) # json UNIT3D 9.1.7 (custom)

View File

@@ -5,6 +5,8 @@ description: "ExtremeBits is a Private Torrent Tracker for EXTREME SPORTS"
language: en-US language: en-US
type: private type: private
encoding: UTF-8 encoding: UTF-8
certificates:
- 0e7f0e9c468938a43058d72c69ffdb9a98e24eab # Expired 26th Nov 2025
links: links:
- https://extremebits.net/ - https://extremebits.net/

View File

@@ -231,4 +231,4 @@ search:
filters: filters:
- name: prepend - name: prepend
args: "{{ .Result.description_verified }} " args: "{{ .Result.description_verified }} "
# NexusPHP v1.9.10 2025-10-30 # NexusPHP v1.9.11 2025-11-02

View File

@@ -5,8 +5,6 @@ description: "HDGalaKtik is a RUSSIAN Semi-Private tracker for MOVIES / TV / GEN
language: ru-RU language: ru-RU
type: semi-private type: semi-private
encoding: UTF-8 encoding: UTF-8
certificates:
- 89cb539248b0d0cb0e92aa3f286ddfdd8347c3be # CN=mail.trackerpmr.com
links: links:
- https://www.trackerpmr.com/ - https://www.trackerpmr.com/
- https://freetmd.com/ - https://freetmd.com/
@@ -16,20 +14,22 @@ legacylinks:
caps: caps:
categorymappings: categorymappings:
- {id: 13, cat: Movies, desc: "Фильмы (Movies)"} # there are no cats in results and searching with cats gives no results
- {id: 6, cat: TV, desc: "Мультфильмы (Cartoons)"} # - {id: 13, cat: Movies, desc: "Фильмы"}
- {id: 10, cat: Audio, desc: "Музыка (Music)"} # - {id: 11, cat: TV, desc: "Сериалы"}
- {id: 26, cat: PC, desc: "Программы (Programs)"} # - {id: 6, cat: TV, desc: "Мультфильмы"}
- {id: 5, cat: Console, desc: "Игры (Games)"} # - {id: 10, cat: Audio, desc: "Музыка"}
- {id: 25, cat: Other, desc: "Картинки (Pictures)"} # - {id: 26, cat: PC, desc: "Программы"}
- {id: 11, cat: TV, desc: "Сериалы (TV Series)"} # - {id: 5, cat: Console, desc: "Игры"}
- {id: 12, cat: TV/Anime, desc: "Аниме (Anime)"} # - {id: 25, cat: Other, desc: "Картинки"}
- {id: 16, cat: Books, desc: "Книги (Books)"} # - {id: 12, cat: TV/Anime, desc: "Аниме"}
- {id: 18, cat: Audio/Video, desc: "Клипы / Ролики (Clips / Trailers)"} # - {id: 16, cat: Books, desc: "Книги"}
- {id: 22, cat: TV, desc: "ТВ / Передачи (TV)"} # - {id: 18, cat: Audio/Video, desc: "Клипы / Ролики"}
- {id: 27, cat: PC/Mobile-Other, desc: "Игры - Мобила / КПК (Mobile)"} # - {id: 22, cat: TV, desc: "ТВ / Передачи"}
- {id: 1, cat: PC/ISO, desc: "Образы (ISO)"} # - {id: 27, cat: PC/Mobile-Other, desc: "Игры - Мобила / КПК"}
- {id: 4, cat: Other, desc: "Другое (Other)"} # - {id: 1, cat: PC/ISO, desc: "Образы"}
# - {id: 4, cat: Other, desc: "Другое"}
- {id: Other, cat: Other, desc: Other}
modes: modes:
search: [q] search: [q]
@@ -44,6 +44,8 @@ settings:
label: Cookie label: Cookie
- name: info_cookie - name: info_cookie
type: info_cookie type: info_cookie
- name: info_category_8000
type: info_category_8000
- name: stripcyrillic - name: stripcyrillic
type: checkbox type: checkbox
label: Strip Cyrillic Letters label: Strip Cyrillic Letters
@@ -56,22 +58,23 @@ settings:
type: checkbox type: checkbox
label: Search freeleech only label: Search freeleech only
default: false default: false
- name: sort # sort is not working
type: select # - name: sort
label: Sort requested from site # type: select
default: 4 # label: Sort requested from site
options: # default: 4
4: created # options:
1: title # 4: created
5: size # 1: title
8: seeders # 5: size
- name: type # 8: seeders
type: select # - name: type
label: Order requested from site # type: select
default: desc # label: Order requested from site
options: # default: desc
desc: desc # options:
asc: asc # desc: desc
# asc: asc
- name: info_tpp - name: info_tpp
type: info type: info
label: Results Per Page label: Results Per Page
@@ -87,24 +90,19 @@ login:
selector: a[href="mybonus.php"] selector: a[href="mybonus.php"]
search: search:
# https://www.trackerpmr.com/browse.php?search=&stype=0&s=0&cat=0&gr=0&kp=0&im=0&incldead=1&sort=0&type=desc #https://www.trackerpmr.com/browse.php?cat[]=0&shw_incl_cats=0&incldead=3&search=&tag=#results
paths: paths:
- path: browse.php - path: browse.php
inputs: inputs:
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}" # searching with cats gives no results
search: "{{ .Keywords }}" # $raw: "{{ range .Categories }}cat[]={{.}}&{{end}}"
# 0 title, 1 descr, 2 filename, 4 infohash shw_incl_cats: 0
stype: 0
# 0 AND 1 OR
s: 0
# release group
gr: 0
# ratings
kp: 0
# 1 active, 2 dead, 3 gold, 4 sticky, lots of others # 1 active, 2 dead, 3 gold, 4 sticky, lots of others
incldead: "{{ if .Config.freeleech }}3{{ else }}1{{ end }}" incldead: "{{ if .Config.freeleech }}3{{ else }}1{{ end }}"
sort: "{{ .Config.sort }}" search: "{{ .Keywords }}"
type: "{{ .Config.type }}" # sort is not working
#sort: "{{ .Config.sort }}"
#type: "{{ .Config.type }}"
keywordsfilters: keywordsfilters:
- name: re_replace # S01 to сезон 1 - name: re_replace # S01 to сезон 1
@@ -117,24 +115,21 @@ search:
args: ["[^a-zA-Z0-9]+", "%"] args: ["[^a-zA-Z0-9]+", "%"]
rows: rows:
selector: table.table > tbody > tr.torcontduo selector: tr.torrent-row
fields: fields:
# categorydesc:
# selector: div.category-badge
# optional: true
# default: Другое
# filters:
# - name: replace
# args: ["---", "Другое"]
category: category:
selector: a[href^="browse.php?cat="] text: Other
attribute: href
optional: true
default: 4
filters:
- name: querystring
args: cat
title: title:
selector: a[href^="details.php?id="] selector: a.torrent-title
attribute: title
filters: filters:
- name: regexp
args: \'>(.+?)</div
- name: htmldecode
# normalize to SXXEYY format # normalize to SXXEYY format
- name: re_replace - name: re_replace
args: ["(?i)[CС]езоны?[\\s:]*(\\d+(?:-\\d+)?).+?(?:\\s*(?:[CС]ери[ияй]|Эпизод|Выпуски?))[\\s:]*(\\d+(?:-\\d+)?)\\s*из\\s*(\\w?)", "S$1E$2 of $3"] args: ["(?i)[CС]езоны?[\\s:]*(\\d+(?:-\\d+)?).+?(?:\\s*(?:[CС]ери[ияй]|Эпизод|Выпуски?))[\\s:]*(\\d+(?:-\\d+)?)\\s*из\\s*(\\w?)", "S$1E$2 of $3"]
@@ -193,64 +188,87 @@ search:
- name: append - name: append
args: "{{ if .Config.addrussiantotitle }} RUS{{ else }}{{ end }}" args: "{{ if .Config.addrussiantotitle }} RUS{{ else }}{{ end }}"
details: details:
selector: a[href^="details.php?id="] selector: a.torrent-title
attribute: href attribute: href
# now only DL in results
# there is either a magnet or a download link
# magnet:
# selector: a[href^="magnet:?xt="]
# attribute: href
# optional: true
# download:
# selector: a[href^="download.php?id="]
# attribute: href
# optional: true
download: download:
selector: a[href^="details.php?id="] selector: a[href^="download.php?id="]
attribute: href attribute: href
filters:
- name: replace
args: ["details", "download"]
poster: poster:
selector: img.s selector: img.torrent-poster
attribute: src attribute: src
imdbid: # no imdb anymore
selector: a[href^="browse.php?imdb="] # imdbid:
attribute: href # selector: a[href^="browse.php?imdb="]
filters: # attribute: href
- name: querystring # filters:
args: imdb # - name: querystring
# args: imdb
size: size:
selector: td:nth-child(4) selector: td:nth-child(5)
seeders: seeders:
selector: span[title="Раздают"] selector: td:nth-child(6) > div > span
leechers: leechers:
selector: span[title="Качают"] selector: td:nth-child(6) > div > span:nth-child(2)
date_day: # no grabs anymore
# Сегодня в 18:22 # grabs:
# Вчера в 20:52 # selector: span:has(i.fa-download)
selector: a[href^="browse.php?date="]:contains("Сегодня"), a[href^="browse.php?date="]:contains("Вчера")
optional: true
filters:
- name: regexp
args: "((Вчера в|Сегодня в)( \\d{2}:\\d{2}))"
- name: replace
args: ["Сегодня в", "Today"]
- name: replace
args: ["Вчера в", "Yesterday"]
- name: fuzzytime
date_year:
# 23:48 24/07
selector: a[href^="browse.php?date="]:contains("/")
optional: true
filters:
- name: regexp
args: "(\\d{2}:\\d{2} \\d{2}/\\d{2})"
- name: append
args: " +03:00" # MSK
- name: dateparse
args: "HH:mm dd/MM zzz"
date: date:
text: "{{ if or .Result.date_year .Result.date_day }}{{ or .Result.date_year .Result.date_day }}{{ else }}now{{ end }}" selector: td:nth-child(8)
filters:
# translations for Turkish|Estonian|Danish|Italian|Polish|Norwegian|Portuguese|Czech|Russian|Romanian|Spanish|French|German|Bulgarian|Dutch|Chinese|Japanese|Swedish
- name: re_replace
args: ["(?i)(önce|tagasi|geleden|fa|temu|siden|há|atrás|nazpět|назад|acum|în urmă|hace|il y a|vor|преди|前|sedan)", " ago"]
- name: re_replace
args: ["(?i)(saniye|sekundit|sekunder|secondi|sekund|segundos|sekundami|секунд|secunde|secondes|Sekunden|секунди|seconden|秒前)", "seconds"]
- name: re_replace
args: ["(?i)(minutit|minutter|minuti|minuty|minutos|минуты|минут|Minuten|минути|minuten|minuter)", "minutes"]
- name: re_replace
args: ["(?i)(dakika|minut|minuto|minuta|minutt|минута|Minute|minuut|分钟|分)", " minute"]
- name: re_replace
args: ["(?i)(tundi|timer|ore|godziny|horas|hodiny|hoden|часа|часов|ore|heures|Stunden|timmar)", "hours"]
- name: re_replace
args: ["(?i)(saat|tund|time|ora|godzina|hora|hodina|час|oră|heure|Stunde|uur|小时|時間|timme)", " hour"]
- name: re_replace
args: ["(?i)(päeva|dage|giorni|dni|dias|dny|дня|дней|zile|días|jours|Tagen|дни|dagen|dagar)", "days"]
- name: re_replace
args: ["(?i)(gün|päev|dag|giorno|dzień|dia|den|день|zi|día|jour|Tag|ден|天|日)", " day"]
- name: re_replace
args: ["(?i)(nädalat|uger|settimane|tygodnie|uker|semanas|týdny|недели|недель|săptămâni|semaines|Wochen|седмици|weken|veckor)", "weeks"]
- name: re_replace
args: ["(?i)(hafta|nädal|uge|settimana|tydzień|uke|semana|týden|неделю|săptămână|semaine|Woche|седмица|周|週間|vecka)", " week"]
- name: re_replace
args: ["(?i) (ay)", "month"]
- name: re_replace
args: ["(?i)(kuud|måneder|mesi|miesiące|meses|měsíce|месяца|месяцев|luni|meses|mois|Monaten|месеца|maanden|månader)", "months"]
- name: re_replace
args: ["(?i)(kuu|måned|mese|miesiąc|mês|měsíc|месяц|lună|mes|Monat|месец|maand|个月|ヶ月|månad)", " month"]
- name: re_replace
args: ["(?i)(aastat|anni|lata|anos|roky|года|ani|años|ans|Jahren|години)", " years"]
- name: re_replace
args: ["(?i)(yil|aasta|år|anno|rok|ano|год|año|Jahr|година|jaar|年)", " year"]
- name: re_replace
args: ["(?i) (an)", "year"]
- name: re_replace
args: ["(?i)(För |und)", ""] # Misc removals
- name: timeago
downloadvolumefactor: downloadvolumefactor:
case: case:
img[src="/pic/freedownload.gif"]: 0 span.bg-warning: 0
"*": 1 "*": 1
uploadvolumefactor: uploadvolumefactor:
text: 1 text: 1
minimumratio: minimumratio:
text: 1.0 text: 1.0
description: description:
selector: a[href*="?tag="] selector: td:nth-child(2) > div > div > div
attribute: title
# engine n/a # engine n/a

View File

@@ -35,10 +35,12 @@ caps:
- {id: Anime, cat: TV/Anime, desc: Anime} - {id: Anime, cat: TV/Anime, desc: Anime}
- {id: AnimeAudioLossless, cat: Audio/Lossless, desc: "Anime Audio Lossless"} - {id: AnimeAudioLossless, cat: Audio/Lossless, desc: "Anime Audio Lossless"}
- {id: "AnimeAudio[Lossless]", cat: Audio/Lossless, desc: "Anime Audio Lossless"} - {id: "AnimeAudio[Lossless]", cat: Audio/Lossless, desc: "Anime Audio Lossless"}
- {id: "AnimeAudio[Lossy]", cat: Audio/MP3, desc: "Anime Audio Lossy"}
- {id: AnimeEnglish-translated, cat: TV/Anime, desc: "Anime English-translated"} - {id: AnimeEnglish-translated, cat: TV/Anime, desc: "Anime English-translated"}
- {id: "AnimeLiveAction[English-translated]", cat: TV/Anime, desc: "Anime Live Action English-translated"} - {id: "AnimeLiveAction[English-translated]", cat: TV/Anime, desc: "Anime Live Action English-translated"}
- {id: "AnimeLiveAction[Non-English]", cat: TV/Anime, desc: "Anime Live Action Non-English"} - {id: "AnimeLiveAction[Non-English]", cat: TV/Anime, desc: "Anime Live Action Non-English"}
- {id: "AnimeLiveAction[Raw]", cat: TV/Anime, desc: "Anime Live Action Raw"} - {id: "AnimeLiveAction[Raw]", cat: TV/Anime, desc: "Anime Live Action Raw"}
- {id: AnimePictures, cat: Other, desc: Anime Pictures}
- {id: AnimeRaw, cat: TV/Anime, desc: Anime Raw} - {id: AnimeRaw, cat: TV/Anime, desc: Anime Raw}
- {id: AnimeSubs, cat: TV/Anime, desc: Anime Subs} - {id: AnimeSubs, cat: TV/Anime, desc: Anime Subs}
- {id: Apps, cat: PC, desc: Apps} - {id: Apps, cat: PC, desc: Apps}

View File

@@ -281,6 +281,7 @@ caps:
- {id: 2281, cat: PC/ISO, desc: "Web Security Dojo"} - {id: 2281, cat: PC/ISO, desc: "Web Security Dojo"}
- {id: 2246, cat: PC/ISO, desc: "Whonix"} - {id: 2246, cat: PC/ISO, desc: "Whonix"}
- {id: 2155, cat: PC/ISO, desc: "Wifislax"} - {id: 2155, cat: PC/ISO, desc: "Wifislax"}
- {id: 2229, cat: PC/ISO, desc: "XiVa Studio"}
- {id: 2251, cat: PC/ISO, desc: "XigmaNAS"} - {id: 2251, cat: PC/ISO, desc: "XigmaNAS"}
- {id: 607, cat: PC/ISO, desc: "Xubuntu"} - {id: 607, cat: PC/ISO, desc: "Xubuntu"}
- {id: 612, cat: PC/ISO, desc: "Zen"} - {id: 612, cat: PC/ISO, desc: "Zen"}

View File

@@ -182,4 +182,4 @@ search:
description: description:
selector: td.rowfollow:nth-child(2) selector: td.rowfollow:nth-child(2)
remove: a, b, font, img, span remove: a, b, font, img, span
# NexusPHP v1.9.9 2025-10-02 # NexusPHP v1.9.11 2025-11-02

View File

@@ -9,16 +9,12 @@ encoding: UTF-8
links: links:
- https://magnetcatcat.com/ - https://magnetcatcat.com/
- https://clmclm.com/ - https://clmclm.com/
- https://www.8800519.xyz/ - https://www.8800524.xyz/
- https://www.8800521.xyz/ - https://www.8800525.xyz/
- https://www.8800522.xyz/ - https://www.8800526.xyz/
- https://www.8800523.xyz/ - https://www.8800527.xyz/
legacylinks: legacylinks:
- https://www.clm472.sbs/ - https://www.clm472.sbs/
- https://www.8800500.xyz/
- https://www.8800503.xyz/
- https://www.8800504.xyz/
- https://www.8800505.xyz/
- https://www.8800506.xyz/ - https://www.8800506.xyz/
- https://www.8800507.xyz/ - https://www.8800507.xyz/
- https://www.8800508.xyz/ - https://www.8800508.xyz/
@@ -31,6 +27,10 @@ legacylinks:
- https://www.8800517.xyz/ - https://www.8800517.xyz/
- https://www.8800518.xyz/ - https://www.8800518.xyz/
- https://www.8800520.xyz/ - https://www.8800520.xyz/
- https://www.8800519.xyz/
- https://www.8800521.xyz/
- https://www.8800522.xyz/
- https://www.8800523.xyz/
caps: caps:
categorymappings: categorymappings:

View File

@@ -32,7 +32,7 @@ search:
paths: paths:
- path: search - path: search
inputs: inputs:
q: "{{ if .Keywords }}{{ .Keywords }}{{ else }}*{{ end }}" query: "{{ if .Keywords }}{{ .Keywords }}{{ else }}*{{ end }}"
rows: rows:
selector: a.list-group-item selector: a.list-group-item

View File

@@ -31,7 +31,7 @@ caps:
- {id: 62, cat: Movies/UHD, desc: "Film/HU/UHD"} - {id: 62, cat: Movies/UHD, desc: "Film/HU/UHD"}
- {id: 4, cat: PC/Games, desc: "Játékok/ISO"} - {id: 4, cat: PC/Games, desc: "Játékok/ISO"}
- {id: 39, cat: PC/Games, desc: "Játékok/Rip/Dox"} - {id: 39, cat: PC/Games, desc: "Játékok/Rip/Dox"}
# - {id: 47, cat: Other, desc: "Klippek"} - {id: 47, cat: Other, desc: "Klippek"}
- {id: 30, cat: Audio/Lossless, desc: "Lossless/EN"} - {id: 30, cat: Audio/Lossless, desc: "Lossless/EN"}
# - {id: 29, cat: Audio/Lossless, desc: "Lossless/HU"} # - {id: 29, cat: Audio/Lossless, desc: "Lossless/HU"}
- {id: 25, cat: Audio/MP3, desc: "MP3/EN"} - {id: 25, cat: Audio/MP3, desc: "MP3/EN"}
@@ -141,7 +141,7 @@ search:
img[src="/pic/categories/uhd_hun.png"]: 62 img[src="/pic/categories/uhd_hun.png"]: 62
img[src="/pic/categories/021.png"]: 4 img[src="/pic/categories/021.png"]: 4
img[src="/pic/categories/cat_games.gif"]: 39 img[src="/pic/categories/cat_games.gif"]: 39
# img[]: 47 img[src="/pic/categories/026.png"]: 47
img[src="/pic/categories/024.png"]: 30 img[src="/pic/categories/024.png"]: 30
# img[]: 29 # img[]: 29
img[src="/pic/categories/023.png"]: 25 img[src="/pic/categories/023.png"]: 25

View File

@@ -23,19 +23,11 @@ caps:
search: [q] search: [q]
settings: settings:
- name: username - name: cookie
type: text type: text
label: Username label: Cookie
- name: password - name: info_cookie
type: password type: info_cookie
label: Password
- name: 2facode
type: text
label: 2FA code
- name: info_2fa
type: info
label: "About 2FA code"
default: "Only fill in the <b>2FA code</b> box if you have enabled <b>2FA</b> on the NicePT Web Site. Otherwise just leave it empty."
- name: freeleech - name: freeleech
type: checkbox type: checkbox
label: Search freeleech only label: Search freeleech only
@@ -66,20 +58,10 @@ settings:
default: "Account retention rules:<ol><li>Veteran Users users and above will be retained forever</li><li>Elite Users and above will not have their account deleted after parking (in the Control Panel)</li><li>Users with a parked account will be deleted if they do not log in for 400 consecutive days</li><li>Users with a non-parked account will be banned if they do not log in for 40 consecutive days</li><li>Users with no traffic (ie, upload/download data are both 0) will be banned if they do not log in for 7 consecutive days.</li></ol>" default: "Account retention rules:<ol><li>Veteran Users users and above will be retained forever</li><li>Elite Users and above will not have their account deleted after parking (in the Control Panel)</li><li>Users with a parked account will be deleted if they do not log in for 400 consecutive days</li><li>Users with a non-parked account will be banned if they do not log in for 40 consecutive days</li><li>Users with no traffic (ie, upload/download data are both 0) will be banned if they do not log in for 7 consecutive days.</li></ol>"
login: login:
path: login.php # using cookie method because site does a JS call to API/Challenge via JQuery to load response parm required for takelogin.php
method: form method: cookie
form: form[action="takelogin.php"]
captcha:
type: image
selector: img[alt="CAPTCHA"]
input: imagestring
inputs: inputs:
secret: "" cookie: "{{ .Config.cookie }}"
username: "{{ .Config.username }}"
password: "{{ .Config.password }}"
two_step_code: "{{ .Config.2facode }}"
error:
- selector: td.embedded:has(h2:contains("失败"))
test: test:
path: index.php path: index.php
selector: a[href="logout.php"] selector: a[href="logout.php"]
@@ -187,4 +169,4 @@ search:
filters: filters:
- name: prepend - name: prepend
args: "{{ .Result.description_verified }} " args: "{{ .Result.description_verified }} "
# NexusPHP v1.9.4 2025-06-01 # NexusPHP v1.9.11 2025-11-02

View File

@@ -10,8 +10,7 @@ type: public
encoding: UTF-8 encoding: UTF-8
# to fetch current domain use https://www.rantop.org/ # to fetch current domain use https://www.rantop.org/
links: links:
- https://www.nortorrent.town/ - https://ww1-nortorrent.me/
- https://nortorrent-proxy.site/
legacylinks: legacylinks:
# latest domains list # latest domains list
- https://www.rantop.org/ - https://www.rantop.org/
@@ -27,8 +26,6 @@ legacylinks:
- https://www.site-torrent.com/ - https://www.site-torrent.com/
- https://www.rantop.my/ - https://www.rantop.my/
# actual legacylinks # actual legacylinks
- https://www.torrent9.run/
- https://www.torrent9.cv/
- https://www.torrent9.ke/ - https://www.torrent9.ke/
- https://www.torrent9.gdn/ - https://www.torrent9.gdn/
- https://www.torrent9.men/ - https://www.torrent9.men/
@@ -42,6 +39,8 @@ legacylinks:
- https://www.nortorrent5.com/ - https://www.nortorrent5.com/
- https://www.nortorrent6.com/ - https://www.nortorrent6.com/
- https://www.nortorrent.net/ - https://www.nortorrent.net/
- https://www.nortorrent.town/
- https://nortorrent-proxy.site/
caps: caps:
categorymappings: categorymappings:

View File

@@ -183,4 +183,4 @@ search:
description: description:
selector: td:nth-child(2) selector: td:nth-child(2)
remove: a, b, font, img, span remove: a, b, font, img, span
# NexusPHP v1.9.6 2025-06-25 # NexusPHP v1.9.11 2025-11-02

View File

@@ -194,4 +194,4 @@ search:
description: description:
selector: td.rowfollow:nth-child(2) selector: td.rowfollow:nth-child(2)
remove: a, b, font, img, span remove: a, b, font, img, span
# NexusPHP v1.9.6 2025-06-25 # NexusPHP v1.9.11 2025-11-02

View File

@@ -227,4 +227,4 @@ search:
filters: filters:
- name: prepend - name: prepend
args: "{{ .Result.description_verified }} " args: "{{ .Result.description_verified }} "
# NexusPHP v1.9.3 2025-05-24 # NexusPHP v1.9.11 2025-11-02

View File

@@ -9,38 +9,38 @@ type: semi-private
encoding: windows-1251 encoding: windows-1251
followredirect: true followredirect: true
links: links:
- https://nov14.rudub.pics/ - https://nov29.rudub.world/
legacylinks: legacylinks:
- https://oct30.rudub.homes/ - https://nov14.rudub.pics/
- http://oct31.rudub.homes/ - http://nov15.rudub.pics/
- https://oct31.rudub.homes/ - https://nov15.rudub.pics/
- http://nov01.rudub.homes/ - http://nov16.rudub.pics/
- https://nov01.rudub.homes/ - https://nov16.rudub.pics/
- http://nov02.rudub.homes/ - http://nov17.rudub.pics/
- https://nov02.rudub.homes/ - https://nov17.rudub.pics/
- http://nov03.rudub.homes/ - http://nov18.rudub.pics/
- https://nov03.rudub.homes/ - https://nov18.rudub.pics/
- http://nov04.rudub.homes/ - http://nov19.rudub.pics/
- https://nov04.rudub.homes/ - https://nov19.rudub.pics/
- http://nov05.rudub.homes/ - http://nov20.rudub.pics/
- https://nov05.rudub.homes/ - https://nov20.rudub.pics/
- http://nov06.rudub.homes/ - http://nov21.rudub.pics/
- https://nov06.rudub.homes/ - https://nov21.rudub.pics/
- http://nov07.rudub.pics/ - http://nov22.rudub.pics/
- https://nov07.rudub.pics/ - https://nov22.rudub.pics/
- http://nov08.rudub.pics/ - http://nov23.rudub.pics/
- https://nov08.rudub.pics/ - https://nov23.rudub.pics/
- http://nov09.rudub.pics/ - http://nov24.rudub.pics/
- https://nov09.rudub.pics/ - https://nov24.rudub.pics/
- http://nov10.rudub.pics/ - http://nov25.rudub.world/
- https://nov10.rudub.pics/ - https://nov25.rudub.world/
- http://nov11.rudub.pics/ - http://nov26.rudub.world/
- https://nov11.rudub.pics/ - https://nov26.rudub.world/
- http://nov12.rudub.pics/ - http://nov27.rudub.world/
- https://nov12.rudub.pics/ - https://nov27.rudub.world/
- http://nov13.rudub.pics/ - http://nov28.rudub.world/
- https://nov13.rudub.pics/ - https://nov28.rudub.world/
- http://nov14.rudub.pics/ - http://nov29.rudub.world/
caps: caps:
categorymappings: categorymappings:
- {id: 1, cat: TV, desc: "TV"} - {id: 1, cat: TV, desc: "TV"}

View File

@@ -6,10 +6,11 @@ language: ru-RU
type: public type: public
encoding: UTF-8 encoding: UTF-8
links: links:
- https://sosulki.com/ - https://sosulki.hlom.ru/
legacylinks: legacylinks:
- http://sosulki.net/ - http://sosulki.net/
- http://sosulki.com/ # site forces https - http://sosulki.com/ # site forces https
- https://sosulki.com/
caps: caps:
categorymappings: categorymappings:
- {id: 12, cat: XXX, desc: "Порно категории"} - {id: 12, cat: XXX, desc: "Порно категории"}
@@ -46,7 +47,7 @@ search:
- path: "{{ if .Keywords }}?do=search&subaction=search&search_start=0&full_search=1&result_from=1&story={{ .Keywords }}&titleonly=3&catlist[]=0&searchdate=0&resorder=desc{{ else }}lastnews/{{ end }}" - path: "{{ if .Keywords }}?do=search&subaction=search&search_start=0&full_search=1&result_from=1&story={{ .Keywords }}&titleonly=3&catlist[]=0&searchdate=0&resorder=desc{{ else }}lastnews/{{ end }}"
rows: rows:
selector: tr.fr_viewn_in:has(td.frs:contains("B")) selector: tr.fr_viewn_in
fields: fields:
category: category:

View File

@@ -40,6 +40,10 @@ settings:
type: checkbox type: checkbox
label: Search freeleech only label: Search freeleech only
default: false default: false
- name: tmdbidonly
type: checkbox
label: Disable IMDB and TVDB ID search (only support TMDB ID) to potentially improve Sonarr and Radarr results
default: false
- name: multilang - name: multilang
type: checkbox type: checkbox
label: Replace MULTi by another language in release name label: Replace MULTi by another language in release name
@@ -110,9 +114,9 @@ search:
name: "{{ .Keywords }}" name: "{{ .Keywords }}"
seasonNumber: "{{ .Query.Season }}" seasonNumber: "{{ .Query.Season }}"
episodeNumber: "{{ .Query.Ep }}" episodeNumber: "{{ .Query.Ep }}"
imdbId: "{{ .Query.IMDBIDShort }}" imdbId: "{{ if .Config.tmdbidonly }}{{ else }}{{ .Query.IMDBIDShort }}{{ end }}"
tmdbId: "{{ .Query.TMDBID }}" tmdbId: "{{ .Query.TMDBID }}"
tvdbId: "{{ .Query.TVDBID }}" tvdbId: "{{ if .Config.tmdbidonly }}{{ else }}{{ .Query.TVDBID }}{{ end }}"
"free[]": "{{ if .Config.freeleech }}100{{ else }}{{ end }}" "free[]": "{{ if .Config.freeleech }}100{{ else }}{{ end }}"
sortField: "{{ .Config.sort }}" sortField: "{{ .Config.sort }}"
sortDirection: "{{ .Config.type }}" sortDirection: "{{ .Config.type }}"

View File

@@ -36,7 +36,7 @@ settings:
search: search:
paths: paths:
- path: "search/{{ if .Keywords }}{{ .Keywords }}{{ else }}{{ .Today.Year }}{{ end }}" - path: "search/{{ if .Keywords }}{{ .Keywords }}{{ else }}{{ .Today.Year }}{{ end }}/"
rows: rows:
selector: table#archiveResult tbody tr:has(a[href^="magnet:?xt="]) selector: table#archiveResult tbody tr:has(a[href^="magnet:?xt="])

View File

@@ -7,14 +7,11 @@ type: public
encoding: UTF-8 encoding: UTF-8
followredirect: true followredirect: true
links: links:
- https://torrentqq394.com/ - https://torrentqq396.com/
- https://torrentegg83.com/ - https://torrentegg84.com/
legacylinks: legacylinks:
- https://torrentegg68.com/
- https://torrentegg69.com/ - https://torrentegg69.com/
- https://torrentqq379.com/
- https://torrentegg70.com/ - https://torrentegg70.com/
- https://torrentqq380.com/
- https://torrentegg71.com/ - https://torrentegg71.com/
- https://torrentqq381.com/ - https://torrentqq381.com/
- https://torrentqq382.com/ - https://torrentqq382.com/
@@ -40,6 +37,9 @@ legacylinks:
- https://torrentqq392.com/ - https://torrentqq392.com/
- https://torrentegg82.com/ - https://torrentegg82.com/
- https://torrentqq393.com/ - https://torrentqq393.com/
- https://torrentqq394.com/
- https://torrentqq395.com/
- https://torrentegg83.com/
caps: caps:
categorymappings: categorymappings:

View File

@@ -9,10 +9,8 @@ followredirect: true
requestDelay: 2 requestDelay: 2
# to fetch current domain use https://tzip.top/ # to fetch current domain use https://tzip.top/
links: links:
- https://torrentsome221.com/ - https://torrentsome223.com/
legacylinks: legacylinks:
- https://torrentsome206.com/
- https://torrentsome207.com/
- https://torrentsome208.com/ - https://torrentsome208.com/
- https://torrentsome209.com/ - https://torrentsome209.com/
- https://torrentsome210.com/ - https://torrentsome210.com/
@@ -26,6 +24,8 @@ legacylinks:
- https://torrentsome218.com/ - https://torrentsome218.com/
- https://torrentsome219.com/ - https://torrentsome219.com/
- https://torrentsome220.com/ - https://torrentsome220.com/
- https://torrentsome221.com/
- https://torrentsome222.com/
caps: caps:
categorymappings: categorymappings:

View File

@@ -9,10 +9,8 @@ followredirect: true
requestDelay: 2 requestDelay: 2
# to fetch current domain use https://tzip.top/ # to fetch current domain use https://tzip.top/
links: links:
- https://torrenttip202.top/ - https://torrenttip204.top/
legacylinks: legacylinks:
- https://torrenttip187.top/
- https://torrenttip188.top/
- https://torrenttip189.top/ - https://torrenttip189.top/
- https://torrenttip190.top/ - https://torrenttip190.top/
- https://torrenttip191.top/ - https://torrenttip191.top/
@@ -26,6 +24,8 @@ legacylinks:
- https://torrenttip199.top/ - https://torrenttip199.top/
- https://torrenttip200.top/ - https://torrenttip200.top/
- https://torrenttip201.top/ - https://torrenttip201.top/
- https://torrenttip202.top/
- https://torrenttip203.top/
caps: caps:
categorymappings: categorymappings:

View File

@@ -171,4 +171,4 @@ search:
description: description:
selector: td:nth-child(2) selector: td:nth-child(2)
remove: a, b, font, img, span remove: a, b, font, img, span
# NexusPHP v1.9.10 2025-10-30 # NexusPHP v1.9.11 2025-11-02

View File

@@ -31,10 +31,8 @@ caps:
- {id: 190, cat: Movies, desc: " |- Фильмы в 4K и 3D"} - {id: 190, cat: Movies, desc: " |- Фильмы в 4K и 3D"}
- {id: 34, cat: Movies, desc: " |- Перевод на узбекский"} - {id: 34, cat: Movies, desc: " |- Перевод на узбекский"}
- {id: 25, cat: Movies, desc: "Узбекские кинофильмы"} - {id: 25, cat: Movies, desc: "Узбекские кинофильмы"}
- {id: 32, cat: Movies, desc: " |- Новинки"} - {id: 32, cat: Movies, desc: " |- Пр-во Узбекфильм (на русском)"}
- {id: 30, cat: Movies, desc: " |- Фильмы 2011-2024 годов"} - {id: 30, cat: Movies, desc: " |- Пр-во Узбекфильм (на узбекском языке)"}
- {id: 29, cat: Movies, desc: " |- Фильмы 2000-2010 годов"}
- {id: 26, cat: Movies, desc: " |- Фильмы до 2000 года"}
# Сериалы, Видео и ТВ # Series, Videos and TV # Сериалы, Видео и ТВ # Series, Videos and TV
- {id: 97, cat: TV, desc: "Сериалы"} - {id: 97, cat: TV, desc: "Сериалы"}
- {id: 333, cat: TV, desc: " |- Игра престолов / Game of Thrones"} - {id: 333, cat: TV, desc: " |- Игра престолов / Game of Thrones"}
@@ -85,6 +83,7 @@ caps:
- {id: 132, cat: Audio, desc: " |- Классическая музыа"} - {id: 132, cat: Audio, desc: " |- Классическая музыа"}
- {id: 125, cat: Audio, desc: " |- New Age, Relax, Meditative & Flamenco"} - {id: 125, cat: Audio, desc: " |- New Age, Relax, Meditative & Flamenco"}
- {id: 124, cat: Audio, desc: " |- Фольклор, Народная и Этническая музыка"} - {id: 124, cat: Audio, desc: " |- Фольклор, Народная и Этническая музыка"}
- {id: 338, cat: Audio, desc: " |- Country"}
- {id: 231, cat: Audio, desc: " |- Сборники и альбомы выходившие неофициальными изданиями."} - {id: 231, cat: Audio, desc: " |- Сборники и альбомы выходившие неофициальными изданиями."}
- {id: 144, cat: Audio, desc: "♫ ROCK & METAL ♫"} - {id: 144, cat: Audio, desc: "♫ ROCK & METAL ♫"}
- {id: 201, cat: Audio, desc: " |- Русский Rock, Metal (mp3)"} - {id: 201, cat: Audio, desc: " |- Русский Rock, Metal (mp3)"}
@@ -170,6 +169,7 @@ caps:
- {id: 289, cat: PC/Games, desc: " |- Horror"} - {id: 289, cat: PC/Games, desc: " |- Horror"}
- {id: 307, cat: PC/Games, desc: " |- Logic"} - {id: 307, cat: PC/Games, desc: " |- Logic"}
- {id: 304, cat: PC/Games, desc: " |- Lifestyle"} - {id: 304, cat: PC/Games, desc: " |- Lifestyle"}
- {id: 336, cat: PC/Games, desc: " |- Sports"}
- {id: 306, cat: PC/Games, desc: " |- Exploration"} - {id: 306, cat: PC/Games, desc: " |- Exploration"}
- {id: 305, cat: PC/Games, desc: " |- Management"} - {id: 305, cat: PC/Games, desc: " |- Management"}
- {id: 115, cat: PC/Games, desc: " |- Аркады"} - {id: 115, cat: PC/Games, desc: " |- Аркады"}

View File

@@ -8,8 +8,8 @@ encoding: UTF-8
requestDelay: 2.5 # 2.5 requests per second (2 causes problems) requestDelay: 2.5 # 2.5 requests per second (2 causes problems)
links: links:
# if the primary domain changes then don't forget to update the details, download and poster replace args # if the primary domain changes then don't forget to update the details, download and poster replace args
- https://yts.mx/ - https://yts.lt/
# official domain list are at https://yifystatus.com/ and official proxies list are at https://ytsproxies.com/ # official domain list are at https://yifystatus.com/ and official proxies list are at https://ytsproxies.com/
- https://yts.unblockninja.com/ - https://yts.unblockninja.com/
- https://yts.ninjaproxy1.com/ - https://yts.ninjaproxy1.com/
- https://yts.proxyninja.org/ - https://yts.proxyninja.org/
@@ -17,9 +17,9 @@ links:
- https://yts.torrentbay.st/ - https://yts.torrentbay.st/
- https://yts.torrentsbay.org/ - https://yts.torrentsbay.org/
legacylinks: legacylinks:
- https://yts.lt/
- https://yts.am/ - https://yts.am/
- https://yts.ag/ - https://yts.ag/
- https://yts.mx/
- https://yts.mrunblock.bond/ - https://yts.mrunblock.bond/
- https://yts.nocensor.cloud/ - https://yts.nocensor.cloud/
- https://yts.unblockit.download/ - https://yts.unblockit.download/
@@ -104,19 +104,19 @@ search:
selector: ..url selector: ..url
filters: filters:
- name: re_replace - name: re_replace
args: ["^https?:\\/\\/yts\\.mx\\/", "{{ .Config.sitelink }}"] # fix for 12494 args: ["^https?:\\/\\/yts\\.(mx|lt)\\/", "{{ .Config.sitelink }}"] # fix for 12494
download: download:
selector: url selector: url
filters: filters:
- name: re_replace - name: re_replace
args: ["^https?:\\/\\/yts\\.mx\\/", "{{ .Config.sitelink }}"] # fix for 12494 args: ["^https?:\\/\\/yts\\.(mx|lt)\\/", "{{ .Config.sitelink }}"] # fix for 12494
infohash: infohash:
selector: hash selector: hash
poster: poster:
selector: ..large_cover_image selector: ..large_cover_image
filters: filters:
- name: re_replace - name: re_replace
args: ["^https?:\\/\\/yts\\.mx\\/", "{{ .Config.sitelink }}"] # fix for 12494 args: ["^https?:\\/\\/yts\\.(mx|lt)\\/", "{{ .Config.sitelink }}"] # fix for 12494
imdbid: imdbid:
selector: ..imdb_code selector: ..imdb_code
date: date:

View File

@@ -7,8 +7,7 @@ type: public
encoding: UTF-8 encoding: UTF-8
# to fetch current domain use https://www.rantop.org/ # to fetch current domain use https://www.rantop.org/
links: links:
- https://www.zetorrents.town/ - https://ww1-zetorrents.me/
- https://zetorrents-proxy.site/
legacylinks: legacylinks:
# latest domains list # latest domains list
- https://www.rantop.org/ - https://www.rantop.org/
@@ -23,8 +22,6 @@ legacylinks:
- https://www.site-torrent.com/ - https://www.site-torrent.com/
- https://www.rantop.my/ - https://www.rantop.my/
# actual legacylinks # actual legacylinks
- https://www.zetorrents.nl/
- https://www.zetorrents.biz/
- https://www.zetorrents.ch/ - https://www.zetorrents.ch/
- https://zetorrents.mrunblock.bond/ - https://zetorrents.mrunblock.bond/
- https://zetorrents.nocensor.cloud/ - https://zetorrents.nocensor.cloud/
@@ -40,6 +37,8 @@ legacylinks:
- https://www.zetorrents1.com/ - https://www.zetorrents1.com/
- https://www.zetorrents.diy/ - https://www.zetorrents.diy/
- https://www.zetorrents2.com/ - https://www.zetorrents2.com/
- https://www.zetorrents.town/
- https://zetorrents-proxy.site/
caps: caps:
categories: categories:

View File

@@ -9,8 +9,7 @@ type: public
encoding: UTF-8 encoding: UTF-8
# to fetch current domain use https://www.rantop.org/ # to fetch current domain use https://www.rantop.org/
links: links:
- https://www.zktorrent.town/ - https://ww1-zktorrent.me/
- https://zktorrent-proxy.site/
legacylinks: legacylinks:
# latest domains list # latest domains list
- https://www.rantop.org/ - https://www.rantop.org/
@@ -26,8 +25,6 @@ legacylinks:
- https://www.site-torrent.com/ - https://www.site-torrent.com/
- https://www.rantop.my/ - https://www.rantop.my/
# actual legacylinks # actual legacylinks
- https://www.gktorrent.si/
- https://www.gktorrent.my/
- https://www.gktorrent.cz/ - https://www.gktorrent.cz/
- https://www.gktorrent.ke/ - https://www.gktorrent.ke/
- https://www.gktorrent.cv/ - https://www.gktorrent.cv/
@@ -41,6 +38,8 @@ legacylinks:
- https://www.zktorrent5.com/ - https://www.zktorrent5.com/
- https://www.zktorrent.net/ - https://www.zktorrent.net/
- https://www.zktorrent6.com/ - https://www.zktorrent6.com/
- https://www.zktorrent.town/
- https://zktorrent-proxy.site/
caps: caps:
categorymappings: categorymappings:

View File

@@ -0,0 +1,34 @@
using System.Security.Cryptography;
using System.Text;
namespace Jackett.Common.Extensions
{
public static class HashingExtensions
{
public static string SHA1Hash(this string input)
{
using var hash = SHA1.Create();
return GetHash(hash.ComputeHash(Encoding.UTF8.GetBytes(input)));
}
public static string SHA256Hash(this string input)
{
using var hash = SHA256.Create();
return GetHash(hash.ComputeHash(Encoding.UTF8.GetBytes(input)));
}
private static string GetHash(byte[] bytes)
{
var stringBuilder = new StringBuilder();
foreach (var b in bytes)
{
stringBuilder.Append(b.ToString("x2"));
}
return stringBuilder.ToString();
}
}
}

View File

@@ -8,10 +8,8 @@ using System.Xml.Linq;
using Jackett.Common.Extensions; using Jackett.Common.Extensions;
using Jackett.Common.Models; using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig.Bespoke; using Jackett.Common.Models.IndexerConfig.Bespoke;
using Jackett.Common.Serializer;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils.Clients; using Jackett.Common.Utils.Clients;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NLog; using NLog;
@@ -204,44 +202,36 @@ namespace Jackett.Common.Indexers.Definitions
seasonPart = Regex.Replace(seasonPart, @"\b\d{4}\b$", ""); seasonPart = Regex.Replace(seasonPart, @"\b\d{4}\b$", "");
var hasPartNumber = Regex.IsMatch(seasonPart, @"\bPart\s+\d+\b", RegexOptions.IgnoreCase); var hasPartNumber = Regex.IsMatch(seasonPart, @"\bPart\s+\d+\b", RegexOptions.IgnoreCase);
var seasonMatch = Regex.Match(seasonPart, var seasonMatch = Regex.Match(seasonPart,
@"\b(?:Season|S|Series)\s*(\d+)|\b(\d+)(?:st|nd|rd|th)?\s*Season\b|\b([IVXLCDM]+)\b|\b(\d+)\b", @"\b(?:Season|S|Series)\s*(?<season_number>\d+)|\b(?<season_number>\d+)(?:st|nd|rd|th)?\s*Season\b|\b(?<roman_number>M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3}))\b|\b(?<season_number>\d+)\b",
RegexOptions.IgnoreCase); RegexOptions.IgnoreCase);
var season = "S01"; var season = "S01";
if (seasonMatch.Success && !hasPartNumber) if (seasonMatch.Success && !hasPartNumber)
{ {
if (!string.IsNullOrEmpty(seasonMatch.Groups[1].Value)) if (seasonMatch.Groups["season_number"].Success
&& !string.IsNullOrWhiteSpace(seasonMatch.Groups["season_number"].Value)
&& int.TryParse(seasonMatch.Groups["season_number"].Value, out var seasonNumber))
{ {
season = $"S{int.Parse(seasonMatch.Groups[1].Value):D2}"; season = $"S{seasonNumber:D2}";
} }
else if (!string.IsNullOrEmpty(seasonMatch.Groups[2].Value)) else if (seasonMatch.Groups["roman_number"].Success && !string.IsNullOrWhiteSpace(seasonMatch.Groups["roman_number"].Value))
{
season = $"S{int.Parse(seasonMatch.Groups[2].Value):D2}";
}
else if (!string.IsNullOrEmpty(seasonMatch.Groups[3].Value))
{ {
season = $"S{RomanToArabic(seasonMatch.Groups[3].Value):D2}"; season = $"S{RomanToArabic(seasonMatch.Groups[3].Value):D2}";
} }
else if (!string.IsNullOrEmpty(seasonMatch.Groups[4].Value))
{
season = $"S{int.Parse(seasonMatch.Groups[4].Value):D2}";
}
} }
var episodes = string.Empty; var episodes = string.Empty;
var epMatch = Regex.Match(episodesPart, @"(\d+)(?:[-–—](\d+))?"); var epMatch = Regex.Match(episodesPart, @"(\d+)(?:[-–—](\d+))?");
if (epMatch.Success) if (epMatch.Success && int.TryParse(epMatch.Groups[1].Value, out var episodeStartNumber))
{ {
var start = int.Parse(epMatch.Groups[1].Value);
if (epMatch.Groups[2].Success) if (epMatch.Groups[2].Success)
{ {
var end = int.Parse(epMatch.Groups[2].Value); episodes = $"E{episodeStartNumber:D2}-E{int.Parse(epMatch.Groups[2].Value):D2}";
episodes = $"E{start:D2}-E{end:D2}";
} }
else else
{ {
episodes = $"E{start:D2}"; episodes = $"E{episodeStartNumber:D2}";
} }
} }
@@ -250,11 +240,12 @@ namespace Jackett.Common.Indexers.Definitions
private static int RomanToArabic(string roman) private static int RomanToArabic(string roman)
{ {
int[] values = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 }; roman = roman.ToUpperInvariant();
string[] numerals = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
var values = new[] { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
var numerals = new[] { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
var result = 0; var result = 0;
var i = 0; var i = 0;
roman = roman.ToUpper();
while (roman.Length > 0) while (roman.Length > 0)
{ {
if (roman.StartsWith(numerals[i])) if (roman.StartsWith(numerals[i]))

View File

@@ -249,13 +249,14 @@ namespace Jackett.Common.Indexers.Definitions
var details = new Uri(qDetailsLink.GetAttribute("href")); var details = new Uri(qDetailsLink.GetAttribute("href"));
var qPosterLink = row.QuerySelector("img[src*=\"/torrents/images/\"]"); var qPosterLink = row.QuerySelector("img[src*=\"/torrents/images/\"]");
var qMagnetLink = row.QuerySelector("a[href^=\"magnet:?xt=\"]");
var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-last-child(5)").TextContent); var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-last-child(5)").TextContent);
var matchDateAdded = Regex.Match(row.QuerySelector(" td:nth-child(2)").TextContent, @"(\d{2}-\d{2}-\d{4} \d{2}:\d{2})", RegexOptions.IgnoreCase); var matchDateAdded = Regex.Match(row.QuerySelector(" td:nth-child(2)").TextContent, @"(\d{2}-\d{2}-\d{4} \d{2}:\d{2})", RegexOptions.IgnoreCase);
var publishDate = matchDateAdded.Groups[1].Success && DateTime.TryParseExact(matchDateAdded.Groups[1].Value, "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var parsedDate) ? parsedDate : DateTime.Now; var publishDate = matchDateAdded.Groups[1].Success && DateTime.TryParseExact(matchDateAdded.Groups[1].Value, "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var parsedDate) ? parsedDate : DateTime.Now;
var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-last-child(4)").TextContent); var grabs = ParseUtil.CoerceLong(row.QuerySelector("td:nth-last-child(4)").TextContent);
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-last-child(3)").TextContent); var seeders = ParseUtil.CoerceLong(row.QuerySelector("td:nth-last-child(3)").TextContent);
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-last-child(2)").TextContent) + seeders; var leechers = ParseUtil.CoerceLong(row.QuerySelector("td:nth-last-child(2)").TextContent) + seeders;
var dlVolumeFactor = 1.0; var dlVolumeFactor = 1.0;
var upVolumeFactor = 1.0; var upVolumeFactor = 1.0;
@@ -287,6 +288,10 @@ namespace Jackett.Common.Indexers.Definitions
{ {
release.Poster = new Uri(qPosterLink.GetAttribute("src")); release.Poster = new Uri(qPosterLink.GetAttribute("src"));
} }
if (qMagnetLink != null)
{
release.MagnetUri = new Uri(qMagnetLink.GetAttribute("href"));
}
releases.Add(release); releases.Add(release);
} }

View File

@@ -104,7 +104,7 @@ namespace Jackett.Common.Indexers.Definitions
var maxPages = 2; // we scrape only 2 pages for recent torrents var maxPages = 2; // we scrape only 2 pages for recent torrents
if (!string.IsNullOrWhiteSpace(query.GetQueryString())) if (!string.IsNullOrWhiteSpace(query.GetQueryString()))
{ {
searchString = Uri.EscapeUriString(query.GetQueryString()); searchString = Uri.EscapeDataString(query.GetQueryString());
maxPages = MaxSearchPageLimit; maxPages = MaxSearchPageLimit;
} }

View File

@@ -26,7 +26,7 @@ namespace Jackett.Common.Indexers.Definitions
public override string Id => "mteamtp"; public override string Id => "mteamtp";
public override string[] Replaces => new[] { "mteamtp2fa" }; public override string[] Replaces => new[] { "mteamtp2fa" };
public override string Name => "M-Team - TP"; public override string Name => "M-Team - TP";
public override string Description => "M-Team TP (MTTP) is a CHINESE Private Torrent Tracker for HD MOVIES / TV / 3X"; public override string Description => "M-Team - TP (MTTP) is a CHINESE Private Torrent Tracker for MOVIES / TV / GENERAL";
public override string SiteLink { get; protected set; } = "https://kp.m-team.cc/"; public override string SiteLink { get; protected set; } = "https://kp.m-team.cc/";
public override string[] AlternativeSiteLinks => new[] public override string[] AlternativeSiteLinks => new[]
{ {
@@ -39,7 +39,7 @@ namespace Jackett.Common.Indexers.Definitions
public override TorznabCapabilities TorznabCaps => SetCapabilities(); public override TorznabCapabilities TorznabCaps => SetCapabilities();
private readonly int[] _trackerAdultCategories = { 410, 429, 424, 430, 426, 437, 431, 432, 436, 425, 433, 411, 412, 413, 440 }; private readonly int[] _trackerAdultCategories = { 410, 424, 437, 431, 429, 430, 426, 432, 436, 440, 425, 433, 411, 412, 413 };
private new ConfigurationDataMTeamTp configData => (ConfigurationDataMTeamTp)base.configData; private new ConfigurationDataMTeamTp configData => (ConfigurationDataMTeamTp)base.configData;
@@ -83,39 +83,37 @@ namespace Jackett.Common.Indexers.Definitions
caps.Categories.AddCategoryMapping(439, TorznabCatType.MoviesHD, "Movie(電影)/Remux"); caps.Categories.AddCategoryMapping(439, TorznabCatType.MoviesHD, "Movie(電影)/Remux");
caps.Categories.AddCategoryMapping(403, TorznabCatType.TVSD, "TV Series(影劇/綜藝)/SD"); caps.Categories.AddCategoryMapping(403, TorznabCatType.TVSD, "TV Series(影劇/綜藝)/SD");
caps.Categories.AddCategoryMapping(402, TorznabCatType.TVHD, "TV Series(影劇/綜藝)/HD"); caps.Categories.AddCategoryMapping(402, TorznabCatType.TVHD, "TV Series(影劇/綜藝)/HD");
caps.Categories.AddCategoryMapping(435, TorznabCatType.TVSD, "TV Series(影劇/綜藝)/DVDiSo");
caps.Categories.AddCategoryMapping(438, TorznabCatType.TVHD, "TV Series(影劇/綜藝)/BD"); caps.Categories.AddCategoryMapping(438, TorznabCatType.TVHD, "TV Series(影劇/綜藝)/BD");
caps.Categories.AddCategoryMapping(435, TorznabCatType.TVSD, "TV Series(影劇/綜藝)/DVDiSo");
caps.Categories.AddCategoryMapping(404, TorznabCatType.TVDocumentary, "紀錄教育"); caps.Categories.AddCategoryMapping(404, TorznabCatType.TVDocumentary, "紀錄教育");
caps.Categories.AddCategoryMapping(434, TorznabCatType.Audio, "Music(無損)");
caps.Categories.AddCategoryMapping(406, TorznabCatType.AudioVideo, "MV(演唱)");
caps.Categories.AddCategoryMapping(423, TorznabCatType.PCGames, "PCGame(PC遊戲)");
caps.Categories.AddCategoryMapping(448, TorznabCatType.ConsoleOther, "TvGame(TV遊戲)");
caps.Categories.AddCategoryMapping(405, TorznabCatType.TVAnime, "Anime(動畫)"); caps.Categories.AddCategoryMapping(405, TorznabCatType.TVAnime, "Anime(動畫)");
caps.Categories.AddCategoryMapping(407, TorznabCatType.TVSport, "Sports(運動)"); caps.Categories.AddCategoryMapping(407, TorznabCatType.TVSport, "Sports(運動)");
caps.Categories.AddCategoryMapping(422, TorznabCatType.PC0day, "Software(軟體)");
caps.Categories.AddCategoryMapping(423, TorznabCatType.PCGames, "PCGame(PC遊戲)");
caps.Categories.AddCategoryMapping(427, TorznabCatType.BooksEBook, "Study/Edu ebook(教育書面)"); caps.Categories.AddCategoryMapping(427, TorznabCatType.BooksEBook, "Study/Edu ebook(教育書面)");
caps.Categories.AddCategoryMapping(441, TorznabCatType.BooksOther, "Study/Edu video(教育影片)"); caps.Categories.AddCategoryMapping(422, TorznabCatType.PC0day, "Software(軟體)");
caps.Categories.AddCategoryMapping(442, TorznabCatType.AudioAudiobook, "Study/Edu audio(教育音檔)"); caps.Categories.AddCategoryMapping(442, TorznabCatType.AudioAudiobook, "Study/Edu audio(教育音檔)");
caps.Categories.AddCategoryMapping(451, TorznabCatType.MoviesOther, "教育影片");
caps.Categories.AddCategoryMapping(409, TorznabCatType.Other, "Misc(其他)"); caps.Categories.AddCategoryMapping(409, TorznabCatType.Other, "Misc(其他)");
// music
caps.Categories.AddCategoryMapping(406, TorznabCatType.AudioVideo, "MV(演唱)");
caps.Categories.AddCategoryMapping(408, TorznabCatType.AudioOther, "Music(AAC/ALAC)");
caps.Categories.AddCategoryMapping(434, TorznabCatType.Audio, "Music(無損)");
// adult // adult
caps.Categories.AddCategoryMapping(410, TorznabCatType.XXX, "AV(有碼)/HD Censored"); caps.Categories.AddCategoryMapping(410, TorznabCatType.XXX, "AV(有碼)/HD Censored");
caps.Categories.AddCategoryMapping(429, TorznabCatType.XXX, "AV(無碼)/HD Uncensored");
caps.Categories.AddCategoryMapping(424, TorznabCatType.XXXSD, "AV(有碼)/SD Censored"); caps.Categories.AddCategoryMapping(424, TorznabCatType.XXXSD, "AV(有碼)/SD Censored");
caps.Categories.AddCategoryMapping(430, TorznabCatType.XXXSD, "AV(無碼)/SD Uncensored");
caps.Categories.AddCategoryMapping(426, TorznabCatType.XXXDVD, "AV(無碼)/DVDiSo Uncensored");
caps.Categories.AddCategoryMapping(437, TorznabCatType.XXXDVD, "AV(有碼)/DVDiSo Censored"); caps.Categories.AddCategoryMapping(437, TorznabCatType.XXXDVD, "AV(有碼)/DVDiSo Censored");
caps.Categories.AddCategoryMapping(431, TorznabCatType.XXX, "AV(有碼)/Blu-Ray Censored"); caps.Categories.AddCategoryMapping(431, TorznabCatType.XXX, "AV(有碼)/Blu-Ray Censored");
caps.Categories.AddCategoryMapping(429, TorznabCatType.XXX, "AV(無碼)/HD Uncensored");
caps.Categories.AddCategoryMapping(430, TorznabCatType.XXXSD, "AV(無碼)/SD Uncensored");
caps.Categories.AddCategoryMapping(426, TorznabCatType.XXXDVD, "AV(無碼)/DVDiSo Uncensored");
caps.Categories.AddCategoryMapping(432, TorznabCatType.XXX, "AV(無碼)/Blu-Ray Uncensored"); caps.Categories.AddCategoryMapping(432, TorznabCatType.XXX, "AV(無碼)/Blu-Ray Uncensored");
caps.Categories.AddCategoryMapping(436, TorznabCatType.XXX, "AV(網站)/0Day"); caps.Categories.AddCategoryMapping(436, TorznabCatType.XXX, "AV(網站)/0Day");
caps.Categories.AddCategoryMapping(440, TorznabCatType.XXX, "AV(Gay)/HD");
caps.Categories.AddCategoryMapping(425, TorznabCatType.XXX, "IV(寫真影集)/Video Collection"); caps.Categories.AddCategoryMapping(425, TorznabCatType.XXX, "IV(寫真影集)/Video Collection");
caps.Categories.AddCategoryMapping(433, TorznabCatType.XXXImageSet, "IV(寫真圖集)/Picture Collection"); caps.Categories.AddCategoryMapping(433, TorznabCatType.XXXImageSet, "IV(寫真圖集)/Picture Collection");
caps.Categories.AddCategoryMapping(411, TorznabCatType.XXX, "H-Game(遊戲)"); caps.Categories.AddCategoryMapping(411, TorznabCatType.XXX, "H-Game(遊戲)");
caps.Categories.AddCategoryMapping(412, TorznabCatType.XXX, "H-Anime(動畫)"); caps.Categories.AddCategoryMapping(412, TorznabCatType.XXX, "H-Anime(動畫)");
caps.Categories.AddCategoryMapping(413, TorznabCatType.XXX, "H-Comic(漫畫)"); caps.Categories.AddCategoryMapping(413, TorznabCatType.XXX, "H-Comic(漫畫)");
caps.Categories.AddCategoryMapping(440, TorznabCatType.XXX, "AV(Gay)/HD");
return caps; return caps;
} }

View File

@@ -72,38 +72,38 @@ namespace Jackett.Common.Indexers.Definitions
} }
}; };
caps.Categories.AddCategoryMapping("23", TorznabCatType.TVAnime); caps.Categories.AddCategoryMapping("23", TorznabCatType.TVAnime, "Anime");
caps.Categories.AddCategoryMapping("22", TorznabCatType.PC0day); caps.Categories.AddCategoryMapping("2", TorznabCatType.PCMac, "Appz-Mac/Linux");
caps.Categories.AddCategoryMapping("1", TorznabCatType.PCISO); caps.Categories.AddCategoryMapping("1", TorznabCatType.PCISO, "Appz-Win/PC");
caps.Categories.AddCategoryMapping("36", TorznabCatType.Books); caps.Categories.AddCategoryMapping("22", TorznabCatType.AudioAudiobook, "Book-Audio");
caps.Categories.AddCategoryMapping("36", TorznabCatType.BooksEBook); caps.Categories.AddCategoryMapping("36", TorznabCatType.BooksEBook, "Book-Ebook");
caps.Categories.AddCategoryMapping("4", TorznabCatType.PCGames); caps.Categories.AddCategoryMapping("40", TorznabCatType.ConsoleWii, "Games-Nin");
caps.Categories.AddCategoryMapping("21", TorznabCatType.PCGames); caps.Categories.AddCategoryMapping("16", TorznabCatType.ConsolePS3, "Games-PS");
caps.Categories.AddCategoryMapping("16", TorznabCatType.ConsolePS3); caps.Categories.AddCategoryMapping("4", TorznabCatType.PCGames, "Games-Win");
caps.Categories.AddCategoryMapping("40", TorznabCatType.ConsoleWii); caps.Categories.AddCategoryMapping("39", TorznabCatType.ConsoleXBox360, "Games-XBOX");
caps.Categories.AddCategoryMapping("39", TorznabCatType.ConsoleXBox360); caps.Categories.AddCategoryMapping("35", TorznabCatType.ConsoleNDS, "Handheld/NDS");
caps.Categories.AddCategoryMapping("35", TorznabCatType.ConsoleNDS); caps.Categories.AddCategoryMapping("34", TorznabCatType.PCMobileOther, "Mobile");
caps.Categories.AddCategoryMapping("34", TorznabCatType.ConsolePSP); caps.Categories.AddCategoryMapping("51", TorznabCatType.MoviesUHD, "Movies/4K");
caps.Categories.AddCategoryMapping("2", TorznabCatType.PCMac); caps.Categories.AddCategoryMapping("10", TorznabCatType.MoviesBluRay, "Movies/BluRay");
caps.Categories.AddCategoryMapping("10", TorznabCatType.MoviesBluRay); caps.Categories.AddCategoryMapping("20", TorznabCatType.MoviesDVD, "Movies/DVDR");
caps.Categories.AddCategoryMapping("20", TorznabCatType.MoviesDVD); caps.Categories.AddCategoryMapping("12", TorznabCatType.MoviesHD, "Movies/HDx264");
caps.Categories.AddCategoryMapping("12", TorznabCatType.MoviesHD); caps.Categories.AddCategoryMapping("44", TorznabCatType.MoviesOther, "Movies/Packs");
caps.Categories.AddCategoryMapping("44", TorznabCatType.MoviesOther); caps.Categories.AddCategoryMapping("11", TorznabCatType.MoviesHD, "Movies/x265");
caps.Categories.AddCategoryMapping("11", TorznabCatType.MoviesSD); caps.Categories.AddCategoryMapping("19", TorznabCatType.MoviesSD, "Movies/XviD");
caps.Categories.AddCategoryMapping("19", TorznabCatType.MoviesSD); caps.Categories.AddCategoryMapping("6", TorznabCatType.Audio, "Music");
caps.Categories.AddCategoryMapping("6", TorznabCatType.Audio); caps.Categories.AddCategoryMapping("8", TorznabCatType.AudioLossless, "Music/FLAC");
caps.Categories.AddCategoryMapping("8", TorznabCatType.AudioLossless); caps.Categories.AddCategoryMapping("46", TorznabCatType.AudioOther, "Music/Packs");
caps.Categories.AddCategoryMapping("46", TorznabCatType.AudioOther); caps.Categories.AddCategoryMapping("29", TorznabCatType.AudioVideo, "MusicVideos");
caps.Categories.AddCategoryMapping("29", TorznabCatType.AudioVideo); caps.Categories.AddCategoryMapping("21", TorznabCatType.TVSport, "Sports");
caps.Categories.AddCategoryMapping("43", TorznabCatType.TVOther); caps.Categories.AddCategoryMapping("43", TorznabCatType.TVOther, "TV/DVDR");
caps.Categories.AddCategoryMapping("42", TorznabCatType.TVHD); caps.Categories.AddCategoryMapping("42", TorznabCatType.TVHD, "TV/HDx264");
caps.Categories.AddCategoryMapping("45", TorznabCatType.TVOther); caps.Categories.AddCategoryMapping("45", TorznabCatType.TVOther, "TV/Packs");
caps.Categories.AddCategoryMapping("41", TorznabCatType.TVSD); caps.Categories.AddCategoryMapping("41", TorznabCatType.TVSD, "TV/SDx264");
caps.Categories.AddCategoryMapping("7", TorznabCatType.TVSD); caps.Categories.AddCategoryMapping("7", TorznabCatType.TVSD, "TV/XViD");
caps.Categories.AddCategoryMapping("9", TorznabCatType.XXX); caps.Categories.AddCategoryMapping("9", TorznabCatType.XXX, "XXX");
caps.Categories.AddCategoryMapping("49", TorznabCatType.XXX); caps.Categories.AddCategoryMapping("49", TorznabCatType.XXX, ">XXX/0DAY");
caps.Categories.AddCategoryMapping("47", TorznabCatType.XXXDVD); caps.Categories.AddCategoryMapping("47", TorznabCatType.XXXDVD, "XXX/DVDR");
caps.Categories.AddCategoryMapping("48", TorznabCatType.XXX); caps.Categories.AddCategoryMapping("48", TorznabCatType.XXX, "XXX/HDx264");
return caps; return caps;
} }

View File

@@ -163,15 +163,18 @@ namespace Jackett.Common.Indexers.Definitions
{ {
throw new Exception("Error, the Download link at the requested path does not exist."); throw new Exception("Error, the Download link at the requested path does not exist.");
} }
var wmDoc = new HtmlParser().ParseDocument(wmPage.ContentString);
var wmHtmlParser = new HtmlParser();
var wmDoc = await wmHtmlParser.ParseDocumentAsync(wmPage.ContentString);
var enlacitoUrl = wmDoc.QuerySelector(".app-message a:not(.buttonPassword)")?.GetAttribute("href"); var enlacitoUrl = wmDoc.QuerySelector(".app-message a:not(.buttonPassword)")?.GetAttribute("href");
var enlacitoPage = await RequestWithCookiesAndRetryAsync(enlacitoUrl, referer: SiteLink); var enlacitoPage = await RequestWithCookiesAndRetryAsync(enlacitoUrl, referer: SiteLink);
var enlacitoDoc = new HtmlParser().ParseDocument(enlacitoPage.ContentString);
var enlacitoHtmlParser = new HtmlParser();
var enlacitoDoc = await enlacitoHtmlParser.ParseDocumentAsync(enlacitoPage.ContentString);
var enlacitoFormUrl = enlacitoDoc.QuerySelector("form").GetAttribute("action"); var enlacitoFormUrl = enlacitoDoc.QuerySelector("form").GetAttribute("action");
var enlacitoFormLinkser = enlacitoDoc.QuerySelector("input[name=\"linkser\"]").GetAttribute("value"); var enlacitoFormLinkser = enlacitoDoc.QuerySelector("input[name=\"linkser\"]").GetAttribute("value");
var body = new Dictionary<string, string> var body = new Dictionary<string, string>
{ {
{ "linkser", enlacitoFormLinkser } { "linkser", enlacitoFormLinkser }
@@ -182,7 +185,7 @@ namespace Jackett.Common.Indexers.Definitions
var linkOut = v.Groups[1].ToString(); var linkOut = v.Groups[1].ToString();
var slink = Encoding.UTF8.GetString(Convert.FromBase64String(linkOut)); var slink = Encoding.UTF8.GetString(Convert.FromBase64String(linkOut));
var ulink = OpenSSLDecrypt(slink, TorrentLinkEncryptionKey); var ulink = await OpenSSLDecryptAsync(slink, TorrentLinkEncryptionKey);
var result = await RequestWithCookiesAndRetryAsync(ulink); var result = await RequestWithCookiesAndRetryAsync(ulink);
return result.ContentBytes; return result.ContentBytes;
@@ -463,7 +466,7 @@ namespace Jackett.Common.Indexers.Definitions
} }
// Thanks to https://stackoverflow.com/a/5454692/2078070 !!! // Thanks to https://stackoverflow.com/a/5454692/2078070 !!!
private string OpenSSLDecrypt(string encrypted, string passphrase) private async Task<string> OpenSSLDecryptAsync(string encrypted, string passphrase)
{ {
// base 64 decode // base 64 decode
var encryptedBytesWithSalt = Convert.FromBase64String(encrypted); var encryptedBytesWithSalt = Convert.FromBase64String(encrypted);
@@ -477,7 +480,7 @@ namespace Jackett.Common.Indexers.Definitions
// get key and iv // get key and iv
DeriveKeyAndIV(passphrase, salt, out var key, out var iv); DeriveKeyAndIV(passphrase, salt, out var key, out var iv);
return DecryptStringFromBytesAes(encryptedBytes, key, iv); return await DecryptStringFromBytesAesAsync(encryptedBytes, key, iv);
} }
private void DeriveKeyAndIV(string passphrase, byte[] salt, out byte[] key, out byte[] iv) private void DeriveKeyAndIV(string passphrase, byte[] salt, out byte[] key, out byte[] iv)
@@ -518,7 +521,7 @@ namespace Jackett.Common.Indexers.Definitions
md5 = null; md5 = null;
} }
private string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv) private static async Task<string> DecryptStringFromBytesAesAsync(byte[] cipherText, byte[] key, byte[] iv)
{ {
if (cipherText == null || cipherText.Length <= 0) if (cipherText == null || cipherText.Length <= 0)
{ {
@@ -535,44 +538,17 @@ namespace Jackett.Common.Indexers.Definitions
throw new ArgumentNullException(nameof(iv)); throw new ArgumentNullException(nameof(iv));
} }
// Declare the RijndaelManaged object using var aesAlg = Aes.Create();
// used to decrypt the data. aesAlg.Key = key;
RijndaelManaged aesAlg = null; aesAlg.IV = iv;
// Declare the string used to hold var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// the decrypted text.
string plaintext;
try using var msDecrypt = new MemoryStream(cipherText);
{ using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
// Create a RijndaelManaged object using var srDecrypt = new StreamReader(csDecrypt);
// with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create a decrytor to perform the stream transform. return await srDecrypt.ReadToEndAsync();
var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
}
finally
{
// Clear the RijndaelManaged object.
aesAlg?.Clear();
}
return plaintext;
} }
} }

View File

@@ -4,12 +4,11 @@ using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AngleSharp.Html.Parser; using AngleSharp.Html.Parser;
using Jackett.Common.Extensions;
using Jackett.Common.Models; using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig; using Jackett.Common.Models.IndexerConfig;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
@@ -253,11 +252,13 @@ namespace Jackett.Common.Indexers.Definitions
if (string.IsNullOrWhiteSpace(sessionId)) if (string.IsNullOrWhiteSpace(sessionId))
throw new ExceptionWithConfigData("Error getting the Session ID", configData); throw new ExceptionWithConfigData("Error getting the Session ID", configData);
await Task.Delay(3000);
// The second page send the login with the hash // The second page send the login with the hash
// The hash is reverse engineering from https://www.zonaq.pw/retorno/2/smf/Themes/smf_ZQ/scripts/script.js // The hash is reverse engineering from https://www.zonaq.pw/retorno/2/smf/Themes/smf_ZQ/scripts/script.js
// doForm.hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_to8bit().php_strtolower() + doForm.passwrd.value.php_to8bit()) + cur_session_id); // doForm.hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_to8bit().php_strtolower() + doForm.passwrd.value.php_to8bit()) + cur_session_id);
Thread.Sleep(3000); var hashPassword = $"{(configData.Username.Value.ToLowerInvariant() + configData.Password.Value).SHA1Hash()}{sessionId}".SHA1Hash();
var hashPassword = Sha1Hash(Sha1Hash(configData.Username.Value.ToLower() + configData.Password.Value) + sessionId);
var pairs = new Dictionary<string, string> { var pairs = new Dictionary<string, string> {
{ "user", configData.Username.Value }, { "user", configData.Username.Value },
{ "passwrd", configData.Password.Value }, { "passwrd", configData.Password.Value },
@@ -288,11 +289,5 @@ namespace Jackett.Common.Indexers.Definitions
Thread.Sleep(3000); Thread.Sleep(3000);
await RequestWithCookiesAsync(Login4Url); await RequestWithCookiesAsync(Login4Url);
} }
private static string Sha1Hash(string input)
{
var hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input));
return string.Concat(hash.Select(b => b.ToString("x2")));
}
} }
} }

View File

@@ -12,7 +12,7 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke
public ConfigurationDataMTeamTp() public ConfigurationDataMTeamTp()
{ {
ApiKey = new StringConfigurationItem("API Key"); ApiKey = new StringConfigurationItem("API Key");
ApiKeyInfo = new DisplayInfoConfigurationItem("ApiKey Info", "The API key can be obtained by accessing your M-Team-TP User Control Panel > Security > Laboratory."); ApiKeyInfo = new DisplayInfoConfigurationItem("ApiKey Info", "The API key can be obtained by accessing your M-Team - TP User CP > Laboratory.");
FreeleechOnly = new BoolConfigurationItem("Search freeleech only") { Value = false }; FreeleechOnly = new BoolConfigurationItem("Search freeleech only") { Value = false };
} }
} }

View File

@@ -1,13 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using Jackett.Common.Extensions;
using System.Text;
using Jackett.Common.Indexers; using Jackett.Common.Indexers;
using Jackett.Common.Models; using Jackett.Common.Models;
using Jackett.Common.Models.Config; using Jackett.Common.Models.Config;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
@@ -36,8 +34,7 @@ namespace Jackett.Common.Services
{ {
private readonly Logger _logger; private readonly Logger _logger;
private readonly ServerConfig _serverConfig; private readonly ServerConfig _serverConfig;
private readonly SHA256Managed _sha256 = new SHA256Managed(); private readonly Dictionary<string, TrackerCache> _cache = new();
private readonly Dictionary<string, TrackerCache> _cache = new Dictionary<string, TrackerCache>();
public CacheService(Logger logger, ServerConfig serverConfig) public CacheService(Logger logger, ServerConfig serverConfig)
{ {
@@ -236,11 +233,11 @@ namespace Jackett.Common.Services
} }
} }
private string GetQueryHash(TorznabQuery query) private static string GetQueryHash(TorznabQuery query)
{ {
var json = GetSerializedQuery(query); var json = GetSerializedQuery(query);
// Compute the hash
return BitConverter.ToString(_sha256.ComputeHash(Encoding.UTF8.GetBytes(json))); return json.SHA256Hash();
} }
private static string GetSerializedQuery(TorznabQuery query) private static string GetSerializedQuery(TorznabQuery query)

View File

@@ -51,7 +51,8 @@ namespace Jackett.Common.Services
if (!Directory.Exists(GetAppDataFolder())) if (!Directory.Exists(GetAppDataFolder()))
{ {
var dir = Directory.CreateDirectory(GetAppDataFolder()); var dir = Directory.CreateDirectory(GetAppDataFolder());
if (Environment.OSVersion.Platform != PlatformID.Unix)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
var access = dir.GetAccessControl(); var access = dir.GetAccessControl();
var directorySecurity = new DirectorySecurity(GetAppDataFolder(), AccessControlSections.All); var directorySecurity = new DirectorySecurity(GetAppDataFolder(), AccessControlSections.All);
@@ -126,7 +127,7 @@ namespace Jackett.Common.Services
if (!Directory.Exists(destFolder)) if (!Directory.Exists(destFolder))
{ {
var dir = Directory.CreateDirectory(destFolder); var dir = Directory.CreateDirectory(destFolder);
if (Environment.OSVersion.Platform != PlatformID.Unix) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
var directorySecurity = new DirectorySecurity(destFolder, AccessControlSections.All); var directorySecurity = new DirectorySecurity(destFolder, AccessControlSections.All);
directorySecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow)); directorySecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow));
@@ -137,7 +138,7 @@ namespace Jackett.Common.Services
{ {
File.Copy(file, destPath); File.Copy(file, destPath);
// The old files were created when running as admin so make sure they are editable by normal users / services. // The old files were created when running as admin so make sure they are editable by normal users / services.
if (Environment.OSVersion.Platform != PlatformID.Unix) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
var fileInfo = new FileInfo(destFolder); var fileInfo = new FileInfo(destFolder);
var fileSecurity = new FileSecurity(destPath, AccessControlSections.All); var fileSecurity = new FileSecurity(destPath, AccessControlSections.All);

View File

@@ -74,8 +74,6 @@ namespace Jackett.Common.Services
} }
} }
private bool AcceptCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => true;
private async Task CheckForUpdates() private async Task CheckForUpdates()
{ {
logger.Info($"Checking for updates... Jackett variant: {variant}"); logger.Info($"Checking for updates... Jackett variant: {variant}");
@@ -180,14 +178,7 @@ namespace Jackett.Common.Services
} }
catch (Exception e) catch (Exception e)
{ {
logger.Error($"Error checking for updates.\n{e}"); logger.Error(e, $"Error checking for updates.\n{e}");
}
finally
{
if (!isWindows)
{
System.Net.ServicePointManager.ServerCertificateValidationCallback -= AcceptCert;
}
} }
} }

View File

@@ -2,6 +2,7 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.Versioning;
using System.ServiceProcess; using System.ServiceProcess;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils; using Jackett.Common.Utils;
@@ -9,6 +10,9 @@ using NLog;
namespace Jackett.Common.Services namespace Jackett.Common.Services
{ {
#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
public class WindowsServiceConfigService : IServiceConfigService public class WindowsServiceConfigService : IServiceConfigService
{ {
private const string NAME = "Jackett"; private const string NAME = "Jackett";

View File

@@ -29,8 +29,13 @@ namespace Jackett.Common.Utils.Clients
} }
[DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages [DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages
public static bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) public bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{ {
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
{
return true;
}
if (sender.GetType() != typeof(HttpWebRequest)) if (sender.GetType() != typeof(HttpWebRequest))
return sslPolicyErrors == SslPolicyErrors.None; return sslPolicyErrors == SslPolicyErrors.None;
@@ -51,24 +56,11 @@ namespace Jackett.Common.Utils.Clients
public override void SetTimeout(int seconds) => ClientTimeout = seconds; public override void SetTimeout(int seconds) => ClientTimeout = seconds;
public override void Init()
{
base.Init();
// custom handler for our own internal certificates
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
else
ServicePointManager.ServerCertificateValidationCallback += ValidateCertificate;
}
protected override async Task<WebResult> Run(WebRequest webRequest) protected override async Task<WebResult> Run(WebRequest webRequest)
{ {
ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072;
var cookies = new CookieContainer var cookies = new CookieContainer
{ {
PerDomainCapacity = 100 // By default only 20 cookies are allowed per domain PerDomainCapacity = 100 // By default, only 20 cookies are allowed per domain
}; };
if (!string.IsNullOrWhiteSpace(webRequest.Cookies)) if (!string.IsNullOrWhiteSpace(webRequest.Cookies))
{ {
@@ -86,14 +78,17 @@ namespace Jackett.Common.Utils.Clients
clearanceHandlr.ProxyUrl = serverConfig.GetProxyUrl(false); clearanceHandlr.ProxyUrl = serverConfig.GetProxyUrl(false);
clearanceHandlr.ProxyUsername = serverConfig.ProxyUsername; clearanceHandlr.ProxyUsername = serverConfig.ProxyUsername;
clearanceHandlr.ProxyPassword = serverConfig.ProxyPassword; clearanceHandlr.ProxyPassword = serverConfig.ProxyPassword;
using (var clientHandlr = new HttpClientHandler using (var clientHandlr = new HttpClientHandler
{ {
CookieContainer = cookies, CookieContainer = cookies,
AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more.
UseCookies = true, UseCookies = true,
Proxy = webProxy, Proxy = webProxy,
UseProxy = (webProxy != null), UseProxy = webProxy != null,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
MaxConnectionsPerServer = 20,
ServerCertificateCustomValidationCallback = ValidateCertificate,
}) })
{ {
clearanceHandlr.InnerHandler = clientHandlr; clearanceHandlr.InnerHandler = clientHandlr;

View File

@@ -33,14 +33,19 @@ namespace Jackett.Common.Utils.Clients
{ {
cookies = new CookieContainer cookies = new CookieContainer
{ {
PerDomainCapacity = 100 // By default only 20 cookies are allowed per domain PerDomainCapacity = 100 // By default, only 20 cookies are allowed per domain
}; };
CreateClient(); CreateClient();
} }
[DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages [DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages
public static bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) public bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{ {
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
{
return true;
}
var hash = certificate.GetCertHashString(); var hash = certificate.GetCertHashString();
trustedCertificates.TryGetValue(hash, out var hosts); trustedCertificates.TryGetValue(hash, out var hosts);
@@ -70,16 +75,12 @@ namespace Jackett.Common.Utils.Clients
AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more.
UseCookies = true, UseCookies = true,
Proxy = webProxy, Proxy = webProxy,
UseProxy = (webProxy != null), UseProxy = webProxy != null,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
MaxConnectionsPerServer = 20,
ServerCertificateCustomValidationCallback = ValidateCertificate,
}; };
// custom certificate validation handler (netcore version)
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
clientHandlr.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
else
clientHandlr.ServerCertificateCustomValidationCallback = ValidateCertificate;
clearanceHandlr.InnerHandler = clientHandlr; clearanceHandlr.InnerHandler = clientHandlr;
client = new HttpClient(clearanceHandlr); client = new HttpClient(clearanceHandlr);
@@ -103,13 +104,6 @@ namespace Jackett.Common.Utils.Clients
client.Timeout = TimeSpan.FromSeconds(ClientTimeout); client.Timeout = TimeSpan.FromSeconds(ClientTimeout);
} }
public override void Init()
{
base.Init();
ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072;
}
protected override async Task<WebResult> Run(WebRequest webRequest) protected override async Task<WebResult> Run(WebRequest webRequest)
{ {
var request = new HttpRequestMessage(); var request = new HttpRequestMessage();

View File

@@ -220,11 +220,7 @@ namespace Jackett.Common.Utils.Clients
return result; return result;
} }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously protected virtual Task<WebResult> Run(WebRequest webRequest) => throw new NotImplementedException();
protected virtual async Task<WebResult> Run(WebRequest webRequest) => throw new NotImplementedException();
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
public virtual void Init() => ServicePointManager.DefaultConnectionLimit = 1000;
public virtual void OnCompleted() => throw new NotImplementedException(); public virtual void OnCompleted() => throw new NotImplementedException();

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.InteropServices;
using System.Security.Principal; using System.Security.Principal;
using Jackett.Common.Utils.Clients; using Jackett.Common.Utils.Clients;
@@ -75,7 +76,11 @@ namespace Jackett.Common.Utils
public static bool IsUserAdministrator() public static bool IsUserAdministrator()
{ {
//bool value to hold our return value if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return false;
}
bool isAdmin; bool isAdmin;
try try
{ {

View File

@@ -1,104 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Jackett.Common.Utils
{
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
}

View File

@@ -189,16 +189,11 @@ namespace Jackett.Common.Utils
{ {
var chars = "abcdefghijklmnopqrstuvwxyz0123456789"; var chars = "abcdefghijklmnopqrstuvwxyz0123456789";
var randBytes = new byte[length]; var randBytes = new byte[length];
using (var rngCsp = new RNGCryptoServiceProvider())
{ using var rngCsp = RandomNumberGenerator.Create();
rngCsp.GetBytes(randBytes); rngCsp.GetBytes(randBytes);
var key = "";
foreach (var b in randBytes) return randBytes.Aggregate(string.Empty, (current, b) => current + chars[b % chars.Length]);
{
key += chars[b % chars.Length];
}
return key;
}
} }
public static IEnumerable<int> AllIndexesOf(this string source, char value) public static IEnumerable<int> AllIndexesOf(this string source, char value)

View File

@@ -29,9 +29,7 @@ namespace Jackett.Server.Services
return null; return null;
var ue = new UnicodeEncoding(); var ue = new UnicodeEncoding();
#pragma warning disable SYSLIB0021 var hashString = SHA512.Create();
var hashString = new SHA512Managed();
#pragma warning restore SYSLIB0021
// Append key as salt // Append key as salt
input += _serverConfig.APIKey; input += _serverConfig.APIKey;

View File

@@ -341,7 +341,6 @@ namespace Jackett.Server.Services
// Load indexers // Load indexers
indexerService.InitIndexers(configService.GetCardigannDefinitionsFolders()); indexerService.InitIndexers(configService.GetCardigannDefinitionsFolders());
client.Init();
updater.CleanupTempDir(); updater.CleanupTempDir();
updater.CheckUpdaterLock(); updater.CheckUpdaterLock();

View File

@@ -48,9 +48,5 @@ namespace Jackett.Test.TestHelpers
}); });
throw new Exception($"You have to mock the URL {request.Url} with RegisterRequestCallback"); throw new Exception($"You have to mock the URL {request.Url} with RegisterRequestCallback");
} }
public override void Init()
{
}
} }
} }

View File

@@ -2,6 +2,7 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using CommandLine; using CommandLine;
using CommandLine.Text; using CommandLine.Text;
using Jackett.Common.Models.Config; using Jackett.Common.Models.Config;
@@ -15,7 +16,6 @@ namespace Jackett.Updater
public class Program public class Program
{ {
private IProcessService processService; private IProcessService processService;
private IServiceConfigService windowsService;
public static Logger logger; public static Logger logger;
private Variants.JackettVariant variant = Variants.JackettVariant.NotFound; private Variants.JackettVariant variant = Variants.JackettVariant.NotFound;
@@ -27,7 +27,7 @@ namespace Jackett.Updater
private void Run(string[] args) private void Run(string[] args)
{ {
var runtimeSettings = new RuntimeSettings() var runtimeSettings = new RuntimeSettings
{ {
CustomLogFileName = "updater.txt" CustomLogFileName = "updater.txt"
}; };
@@ -42,7 +42,8 @@ namespace Jackett.Updater
variant = variants.GetVariant(); variant = variants.GetVariant();
logger.Info("Jackett variant: " + variant.ToString()); logger.Info("Jackett variant: " + variant.ToString());
var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
if (isWindows) if (isWindows)
{ {
//The updater starts before Jackett closes //The updater starts before Jackett closes
@@ -51,18 +52,13 @@ namespace Jackett.Updater
} }
processService = new ProcessService(logger); processService = new ProcessService(logger);
windowsService = new WindowsServiceConfigService(processService, logger);
var commandLineParser = new Parser(settings => settings.CaseSensitive = false); var commandLineParser = new Parser(settings => settings.CaseSensitive = false);
try try
{ {
var optionsResult = commandLineParser.ParseArguments<UpdaterConsoleOptions>(args); var optionsResult = commandLineParser.ParseArguments<UpdaterConsoleOptions>(args);
optionsResult.WithParsed(options => optionsResult.WithParsed(ProcessUpdate);
{
ProcessUpdate(options);
}
);
optionsResult.WithNotParsed(errors => optionsResult.WithNotParsed(errors =>
{ {
logger.Error(HelpText.AutoBuild(optionsResult)); logger.Error(HelpText.AutoBuild(optionsResult));
@@ -135,10 +131,10 @@ namespace Jackett.Updater
if (options.KillPids != null) if (options.KillPids != null)
{ {
var pidsStr = options.KillPids.Split(',').Where(pid => !string.IsNullOrWhiteSpace(pid)).ToArray(); var pidsStr = options.KillPids.Split(',').Where(pid => !string.IsNullOrWhiteSpace(pid)).ToArray();
pids = Array.ConvertAll(pidsStr, pid => int.Parse(pid)); pids = Array.ConvertAll(pidsStr, int.Parse);
} }
var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var trayRunning = false; var trayRunning = false;
var trayProcesses = Process.GetProcessesByName("JackettTray"); var trayProcesses = Process.GetProcessesByName("JackettTray");
if (isWindows) if (isWindows)
@@ -897,7 +893,9 @@ namespace Jackett.Updater
// kill pids after the update on UNIX // kill pids after the update on UNIX
if (!isWindows) if (!isWindows)
{
KillPids(pids); KillPids(pids);
}
if (!options.NoRestart) if (!options.NoRestart)
{ {
@@ -913,6 +911,8 @@ namespace Jackett.Updater
logger.Info("Starting Tray: " + startInfo.FileName + " " + startInfo.Arguments); logger.Info("Starting Tray: " + startInfo.FileName + " " + startInfo.Arguments);
Process.Start(startInfo); Process.Start(startInfo);
var windowsService = new WindowsServiceConfigService(processService, logger);
if (!windowsService.ServiceExists()) if (!windowsService.ServiceExists())
{ {
//User was running the tray icon, but not using the Windows service, starting Tray icon will start JackettConsole as well //User was running the tray icon, but not using the Windows service, starting Tray icon will start JackettConsole as well
@@ -920,10 +920,12 @@ namespace Jackett.Updater
} }
} }
if (string.Equals(options.Type, "WindowsService", StringComparison.OrdinalIgnoreCase)) if (isWindows && string.Equals(options.Type, "WindowsService", StringComparison.OrdinalIgnoreCase))
{ {
logger.Info("Starting Windows service"); logger.Info("Starting Windows service");
var windowsService = new WindowsServiceConfigService(processService, logger);
try try
{ {
windowsService.Start(); windowsService.Start();