mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-12 15:04:13 +02:00
Compare commits
92 Commits
v0.20.2697
...
v0.20.2904
Author | SHA1 | Date | |
---|---|---|---|
![]() |
384b7bb3e4 | ||
![]() |
8ce9aeaae9 | ||
![]() |
8c9e327ae6 | ||
![]() |
30854838c1 | ||
![]() |
3dc9b6c532 | ||
![]() |
aa484e4618 | ||
![]() |
cd0ca16d9b | ||
![]() |
871b857f48 | ||
![]() |
d74aa2317a | ||
![]() |
44adbb1033 | ||
![]() |
d2b0d7b21e | ||
![]() |
34eb822137 | ||
![]() |
a0afe0aaa1 | ||
![]() |
14bcfcc018 | ||
![]() |
470b18d664 | ||
![]() |
3b7110880f | ||
![]() |
74fdceba96 | ||
![]() |
6fca20b776 | ||
![]() |
733b4c854b | ||
![]() |
b3c7ce5818 | ||
![]() |
cd582ced27 | ||
![]() |
8788ce1e93 | ||
![]() |
eb3a9ab300 | ||
![]() |
690265d45e | ||
![]() |
435b7e84e4 | ||
![]() |
489e0c895a | ||
![]() |
7e819a2b47 | ||
![]() |
5d7ee40a04 | ||
![]() |
a2e5fc88cb | ||
![]() |
3b7962210a | ||
![]() |
771519385c | ||
![]() |
8171a7986a | ||
![]() |
38a3314f6f | ||
![]() |
d756ff0ccf | ||
![]() |
5aae699e91 | ||
![]() |
62aa75b7ad | ||
![]() |
e8875d38fc | ||
![]() |
22af3a09a2 | ||
![]() |
749167ba4a | ||
![]() |
872c8674bf | ||
![]() |
aac8469ffc | ||
![]() |
f8a9c57656 | ||
![]() |
0d2621b24d | ||
![]() |
231352dad5 | ||
![]() |
aef0802c21 | ||
![]() |
ef9a4fbaa6 | ||
![]() |
aad95a64ae | ||
![]() |
2ca375c33f | ||
![]() |
0ba4d305b0 | ||
![]() |
40fcb1e43b | ||
![]() |
24d4198e59 | ||
![]() |
d529b340ea | ||
![]() |
94b7f5434e | ||
![]() |
e45e8a9e4f | ||
![]() |
d1f078b36b | ||
![]() |
8cb43e3bdd | ||
![]() |
c886faf7df | ||
![]() |
885da5d30f | ||
![]() |
c61526182a | ||
![]() |
a950ee0071 | ||
![]() |
0d45b29a8e | ||
![]() |
c1fc63b8c6 | ||
![]() |
df46540efc | ||
![]() |
40acf3c4a7 | ||
![]() |
329c17ab25 | ||
![]() |
c479596a49 | ||
![]() |
993d5f2045 | ||
![]() |
5b7deb8250 | ||
![]() |
fba7b11697 | ||
![]() |
44caa63a2e | ||
![]() |
cf6f67d7cc | ||
![]() |
137e112964 | ||
![]() |
3ee74aa52a | ||
![]() |
7fb648d786 | ||
![]() |
19a556cd8f | ||
![]() |
33be5ec331 | ||
![]() |
12bd05422a | ||
![]() |
691a8c3757 | ||
![]() |
a63c8b012c | ||
![]() |
abe345a803 | ||
![]() |
ce583219a9 | ||
![]() |
ab76dde943 | ||
![]() |
c7a5d8c9a5 | ||
![]() |
2b66e79a39 | ||
![]() |
6d5f8dac65 | ||
![]() |
b0c9419345 | ||
![]() |
1dd08bd63c | ||
![]() |
c3f62a1ac2 | ||
![]() |
655ab08d57 | ||
![]() |
2a593a195c | ||
![]() |
e7cd1a8e68 | ||
![]() |
21a6ce12c8 |
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -18,6 +18,7 @@ on:
|
||||
- src/**/*.cs
|
||||
- src/**/*.js
|
||||
- '!src/Jackett.Common/Indexers/**'
|
||||
- '!src/Jackett.Common/Models/IndexerConfig/**'
|
||||
- '!src/Jackett.IntegrationTests/**'
|
||||
- '!src/Jackett.Test/**'
|
||||
pull_request:
|
||||
@@ -27,6 +28,7 @@ on:
|
||||
- src/**/*.cs
|
||||
- src/**/*.js
|
||||
- '!src/Jackett.Common/Indexers/**'
|
||||
- '!src/Jackett.Common/Models/IndexerConfig/**'
|
||||
- '!src/Jackett.IntegrationTests/**'
|
||||
- '!src/Jackett.Test/**'
|
||||
schedule:
|
||||
|
11
README.md
11
README.md
@@ -177,10 +177,12 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* BookTracker
|
||||
* BootyTape
|
||||
* Catorrent
|
||||
* Devil-Torrents
|
||||
* Darmowe torrenty
|
||||
* Deildu
|
||||
* DimeADozen (EzTorrent)
|
||||
* DXP (Deaf Experts)
|
||||
* Electro-Torrent
|
||||
* EniaHD
|
||||
* Erai-Raws
|
||||
* ExKinoRay
|
||||
@@ -222,6 +224,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* Torrents-Local
|
||||
* TribalMixes
|
||||
* Union Fansub
|
||||
* vTorrent
|
||||
* xTorrenty
|
||||
* YggTorrent (YGG)
|
||||
* ZOMB
|
||||
@@ -233,9 +236,9 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* 0day.kiev
|
||||
* 1ptbar
|
||||
* 2 Fast 4 You [![(invite needed)][inviteneeded]](#)
|
||||
* 2xFree
|
||||
* 3ChangTrai (3CT) [![(invite needed)][inviteneeded]](#)
|
||||
* 3D Torrents (3DT)
|
||||
* 3Evils
|
||||
* 4thD (4th Dimension)
|
||||
* 52PT
|
||||
* Abnormal
|
||||
@@ -376,6 +379,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* HDCity [![(invite needed)][inviteneeded]](#)
|
||||
* HDFans
|
||||
* HDHome (HDBigger) [![(invite needed)][inviteneeded]](#)
|
||||
* HDMaYi
|
||||
* HDMonkey
|
||||
* HDRoute [![(invite needed)][inviteneeded]](#)
|
||||
* HDSky [![(invite needed)][inviteneeded]](#)
|
||||
@@ -389,6 +393,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* HHanClub
|
||||
* HQMusic
|
||||
* House of Devil
|
||||
* ICC2022
|
||||
* iHDBits
|
||||
* ImmortalSeed (iS)
|
||||
* Immortuos
|
||||
@@ -439,6 +444,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* MySpleen [![(invite needed)][inviteneeded]](#)
|
||||
* NCore
|
||||
* Nebulance (NBL) (TransmiTheNet)
|
||||
* NicePT
|
||||
* NorBits
|
||||
* Old Toons World
|
||||
* OpenCD [![(invite needed)][inviteneeded]](#)
|
||||
@@ -491,6 +497,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* Secret Cinema
|
||||
* SeedFile
|
||||
* Shareisland
|
||||
* SharkPT
|
||||
* Shazbat [![(invite needed)][inviteneeded]](#)
|
||||
* SiamBIT
|
||||
* SkipTheCommercials
|
||||
@@ -528,6 +535,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* The Vault [![(invite needed)][inviteneeded]](#)
|
||||
* The-Crazy-Ones
|
||||
* The-New-Fun
|
||||
* TheDarkCommunity (TDC)
|
||||
* TheEmpire (TE)
|
||||
* TheLeachZone (TLZ)
|
||||
* TheScenePlace (TSP)
|
||||
@@ -566,6 +574,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht
|
||||
* U2 (U2分享園@動漫花園) [![(invite needed)][inviteneeded]](#)
|
||||
* UHDBits
|
||||
* UnionGang
|
||||
* UnleashTheCartoons
|
||||
* UnlimitZ
|
||||
* White Angel
|
||||
* wOOt [![(invite needed)][inviteneeded]](#)
|
||||
|
@@ -7,7 +7,7 @@ variables:
|
||||
jackettVersion: $(majorVersion).$(minorVersion).$(patchVersion)
|
||||
buildConfiguration: Release
|
||||
netCoreFramework: net6.0
|
||||
netCoreSdkVersion: 6.0.403 # #13806 & dotnet/runtime#79796
|
||||
netCoreSdkVersion: 6.0.x
|
||||
# system.debug: true
|
||||
|
||||
trigger:
|
||||
|
@@ -570,39 +570,39 @@
|
||||
<table id="jackett-search-results-datatable" class="dataTable compact cell-border hover stripe">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Published</th>
|
||||
<th>Published</th>
|
||||
<th>Tracker</th>
|
||||
<th class="text-center">Published</th>
|
||||
<th class="text-center">Published</th>
|
||||
<th class="text-center">Tracker</th>
|
||||
<th>Name</th>
|
||||
<th>Size</th>
|
||||
<th>Size</th>
|
||||
<th title="Files">F</th>
|
||||
<th>Category</th>
|
||||
<th title="Grabs">G</th>
|
||||
<th title="Seeders">S</th>
|
||||
<th title="Leechers">L</th>
|
||||
<th title="DownloadVolumeFactor" class="fit">DLF</th>
|
||||
<th title="UploadVolumeFactor" class="fit">ULF</th>
|
||||
<th title="Download">DL</th>
|
||||
<th class="text-center">Size</th>
|
||||
<th class="text-center">Size</th>
|
||||
<th class="text-center" title="Files">F</th>
|
||||
<th class="text-center">Category</th>
|
||||
<th class="text-center" title="Grabs">G</th>
|
||||
<th class="text-center" title="Seeders">S</th>
|
||||
<th class="text-center" title="Leechers">L</th>
|
||||
<th class="text-center fit" title="DownloadVolumeFactor">DLF</th>
|
||||
<th class="text-center fit" title="UploadVolumeFactor">ULF</th>
|
||||
<th class="text-center" title="Download">DL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each Results}}
|
||||
<tr class="jackett-search-results-row" data-imdb="{{Imdb}}" data-tmdb="{{TMDb}}" data-tvdb="{{TVDBId}}" data-tvmaze="{{TVMazeId}}" data-trakt="{{TraktId}}" data-douban="{{DoubanId}}" data-poster="{{Poster}}" data-description="{{Description}}">
|
||||
<td>{{PublishDate}}</td>
|
||||
<td>{{jacketTimespan PublishDate}}</td>
|
||||
<td>{{Tracker}}</td>
|
||||
<td class="text-center">{{PublishDate}}</td>
|
||||
<td class="text-center" title="{{dateFormat PublishDate format="YYYY-MM-DD HH:mm:ss Z"}}">{{jacketTimespan PublishDate}}</td>
|
||||
<td class="text-center">{{Tracker}}</td>
|
||||
<td class="Title"><a href="{{Details}}" target="_blank">{{Title}}</a> <span class="release-labels"></span></td>
|
||||
<td>{{Size}}</td>
|
||||
<td class="fit">{{jacketSize Size}}</td>
|
||||
<td>{{Files}}</td>
|
||||
<td class="Cat">{{CategoryDesc}}</td>
|
||||
<td>{{Grabs}}</td>
|
||||
<td>{{Seeders}}</td>
|
||||
<td>{{Peers}}</td>
|
||||
<td class="DownloadVolumeFactor">{{DownloadVolumeFactor}}</td>
|
||||
<td class="UploadVolumeFactor">{{UploadVolumeFactor}}</td>
|
||||
<td class="downloadcolumn">
|
||||
<td class="text-right">{{Size}}</td>
|
||||
<td class="text-right fit">{{jacketSize Size}}</td>
|
||||
<td class="text-center">{{Files}}</td>
|
||||
<td class="text-center Cat">{{CategoryDesc}}</td>
|
||||
<td class="text-center">{{Grabs}}</td>
|
||||
<td class="text-center">{{Seeders}}</td>
|
||||
<td class="text-center">{{Peers}}</td>
|
||||
<td class="text-center DownloadVolumeFactor">{{DownloadVolumeFactor}}</td>
|
||||
<td class="text-center UploadVolumeFactor">{{UploadVolumeFactor}}</td>
|
||||
<td class="text-center downloadcolumn">
|
||||
{{#if Link}}
|
||||
<a class="downloadlink" title="Download locally" href="{{Link}}"><i class="fa fa-download"></i></a>
|
||||
{{/if}}
|
||||
|
@@ -110,6 +110,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
attribute: href
|
||||
@@ -159,4 +162,4 @@ search:
|
||||
description:
|
||||
selector: td:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP Standard v1.5 Beta 5
|
||||
# NexusPHP v1.7.32 2022-12-05
|
||||
|
217
src/Jackett.Common/Definitions/2xfree.yml
Normal file
217
src/Jackett.Common/Definitions/2xfree.yml
Normal file
@@ -0,0 +1,217 @@
|
||||
---
|
||||
id: 2xfree
|
||||
name: 2xFree
|
||||
description: "2xFree is a CHINESE Private Torrent Tracker for HD MOVIES / TV / GENERAL"
|
||||
language: zh-CN
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
requestDelay: 2
|
||||
links:
|
||||
- https://pt.2xfree.org/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 401, cat: Movies, desc: "Movies(电影)", default: true}
|
||||
- {id: 402, cat: TV, desc: "TV Series(电视剧)", default: true}
|
||||
- {id: 403, cat: TV, desc: "TV Shows(综艺)", default: true}
|
||||
- {id: 404, cat: TV/Documentary, desc: "Documentaries(纪录片)", default: true}
|
||||
- {id: 405, cat: TV/Anime, desc: "Animations(动画)", default: true}
|
||||
- {id: 406, cat: Audio/Video, desc: "Music Videos(MV)", default: true}
|
||||
- {id: 407, cat: TV/Sport, desc: "Sports(体育运动)", default: true}
|
||||
- {id: 408, cat: Audio, desc: "HQ Audio(音乐)", default: true}
|
||||
- {id: 409, cat: Other, desc: "Misc(其他)", default: true}
|
||||
- {id: 410, cat: Books, desc: "eBook(电子书)", default: true}
|
||||
- {id: 411, cat: PC/Games, desc: "PCGame(游戏)", default: true}
|
||||
- {id: 413, cat: Audio/Video, desc: "AV(无码)", default: true}
|
||||
- {id: 414, cat: Audio/Video, desc: "AV(有码)", default: true}
|
||||
- {id: 420, cat: XXX, desc: "HAnime(H动画)", default: true}
|
||||
- {id: 421, cat: XXX, desc: "HComic(H漫画)", default: true}
|
||||
- {id: 422, cat: XXX, desc: "HGame(H游戏)", default: true}
|
||||
- {id: 423, cat: XXX, desc: "IV(写真影片)", default: true}
|
||||
- {id: 424, cat: XXX, desc: "IV(写真图集)", default: true}
|
||||
# special
|
||||
- {id: 526, cat: Movies, desc: "VRMovies(3D/VR电影)", default: true}
|
||||
- {id: 527, cat: TV, desc: "VRSeries(3D/VR剧集)", default: true}
|
||||
- {id: 528, cat: Audio/Video, desc: "AV(VR无码)", default: true}
|
||||
- {id: 529, cat: Audio/Video, desc: "AV(VR有码)", default: true}
|
||||
- {id: 530, cat: Console, desc: "VRGame(VR一体机游戏)", default: true}
|
||||
- {id: 531, cat: PC/Games, desc: "PCVRGame(PCVR游戏)", default: true}
|
||||
- {id: 532, cat: Other, desc: "VRTools(VR工具软件)", default: true}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid, doubanid]
|
||||
movie-search: [q, imdbid, doubanid]
|
||||
music-search: [q]
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
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 ICC2022 Web Site. Otherwise just leave it empty."
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: 4
|
||||
options:
|
||||
4: created
|
||||
7: seeders
|
||||
5: size
|
||||
1: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrents per page:</b> setting to <b>100</b> on your account profile.
|
||||
|
||||
login:
|
||||
path: login.php
|
||||
method: form
|
||||
form: form[action="takelogin.php"]
|
||||
captcha:
|
||||
type: image
|
||||
selector: img[alt="CAPTCHA"]
|
||||
input: imagestring
|
||||
inputs:
|
||||
secret: ""
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
two_step_code: "{{ .Config.2facode }}"
|
||||
logout: ""
|
||||
securelogin: ""
|
||||
ssl: yes
|
||||
trackerssl: yes
|
||||
error:
|
||||
- selector: td.embedded:has(h2:contains("失败"))
|
||||
- selector: td.embedded:has(h2:contains("Failed"))
|
||||
test:
|
||||
path: index.php
|
||||
selector: a[href="logout.php"]
|
||||
|
||||
search:
|
||||
paths:
|
||||
- path: torrents.php
|
||||
categories: [401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 413, 420, 421, 422, 423, 424]
|
||||
- path: special.php
|
||||
categories: [526, 527, 528, 529, 530, 531, 532]
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}cat{{.}}=1&{{end}}"
|
||||
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBID }}{{ else }}{{ end }}{{ if or .Query.IMDBID .Query.DoubanID }} {{ else }}{{ .Keywords }}{{ end }}{{ if .Query.DoubanID }}{{ .Query.DoubanID }}{{ else }}{{ end }}"
|
||||
# 0 incldead, 1 active, 2 dead
|
||||
incldead: 0
|
||||
# 0 all, 1 normal, 2 free, 3 2x, 4 2xfree, 5 50%, 6 2x50%, 7 30%
|
||||
spstate: "{{ if .Config.freeleech }}2{{ else }}0{{ end }}"
|
||||
# 0 title, 1 descr, 3 uploader, 4 imdburl (4 does not appear to work)
|
||||
search_area: "{{ if or .Query.IMDBID .Query.DoubanID }}1{{ else }}0{{ end }}"
|
||||
# 0 AND, 1 OR, 2 exact
|
||||
search_mode: 0
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: table.torrents > tbody > tr:has(a[href^="details.php?id="])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title_default:
|
||||
selector: a[href^="details.php?id="]
|
||||
title_optional:
|
||||
optional: true
|
||||
selector: a[title][href^="details.php?id="]
|
||||
attribute: title
|
||||
title:
|
||||
text: "{{ if .Result.title_optional }}{{ .Result.title_optional }}{{ else }}{{ .Result.title_default }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
attribute: href
|
||||
doubanid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="movie.douban.com/subject/"]
|
||||
attribute: href
|
||||
date_elapsed:
|
||||
# time type: time elapsed (default)
|
||||
selector: td.rowfollow:nth-child(4) > span[title]
|
||||
attribute: title
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-02 15:04:05 -07:00"
|
||||
date_added:
|
||||
# time added
|
||||
selector: td.rowfollow:nth-child(4):not(:has(span))
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-0215:04:05 -07:00"
|
||||
date:
|
||||
text: "{{ if or .Result.date_elapsed .Result.date_added }}{{ or .Result.date_elapsed .Result.date_added }}{{ else }}now{{ end }}"
|
||||
size:
|
||||
selector: td.rowfollow:nth-child(5)
|
||||
seeders:
|
||||
selector: td.rowfollow:nth-child(6)
|
||||
leechers:
|
||||
selector: td.rowfollow:nth-child(7)
|
||||
grabs:
|
||||
selector: td.rowfollow:nth-child(8)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img.pro_free: 0
|
||||
img.pro_free2up: 0
|
||||
img.pro_50pctdown: 0.5
|
||||
img.pro_50pctdown2up: 0.5
|
||||
img.pro_30pctdown: 0.3
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
img.pro_50pctdown2up: 2
|
||||
img.pro_free2up: 2
|
||||
img.pro_2up: 2
|
||||
"*": 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
minimumseedtime:
|
||||
# 1 day (as seconds = 24 x 60 x 60)
|
||||
text: 86400
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.8.0 2023-01-26
|
@@ -177,4 +177,4 @@ search:
|
||||
description:
|
||||
selector: td:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP Standard v1.5 Beta 4
|
||||
# NexusPHP v3.0 2020-04-30
|
||||
|
@@ -1,181 +0,0 @@
|
||||
---
|
||||
id: 3evils
|
||||
name: 3Evils
|
||||
description: "3Evils is a Private Torrent Tracker for MOVIES / TV / GENERAL"
|
||||
language: en-US
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://3evils.net/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: PC, desc: "Apps"}
|
||||
- {id: 24, cat: Books, desc: "Books/Magazines"}
|
||||
- {id: 12, cat: TV/Anime, desc: "Movies/Anime"}
|
||||
- {id: 31, cat: Movies, desc: "Movies/FooKaS RG"}
|
||||
- {id: 84, cat: Movies, desc: "Movies/Kids"}
|
||||
- {id: 55, cat: Movies/WEB-DL, desc: "Movies/WEB-DL"}
|
||||
- {id: 70, cat: Movies/WEB-DL, desc: "Movies/WEBRip"}
|
||||
- {id: 71, cat: Movies/HD, desc: "Movies/x265"}
|
||||
- {id: 64, cat: Movies/SD, desc: "Movies/XViD"}
|
||||
- {id: 26, cat: Audio/Lossless, desc: "Music/FLAC"}
|
||||
- {id: 10, cat: Audio/MP3, desc: "Music/MP3"}
|
||||
- {id: 63, cat: Audio/Video, desc: "Music/Videos"}
|
||||
- {id: 29, cat: Movies, desc: "Movies/Packs"}
|
||||
- {id: 19, cat: Audio, desc: "Music/Packs"}
|
||||
- {id: 61, cat: TV/Anime, desc: "TV/Anime"}
|
||||
- {id: 85, cat: TV, desc: "TV/Kids"}
|
||||
- {id: 86, cat: TV, desc: "TV/Packs"}
|
||||
- {id: 82, cat: TV/Sport, desc: "TV/Sports"}
|
||||
- {id: 36, cat: TV/HD, desc: "TV/x265"}
|
||||
- {id: 45, cat: TV/SD, desc: "TV/XViD"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
music-search: [q]
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: 4
|
||||
options:
|
||||
4: created
|
||||
7: seeders
|
||||
5: size
|
||||
1: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrents per page:</b> setting to <b>100</b> on your account profile. The default is <i>15</i>.
|
||||
|
||||
login:
|
||||
path: takelogin.php
|
||||
method: post
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
use_ssl: 1
|
||||
perm_ssl: ""
|
||||
error:
|
||||
- selector: td.embedded:contains("Login failed!")
|
||||
test:
|
||||
path: /
|
||||
selector: a[href*="/logout.php?hash_please="]
|
||||
|
||||
search:
|
||||
paths:
|
||||
# https://www.3evils.net/browse.php?c16=1&c17=1&c3=1&c4=1&search=&searchin=title&incldead=0&only_free=1
|
||||
- path: browse.php
|
||||
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
|
||||
search: "{{ .Keywords }}"
|
||||
# title, descr, genre, all
|
||||
searchin: title
|
||||
# 0 active, 1 incldead, 2 onlydead
|
||||
incldead: 1
|
||||
only_free: "{{ if .Config.freeleech }}1{{ else }}{{ end }}"
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["(\\w+)", "+$1"] # prepend + to each word
|
||||
|
||||
rows:
|
||||
selector: table.table-bordered tbody tr:has(a[href^="download.php?torrent="])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="browse.php?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: onmouseover
|
||||
filters:
|
||||
- name: regexp
|
||||
args: "Tip\\('<b>(.*?)</b>"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php?torrent="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: onmouseover
|
||||
filters:
|
||||
# onmouseover="Tip('<b>blahblah /><img src=\'img.php/tvmaze/80.jpg\' blahblah />');"
|
||||
# <img src=\'./pic/noposter.png\'
|
||||
- name: regexp
|
||||
args: "src=\\\\'(.+?)\\\\'"
|
||||
- name: replace
|
||||
args: ["./pic/noposter.png", ""]
|
||||
files:
|
||||
selector: td:nth-last-child(9)
|
||||
# 2 flavours of dates
|
||||
date_day:
|
||||
# Today<br> 10:20 AM
|
||||
# Yesterday<br> 08:03 PM
|
||||
selector: td:nth-last-child(7):contains("day")
|
||||
# auto adjusted by site account profile
|
||||
optional: true
|
||||
date_year:
|
||||
# Feb 14 2019<br> 10:20 AM
|
||||
selector: td:nth-last-child(7):not(:contains("day"))
|
||||
# auto adjusted by site account profile
|
||||
optional: true
|
||||
filters:
|
||||
- name: dateparse
|
||||
args: "Jan 2 2006 03:04 PM"
|
||||
date:
|
||||
text: "{{ if or .Result.date_day .Result.date_year }}{{ or .Result.date_day .Result.date_year }}{{ else }}now{{ end }}"
|
||||
size:
|
||||
selector: td:nth-last-child(6)
|
||||
grabs:
|
||||
selector: td:nth-last-child(5)
|
||||
filters:
|
||||
- name: regexp
|
||||
args: (\d+)
|
||||
seeders:
|
||||
selector: td:nth-last-child(4)
|
||||
leechers:
|
||||
selector: td:nth-last-child(3)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
"a.info:contains(\"[FREE]\")": 0
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
"*": 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
minimumseedtime:
|
||||
# 2 days (as seconds = 2 x 24 x 60 x 60)
|
||||
text: 172800
|
||||
# U-232 V5 (customised)
|
@@ -11,17 +11,22 @@ links:
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies, desc: "Filmes"}
|
||||
- {id: 2, cat: TV, desc: "TV Séries"}
|
||||
- {id: 3, cat: Other, desc: "Cursos"}
|
||||
- {id: 4, cat: Console, desc: "Jogos"}
|
||||
- {id: 5, cat: PC, desc: "Aplicativos"}
|
||||
- {id: 6, cat: TV/Anime, desc: "Animes"}
|
||||
- {id: 7, cat: Other, desc: "Materiais de Apoio"}
|
||||
- {id: 2, cat: TV, desc: "Séries"}
|
||||
- {id: 8, cat: TV/Anime, desc: "Animes"}
|
||||
- {id: 5, cat: Other, desc: "Cursos"}
|
||||
- {id: 6, cat: Other, desc: "Materiais de Apoio"}
|
||||
- {id: 7, cat: Books, desc: "eBooks / Revistas / Apostilas"}
|
||||
- {id: 9, cat: Audio/Video, desc: "Shows"}
|
||||
- {id: 10, cat: PC, desc: "Programas"}
|
||||
- {id: 11, cat: TV/Documentary, desc: "Documentários"}
|
||||
- {id: 4, cat: Console, desc: "Games"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid, tvdbid, tmdbid]
|
||||
movie-search: [q, imdbid, tmdbid]
|
||||
book-search: [q]
|
||||
music-search: [q]
|
||||
|
||||
settings:
|
||||
- name: apikey
|
||||
@@ -169,6 +174,6 @@ search:
|
||||
# minimumratio:
|
||||
# text: 0.4
|
||||
minimumseedtime:
|
||||
# 5 days (as seconds = 5 x 24 x 60 x 60)
|
||||
text: 432000
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
# json UNIT3D 6.1.0
|
||||
|
@@ -99,9 +99,6 @@ login:
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
use_ssl: 1
|
||||
perm_ssl: ""
|
||||
returnto: "/"
|
||||
error:
|
||||
- selector: table.main:contains("failed")
|
||||
test:
|
||||
|
@@ -93,6 +93,7 @@ search:
|
||||
paths:
|
||||
- path: browse.php
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
|
||||
search: "{{ .Keywords }}"
|
||||
# 0 active, 1 incldead, 2 onlydead
|
||||
incldead: 1
|
||||
@@ -101,10 +102,15 @@ search:
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["\\s+", " "] # More than 1 space to 1 space
|
||||
- name: re_replace
|
||||
args: ["(\\w+)", "+$1"] # prepend + to each word
|
||||
- name: trim
|
||||
|
||||
rows:
|
||||
selector: table > tbody > tr[class]
|
||||
filters:
|
||||
- name: andmatch
|
||||
|
||||
fields:
|
||||
# there are two styles, we support both
|
||||
|
@@ -127,6 +127,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
@@ -186,4 +189,4 @@ search:
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.7.16
|
||||
# NexusPHP v1.7.31 2022-11-14
|
||||
|
@@ -35,6 +35,10 @@ download:
|
||||
attribute: href
|
||||
|
||||
search:
|
||||
headers:
|
||||
# site blocks automation User-Agents, so slightly alter it here (e.g. Safari/537.37 > Safari/537.36)
|
||||
User-Agent: ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"]
|
||||
|
||||
paths:
|
||||
- path: "{{ if .Keywords }}search?query={{ .Keywords }}{{ else }}latest{{ end }}"
|
||||
|
||||
@@ -65,7 +69,7 @@ search:
|
||||
attribute: title
|
||||
filters:
|
||||
- name: append
|
||||
args: " -09:00" # CUS
|
||||
args: " +00:00" # GMT
|
||||
- name: dateparse
|
||||
args: "02 Jan, 2006 15:04 -07:00"
|
||||
size:
|
||||
|
169
src/Jackett.Common/Definitions/devil-torrents.yml
Normal file
169
src/Jackett.Common/Definitions/devil-torrents.yml
Normal file
@@ -0,0 +1,169 @@
|
||||
---
|
||||
id: devil-torrents
|
||||
name: Devil-Torrents
|
||||
description: "Devil-Torrents is a POLISH Semi-Private Torrent Tracker for MOVIES / TV / GENERAL"
|
||||
language: pl-PL
|
||||
type: semi-private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://devil-torrents.pl/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies/SD, desc: "Filmy XviD/DivX"}
|
||||
- {id: 748, cat: Movies/UHD, desc: "Filmy 4K"}
|
||||
- {id: 4, cat: Movies/BluRay, desc: "Filmy Blu-Ray/HD"}
|
||||
- {id: 642, cat: Movies/HD, desc: "Filmy x264/h264"}
|
||||
- {id: 596, cat: Movies/HD, desc: "Filmy x265/h265"}
|
||||
- {id: 3, cat: Movies/DVD, desc: "Filmy DVD"}
|
||||
- {id: 5, cat: Movies/3D, desc: "Filmy 3D"}
|
||||
- {id: 2, cat: Movies/HD, desc: "Filmy RMVB"}
|
||||
- {id: 362, cat: Movies/SD, desc: "Filmy IVO"}
|
||||
- {id: 7, cat: TV, desc: "TV/Seriale"}
|
||||
- {id: 702, cat: Movies/SD, desc: "TS/CAM"}
|
||||
- {id: 8, cat: XXX, desc: "Erotyka"}
|
||||
- {id: 10, cat: Audio, desc: "Muzyka"}
|
||||
- {id: 11, cat: PC, desc: "Programy"}
|
||||
- {id: 12, cat: PC/Mobile-Other, desc: "GSM/PDA"}
|
||||
- {id: 13, cat: Console, desc: "Konsole"}
|
||||
- {id: 14, cat: PC/Games, desc: "Gry PC"}
|
||||
- {id: 15, cat: Movies, desc: "Dla Dzieci"}
|
||||
- {id: 16, cat: Books, desc: "Książki"}
|
||||
- {id: 525, cat: PC/Mac, desc: "Mac"}
|
||||
- {id: 18, cat: PC, desc: "Linux"}
|
||||
- {id: 19, cat: TV/Sport, desc: "Sport"}
|
||||
- {id: 699, cat: TV/Anime, desc: "Anime"}
|
||||
- {id: 21, cat: Other, desc: "Inne"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
music-search: [q]
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: multilang
|
||||
type: checkbox
|
||||
label: Replace MULTI by another language in release name
|
||||
default: false
|
||||
- name: multilanguage
|
||||
type: select
|
||||
label: Replace MULTI by this language
|
||||
default: POLISH
|
||||
options:
|
||||
POLISH: POLISH
|
||||
MULTI.POLISH: MULTI.POLISH
|
||||
|
||||
login:
|
||||
path: logowanie
|
||||
method: form
|
||||
form: form[action="takelogin.php"]
|
||||
captcha:
|
||||
type: image
|
||||
selector: img[src^="img.php?size=3"]
|
||||
input: vImageCodP
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
returnto: ""
|
||||
error:
|
||||
- selector: div#center-side:contains("Logowanie nie")
|
||||
test:
|
||||
path: /
|
||||
selector: a[href$="/logout.php"]
|
||||
|
||||
search:
|
||||
# https://devil-torrents.pl/szukaj.php?search=%&typ=torrent&c4=1&c748=1
|
||||
paths:
|
||||
- path: szukaj.php
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
|
||||
typ: torrent
|
||||
search: "{{ if .Keywords }}{{ .Keywords }}{{ else }}%{{ end }}"
|
||||
|
||||
rows:
|
||||
selector: table.test5 > tbody > tr > td > div[id]:has(a[href^="download/"])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: div#kategoria-gatunek-1
|
||||
case:
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy XviD/DivX\")": 1
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy 4K\")": 748
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy Blu-Ray/HD\")": 4
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x264/h264\")": 642
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x265/h265\")": 596
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy DVD\")": 3
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy 3D\")": 5
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy RMVB\")": 2
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy IVO\")": 362
|
||||
"div#kategoria-gatunek-1:contains(\"TV/Seriale\")": 7
|
||||
"div#kategoria-gatunek-1:contains(\"TS/CAM\")": 702
|
||||
"div#kategoria-gatunek-1:contains(\"Erotyka\")": 8
|
||||
"div#kategoria-gatunek-1:contains(\"Muzyka\")": 10
|
||||
"div#kategoria-gatunek-1:contains(\"Programy\")": 11
|
||||
"div#kategoria-gatunek-1:contains(\"GSM/PDA\")": 12
|
||||
"div#kategoria-gatunek-1:contains(\"Konsole\")": 13
|
||||
"div#kategoria-gatunek-1:contains(\"Gry PC\")": 14
|
||||
"div#kategoria-gatunek-1:contains(\"Dla Dzieci\")": 15
|
||||
"div#kategoria-gatunek-1:contains(\"Książki\")": 16
|
||||
"div#kategoria-gatunek-1:contains(\"Mac\")": 525
|
||||
"div#kategoria-gatunek-1:contains(\"Linux\")": 18
|
||||
"div#kategoria-gatunek-1:contains(\"Sport\")": 19
|
||||
"div#kategoria-gatunek-1:contains(\"Anime\")": 699
|
||||
"div#kategoria-gatunek-1:contains(\"Inne\")": 21
|
||||
title_phase1:
|
||||
selector: a[href^="/torrent/"]
|
||||
attribute: title
|
||||
title_multilang:
|
||||
selector: a[href^="/torrent/"]
|
||||
attribute: title
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)(\\bmulti\\b)", "{{ .Config.multilanguage }}"]
|
||||
title:
|
||||
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="/torrent/"]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download/"]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img.browse_poster
|
||||
attribute: src
|
||||
date:
|
||||
selector: td.descr3
|
||||
filters:
|
||||
- name: regexp
|
||||
args: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})
|
||||
- name: append
|
||||
args: " +01:00" # CET
|
||||
- name: dateparse
|
||||
args: "2006-01-02 15:04:05 -07:00"
|
||||
size:
|
||||
selector: td.descr3
|
||||
filters:
|
||||
- name: regexp
|
||||
args: (\d{1,4}\.\d{2}\s+?[T|G|M|k]B)
|
||||
seeders:
|
||||
selector: font[color="green"] > b, font[color="red"] > b
|
||||
leechers:
|
||||
selector: font[color="green"]:nth-of-type(2) > b, font[color="red"]:nth-of-type(2) > b
|
||||
grabs:
|
||||
selector: td.descr3
|
||||
filters:
|
||||
- name: regexp
|
||||
args: (\d{1,4}) razy
|
||||
downloadvolumefactor:
|
||||
text: 0
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
# engine n/a
|
183
src/Jackett.Common/Definitions/electro-torrent.yml
Normal file
183
src/Jackett.Common/Definitions/electro-torrent.yml
Normal file
@@ -0,0 +1,183 @@
|
||||
---
|
||||
id: electro-torrent
|
||||
name: Electro-Torrent
|
||||
description: "Electro-Torrent is a POLISH Semi-Private Torrent Tracker for MOVIES / TV / GENERAL"
|
||||
language: pl-PL
|
||||
type: semi-private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- http://electro-torrent.pl/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies/SD, desc: "Filmy XviD/DivX"}
|
||||
- {id: 769, cat: Movies/HD, desc: "Filmy 1080p AVC"}
|
||||
- {id: 770, cat: Movies/HD, desc: "Filmy x264/1080p"}
|
||||
- {id: 4, cat: Movies/HD, desc: "Filmy x264/720p"}
|
||||
- {id: 642, cat: Movies/HD, desc: "Filmy x264/h264"}
|
||||
- {id: 723, cat: Movies/UHD, desc: "Filmy 4K UHD"}
|
||||
- {id: 1160, cat: Movies/UHD, desc: "Filmy x265/2160p"}
|
||||
- {id: 1116, cat: Movies/HD, desc: "Filmy x265/1080p"}
|
||||
- {id: 1204, cat: Movies/HD, desc: "Filmy x265/720p"}
|
||||
- {id: 596, cat: Movies/HD, desc: "Filmy x265/h265"}
|
||||
- {id: 1072, cat: Movies, desc: "Filmy - WAREZY"}
|
||||
- {id: 3, cat: Movies/DVD, desc: "Filmy DVD"}
|
||||
- {id: 5, cat: Movies/3D, desc: "Filmy 3D"}
|
||||
- {id: 362, cat: Movies/SD, desc: "Filmy IVO"}
|
||||
- {id: 696, cat: Movies/SD, desc: "Filmy TS/CAM"}
|
||||
- {id: 7, cat: TV, desc: "TV/Seriale"}
|
||||
- {id: 8, cat: XXX, desc: "Erotyka"}
|
||||
- {id: 10, cat: Audio, desc: "Muzyka"}
|
||||
- {id: 11, cat: PC, desc: "Programy"}
|
||||
- {id: 12, cat: PC/Mobile-Other, desc: "GSM/PDA"}
|
||||
- {id: 13, cat: Console, desc: "Konsole"}
|
||||
- {id: 14, cat: PC/Games, desc: "Gry PC"}
|
||||
- {id: 1045, cat: PC/Games, desc: "Gry PC - Warezy"}
|
||||
- {id: 15, cat: Movies, desc: "Dla Dzieci"}
|
||||
- {id: 16, cat: Books, desc: "Książki"}
|
||||
- {id: 525, cat: PC/Mac, desc: "Mac"}
|
||||
- {id: 18, cat: PC, desc: "Linux"}
|
||||
- {id: 19, cat: TV/Sport, desc: "Sport"}
|
||||
- {id: 907, cat: TV/Anime, desc: "Anime"}
|
||||
- {id: 21, cat: Other, desc: "Inne"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
music-search: [q]
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: multilang
|
||||
type: checkbox
|
||||
label: Replace MULTI by another language in release name
|
||||
default: false
|
||||
- name: multilanguage
|
||||
type: select
|
||||
label: Replace MULTI by this language
|
||||
default: POLISH
|
||||
options:
|
||||
POLISH: POLISH
|
||||
MULTI.POLISH: MULTI.POLISH
|
||||
|
||||
login:
|
||||
path: logowanie
|
||||
method: form
|
||||
form: form[action="takelogin.php"]
|
||||
captcha:
|
||||
type: image
|
||||
selector: img[src^="img.php?size=3"]
|
||||
input: vImageCodP
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
returnto: ""
|
||||
error:
|
||||
- selector: div#center-side:contains("Logowanie nie")
|
||||
test:
|
||||
path: /
|
||||
selector: a[href$="/logout.php"]
|
||||
|
||||
search:
|
||||
# http://electro-torrent.pl/szukaj.php?search=&typ=torrent&cat=0
|
||||
paths:
|
||||
- path: szukaj.php
|
||||
inputs:
|
||||
# does not support multi cat selection, defaulting to all
|
||||
# $raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
|
||||
cat: 0
|
||||
typ: torrent
|
||||
search: "{{ .Keywords }}"
|
||||
|
||||
rows:
|
||||
selector: table.test5 > tbody > tr > td > div[id]:has(a[href*="/download/"])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: div#kategoria-gatunek-1
|
||||
case:
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy XviD/DivX\")": 1
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy 1080p AVC\")": 769
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x264/1080p\")": 770
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x264/720p\")": 4
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x264/h264\")": 642
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy 4K UHD\")": 723
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x265/2160p\")": 1160
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x265/1080p\")": 1116
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x265/720p\")": 1204
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy x265/h265\")": 596
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy - WAREZY\")": 1072
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy DVD\")": 3
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy 3D\")": 5
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy IVO\")": 362
|
||||
"div#kategoria-gatunek-1:contains(\"Filmy TS/CAM\")": 696
|
||||
"div#kategoria-gatunek-1:contains(\"TV/Seriale\")": 7
|
||||
"div#kategoria-gatunek-1:contains(\"Erotyka\")": 8
|
||||
"div#kategoria-gatunek-1:contains(\"Muzyka\")": 10
|
||||
"div#kategoria-gatunek-1:contains(\"Programy\")": 11
|
||||
"div#kategoria-gatunek-1:contains(\"GSM/PDA\")": 12
|
||||
"div#kategoria-gatunek-1:contains(\"Konsole\")": 13
|
||||
"div#kategoria-gatunek-1:contains(\"Gry PC - Warezy\")": 1045
|
||||
"div#kategoria-gatunek-1:contains(\"Gry PC\")": 14
|
||||
"div#kategoria-gatunek-1:contains(\"Dla Dzieci\")": 15
|
||||
"div#kategoria-gatunek-1:contains(\"Książki\")": 16
|
||||
"div#kategoria-gatunek-1:contains(\"Mac\")": 525
|
||||
"div#kategoria-gatunek-1:contains(\"Linux\")": 18
|
||||
"div#kategoria-gatunek-1:contains(\"Sport\")": 19
|
||||
"div#kategoria-gatunek-1:contains(\"Anime\")": 907
|
||||
"div#kategoria-gatunek-1:contains(\"Inne\")": 21
|
||||
title_phase1:
|
||||
selector: a[href^="/torrent/"]
|
||||
attribute: title
|
||||
title_multilang:
|
||||
selector: a[href^="/torrent/"]
|
||||
attribute: title
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)(\\bmulti\\b)", "{{ .Config.multilanguage }}"]
|
||||
title:
|
||||
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="/torrent/"]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href*="/download/"]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img.browse_poster
|
||||
attribute: src
|
||||
date:
|
||||
selector: td.descr3
|
||||
filters:
|
||||
- name: regexp
|
||||
args: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})
|
||||
- name: append
|
||||
args: " +01:00" # CET
|
||||
- name: dateparse
|
||||
args: "2006-01-02 15:04:05 -07:00"
|
||||
size:
|
||||
selector: td.descr3
|
||||
filters:
|
||||
- name: regexp
|
||||
args: (\d{1,4}\.\d{2}\s+?[T|G|M|k]B)
|
||||
seeders:
|
||||
selector: font[color="green"] > b, font[color="red"] > b
|
||||
leechers:
|
||||
selector: font[color="green"]:nth-of-type(2) > b, font[color="red"]:nth-of-type(2) > b
|
||||
grabs:
|
||||
selector: td.descr3
|
||||
filters:
|
||||
- name: regexp
|
||||
args: (\d{1,4}) razy
|
||||
downloadvolumefactor:
|
||||
text: 0
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
# engine n/a
|
@@ -170,4 +170,4 @@ search:
|
||||
minimumseedtime:
|
||||
# 1 day (as seconds = 24 x 60 x 60)
|
||||
text: 86400
|
||||
# NexusPHP v1.0
|
||||
# NexusPHP v1.1 2021-10-15
|
||||
|
@@ -32,6 +32,13 @@ settings:
|
||||
- name: password
|
||||
type: password
|
||||
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 HDAtmos Web Site. Otherwise just leave it empty."
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
@@ -66,12 +73,14 @@ login:
|
||||
selector: img[alt="CAPTCHA"]
|
||||
input: imagestring
|
||||
inputs:
|
||||
secret: ""
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
two_step_code: "{{ .Config.2facode }}"
|
||||
logout: ""
|
||||
securelogin: ""
|
||||
ssl: yes
|
||||
trackerssl: ""
|
||||
trackerssl: yes
|
||||
error:
|
||||
- selector: td.embedded:has(h2:contains("失败"))
|
||||
message:
|
||||
@@ -172,4 +181,4 @@ search:
|
||||
remove: a, img
|
||||
minimumratio:
|
||||
text: 0.81
|
||||
# NexusPHP Standard v1.5 Beta 4
|
||||
# NexusPHP 1.7.31 2022-11-14
|
||||
|
@@ -1,123 +0,0 @@
|
||||
---
|
||||
id: hdbits
|
||||
name: HDBits
|
||||
description: "Best HD Tracker"
|
||||
language: en-US
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://hdbits.org/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: "Movies", desc: "Movie"}
|
||||
- {id: 2, cat: "TV", desc: "TV"}
|
||||
- {id: 3, cat: "TV/Documentary", desc: "Documentary"}
|
||||
- {id: 4, cat: "Audio", desc: "Music"}
|
||||
- {id: 5, cat: "TV/Sport", desc: "Sport"}
|
||||
- {id: 6, cat: "Audio", desc: "Audio Track"}
|
||||
- {id: 7, cat: "XXX", desc: "XXX"}
|
||||
- {id: 8, cat: "Other", desc: "Misc/Demo"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid]
|
||||
movie-search: [q, imdbid]
|
||||
music-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Filter FreeLeech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: added
|
||||
options:
|
||||
added: created
|
||||
seeders: seeders
|
||||
size: size
|
||||
name: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: DESC
|
||||
options:
|
||||
DESC: desc
|
||||
ASC: asc
|
||||
|
||||
login:
|
||||
path: login
|
||||
method: form
|
||||
form: form
|
||||
inputs:
|
||||
uname: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
error:
|
||||
- selector: table.main:contains("Login Failed!")
|
||||
test:
|
||||
path: my.php
|
||||
|
||||
search:
|
||||
paths:
|
||||
- path: browse.php
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}filter_cat[{{.}}]=1&{{end}}"
|
||||
search: "{{ .Keywords }}"
|
||||
descriptions: 0
|
||||
imdbgt: 0
|
||||
imdblt: 10
|
||||
imdb: "{{ .Query.IMDBID }}"
|
||||
sort: "{{ .Config.sort }}"
|
||||
d: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: "table#torrent-list > tbody > tr:has(a[href^=\"/details.php?id=\"]){{ if .Config.freeleech }}:has(a[title=\"100% FL: no download is counted.\"]){{ else }}{{ end }}"
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title:
|
||||
selector: td:nth-child(3) a
|
||||
download:
|
||||
selector: a[href^="/download.php"]
|
||||
attribute: href
|
||||
details:
|
||||
selector: a[href^="/details.php?id="]
|
||||
attribute: href
|
||||
grabs:
|
||||
selector: td:nth-child(7) a
|
||||
size:
|
||||
selector: td:nth-child(6)
|
||||
seeders:
|
||||
selector: td:nth-child(8)
|
||||
leechers:
|
||||
selector: td:nth-child(9)
|
||||
date:
|
||||
selector: td:nth-child(5)
|
||||
filters:
|
||||
- name: append
|
||||
args: " ago"
|
||||
imdbid:
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
attribute: href
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
"a[title=\"25% Free Leech: only 75% of the download is counted.\"]": 0.25
|
||||
"a[title=\"50% Free Leech: only half the download is counted.\"]": 0.5
|
||||
"a[title=\"100% FL: no download is counted.\"]": 0
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
# engine tbd
|
@@ -145,4 +145,4 @@ search:
|
||||
img.pro_free2up: 2
|
||||
img.pro_2up: 2
|
||||
"*": 1
|
||||
# NexusPHP 146364c08c (Customised)
|
||||
# NexusPHP 2c858e7 (Customised)
|
||||
|
@@ -82,6 +82,7 @@ login:
|
||||
selector: img[alt="CAPTCHA"]
|
||||
input: imagestring
|
||||
inputs:
|
||||
secret: ""
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
two_step_code: "{{ .Config.2facode }}"
|
||||
@@ -138,6 +139,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
attribute: href
|
||||
@@ -189,4 +193,4 @@ search:
|
||||
remove: a, img
|
||||
minimumratio:
|
||||
text: 0.81
|
||||
# NexusPHP Standard v1.7.6
|
||||
# NexusPHP v1.8.0 2023-01-20
|
||||
|
@@ -170,4 +170,4 @@ search:
|
||||
description:
|
||||
selector: td:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP Standard v1.5 Beta 4
|
||||
# NexusPHP v2.0 2014-11-24
|
||||
|
173
src/Jackett.Common/Definitions/hdmayi.yml
Normal file
173
src/Jackett.Common/Definitions/hdmayi.yml
Normal file
@@ -0,0 +1,173 @@
|
||||
---
|
||||
id: hdmayi
|
||||
name: HDMaYi
|
||||
description: "HDMaYi (小蚂蚁PT站) is a CHINESE Private Torrent Tracker for HD MOVIES / TV / GENERAL"
|
||||
language: zh-CN
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- http://hdmayi.com/ # does not support https properly
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 401, cat: Movies, desc: "Movies/电影"}
|
||||
- {id: 404, cat: TV/Documentary, desc: "Documentaries/纪录片"}
|
||||
- {id: 405, cat: TV/Anime, desc: "Animations/动漫"}
|
||||
- {id: 402, cat: TV, desc: "TV Series/电视剧"}
|
||||
- {id: 403, cat: TV, desc: "TV Shows/综艺"}
|
||||
- {id: 406, cat: Audio/Video, desc: "MusicVideo/MV"}
|
||||
- {id: 407, cat: TV/Sport, desc: "Sports/体育"}
|
||||
- {id: 409, cat: Other, desc: "Misc/其他"}
|
||||
- {id: 408, cat: Audio, desc: "Music/音乐"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid, doubanid]
|
||||
movie-search: [q, imdbid, doubanid]
|
||||
music-search: [q]
|
||||
|
||||
settings:
|
||||
- name: cookie
|
||||
type: text
|
||||
label: Cookie
|
||||
- name: info
|
||||
type: info
|
||||
label: How to get the Cookie
|
||||
default: "<ol><li>Login to this tracker with your browser<li>Open the <b>DevTools</b> panel by pressing <b>F12</b><li>Select the <b>Network</b> tab<li>Click on the <b>Doc</b> button (Chrome Browser) or <b>HTML</b> button (FireFox)<li>Refresh the page by pressing <b>F5</b><li>Click on the first row entry<li>Select the <b>Headers</b> tab on the Right panel<li>Find <b>'cookie:'</b> in the <b>Request Headers</b> section<li><b>Select</b> and <b>Copy</b> the whole cookie string <i>(everything after 'cookie: ')</i> and <b>Paste</b> here.</ol>"
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: 4
|
||||
options:
|
||||
4: created
|
||||
7: seeders
|
||||
5: size
|
||||
1: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrents per page:</b> setting to <b>100</b> on your account profile.
|
||||
|
||||
login:
|
||||
method: cookie
|
||||
inputs:
|
||||
cookie: "{{ .Config.cookie }}"
|
||||
test:
|
||||
path: index.php
|
||||
selector: a[href="logout.php"]
|
||||
|
||||
search:
|
||||
paths:
|
||||
- path: torrents.php
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}cat{{.}}=1&{{end}}"
|
||||
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBID }}{{ else }}{{ end }}{{ if or .Query.IMDBID .Query.DoubanID }} {{ else }}{{ .Keywords }}{{ end }}{{ if .Query.DoubanID }}{{ .Query.DoubanID }}{{ else }}{{ end }}"
|
||||
# 0 incldead, 1 active, 2 dead
|
||||
incldead: 0
|
||||
# 0 all, 1 normal, 2 free, 3 2x, 4 2xfree, 5 50%, 6 2x50%, 7 30%
|
||||
spstate: "{{ if .Config.freeleech }}2{{ else }}0{{ end }}"
|
||||
# 0 title, 1 descr, 3 uploader, 4 imdburl (4 does not appear to work)
|
||||
search_area: "{{ if or .Query.IMDBID .Query.DoubanID }}1{{ else }}0{{ end }}"
|
||||
# 0 AND, 1 OR, 2 exact
|
||||
search_mode: 0
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: table.torrents > tbody > tr:has(a[href^="details.php?id="])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title_default:
|
||||
selector: a[href^="details.php?id="]
|
||||
title_optional:
|
||||
optional: true
|
||||
selector: a[title][href^="details.php?id="]
|
||||
attribute: title
|
||||
title:
|
||||
text: "{{ if .Result.title_optional }}{{ .Result.title_optional }}{{ else }}{{ .Result.title_default }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
attribute: href
|
||||
doubanid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="movie.douban.com/subject/"]
|
||||
attribute: href
|
||||
date_elapsed:
|
||||
# time type: time elapsed (default)
|
||||
selector: td.rowfollow:nth-child(4) > span[title]
|
||||
attribute: title
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-02 15:04:05 -07:00"
|
||||
date_added:
|
||||
# time added
|
||||
selector: td.rowfollow:nth-child(4):not(:has(span))
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-0215:04:05 -07:00"
|
||||
date:
|
||||
text: "{{ if or .Result.date_elapsed .Result.date_added }}{{ or .Result.date_elapsed .Result.date_added }}{{ else }}now{{ end }}"
|
||||
size:
|
||||
selector: td.rowfollow:nth-child(5)
|
||||
seeders:
|
||||
selector: td.rowfollow:nth-child(6)
|
||||
leechers:
|
||||
selector: td.rowfollow:nth-child(7)
|
||||
grabs:
|
||||
selector: td.rowfollow:nth-child(8)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img.pro_free: 0
|
||||
img.pro_free2up: 0
|
||||
img.pro_50pctdown: 0.5
|
||||
img.pro_50pctdown2up: 0.5
|
||||
img.pro_30pctdown: 0.3
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
img.pro_50pctdown2up: 2
|
||||
img.pro_free2up: 2
|
||||
img.pro_2up: 2
|
||||
"*": 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
minimumseedtime:
|
||||
# 1 day (as seconds = 24 x 60 x 60)
|
||||
text: 86400
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.7.29 2022-10-12
|
@@ -130,6 +130,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
|
@@ -130,6 +130,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
@@ -189,4 +192,4 @@ search:
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.7.24 2022-08-30
|
||||
# NexusPHP v1.7.30 2022-11-05
|
||||
|
203
src/Jackett.Common/Definitions/icc2022.yml
Normal file
203
src/Jackett.Common/Definitions/icc2022.yml
Normal file
@@ -0,0 +1,203 @@
|
||||
---
|
||||
id: icc2022
|
||||
name: ICC2022
|
||||
description: "ICC2022 (冰淇淋) is a CHINESE Private Torrent Tracker for HD MOVIES / TV / GENERAL"
|
||||
language: zh-CN
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
requestDelay: 2
|
||||
links:
|
||||
- https://www.icc2022.com/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 401, cat: Movies, desc: "Movies/电影", default: true}
|
||||
- {id: 404, cat: TV/Documentary, desc: "Documentaries/纪录片", default: true}
|
||||
- {id: 405, cat: TV/Anime, desc: "Animations/动漫", default: true}
|
||||
- {id: 402, cat: TV, desc: "TV Series/电视剧", default: true}
|
||||
- {id: 403, cat: TV, desc: "TV Shows/综艺", default: true}
|
||||
- {id: 406, cat: Audio/Video, desc: "MusicVideo/MV", default: true}
|
||||
- {id: 407, cat: TV/Sport, desc: "Sports/体育", default: true}
|
||||
- {id: 409, cat: Other, desc: "Misc/其他", default: true}
|
||||
- {id: 408, cat: Audio, desc: "Music/音乐", default: true}
|
||||
# special
|
||||
- {id: 410, cat: Movies, desc: "Video/视频资料", default: true}
|
||||
- {id: 411, cat: Audio, desc: "Audio/音频资料", default: true}
|
||||
- {id: 412, cat: Other, desc: "Other/其他资料", default: true}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid, doubanid]
|
||||
movie-search: [q, imdbid, doubanid]
|
||||
music-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
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 ICC2022 Web Site. Otherwise just leave it empty."
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: 4
|
||||
options:
|
||||
4: created
|
||||
7: seeders
|
||||
5: size
|
||||
1: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrents per page:</b> setting to <b>100</b> on your account profile.
|
||||
|
||||
login:
|
||||
path: login.php
|
||||
method: form
|
||||
form: form[action="takelogin.php"]
|
||||
captcha:
|
||||
type: image
|
||||
selector: img[alt="CAPTCHA"]
|
||||
input: imagestring
|
||||
inputs:
|
||||
secret: ""
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
two_step_code: "{{ .Config.2facode }}"
|
||||
logout: ""
|
||||
securelogin: ""
|
||||
ssl: yes
|
||||
trackerssl: yes
|
||||
error:
|
||||
- selector: td.embedded:has(h2:contains("失败"))
|
||||
- selector: td.embedded:has(h2:contains("Failed"))
|
||||
test:
|
||||
path: index.php
|
||||
selector: a[href="logout.php"]
|
||||
|
||||
search:
|
||||
paths:
|
||||
- path: torrents.php
|
||||
categories: [401, 402, 403, 404, 405, 406, 407, 408, 409]
|
||||
- path: special.php
|
||||
categories: [410, 411, 412]
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}cat{{.}}=1&{{end}}"
|
||||
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBID }}{{ else }}{{ end }}{{ if or .Query.IMDBID .Query.DoubanID }} {{ else }}{{ .Keywords }}{{ end }}{{ if .Query.DoubanID }}{{ .Query.DoubanID }}{{ else }}{{ end }}"
|
||||
# 0 incldead, 1 active, 2 dead
|
||||
incldead: 0
|
||||
# 0 all, 1 normal, 2 free, 3 2x, 4 2xfree, 5 50%, 6 2x50%, 7 30%
|
||||
spstate: "{{ if .Config.freeleech }}2{{ else }}0{{ end }}"
|
||||
# 0 title, 1 descr, 3 uploader, 4 imdburl (4 does not appear to work)
|
||||
search_area: "{{ if or .Query.IMDBID .Query.DoubanID }}1{{ else }}0{{ end }}"
|
||||
# 0 AND, 1 OR, 2 exact
|
||||
search_mode: 0
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: table.torrents > tbody > tr:has(a[href^="details.php?id="])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title_default:
|
||||
selector: a[href^="details.php?id="]
|
||||
title_optional:
|
||||
optional: true
|
||||
selector: a[title][href^="details.php?id="]
|
||||
attribute: title
|
||||
title:
|
||||
text: "{{ if .Result.title_optional }}{{ .Result.title_optional }}{{ else }}{{ .Result.title_default }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
attribute: href
|
||||
doubanid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="movie.douban.com/subject/"]
|
||||
attribute: href
|
||||
date_elapsed:
|
||||
# time type: time elapsed (default)
|
||||
selector: td.rowfollow:nth-child(4) > span[title]
|
||||
attribute: title
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-02 15:04:05 -07:00"
|
||||
date_added:
|
||||
# time added
|
||||
selector: td.rowfollow:nth-child(4):not(:has(span))
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-0215:04:05 -07:00"
|
||||
date:
|
||||
text: "{{ if or .Result.date_elapsed .Result.date_added }}{{ or .Result.date_elapsed .Result.date_added }}{{ else }}now{{ end }}"
|
||||
size:
|
||||
selector: td.rowfollow:nth-child(5)
|
||||
seeders:
|
||||
selector: td.rowfollow:nth-child(6)
|
||||
leechers:
|
||||
selector: td.rowfollow:nth-child(7)
|
||||
grabs:
|
||||
selector: td.rowfollow:nth-child(8)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img.pro_free: 0
|
||||
img.pro_free2up: 0
|
||||
img.pro_50pctdown: 0.5
|
||||
img.pro_50pctdown2up: 0.5
|
||||
img.pro_30pctdown: 0.3
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
img.pro_50pctdown2up: 2
|
||||
img.pro_free2up: 2
|
||||
img.pro_2up: 2
|
||||
"*": 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
minimumseedtime:
|
||||
# 1 day (as seconds = 24 x 60 x 60)
|
||||
text: 86400
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.7.29 2022-10-13
|
@@ -130,6 +130,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
@@ -189,4 +192,4 @@ search:
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP 1.7.29 2022-10-13
|
||||
# NexusPHP v1.7.30 2022-11-05
|
||||
|
@@ -439,6 +439,13 @@ settings:
|
||||
type: info
|
||||
label: How to get the Cookie
|
||||
default: "<ol><li><a href=\"http://filbi1976.org/ucp.php?mode=login\" target =_blank>Login</a> to this tracker with your browser<li>Open the <b>DevTools</b> panel by pressing <b>F12</b><li>Select the <b>Network</b> tab<li>Click on the <b>Doc</b> button (Chrome Browser) or <b>HTML</b> button (FireFox)<li>Refresh the page by pressing <b>F5</b><li>Click on the first row entry<li>Select the <b>Headers</b> tab on the Right panel<li>Find <b>'cookie:'</b> in the <b>Request Headers</b> section<li><b>Select</b> and <b>Copy</b> the whole cookie string <i>(everything after 'cookie: ')</i> and <b>Paste</b> here.</ol>"
|
||||
- name: useragent
|
||||
type: text
|
||||
label: User-Agent
|
||||
- name: info_useragent
|
||||
type: info
|
||||
label: How to get the User-Agent
|
||||
default: "<ol><li>From the same place you fetched the cookie,<li>Find <b>'user-agent:'</b> in the <b>Request Headers</b> section<li><b>Select</b> and <b>Copy</b> the whole user-agent string <i>(everything after 'user-agent: ')</i> and <b>Paste</b> here.</ol>"
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
@@ -464,6 +471,9 @@ login:
|
||||
path: index.php
|
||||
|
||||
search:
|
||||
headers:
|
||||
User-Agent: ["{{ .Config.useragent }}"]
|
||||
|
||||
paths:
|
||||
# http://filbi1976.org/search.php?t=0&cs=1&cs_post=1&sc=1&keywords=&cs_where=title&cs_forb=&submit=Hand+Search&fid%5B%5D=0&cs_format=0&cs_year=0&cs_filter=0&sk=nt&sd=d&cs_private=0
|
||||
- path: search.php
|
||||
@@ -490,11 +500,11 @@ search:
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href*="/viewtopic.php?f="]
|
||||
selector: a[href$=".html"]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: f
|
||||
- name: regexp
|
||||
args: -f(\d+)
|
||||
title:
|
||||
selector: a.topictitle
|
||||
details:
|
||||
|
@@ -8,58 +8,58 @@ encoding: utf-8
|
||||
followredirect: true
|
||||
requestDelay: 2
|
||||
links:
|
||||
- https://www.lastfiles.ro/
|
||||
- http://www.lastfiles.ro/
|
||||
- https://www.last-torrents.org/
|
||||
- http://www.last-torrents.org/
|
||||
legacylinks:
|
||||
- http://last-torrents.org/
|
||||
- https://last-torrents.org/
|
||||
- https://www.lastfiles.ro/
|
||||
- http://www.lastfiles.ro/
|
||||
- http://www.last-torrents.org/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 31, cat: Movies/UHD, desc: "Movies: 4K", default: true}
|
||||
- {id: 1, cat: TV/Anime, desc: "Movies: Anime", default: true}
|
||||
- {id: 2, cat: TV/Anime, desc: "Movies: Anime-Ro", default: true}
|
||||
- {id: 5, cat: Movies/BluRay, desc: "Movies: BluRay", default: true}
|
||||
- {id: 9, cat: Movies/DVD, desc: "Movies: DVD", default: true}
|
||||
- {id: 11, cat: Movies/HD, desc: "Movies: HD", default: true}
|
||||
- {id: 58, cat: Movies/SD, desc: "Movies: Cam", default: true}
|
||||
- {id: 61, cat: Movies/3D, desc: "Movies: 3D", default: true}
|
||||
- {id: 24, cat: Movies/SD, desc: "Movies: XVID", default: true}
|
||||
- {id: 16, cat: Movies, desc: "Movies: Old", default: true}
|
||||
- {id: 54, cat: Movies/WEB-DL, desc: "Movies: WEB-DL", default: true}
|
||||
- {id: 56, cat: TV/Documentary, desc: "Documentary", default: true}
|
||||
- {id: 18, cat: Movies, desc: "Movies: Pack", default: true}
|
||||
- {id: 32, cat: Movies/UHD, desc: "Movies: 4KRO", default: true}
|
||||
- {id: 6, cat: Movies/BluRay, desc: "Movies: BluRay-Ro", default: true}
|
||||
- {id: 12, cat: Movies/HD, desc: "Movies: HD-Ro", default: true}
|
||||
- {id: 81, cat: Movies/HD, desc: "Movies: x265-Ro", default: true}
|
||||
- {id: 82, cat: Movies/HD, desc: "Movies: x265", default: true}
|
||||
- {id: 9, cat: Movies/DVD, desc: "Movies: DVD", default: true}
|
||||
- {id: 10, cat: Movies/DVD, desc: "Movies: DVD-Ro", default: true}
|
||||
- {id: 59, cat: Movies/SD, desc: "Movies: Cam-RO", default: true}
|
||||
- {id: 25, cat: Movies/SD, desc: "Movies: XVID-Ro", default: true}
|
||||
- {id: 11, cat: Movies/HD, desc: "Movies: HD", default: true}
|
||||
- {id: 12, cat: Movies/HD, desc: "Movies: HD-Ro", default: true}
|
||||
- {id: 13, cat: TV/HD, desc: "HDTV Episodes", default: true}
|
||||
- {id: 14, cat: TV/HD, desc: "HDTV Episodes-Ro", default: true}
|
||||
- {id: 16, cat: Movies, desc: "Movies: Old", default: true}
|
||||
- {id: 17, cat: Movies, desc: "Movies: Old-Ro", default: true}
|
||||
- {id: 55, cat: Movies/WEB-DL, desc: "Movies: WEB-DL Ro", default: true}
|
||||
- {id: 57, cat: TV/Documentary, desc: "Documentary-Ro", default: true}
|
||||
- {id: 62, cat: Movies/3D, desc: "Movies: 3D-Ro", default: true}
|
||||
- {id: 18, cat: Movies, desc: "Movies: Pack", default: true}
|
||||
- {id: 19, cat: Movies, desc: "Movies: Pack-Ro", default: true}
|
||||
- {id: 20, cat: TV, desc: "TV Episodes", default: true}
|
||||
- {id: 21, cat: TV, desc: "TV Episodes-Ro", default: true}
|
||||
- {id: 13, cat: TV/HD, desc: "HDTV Episodes", default: true}
|
||||
- {id: 14, cat: TV/HD, desc: "HDTV Episodes-Ro", default: true}
|
||||
- {id: 28, cat: Audio, desc: "Music", default: true}
|
||||
- {id: 51, cat: PC/Mobile-Android, desc: "Android Apps", default: true}
|
||||
- {id: 22, cat: Other, desc: "RoContent", default: true}
|
||||
- {id: 24, cat: Movies/SD, desc: "Movies: XVID", default: true}
|
||||
- {id: 25, cat: Movies/SD, desc: "Movies: XVID-Ro", default: true}
|
||||
- {id: 26, cat: PC/0day, desc: "Software", default: true}
|
||||
- {id: 27, cat: XXX, desc: "Movies: XXX", default: false}
|
||||
- {id: 28, cat: Audio, desc: "Music", default: true}
|
||||
- {id: 30, cat: PC/Games, desc: "Games: PC-ISO", default: true}
|
||||
- {id: 31, cat: Movies/UHD, desc: "Movies: 4K", default: true}
|
||||
- {id: 32, cat: Movies/UHD, desc: "Movies: 4K-Ro", default: true}
|
||||
- {id: 33, cat: PC/Games, desc: "Games: Packs", default: true}
|
||||
- {id: 1, cat: TV/Anime, desc: "Movies: Anime", default: true}
|
||||
- {id: 2, cat: TV/Anime, desc: "Movies: Anime-Ro", default: true}
|
||||
- {id: 42, cat: TV/Sport, desc: "Sport", default: true}
|
||||
- {id: 43, cat: Books, desc: "Documents", default: true}
|
||||
- {id: 44, cat: Other, desc: "Images", default: true}
|
||||
- {id: 49, cat: Other, desc: "Diverse", default: true}
|
||||
- {id: 22, cat: Other, desc: "RoContent", default: true}
|
||||
- {id: 51, cat: PC/Mobile-Android, desc: "Android Apps", default: true}
|
||||
- {id: 54, cat: Movies/WEB-DL, desc: "Movies: WEB-DL", default: true}
|
||||
- {id: 55, cat: Movies/WEB-DL, desc: "Movies: WEB-DL Ro", default: true}
|
||||
- {id: 56, cat: TV/Documentary, desc: "Documentary", default: true}
|
||||
- {id: 57, cat: TV/Documentary, desc: "Documentary-Ro", default: true}
|
||||
- {id: 58, cat: Movies/SD, desc: "Movies: Cam", default: true}
|
||||
- {id: 59, cat: Movies/SD, desc: "Movies: Cam-Ro", default: true}
|
||||
- {id: 60, cat: XXX/ImageSet, desc: "Images: XXX", default: false}
|
||||
- {id: 27, cat: XXX, desc: "Movies: XXX", default: false}
|
||||
- {id: 61, cat: Movies/3D, desc: "Movies: 3D", default: true}
|
||||
- {id: 62, cat: Movies/3D, desc: "Movies: 3D-Ro", default: true}
|
||||
- {id: 81, cat: Movies/HD, desc: "Movies: x265-Ro", default: true}
|
||||
- {id: 82, cat: Movies/HD, desc: "Movies: x265", default: true}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
@@ -83,22 +83,22 @@ settings:
|
||||
type: info
|
||||
label: FlareSolverr
|
||||
default: This site may use Cloudflare DDoS Protection, therefore Jackett requires <a href="https://github.com/Jackett/Jackett#configuring-flaresolverr" target="_blank">FlareSolverr</a> to access it.
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: 3
|
||||
options:
|
||||
3: created
|
||||
6: seeders
|
||||
4: size
|
||||
1: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
# - name: sort
|
||||
# type: select
|
||||
# label: Sort requested from site
|
||||
# default: 3
|
||||
# options:
|
||||
# 3: created
|
||||
# 6: seeders
|
||||
# 4: size
|
||||
# 1: title
|
||||
# - name: type
|
||||
# type: select
|
||||
# label: Order requested from site
|
||||
# default: desc
|
||||
# options:
|
||||
# desc: desc
|
||||
# asc: asc
|
||||
|
||||
login:
|
||||
path: takelogin.php
|
||||
@@ -118,88 +118,54 @@ login:
|
||||
|
||||
search:
|
||||
paths:
|
||||
# https://www.last-torrents.org/externalid?searchex=tt5834760&search_by=imdbid
|
||||
# cannot support imdbid or tmdbid searches while using path category filters
|
||||
- path: browse.php
|
||||
categories: [31, 5, 9, 11, 58, 61, 24, 16, 54, 56, 18, 32, 6, 12, 81, 82, 10, 59, 25, 17, 55, 57, 62, 19, 20, 21, 13, 14, 28, 51, 26, 30, 33, 1, 2, 42, 43, 44, 49, 22]
|
||||
categories: [1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 30, 31, 32, 33, 42, 43, 44, 49, 51, 54, 55, 56, 57, 58, 59, 60, 61, 62, 81, 82]
|
||||
- path: browseadult.php
|
||||
categories: [60, 27]
|
||||
categories: [27, 60]
|
||||
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["(\\w+)", " +$1"] # prepend + to each word
|
||||
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
|
||||
search: "{{ if .Query.Genre }}{{ .Query.Genre }} {{ else }}{{ end }}{{ .Keywords }}"
|
||||
# title, descr, genre, all
|
||||
# title, genre, all
|
||||
searchin: "{{ if .Query.Genre }}all{{ else }}title{{ end }}"
|
||||
# 0 active, 1 incldead, 2 onlydead
|
||||
incldead: 1
|
||||
only_free: "{{ if .Config.freeleech }}1{{ else }}{{ end }}"
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
# 0 active, 1 incldead, 2 onlydead, 3 free, 4 silver, 5 seedbox
|
||||
type: "{{ if .Config.freeleech }}3{{ else }}1{{ end }}"
|
||||
# sort and type can only be used in a non-search query due to conflicting parameters
|
||||
# sort: "{{ .Config.sort }}"
|
||||
# type: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: tbody > tr:has(a[href^="download.php"])
|
||||
selector: div.py-3
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: img[src*="pic/caticons/1/categories"]
|
||||
attribute: src
|
||||
case:
|
||||
img[src$="4k.png"]: 31
|
||||
img[src$="bluray.png"]: 5
|
||||
img[src$="dvd.png"]: 9
|
||||
img[src$="hd.png"]: 11
|
||||
img[src$="cam.png"]: 58
|
||||
img[src$="3D.png"]: 61
|
||||
img[src$="xvid.png"]: 24
|
||||
img[src$="oldies.png"]: 16
|
||||
img[src$="web-DL.png"]: 54
|
||||
img[src$="doc.png"]: 56
|
||||
img[src$="4kRO.png"]: 32
|
||||
img[src$="bluray-ro.png"]: 6
|
||||
img[src$="hd-ro.png"]: 12
|
||||
img[src$="x265ro.png"]: 81
|
||||
img[src$="x265.png"]: 82
|
||||
img[src$="dvd-ro.png"]: 10
|
||||
img[src$="cam_ro.png"]: 59
|
||||
img[src$="xvid-ro.png"]: 25
|
||||
img[src$="oldies-ro.png"]: 17
|
||||
img[src$="web-DLRO.png"]: 55
|
||||
img[src$="doc-ro.png"]: 57
|
||||
img[src$="3DRO.png"]: 62
|
||||
img[src$="pack-ro.png"]: 19
|
||||
img[src$="tvepisode.png"]: 20
|
||||
img[src$="tvepisode-ro.png"]: 21
|
||||
img[src$="hdtve.png"]: 13
|
||||
img[src$="hdtve-ro.png"]: 14
|
||||
img[src$="music.png"]: 28
|
||||
img[src$="android.png"]: 51
|
||||
img[src$="soft.png"]: 26
|
||||
img[src$="pciso.png"]: 30
|
||||
img[src$="gpack.png"]: 33
|
||||
img[src$="pack.png"]: 18
|
||||
img[src$="anime.png"]: 1
|
||||
img[src$="anime-ro.png"]: 2
|
||||
img[src$="sport.png"]: 42
|
||||
img[src$="docs.png"]: 43
|
||||
img[src$="images.png"]: 44
|
||||
img[src$="misc.png"]: 49
|
||||
img[src$="rocontent.png"]: 22
|
||||
img[src$="xxximgset.png"]: 60
|
||||
img[src$="xxx.png"]: 27
|
||||
selector: a[href*="cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title:
|
||||
selector: a[onmouseover]
|
||||
selector: a[href^="t"]
|
||||
details:
|
||||
selector: a[onmouseover]
|
||||
selector: a[href^="t"]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: a[onmouseover]
|
||||
attribute: onmouseover
|
||||
selector: a[href^="t"]
|
||||
attribute: title
|
||||
filters:
|
||||
- name: regexp
|
||||
args: "src=(.+?) "
|
||||
- name: replace
|
||||
args: ["./pic/noposter.png", ""]
|
||||
genre:
|
||||
selector: font[size]
|
||||
selector: i:has(a[href$="searchin=genre"]), font[size]
|
||||
filters:
|
||||
- name: replace
|
||||
args: [" & ", "_&_"]
|
||||
- name: replace
|
||||
args: ["Hip Hop", "Hip_Hop"]
|
||||
- name: replace
|
||||
@@ -210,28 +176,28 @@ search:
|
||||
selector: a[href^="download.php"]
|
||||
attribute: href
|
||||
date_day:
|
||||
selector: td:nth-child(4) b:contains("day")
|
||||
selector: div.col-sm-4:nth-of-type(3):contains("day")
|
||||
# auto adjusted by site account profile
|
||||
optional: true
|
||||
filters:
|
||||
- name: fuzzytime
|
||||
date_year:
|
||||
selector: td:nth-child(4) b:not(:contains("day"))
|
||||
selector: div.col-sm-4:nth-of-type(3):contains(":"):not(:contains("day"))
|
||||
# auto adjusted by site account profile
|
||||
optional: true
|
||||
filters:
|
||||
- name: dateparse
|
||||
args: "Jan 2 2006 03:04 PM"
|
||||
args: "Jan 2 2006, 03:04 PM"
|
||||
date:
|
||||
text: "{{ if or .Result.date_day .Result.date_year }}{{ or .Result.date_day .Result.date_year }}{{ else }}now{{ end }}"
|
||||
size:
|
||||
selector: td:nth-child(5)
|
||||
selector: div.col-sm-4:nth-of-type(4)
|
||||
grabs:
|
||||
selector: td:nth-child(6)
|
||||
selector: div.col-sm-4:contains("Completed") b
|
||||
seeders:
|
||||
selector: td:nth-child(7)
|
||||
selector: div.col-sm-4:contains("Seeders") b
|
||||
leechers:
|
||||
selector: td:nth-child(8)
|
||||
selector: div.col-sm-4:contains("Leechers") b
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img[src$="half2.png"]: 0.5
|
||||
|
@@ -243,7 +243,7 @@ search:
|
||||
img[src$="/docdivers.png"]: 21
|
||||
img[src$="/dochistoire.png"]: 22
|
||||
img[src$="/docsemitv.png"]: 164
|
||||
img[src$="/docsseries.png"]: 198
|
||||
img[src$="/unknown198.png"]: 198 # film doc spectacle
|
||||
img[src$="/film3d.png"]: 25
|
||||
img[src$="/film4k.png"]: 26
|
||||
img[src$="/film4klight.png"]: 27
|
||||
@@ -283,7 +283,7 @@ search:
|
||||
img[src$="/loglinux.png"]: 71
|
||||
img[src$="/logwindows.png"]: 72
|
||||
img[src$="/animcoffret.png"]: 7
|
||||
img[src$="/unknown197.png"]: 197 # serie episode
|
||||
img[src$="/docsseries.png"]: 197
|
||||
img[src$="/unknown182.png"]: 182 # serie jap anim
|
||||
img[src$="/unknown166.png"]: 166 # serie docu
|
||||
img[src$="/unknown194.png"]: 194 # serie docu divers
|
||||
@@ -304,7 +304,7 @@ search:
|
||||
img[src$="/seriewebrip.png"]: 93
|
||||
img[src$="/seriesfrwebdl720p.png"]: 178
|
||||
img[src$="/seriesfrwebdl1080p.png"]: 179
|
||||
img[src$="/unknown199.png"]: 199 # serie webdl
|
||||
img[src$="/seriewebdl.png"]: 199
|
||||
img[src$="/serievostfrbdrip.png"]: 188
|
||||
img[src$="/serievostfrdvdrip.png"]: 189
|
||||
img[src$="/serievostfrhdrip.png"]: 190
|
||||
|
179
src/Jackett.Common/Definitions/nicept.yml
Normal file
179
src/Jackett.Common/Definitions/nicept.yml
Normal file
@@ -0,0 +1,179 @@
|
||||
---
|
||||
id: nicept
|
||||
name: NicePT
|
||||
description: "NicePT is a CHINESE Private Torrent Tracker for 3X"
|
||||
language: zh-CN
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://www.nicept.net/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 500, cat: XXX, desc: "日本有码"}
|
||||
- {id: 401, cat: XXX, desc: "日本无码"}
|
||||
- {id: 402, cat: XXX, desc: "欧美"}
|
||||
- {id: 501, cat: XXX, desc: "其他(限制级)"}
|
||||
- {id: 403, cat: XXX/Other, desc: "动漫(限制级)"}
|
||||
- {id: 503, cat: XXX, desc: "真人秀,自拍(限制级)"}
|
||||
- {id: 404, cat: XXX/ImageSet, desc: "写真、套图"}
|
||||
- {id: 504, cat: XXX, desc: "SM调教(限制级)"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
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
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: 4
|
||||
options:
|
||||
4: created
|
||||
7: seeders
|
||||
5: size
|
||||
1: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrents per page:</b> setting to <b>100</b> on your account profile.
|
||||
|
||||
login:
|
||||
path: login.php
|
||||
method: form
|
||||
form: form[action="takelogin.php"]
|
||||
captcha:
|
||||
type: image
|
||||
selector: img[alt="CAPTCHA"]
|
||||
input: imagestring
|
||||
inputs:
|
||||
secret: ""
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
two_step_code: "{{ .Config.2facode }}"
|
||||
error:
|
||||
- selector: td.embedded:has(h2:contains("失败"))
|
||||
- selector: td.embedded:has(h2:contains("Failed"))
|
||||
test:
|
||||
path: index.php
|
||||
selector: a[href="logout.php"]
|
||||
|
||||
search:
|
||||
paths:
|
||||
- path: torrents.php
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}cat{{.}}=1&{{end}}"
|
||||
search: "{{ .Keywords }}"
|
||||
# 0 incldead, 1 active, 2 dead
|
||||
incldead: 0
|
||||
# 0 all, 1 normal, 2 free, 3 2x, 4 2xfree, 5 50%, 6 2x50%, 7 30%
|
||||
spstate: "{{ if .Config.freeleech }}2{{ else }}0{{ end }}"
|
||||
# 0 title, 1 descr, 3 uploader, 4 imdburl (unused)
|
||||
search_area: 0
|
||||
# 0 AND, 1 OR, 2 exact
|
||||
search_mode: 0
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: table.torrents > tbody > tr:has(a[href^="details.php?id="])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title_default:
|
||||
selector: a[href^="details.php?id="]
|
||||
title_optional:
|
||||
optional: true
|
||||
selector: a[title][href^="details.php?id="]
|
||||
attribute: title
|
||||
title:
|
||||
text: "{{ if .Result.title_optional }}{{ .Result.title_optional }}{{ else }}{{ .Result.title_default }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
date_elapsed:
|
||||
# time type: time elapsed (default)
|
||||
selector: td.rowfollow:nth-child(4) > span[title]
|
||||
attribute: title
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-02 15:04:05 -07:00"
|
||||
date_added:
|
||||
# time added
|
||||
selector: td.rowfollow:nth-child(4):not(:has(span))
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-0215:04:05 -07:00"
|
||||
date:
|
||||
text: "{{ if or .Result.date_elapsed .Result.date_added }}{{ or .Result.date_elapsed .Result.date_added }}{{ else }}now{{ end }}"
|
||||
size:
|
||||
selector: td.rowfollow:nth-child(5)
|
||||
seeders:
|
||||
selector: td.rowfollow:nth-child(6)
|
||||
leechers:
|
||||
selector: td.rowfollow:nth-child(7)
|
||||
grabs:
|
||||
selector: td.rowfollow:nth-child(8)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img.pro_free: 0
|
||||
img.pro_free2up: 0
|
||||
img.pro_50pctdown: 0.5
|
||||
img.pro_50pctdown2up: 0.5
|
||||
img.pro_30pctdown: 0.3
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
img.pro_50pctdown2up: 2
|
||||
img.pro_free2up: 2
|
||||
img.pro_2up: 2
|
||||
"*": 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
minimumseedtime:
|
||||
# 1 day (as seconds = 24 x 60 x 60)
|
||||
text: 86400
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.7.29 2022-10-13
|
@@ -132,7 +132,7 @@ search:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img.nexus-lazy-load
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
@@ -191,4 +191,4 @@ search:
|
||||
remove: a, img, span
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
# NexusPHP 1.7.29 2022-10-13
|
||||
# NexusPHP v1.7.29 2022-10-13
|
||||
|
@@ -131,6 +131,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
@@ -185,4 +188,4 @@ search:
|
||||
description:
|
||||
selector: td:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.8.0 2023-01-05
|
||||
# NexusPHP v1.8.0 2023-01-11
|
||||
|
@@ -138,4 +138,4 @@ search:
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP Standard v1.5 Beta 4
|
||||
# Ourbits 1.1.0 (Based on NexusPHP Standard v1.5 Beta 4) 3f7f4b0 2023-02-01
|
||||
|
@@ -128,8 +128,8 @@ search:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img.pr5
|
||||
attribute: src
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
@@ -187,4 +187,4 @@ search:
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.7.16
|
||||
# NexusPHP v1.8.0 2023-01-16
|
||||
|
@@ -123,6 +123,10 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
# site does not have posters enabled. just in case a future update.
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
|
@@ -136,8 +136,8 @@ search:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-orig]
|
||||
attribute: data-orig
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
selector: a[href$="&search_area=4"]
|
||||
attribute: href
|
||||
|
@@ -139,4 +139,4 @@ search:
|
||||
description:
|
||||
selector: td:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP
|
||||
# NexusPHP v3.1 2021-07-05
|
||||
|
192
src/Jackett.Common/Definitions/sharkpt.yml
Normal file
192
src/Jackett.Common/Definitions/sharkpt.yml
Normal file
@@ -0,0 +1,192 @@
|
||||
---
|
||||
id: sharkpt
|
||||
name: SharkPT
|
||||
description: "SharkPT is a CHINESE Private Torrent Tracker for MOVIES / TV / GENERAL"
|
||||
language: zh-CN
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://sharkpt.net/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 401, cat: Movies, desc: "Movies/电影"}
|
||||
- {id: 404, cat: TV/Documentary, desc: "Documentaries/纪录片"}
|
||||
- {id: 405, cat: TV/Anime, desc: "Animations/动漫"}
|
||||
- {id: 402, cat: TV, desc: "TV Series/电视连续剧"}
|
||||
- {id: 403, cat: TV, desc: "TV Shows/综艺"}
|
||||
- {id: 406, cat: Audio/Video, desc: "MusicVideo/音乐视频"}
|
||||
- {id: 407, cat: TV/Sport, desc: "Sports/体育"}
|
||||
- {id: 409, cat: Other, desc: "Misc/其他"}
|
||||
- {id: 408, cat: Audio, desc: "Music/HQ Audio"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid, doubanid]
|
||||
movie-search: [q, imdbid, doubanid]
|
||||
music-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
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 SharkPT Web Site. Otherwise just leave it empty."
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: 4
|
||||
options:
|
||||
4: created
|
||||
7: seeders
|
||||
5: size
|
||||
1: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrents per page:</b> setting to <b>100</b> on your account profile.
|
||||
|
||||
login:
|
||||
path: login.php
|
||||
method: form
|
||||
form: form[action="takelogin.php"]
|
||||
captcha:
|
||||
type: image
|
||||
selector: img[alt="CAPTCHA"]
|
||||
input: imagestring
|
||||
inputs:
|
||||
secret: ""
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
two_step_code: "{{ .Config.2facode }}"
|
||||
logout: ""
|
||||
securelogin: ""
|
||||
ssl: yes
|
||||
trackerssl: yes
|
||||
error:
|
||||
- selector: td.embedded:has(h2:contains("失败"))
|
||||
test:
|
||||
path: index.php
|
||||
selector: a[href="mybonus.php"]
|
||||
|
||||
search:
|
||||
paths:
|
||||
- path: torrents.php
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}cat{{.}}=1&{{end}}"
|
||||
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBID }}{{ else }}{{ end }}{{ if or .Query.IMDBID .Query.DoubanID }} {{ else }}{{ .Keywords }}{{ end }}{{ if .Query.DoubanID }}{{ .Query.DoubanID }}{{ else }}{{ end }}"
|
||||
# 0 incldead, 1 active, 2 dead
|
||||
incldead: 0
|
||||
# 0 all, 1 normal, 2 free, 3 2x, 4 2xfree, 5 50%, 6 2x50%, 7 30%
|
||||
spstate: "{{ if .Config.freeleech }}2{{ else }}0{{ end }}"
|
||||
# 0 title, 1 descr, 3 uploader, 4 imdburl (4 does not appear to work)
|
||||
search_area: "{{ if or .Query.IMDBID .Query.DoubanID }}1{{ else }}0{{ end }}"
|
||||
# 0 AND, 1 OR, 2 exact
|
||||
search_mode: 0
|
||||
sort: "{{ .Config.sort }}"
|
||||
type: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: table.torrents > tbody > tr:has(a[href^="details.php?id="])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
title_default:
|
||||
selector: a[href^="details.php?id="]
|
||||
title_optional:
|
||||
optional: true
|
||||
selector: a[title][href^="details.php?id="]
|
||||
attribute: title
|
||||
title:
|
||||
text: "{{ if .Result.title_optional }}{{ .Result.title_optional }}{{ else }}{{ .Result.title_default }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
imdbid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="imdb.com/title/tt"]
|
||||
attribute: href
|
||||
doubanid:
|
||||
# site currently only has a badge and rating, the id is not present. just in case a future update.
|
||||
selector: a[href*="movie.douban.com/subject/"]
|
||||
attribute: href
|
||||
date_elapsed:
|
||||
# time type: time elapsed (default)
|
||||
selector: td.rowfollow:nth-child(4) > span[title]
|
||||
attribute: title
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-02 15:04:05 -07:00"
|
||||
date_added:
|
||||
# time added
|
||||
selector: td.rowfollow:nth-child(4):not(:has(span))
|
||||
optional: true
|
||||
filters:
|
||||
- name: append
|
||||
args: " +08:00" # CST
|
||||
- name: dateparse
|
||||
args: "2006-01-0215:04:05 -07:00"
|
||||
date:
|
||||
text: "{{ if or .Result.date_elapsed .Result.date_added }}{{ or .Result.date_elapsed .Result.date_added }}{{ else }}now{{ end }}"
|
||||
size:
|
||||
selector: td.rowfollow:nth-child(5)
|
||||
seeders:
|
||||
selector: td.rowfollow:nth-child(6)
|
||||
leechers:
|
||||
selector: td.rowfollow:nth-child(7)
|
||||
grabs:
|
||||
selector: td.rowfollow:nth-child(8)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img.pro_free: 0
|
||||
img.pro_free2up: 0
|
||||
img.pro_50pctdown: 0.5
|
||||
img.pro_50pctdown2up: 0.5
|
||||
img.pro_30pctdown: 0.3
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
img.pro_50pctdown2up: 2
|
||||
img.pro_free2up: 2
|
||||
img.pro_2up: 2
|
||||
"*": 1
|
||||
minimumseedtime:
|
||||
# 7 day (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
description:
|
||||
selector: td.rowfollow:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP v1.7.33 2022-12-19
|
@@ -23,6 +23,7 @@ caps:
|
||||
- {id: 90, cat: Movies/3D, desc: "Movies-3-D"}
|
||||
- {id: 91, cat: Movies, desc: "Movies-Packs"}
|
||||
- {id: 108, cat: Movies, desc: "Movies Remux"}
|
||||
- {id: 32, cat: Movies, desc: "Movies"}
|
||||
- {id: 14, cat: Audio/Other, desc: "Alben / Sampler / Singles"}
|
||||
- {id: 36, cat: Audio/Audiobook, desc: "Hörbuch"}
|
||||
- {id: 71, cat: Audio/Other, desc: "Soundtracks"}
|
||||
|
@@ -175,7 +175,7 @@ search:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img.nexus-lazy-load
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
date_elapsed:
|
||||
# time type: time elapsed (default)
|
||||
@@ -222,4 +222,4 @@ search:
|
||||
"*": 1
|
||||
minimumratio:
|
||||
text: 0.81
|
||||
# NexusPHP Custom 1.7.24 2022-09-11
|
||||
# NexusPHP v1.7.33 2022-12-19 (custom)
|
||||
|
@@ -184,4 +184,4 @@ search:
|
||||
minimumseedtime:
|
||||
# 3 days (as seconds = 3 x 24 x 60 x 60)
|
||||
text: 259200
|
||||
# NexusPHP Standard v1.5 Beta 4
|
||||
# Engine n/a
|
||||
|
@@ -196,6 +196,9 @@ search:
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img[data-src]
|
||||
attribute: data-src
|
||||
date_elapsed:
|
||||
# time type: time elapsed (default)
|
||||
selector: td:nth-child(4) > span[title]
|
||||
@@ -241,4 +244,4 @@ search:
|
||||
"*": 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
# NexusPHP v1.7.30 2022-10-21
|
||||
# NexusPHP v1.7.30 2022-11-05
|
||||
|
158
src/Jackett.Common/Definitions/thedarkcommunity-api.yml
Normal file
158
src/Jackett.Common/Definitions/thedarkcommunity-api.yml
Normal file
@@ -0,0 +1,158 @@
|
||||
---
|
||||
id: thedarkcommunity
|
||||
name: TheDarkCommunity (API)
|
||||
description: "TheDarkCommunity (TDC) is a Private Torrent Tracker for MOVIES / TV"
|
||||
language: en-US
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://thedarkcommunity.cc/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies, desc: "Movies"}
|
||||
- {id: 2, cat: TV, desc: "TV"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid, tvdbid, tmdbid]
|
||||
movie-search: [q, imdbid, tmdbid]
|
||||
|
||||
settings:
|
||||
- name: apikey
|
||||
type: text
|
||||
label: APIKey
|
||||
- name: info_key
|
||||
type: info
|
||||
label: About your API key
|
||||
default: "Find or Generate a new API Token by accessing your <a href=\"https://thedarkcommunity.cc//\" target =_blank>TheDarkCommunity</a> account <i>My Security</i> page and clicking on the <b>API Token</b> tab."
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: created_at
|
||||
options:
|
||||
created_at: created
|
||||
seeders: seeders
|
||||
size: size
|
||||
name: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
|
||||
login:
|
||||
path: /api/torrents
|
||||
method: get
|
||||
inputs:
|
||||
api_token: "{{ .Config.apikey }}"
|
||||
error:
|
||||
- selector: a[href*="/login"]
|
||||
message:
|
||||
text: "The API key was not accepted by {{ .Config.sitelink }}."
|
||||
|
||||
search:
|
||||
paths:
|
||||
# https://hdinnovations.github.io/UNIT3D-Community-Edition-Docs/api_endpoints.html
|
||||
# https://github.com/HDInnovations/UNIT3D-Community-Edition/blob/master/app/Http/Controllers/API/TorrentController.php
|
||||
- path: "/api/torrents/filter"
|
||||
response:
|
||||
type: json
|
||||
|
||||
inputs:
|
||||
# if we have an id based search, add Season and Episode as query in name for UNIT3D < v6. Else pass S/E Params for UNIT3D >= v6
|
||||
api_token: "{{ .Config.apikey }}"
|
||||
name: "{{ .Keywords }}"
|
||||
$raw: "{{ if .Query.Season }}&seasonNumber={{ .Query.Season }}{{ else }}{{ end }}{{ if .Query.Ep }}&episodeNumber={{ .Query.Ep }}{{ else }}{{ end }}{{ if .Query.TMDBID }}&tmdbId={{ .Query.TMDBID }}{{ else }}{{ end }}{{ if .Query.IMDBIDShort }}&imdbId={{ .Query.IMDBIDShort }}{{ else }}{{ end }}{{ if .Query.TVDBID }}&tvdbId={{ .Query.TVDBID }}{{ else }}{{ end }}{{ range .Categories }}&categories[]={{.}}{{end}}{{ if .Config.freeleech }}&free[]=100{{ else }}{{ end }}"
|
||||
sortField: "{{ .Config.sort }}"
|
||||
sortDirection: "{{ .Config.type }}"
|
||||
perPage: 100
|
||||
page: 1
|
||||
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["\\.", " "]
|
||||
|
||||
rows:
|
||||
selector: data
|
||||
attribute: attributes
|
||||
count:
|
||||
selector: meta.total
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: category_id
|
||||
title:
|
||||
selector: name
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
selector: download_link
|
||||
infohash:
|
||||
selector: info_hash
|
||||
poster:
|
||||
selector: meta.poster
|
||||
filters:
|
||||
- name: replace
|
||||
args: ["https://via.placeholder.com/90x135", ""]
|
||||
imdbid:
|
||||
selector: imdb_id
|
||||
tmdbid:
|
||||
selector: tmdb_id
|
||||
tvdbid:
|
||||
selector: tvdb_id
|
||||
genre:
|
||||
selector: meta.genres
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)(Science Fiction)", "Science_Fiction"]
|
||||
- name: re_replace
|
||||
args: ["(?i)(TV Movie)", "TV_Movie"]
|
||||
- name: replace
|
||||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
selector: leechers
|
||||
grabs:
|
||||
selector: times_completed
|
||||
date:
|
||||
# "created_at": "2021-10-18T00:34:50.000000Z" is returned by Newtonsoft.Json.Linq as 18/10/2021 00:34:50
|
||||
selector: created_at
|
||||
filters:
|
||||
- name: append
|
||||
args: " +00:00" # GMT
|
||||
- name: dateparse
|
||||
args: "01/02/2006 15:04:05 -07:00"
|
||||
size:
|
||||
selector: size
|
||||
downloadvolumefactor:
|
||||
# api returns 0%, 25%, 50%, 75%, 100%
|
||||
selector: freeleech
|
||||
case:
|
||||
0%: 1 # not free
|
||||
25%: 0.75
|
||||
50%: 0.5
|
||||
75%: 0.25
|
||||
100%: 0 # freeleech
|
||||
"*": 0 # catch errors
|
||||
uploadvolumefactor:
|
||||
# api returns 0=false, 1=true
|
||||
selector: double_upload
|
||||
case:
|
||||
0: 1 # normal
|
||||
1: 2 # double
|
||||
minimumseedtime:
|
||||
# 7 day (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
# json UNIT3D 6.5.0
|
@@ -172,4 +172,4 @@ search:
|
||||
description:
|
||||
selector: td:nth-child(2)
|
||||
remove: a, img
|
||||
# NexusPHP Standard v1.5 Beta 4
|
||||
# NexusPHP Standard v1.5 Beta 4
|
||||
|
@@ -124,9 +124,6 @@ login:
|
||||
search:
|
||||
paths:
|
||||
- path: /
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["[^a-zA-Z0-9]+", "%25"]
|
||||
inputs:
|
||||
p: torrents
|
||||
pid: 32
|
||||
@@ -142,6 +139,8 @@ search:
|
||||
|
||||
rows:
|
||||
selector: "table#torrents_table_classic > tbody > tr:has(td.torrent_name){{ if .Config.freeleech }}:has(img[title=\"FREE!\"]){{ else }}{{ end }}"
|
||||
filters:
|
||||
- name: andmatch
|
||||
|
||||
fields:
|
||||
category:
|
||||
|
@@ -46,6 +46,7 @@ caps:
|
||||
- {id: Séries, cat: TV, desc: "TV"}
|
||||
- {id: Musiques, cat: Audio, desc: "Music"}
|
||||
- {id: Ebooks, cat: Books, desc: "Books"}
|
||||
- {id: Livres, cat: Books, desc: "Livres"}
|
||||
- {id: Logiciels, cat: PC, desc: "Software"}
|
||||
- {id: Jeux-PC, cat: PC/Games, desc: "PC Games"}
|
||||
- {id: Jeux-Consoles, cat: Console/XBox 360, desc: "Console Games"}
|
||||
|
@@ -39,6 +39,7 @@ caps:
|
||||
- {id: Séries, cat: TV, desc: "TV"}
|
||||
- {id: Musiques, cat: Audio, desc: "Music"}
|
||||
- {id: Ebooks, cat: Books, desc: "Books"}
|
||||
- {id: Livres, cat: Books, desc: "Livres"}
|
||||
- {id: Logiciels, cat: PC, desc: "Software"}
|
||||
- {id: Jeux-PC, cat: PC/Games, desc: "PC Games"}
|
||||
- {id: Jeux-Consoles, cat: Console/XBox 360, desc: "Console Games"}
|
||||
|
@@ -83,6 +83,10 @@ caps:
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: excludeads
|
||||
type: checkbox
|
||||
label: Exclude results which include advertisements
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
@@ -127,9 +131,13 @@ search:
|
||||
order: "{{ .Config.type }}"
|
||||
|
||||
rows:
|
||||
selector: div.tgxtable > div:has(div[class^="tgxtablecell shrink"])
|
||||
selector: "div.tgxtable > div:has(div[class^=\"tgxtablecell shrink\"]){{ if .Config.excludeads }}:not(:has(i.fab.fa-adversal)){{ else }}{{ end }}"
|
||||
|
||||
fields:
|
||||
_ads:
|
||||
optional: true
|
||||
selector: i.fab.fa-adversal
|
||||
attribute: title
|
||||
category:
|
||||
selector: div a[href^="/torrents.php?cat="]
|
||||
attribute: href
|
||||
@@ -152,7 +160,7 @@ search:
|
||||
- name: re_replace
|
||||
args: ["-", " "]
|
||||
title:
|
||||
text: "{{ if or .Result.title_full .Result.title_text }}{{ or .Result.title_full .Result.title_text }}{{ else }}{{ .Result.href }}{{ end }}"
|
||||
text: "{{ if or .Result.title_full .Result.title_text }}{{ or .Result.title_full .Result.title_text }}{{ else }}{{ .Result.href }}{{ end }}{{ if .Result._ads }} (Ads included!){{ else }}{{ end }}"
|
||||
details:
|
||||
selector: div a[href^="/torrent/"]
|
||||
attribute: href
|
||||
|
@@ -7,10 +7,8 @@ type: public
|
||||
encoding: UTF-8
|
||||
followredirect: true
|
||||
links:
|
||||
- https://torrentqq240.com/
|
||||
- https://torrentqq242.com/
|
||||
legacylinks:
|
||||
- https://torrentqq225.com/
|
||||
- https://torrentqq226.com/
|
||||
- https://torrentqq227.com/
|
||||
- https://torrentqq228.com/
|
||||
- https://torrentqq229.com/
|
||||
@@ -24,6 +22,8 @@ legacylinks:
|
||||
- https://torrentqq237.com/
|
||||
- https://torrentqq238.com/
|
||||
- https://torrentqq239.com/
|
||||
- https://torrentqq240.com/
|
||||
- https://torrentqq241.com/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
@@ -7,10 +7,8 @@ type: public
|
||||
encoding: UTF-8
|
||||
followredirect: true
|
||||
links:
|
||||
- https://torrentsir89.com/
|
||||
- https://torrentsir90.com/
|
||||
legacylinks:
|
||||
- http://torrentsir78.com/
|
||||
- https://torrentsir78.com/
|
||||
- http://torrentsir79.com/
|
||||
- https://torrentsir79.com/
|
||||
- http://torrentsir80.com/
|
||||
@@ -30,6 +28,8 @@ legacylinks:
|
||||
- http://torrentsir88.com/
|
||||
- https://torrentsir88.com/
|
||||
- http://torrentsir89.com/
|
||||
- https://torrentsir89.com/
|
||||
- http://torrentsir90.com/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
@@ -7,11 +7,10 @@ type: public
|
||||
encoding: UTF-8
|
||||
followredirect: true
|
||||
links:
|
||||
- https://viewtorrent2.com/
|
||||
- https://viewtorrent4.com/
|
||||
legacylinks:
|
||||
- https://torrentview.net/
|
||||
- https://torrentview.co/
|
||||
- https://torrentview47.com/
|
||||
- https://torrentview49.com/
|
||||
- https://torrentview50.com/
|
||||
- https://torrentview52.com/
|
||||
@@ -25,6 +24,7 @@ legacylinks:
|
||||
- https://torrentview67.com/
|
||||
- https://torrentview68.com/
|
||||
- https://viewtorrent1.com/
|
||||
- https://viewtorrent2.com/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
@@ -7,9 +7,8 @@ type: public
|
||||
encoding: UTF-8
|
||||
followredirect: true
|
||||
links:
|
||||
- https://torrentwiz51.com/
|
||||
- https://torrentwiz52.com/
|
||||
legacylinks:
|
||||
- https://torrentwiz35.com/
|
||||
- https://torrentwiz36.com/
|
||||
- https://torrentwiz37.com/
|
||||
- https://torrentwiz38.com/
|
||||
@@ -24,6 +23,7 @@ legacylinks:
|
||||
- https://torrentwiz48.com/
|
||||
- https://torrentwiz49.com/
|
||||
- https://torrentwiz50.com/
|
||||
- https://torrentwiz51.com/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
@@ -16,6 +16,22 @@ caps:
|
||||
search: [q]
|
||||
music-search: [q, artist]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Filter freeleech only
|
||||
default: false
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrents per page:</b> setting to <b>100</b> on your account profile.
|
||||
|
||||
login:
|
||||
path: takelogin.php
|
||||
method: post
|
||||
@@ -32,6 +48,7 @@ search:
|
||||
- path: browse.php
|
||||
inputs:
|
||||
search: "{{ if .Query.Artist }}{{ .Query.Artist }}{{ else }}{{ .Keywords }}{{ end }}"
|
||||
$raw: "{{ if .Config.freeleech }}&includeFL=on{{ else }}{{ end }}"
|
||||
|
||||
rows:
|
||||
selector: table.mainouter table > tbody > tr:has(a[href^="details.php?id="])
|
||||
@@ -47,6 +64,9 @@ search:
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: replace
|
||||
args: ["&hit=1", ""] # avoid redirect
|
||||
date:
|
||||
selector: td:nth-child(6)
|
||||
# auto adjusted by site account profile
|
||||
@@ -64,7 +84,9 @@ search:
|
||||
size:
|
||||
selector: td:nth-child(7)
|
||||
downloadvolumefactor:
|
||||
text: 1
|
||||
case:
|
||||
"span:contains(\"FREELEECH\")": 0
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
# engine tbd
|
||||
|
175
src/Jackett.Common/Definitions/unleashthecartoons.yml
Normal file
175
src/Jackett.Common/Definitions/unleashthecartoons.yml
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
id: unleashthecartoons
|
||||
name: UnleashTheCartoons
|
||||
description: "UnleashTheCartoons is a ROMANIAN Private Torrent Tracker for ANIMATED MOVIES / TV"
|
||||
language: ro-RO
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://unleashthecartoons.world/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies, desc: "Movies"}
|
||||
- {id: 2, cat: TV, desc: "TV Series"}
|
||||
- {id: 3, cat: TV/Anime, desc: "Anime"}
|
||||
- {id: 4, cat: Books, desc: "Ebooks"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: freeleech
|
||||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: multilang
|
||||
type: checkbox
|
||||
label: Replace MULTi by another language in release name
|
||||
default: false
|
||||
- name: multilanguage
|
||||
type: select
|
||||
label: Replace MULTi by this language
|
||||
default: Romanian
|
||||
options:
|
||||
Romanian: Romanian
|
||||
MULTi Romanian: MULTi Romanian
|
||||
English: English
|
||||
MULTi English: MULTi English
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
default: id
|
||||
options:
|
||||
id: created
|
||||
seeders: seeders
|
||||
size: size
|
||||
name: title
|
||||
- name: type
|
||||
type: select
|
||||
label: Order requested from site
|
||||
default: desc
|
||||
options:
|
||||
desc: desc
|
||||
asc: asc
|
||||
|
||||
login:
|
||||
path: account-login.php
|
||||
method: post
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
returnto: /
|
||||
error:
|
||||
- selector: div.myFrame-caption:contains("Error")
|
||||
message:
|
||||
selector: div.myFrame-content
|
||||
- selector: div.myFrame-caption:contains("Access denied")
|
||||
message:
|
||||
selector: div.myFrame-content
|
||||
test:
|
||||
path: /
|
||||
selector: a[href="account-logout.php"]
|
||||
|
||||
search:
|
||||
paths:
|
||||
# https://unleashthecartoons.world/torrents-search.php?search=&cat=0&incldead=1&freeleech=0&inclexternal=0&lang=0&sort=id&order=desc
|
||||
- path: torrents-search.php
|
||||
inputs:
|
||||
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
|
||||
search: "{{ .Keywords }}"
|
||||
# 0 active, 1 incldead, 2 onlydead
|
||||
incldead: 1
|
||||
# 0 all, 1 nofree, 2 onlyfree
|
||||
freeleech: "{{ if .Config.freeleech }}2{{ else }}0{{ end }}"
|
||||
# 0 Local/External, 1 Local Only, 2 External Only
|
||||
inclexternal: 0
|
||||
# 0 all, 1 Romanian, 2 English, 3 Romanian/English
|
||||
lang: 0
|
||||
sort: "{{ .Config.sort }}"
|
||||
order: "{{ .Config.type }}"
|
||||
# does not support imdbid searches, does not return imdb link in results
|
||||
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["\\.", " "]
|
||||
- name: re_replace
|
||||
args: ["\\s+", " "]
|
||||
- name: re_replace
|
||||
args: ["(\\w+)", "+$1"] # prepend + to each word
|
||||
|
||||
rows:
|
||||
selector: table.ttable_headinner tr.t-row
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href*="cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
_lang:
|
||||
optional: true
|
||||
selector: img[src*="images/languages"]
|
||||
attribute: alt
|
||||
filters:
|
||||
- name: replace
|
||||
args: ["Ro/Eng", "MULTi"]
|
||||
title_phase1:
|
||||
selector: a[href^="torrents-details.php?id="]
|
||||
filters:
|
||||
- name: append
|
||||
args: "{{ if .Result._lang }} ({{ .Result._lang }}){{ else }}{{ end }}"
|
||||
title_multilang:
|
||||
text: "{{ .Result.title_phase1 }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)(\\bmulti\\b)", "{{ .Config.multilanguage }}"]
|
||||
title:
|
||||
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="torrents-details.php?id="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: replace
|
||||
args: ["&hit=1", ""] # avoid redirect
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: a[onMouseover]
|
||||
attribute: onMouseover
|
||||
filters:
|
||||
- name: regexp
|
||||
args: src=(.+?)>
|
||||
- name: replace
|
||||
args: ["images/nocover.png", ""]
|
||||
size:
|
||||
selector: td:nth-last-child(7)
|
||||
date:
|
||||
selector: td:nth-last-child(3)
|
||||
seeders:
|
||||
selector: td:nth-last-child(6)
|
||||
leechers:
|
||||
selector: td:nth-last-child(5)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img[src="images/free.png"]: 0
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
minimumseedtime:
|
||||
# 2 days (as seconds = 2 x 24 x 60 x 60)
|
||||
text: 172800
|
||||
# TorrentTrader
|
154
src/Jackett.Common/Definitions/vtorrent.yml
Normal file
154
src/Jackett.Common/Definitions/vtorrent.yml
Normal file
@@ -0,0 +1,154 @@
|
||||
---
|
||||
id: vtorrent
|
||||
name: vTorrent
|
||||
description: "vTorrent is a POLISH Semi-Private Torrent Tracker for MOVIES / TV / GENERAL"
|
||||
language: pl-PL
|
||||
type: semi-private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://vtorrent.pl/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 695, cat: Movies, desc: "FILMY"}
|
||||
- {id: 94, cat: Movies/HD, desc: "FILMY RMVB"}
|
||||
- {id: 124, cat: Movies/SD, desc: "FILMY (S)VCD"}
|
||||
- {id: 64, cat: Movies/SD, desc: "FILMY Divx / Xvid"}
|
||||
- {id: 81, cat: Movies/DVD, desc: "FILMY DVD-R"}
|
||||
- {id: 109, cat: Movies/HD, desc: "FILMY x264 / HDTV"}
|
||||
- {id: 697, cat: Movies/UHD, desc: "FILMY 4K"}
|
||||
- {id: 696, cat: Movies/3D, desc: "FILMY 3D"}
|
||||
- {id: 230, cat: TV, desc: "TV / Seriale"}
|
||||
- {id: 307, cat: TV/Anime, desc: "Anime"}
|
||||
- {id: 698, cat: PC/Games, desc: "GRY"}
|
||||
- {id: 155, cat: PC/Games, desc: "GRY Gry PC"}
|
||||
- {id: 173, cat: Console, desc: "GRY Gry Konsole"}
|
||||
- {id: 704, cat: Other, desc: "GRY Poradniki, spolszczenia i inne"}
|
||||
- {id: 699, cat: PC, desc: "PROGRAMY"}
|
||||
- {id: 138, cat: PC/0day, desc: "PROGRAMY Windows"}
|
||||
- {id: 288, cat: PC/Mac, desc: "PROGRAMY Linux / Mac"}
|
||||
- {id: 700, cat: Audio, desc: "MUZYKA"}
|
||||
- {id: 187, cat: Audio, desc: "MUZYKA Albumy i składanki"}
|
||||
- {id: 701, cat: Audio/Video, desc: "MUZYKA Koncerty"}
|
||||
- {id: 702, cat: TV/Documentary, desc: "DOKUMENTY"}
|
||||
- {id: 249, cat: Books/EBook, desc: "DOKUMENTY Książki"}
|
||||
- {id: 283, cat: Audio/Audiobook, desc: "DOKUMENTY Audiobooki"}
|
||||
- {id: 251, cat: Books/Mags, desc: "DOKUMENTY Czasopisma"}
|
||||
- {id: 284, cat: Books/Comics, desc: "DOKUMENTY Komiksy"}
|
||||
- {id: 703, cat: Other, desc: "POZOSTAŁE"}
|
||||
- {id: 310, cat: Other, desc: "POZOSTAŁE Dla Dzieci"}
|
||||
- {id: 294, cat: TV/Sport, desc: "POZOSTAŁE Sport"}
|
||||
- {id: 316, cat: PC/Mobile-Other, desc: "POZOSTAŁE GSM / PDA"}
|
||||
- {id: 333, cat: Other, desc: "POZOSTAŁE Tapety"}
|
||||
- {id: 325, cat: Other/Misc, desc: "POZOSTAŁE Różne"}
|
||||
- {id: 334, cat: XXX, desc: "EROTYKA"}
|
||||
- {id: 705, cat: XXX/x264, desc: "EROTYKA Filmy XXX"}
|
||||
- {id: 706, cat: XXX/ImageSet, desc: "EROTYKA Zdjęcia XXX"}
|
||||
- {id: 340, cat: XXX/Other, desc: "EROTYKA Czasopisma XXX"}
|
||||
- {id: 342, cat: XXX/Other, desc: "EROTYKA Gry XXX"}
|
||||
- {id: 308, cat: XXX/Other, desc: "EROTYKA Hentai"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
music-search: [q]
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: username
|
||||
type: text
|
||||
label: Username
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: multilang
|
||||
type: checkbox
|
||||
label: Replace MULTI by another language in release name
|
||||
default: false
|
||||
- name: multilanguage
|
||||
type: select
|
||||
label: Replace MULTI by this language
|
||||
default: POLISH
|
||||
options:
|
||||
POLISH: POLISH
|
||||
MULTI.POLISH: MULTI.POLISH
|
||||
- name: info_tpp
|
||||
type: info
|
||||
label: Results Per Page
|
||||
default: For best results, change the <b>Torrentów na stronę:</b> setting to <b>100</b> on your account profile.
|
||||
|
||||
login:
|
||||
path: login.php
|
||||
method: form
|
||||
form: form
|
||||
inputs:
|
||||
uid: "{{ .Config.username }}"
|
||||
pwd: "{{ .Config.password }}"
|
||||
keeplogged: 1
|
||||
error:
|
||||
- selector: font[color="#FF0000"]
|
||||
test:
|
||||
path: index.php
|
||||
selector: a[href^="logout.php?check_hash="]
|
||||
|
||||
search:
|
||||
paths:
|
||||
# https://vtorrent.pl/torrents.php?erotyka=1&page=0
|
||||
- path: torrents.php
|
||||
inputs:
|
||||
# does not support multi category selection. so using default for all
|
||||
# $raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
|
||||
category: 0
|
||||
search: "{{ .Keywords }}"
|
||||
erotyka: 1
|
||||
page: 0
|
||||
# does not support sorting results, or imdbid searching, or have imdb in results
|
||||
|
||||
rows:
|
||||
selector: table.lista[width="100%"]:not(table[align]) > tbody > tr:has(a[href^="details.php?id="])
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="torrents.php?category="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: category
|
||||
title_phase1:
|
||||
selector: a[href^="details.php?id="]
|
||||
title_multilang:
|
||||
selector: a[href^="details.php?id="]
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)(\\.multi\\.)", ".{{ .Config.multilanguage }}."]
|
||||
- name: re_replace
|
||||
args: ["(?i)(\\.pl\\.)", ".POLISH."]
|
||||
title:
|
||||
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
poster:
|
||||
selector: img
|
||||
attribute: src
|
||||
date:
|
||||
selector: td:nth-child(6)
|
||||
# auto adjusted by site account profile
|
||||
filters:
|
||||
- name: dateparse
|
||||
args: "02/01/2006 15:04:05"
|
||||
size:
|
||||
selector: td:nth-child(7)
|
||||
seeders:
|
||||
selector: td:nth-child(9)
|
||||
leechers:
|
||||
selector: td:nth-child(10)
|
||||
downloadvolumefactor:
|
||||
text: 0
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
# engine n/a
|
@@ -37,7 +37,7 @@ namespace Jackett.Common.Indexers
|
||||
private const string SearchUrl = "buscar/";
|
||||
|
||||
public override string[] AlternativeSiteLinks { get; protected set; } = {
|
||||
"https://dontorrent.surf/",
|
||||
"https://dontorrent.how/",
|
||||
"https://todotorrents.net/",
|
||||
"https://tomadivx.net/",
|
||||
"https://seriesblanco.one/",
|
||||
@@ -60,7 +60,8 @@ namespace Jackett.Common.Indexers
|
||||
"https://dontorrent.mba/",
|
||||
"https://dontorrent.army/",
|
||||
"https://dontorrent.blue/",
|
||||
"https://dontorrent.beer/"
|
||||
"https://dontorrent.beer/",
|
||||
"https://dontorrent.surf/"
|
||||
};
|
||||
|
||||
private static Dictionary<string, string> CategoriesMap => new Dictionary<string, string>
|
||||
@@ -78,7 +79,7 @@ namespace Jackett.Common.Indexers
|
||||
: base(id: "dontorrent",
|
||||
name: "DonTorrent",
|
||||
description: "DonTorrent is a SPANISH public tracker for MOVIES / TV / GENERAL",
|
||||
link: "https://dontorrent.surf/",
|
||||
link: "https://dontorrent.how/",
|
||||
caps: new TorznabCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
@@ -105,6 +106,9 @@ namespace Jackett.Common.Indexers
|
||||
Language = "es-ES";
|
||||
Type = "public";
|
||||
|
||||
// avoid CLoudflare too many requests limiter
|
||||
webclient.requestDelay = 2.1;
|
||||
|
||||
var matchWords = new BoolConfigurationItem("Match words in title") { Value = true };
|
||||
configData.AddDynamic("MatchWords", matchWords);
|
||||
|
||||
|
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jackett.Common.Models;
|
||||
@@ -17,11 +18,15 @@ namespace Jackett.Common.Indexers
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class FileList : BaseWebIndexer
|
||||
{
|
||||
public override string[] AlternativeSiteLinks { get; protected set; } = {
|
||||
"https://filelist.io/",
|
||||
"https://flro.org/"
|
||||
};
|
||||
|
||||
public override string[] LegacySiteLinks { get; protected set; } =
|
||||
{
|
||||
"http://filelist.ro/",
|
||||
"https://filelist.ro/",
|
||||
"https://flro.org/",
|
||||
"http://filelist.ro/",
|
||||
"http://flro.org/"
|
||||
};
|
||||
|
||||
@@ -128,35 +133,42 @@ namespace Jackett.Common.Indexers
|
||||
try
|
||||
{
|
||||
var json = JArray.Parse(response);
|
||||
|
||||
foreach (var row in json)
|
||||
{
|
||||
var detailsUri = new Uri(DetailsUrl + "?id=" + (string)row["id"]);
|
||||
var seeders = (int)row["seeders"];
|
||||
var peers = seeders + (int)row["leechers"];
|
||||
var publishDate = DateTimeUtil.FromFuzzyTime((string)row["upload_date"] + " +0200");
|
||||
var downloadVolumeFactor = (int)row["freeleech"] == 1 ? 0 : 1;
|
||||
var uploadVolumeFactor = (int)row["doubleup"] == 1 ? 2 : 1;
|
||||
var imdbId = ((JObject)row).ContainsKey("imdb") ? ParseUtil.GetImdbID((string)row["imdb"]) : null;
|
||||
var link = new Uri((string)row["download_link"]);
|
||||
var isFreeleech = row.Value<bool>("freeleech");
|
||||
|
||||
// skip non-freeleech results when freeleech only is set
|
||||
if (configData.Freeleech.Value && !isFreeleech)
|
||||
continue;
|
||||
|
||||
var detailsUri = new Uri(DetailsUrl + "?id=" + row.Value<string>("id"));
|
||||
var seeders = row.Value<int>("seeders");
|
||||
var peers = seeders + row.Value<int>("leechers");
|
||||
var publishDate = DateTime.Parse(row.Value<string>("upload_date") + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
|
||||
var downloadVolumeFactor = isFreeleech ? 0 : 1;
|
||||
var uploadVolumeFactor = row.Value<bool>("doubleup") ? 2 : 1;
|
||||
var imdbId = ((JObject)row).ContainsKey("imdb") ? ParseUtil.GetImdbID(row.Value<string>("imdb")) : null;
|
||||
var link = new Uri(row.Value<string>("download_link"));
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
Title = (string)row["name"],
|
||||
Guid = detailsUri,
|
||||
Details = detailsUri,
|
||||
Link = link,
|
||||
Category = MapTrackerCatDescToNewznab((string)row["category"]),
|
||||
Size = (long)row["size"],
|
||||
Files = (long)row["files"],
|
||||
Grabs = (long)row["times_completed"],
|
||||
Title = row.Value<string>("name").Trim(),
|
||||
Category = MapTrackerCatDescToNewznab(row.Value<string>("category")),
|
||||
Size = row.Value<long>("size"),
|
||||
Files = row.Value<long>("files"),
|
||||
Grabs = row.Value<long>("times_completed"),
|
||||
Seeders = seeders,
|
||||
Peers = peers,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 172800, //48 hours
|
||||
Imdb = imdbId,
|
||||
PublishDate = publishDate,
|
||||
DownloadVolumeFactor = downloadVolumeFactor,
|
||||
UploadVolumeFactor = uploadVolumeFactor,
|
||||
Guid = detailsUri,
|
||||
Imdb = imdbId
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 172800 // 48 hours
|
||||
};
|
||||
|
||||
releases.Add(release);
|
||||
@@ -175,29 +187,33 @@ namespace Jackett.Common.Indexers
|
||||
private async Task<string> CallProviderAsync(TorznabQuery query)
|
||||
{
|
||||
var searchUrl = ApiUrl;
|
||||
var searchString = query.GetQueryString();
|
||||
var cat = string.Join(",", MapTorznabCapsToTrackers(query));
|
||||
var searchString = query.GetQueryString().Trim();
|
||||
|
||||
var queryCollection = new NameValueCollection
|
||||
{
|
||||
{"category", cat}
|
||||
{"category", string.Join(",", MapTorznabCapsToTrackers(query))}
|
||||
};
|
||||
|
||||
if (configData.Freeleech.Value)
|
||||
queryCollection.Set("freeleech", "1");
|
||||
|
||||
if (query.IsImdbQuery)
|
||||
{
|
||||
queryCollection.Add("type", "imdb");
|
||||
queryCollection.Add("query", query.ImdbID);
|
||||
queryCollection.Add("action", "search-torrents");
|
||||
queryCollection.Set("action", "search-torrents");
|
||||
queryCollection.Set("type", "imdb");
|
||||
queryCollection.Set("query", query.ImdbID);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
queryCollection.Add("type", "name");
|
||||
queryCollection.Add("query", searchString);
|
||||
queryCollection.Add("action", "search-torrents");
|
||||
queryCollection.Set("action", "search-torrents");
|
||||
queryCollection.Set("type", "name");
|
||||
queryCollection.Set("query", searchString);
|
||||
}
|
||||
else
|
||||
queryCollection.Add("action", "latest-torrents");
|
||||
queryCollection.Set("action", "latest-torrents");
|
||||
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
try
|
||||
{
|
||||
var auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(configData.Username.Value + ":" + configData.Passkey.Value));
|
||||
@@ -206,6 +222,7 @@ namespace Jackett.Common.Indexers
|
||||
{"Authorization", "Basic " + auth}
|
||||
};
|
||||
var response = await RequestWithCookiesAsync(searchUrl, headers: headers);
|
||||
|
||||
return response.ContentString;
|
||||
}
|
||||
catch (Exception inner)
|
||||
|
@@ -80,6 +80,7 @@ namespace Jackett.Common.Indexers
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value },
|
||||
{ "returnto", "" },
|
||||
{ "login", "Login" }
|
||||
};
|
||||
|
||||
@@ -107,11 +108,12 @@ namespace Jackett.Common.Indexers
|
||||
* so ?search=reality+love+s04e19&s_title=1&s_tag=1
|
||||
* will find Love Island S04E19 as well as My Kitchen Rules S12E02
|
||||
* since the former has a match for Love in the title, and the latter has a tag for Reality-TV.
|
||||
*
|
||||
*
|
||||
* FunFiles only has genres for movies and tv
|
||||
*/
|
||||
|
||||
var ValidList = new List<string>() {
|
||||
var validList = new List<string>
|
||||
{
|
||||
"action",
|
||||
"adventure",
|
||||
"animation",
|
||||
@@ -147,25 +149,27 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
var qc = new NameValueCollection
|
||||
{
|
||||
{"incldead", "1"},
|
||||
{"showspam", "1"},
|
||||
{"cat", MapTorznabCapsToTrackers(query).FirstIfSingleOrDefault("0")}
|
||||
{ "cat", "0" },
|
||||
{ "incldead", "1" },
|
||||
{ "showspam", "1" },
|
||||
{ "s_title", "1" }
|
||||
};
|
||||
|
||||
var queryCats = MapTorznabCapsToTrackers(query);
|
||||
queryCats.ForEach(cat => qc.Set($"c{cat}", "1"));
|
||||
|
||||
if (query.IsImdbQuery)
|
||||
{
|
||||
qc.Add("search", query.ImdbID);
|
||||
qc.Add("s_desc", "1");
|
||||
qc.Set("search", query.ImdbID);
|
||||
qc.Set("s_desc", "1");
|
||||
}
|
||||
else
|
||||
if (query.IsGenreQuery)
|
||||
else if (query.IsGenreQuery)
|
||||
{
|
||||
qc.Add("search", query.Genre + " " + query.GetQueryString());
|
||||
qc.Add("s_tag", "1");
|
||||
qc.Add("s_title", "1");
|
||||
qc.Set("search", query.Genre + " " + query.GetQueryString());
|
||||
qc.Set("s_tag", "1");
|
||||
}
|
||||
else
|
||||
qc.Add("search", query.GetQueryString());
|
||||
qc.Set("search", query.GetQueryString());
|
||||
|
||||
var searchUrl = SearchUrl + "?" + qc.GetQueryString();
|
||||
var results = await RequestWithCookiesAndRetryAsync(searchUrl);
|
||||
@@ -176,64 +180,64 @@ namespace Jackett.Common.Indexers
|
||||
results = await RequestWithCookiesAndRetryAsync(searchUrl);
|
||||
}
|
||||
|
||||
char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' };
|
||||
|
||||
try
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(results.ContentString);
|
||||
var rows = dom.QuerySelectorAll("table[cellpadding=2] > tbody > tr:has(td.row3)");
|
||||
|
||||
var rows = dom.QuerySelectorAll("table.mainframe table[cellpadding=\"2\"] > tbody > tr:has(td.row3)");
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var qDownloadLink = row.QuerySelector("a[href^=\"download.php\"]");
|
||||
if (qDownloadLink == null)
|
||||
throw new Exception("Download links not found. Make sure you can download from the website.");
|
||||
|
||||
var link = new Uri(SiteLink + qDownloadLink.GetAttribute("href"));
|
||||
|
||||
var qDetailsLink = row.QuerySelector("a[href^=\"details.php?id=\"]");
|
||||
var title = qDetailsLink.GetAttribute("title").Trim();
|
||||
var details = new Uri(SiteLink + qDetailsLink.GetAttribute("href"));
|
||||
var title = qDetailsLink?.GetAttribute("title")?.Trim();
|
||||
var details = new Uri(SiteLink + qDetailsLink?.GetAttribute("href")?.Replace("&hit=1", ""));
|
||||
|
||||
var qCatLink = row.QuerySelector("a[href^=\"browse.php?cat=\"]");
|
||||
var catStr = qCatLink.GetAttribute("href").Split('=')[1].Split('&')[0];
|
||||
var categoryLink = row.QuerySelector("a[href^=\"browse.php?cat=\"]")?.GetAttribute("href");
|
||||
var cat = ParseUtil.GetArgumentFromQueryString(categoryLink, "cat");
|
||||
|
||||
var files = ParseUtil.CoerceInt(row.Children[3].TextContent);
|
||||
var publishDate = DateTimeUtil.FromTimeAgo(row.Children[5].TextContent);
|
||||
var size = ReleaseInfo.GetBytes(row.Children[7].TextContent);
|
||||
var grabs = ParseUtil.CoerceInt(row.Children[8].TextContent);
|
||||
var seeders = ParseUtil.CoerceInt(row.Children[9].TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(row.Children[10].TextContent);
|
||||
|
||||
var ka = row.NextElementSibling.QuerySelector("table > tbody > tr:nth-child(3)");
|
||||
var ulFactor = ParseUtil.CoerceDouble(ka.Children[0].TextContent.Replace("X", ""));
|
||||
var dlFactor = ParseUtil.CoerceDouble(ka.Children[1].TextContent.Replace("X", ""));
|
||||
ka = row.NextElementSibling.QuerySelector("span[style=\"float:left\"]");
|
||||
var description = ka.TextContent;
|
||||
var qGenres = description.ToLower().Replace(" & ", "_&_").Replace(" and ", "_and_");
|
||||
char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' };
|
||||
var releaseGenres = ValidList.Intersect(qGenres.Split(delimiters, System.StringSplitOptions.RemoveEmptyEntries));
|
||||
releaseGenres = releaseGenres.Select(x => x.Replace("_", " "));
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
Title = title,
|
||||
Details = details,
|
||||
Link = link,
|
||||
Guid = link,
|
||||
Category = MapTrackerCatToNewznab(catStr),
|
||||
PublishDate = publishDate,
|
||||
Size = size,
|
||||
Files = files,
|
||||
Grabs = grabs,
|
||||
Link = link,
|
||||
Details = details,
|
||||
Title = title,
|
||||
Category = MapTrackerCatToNewznab(cat),
|
||||
Size = ReleaseInfo.GetBytes(row.Children[7].TextContent),
|
||||
Files = ParseUtil.CoerceInt(row.Children[3].TextContent),
|
||||
Grabs = ParseUtil.CoerceInt(row.Children[8].TextContent),
|
||||
Seeders = seeders,
|
||||
Peers = leechers + seeders,
|
||||
Description = description,
|
||||
PublishDate = DateTimeUtil.FromTimeAgo(row.Children[5].TextContent),
|
||||
DownloadVolumeFactor = 1,
|
||||
UploadVolumeFactor = 1,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 172800, // 48 hours
|
||||
DownloadVolumeFactor = dlFactor,
|
||||
UploadVolumeFactor = ulFactor
|
||||
MinimumSeedTime = 172800 // 48 hours
|
||||
};
|
||||
if (release.Genres == null)
|
||||
release.Genres = new List<string>();
|
||||
release.Genres = releaseGenres.ToList();
|
||||
|
||||
var nextRow = row.NextElementSibling;
|
||||
if (nextRow != null)
|
||||
{
|
||||
var qStats = nextRow.QuerySelector("table > tbody > tr:nth-child(3)");
|
||||
release.UploadVolumeFactor = ParseUtil.CoerceDouble(qStats?.Children[0].TextContent.Replace("X", ""));
|
||||
release.DownloadVolumeFactor = ParseUtil.CoerceDouble(qStats?.Children[1].TextContent.Replace("X", ""));
|
||||
|
||||
release.Description = nextRow.QuerySelector("span[style=\"float:left\"]")?.TextContent.Trim();
|
||||
var genres = release.Description.ToLower().Replace(" & ", "_&_").Replace(" and ", "_and_");
|
||||
|
||||
var releaseGenres = validList.Intersect(genres.Split(delimiters, StringSplitOptions.RemoveEmptyEntries));
|
||||
release.Genres = releaseGenres.Select(x => x.Trim().Replace("_", " ")).ToList();
|
||||
}
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
@@ -11,10 +12,10 @@ using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.IndexerConfig;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Jackett.Common.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using static Jackett.Common.Models.IndexerConfig.ConfigurationData;
|
||||
using WebClient = Jackett.Common.Utils.Clients.WebClient;
|
||||
|
||||
namespace Jackett.Common.Indexers
|
||||
{
|
||||
@@ -22,7 +23,7 @@ namespace Jackett.Common.Indexers
|
||||
public class HDSpace : BaseWebIndexer
|
||||
{
|
||||
private string LoginUrl => SiteLink + "index.php?page=login";
|
||||
private string SearchUrl => SiteLink + "index.php?page=torrents&";
|
||||
private string SearchUrl => SiteLink + "index.php?page=torrents";
|
||||
|
||||
private new ConfigurationDataBasicLogin configData => (ConfigurationDataBasicLogin)base.configData;
|
||||
|
||||
@@ -121,17 +122,16 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
if (query.IsImdbQuery)
|
||||
{
|
||||
queryCollection.Add("options", "2");
|
||||
queryCollection.Add("search", query.ImdbIDShort);
|
||||
queryCollection.Set("options", "2");
|
||||
queryCollection.Set("search", query.ImdbIDShort);
|
||||
}
|
||||
else
|
||||
{
|
||||
queryCollection.Add("options", "0");
|
||||
queryCollection.Add("search", query.GetQueryString());
|
||||
queryCollection.Set("options", "0");
|
||||
queryCollection.Set("search", query.GetQueryString().Replace(".", " "));
|
||||
}
|
||||
|
||||
// remove . as not used in titles
|
||||
var response = await RequestWithCookiesAndRetryAsync(SearchUrl + queryCollection.GetQueryString().Replace(".", " "));
|
||||
var response = await RequestWithCookiesAndRetryAsync($"{SearchUrl}&{queryCollection.GetQueryString()}");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -156,6 +156,11 @@ namespace Jackett.Common.Indexers
|
||||
release.Title = qLink.TextContent.Trim();
|
||||
release.Details = new Uri(SiteLink + qLink.GetAttribute("href"));
|
||||
release.Guid = release.Details;
|
||||
release.Link = new Uri(SiteLink + row.Children[3].FirstElementChild.GetAttribute("href"));
|
||||
|
||||
var torrentTitle = ParseUtil.GetArgumentFromQueryString(release.Link.ToString(), "f")?.Replace(".torrent", "").Trim();
|
||||
if (!string.IsNullOrWhiteSpace(torrentTitle))
|
||||
release.Title = WebUtility.HtmlDecode(torrentTitle);
|
||||
|
||||
var qGenres = row.QuerySelector("span[style=\"color: #000000 \"]");
|
||||
var description = "";
|
||||
@@ -166,9 +171,6 @@ namespace Jackett.Common.Indexers
|
||||
if (imdbLink != null)
|
||||
release.Imdb = ParseUtil.GetImdbID(imdbLink.GetAttribute("href").Split('/').Last());
|
||||
|
||||
var qDownload = row.Children[3].FirstElementChild;
|
||||
release.Link = new Uri(SiteLink + qDownload.GetAttribute("href"));
|
||||
|
||||
var dateStr = row.Children[4].TextContent.Trim();
|
||||
//"July 11, 2015, 13:34:09", "Today|Yesterday at 20:04:23"
|
||||
release.PublishDate = DateTimeUtil.FromUnknown(dateStr);
|
||||
@@ -188,8 +190,9 @@ namespace Jackett.Common.Indexers
|
||||
else
|
||||
release.DownloadVolumeFactor = 1;
|
||||
release.UploadVolumeFactor = 1;
|
||||
var qCat = row.QuerySelector("a[href^=\"index.php?page=torrents&category=\"]");
|
||||
var cat = qCat.GetAttribute("href").Split('=')[2];
|
||||
|
||||
var categoryLink = row.QuerySelector("a[href^=\"index.php?page=torrents&category=\"]").GetAttribute("href");
|
||||
var cat = ParseUtil.GetArgumentFromQueryString(categoryLink, "category");
|
||||
release.Category = MapTrackerCatToNewznab(cat);
|
||||
|
||||
release.Description = description;
|
||||
|
@@ -170,15 +170,14 @@ namespace Jackett.Common.Indexers
|
||||
var poster = posterMatch.Success ? new Uri(SiteLink + posterMatch.Groups[1].Value.Replace("\\", "/")) : null;
|
||||
|
||||
var link = new Uri(SiteLink + row.Children[4].FirstElementChild.GetAttribute("href"));
|
||||
var description = row.Children[2].QuerySelector("span").TextContent;
|
||||
var description = row.Children[2].QuerySelector("span")?.TextContent.Trim();
|
||||
var size = ReleaseInfo.GetBytes(row.Children[7].TextContent);
|
||||
|
||||
var dateTag = row.Children[6].FirstElementChild;
|
||||
var dateString = string.Join(" ", dateTag.Attributes.Select(attr => attr.Name));
|
||||
var publishDate = DateTime.ParseExact(dateString, "dd MMM yyyy HH:mm:ss zz00", CultureInfo.InvariantCulture).ToLocalTime();
|
||||
var dateAdded = string.Join(" ", row.Children[6].FirstElementChild.Attributes.Select(a => a.Name).Take(4));
|
||||
var publishDate = DateTime.ParseExact(dateAdded, "dd MMM yyyy HH:mm:ss", CultureInfo.InvariantCulture);
|
||||
|
||||
var catStr = row.FirstElementChild.FirstElementChild.GetAttribute("href").Split('=')[1];
|
||||
var cat = MapTrackerCatToNewznab(catStr);
|
||||
var categoryLink = row.FirstElementChild.FirstElementChild.GetAttribute("href");
|
||||
var cat = ParseUtil.GetArgumentFromQueryString(categoryLink, "category");
|
||||
|
||||
// Sometimes the uploader column is missing, so seeders, leechers, and grabs may be at a different index.
|
||||
// There's room for improvement, but this works for now.
|
||||
@@ -230,7 +229,7 @@ namespace Jackett.Common.Indexers
|
||||
Guid = details,
|
||||
Link = link,
|
||||
PublishDate = publishDate,
|
||||
Category = cat,
|
||||
Category = MapTrackerCatToNewznab(cat),
|
||||
Description = description,
|
||||
Poster = poster,
|
||||
Imdb = imdb,
|
||||
|
@@ -5,6 +5,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Html.Parser;
|
||||
using Jackett.Common.Models;
|
||||
@@ -22,6 +23,7 @@ namespace Jackett.Common.Indexers
|
||||
private string BrowsePage => SiteLink + "browse.php";
|
||||
private string LoginUrl => SiteLink + "takelogin.php";
|
||||
private string QueryString => "?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no";
|
||||
private readonly Regex _dateMatchRegex = new Regex(@"\d{4}-\d{2}-\d{2} \d{2}:\d{2} [AaPp][Mm]", RegexOptions.Compiled);
|
||||
|
||||
public override string[] LegacySiteLinks { get; protected set; } = {
|
||||
"http://immortalseed.me/"
|
||||
@@ -131,12 +133,9 @@ namespace Jackett.Common.Indexers
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var document = parser.ParseDocument(response.ContentString);
|
||||
var messageEl = document.QuerySelector("#main table");
|
||||
var errorMessage = response.ContentString;
|
||||
if (messageEl != null)
|
||||
errorMessage = messageEl.TextContent.Trim();
|
||||
var errorMessage = document.QuerySelector("#main table td:contains(\"ERROR\")")?.TextContent.Trim();
|
||||
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
throw new ExceptionWithConfigData(errorMessage ?? "Login failed.", configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
@@ -189,25 +188,25 @@ namespace Jackett.Common.Indexers
|
||||
release.Details = new Uri(qDetails.GetAttribute("href"));
|
||||
|
||||
// 2021-03-17 03:39 AM
|
||||
var dateString = row.QuerySelectorAll("td:nth-of-type(2) div").Last().LastChild.TextContent.Trim();
|
||||
release.PublishDate = DateTime.ParseExact(dateString, "yyyy-MM-dd hh:mm tt", CultureInfo.InvariantCulture);
|
||||
|
||||
var sizeStr = row.QuerySelector("td:nth-of-type(5)").TextContent.Trim();
|
||||
release.Size = ReleaseInfo.GetBytes(sizeStr);
|
||||
// requests can be 'Pre Release Time: 2013-04-22 02:00 AM Uploaded: 3 Years, 6 Months, 4 Weeks, 2 Days, 16 Hours, 52 Minutes, 41 Seconds after Pre'
|
||||
var dateMatch = _dateMatchRegex.Match(row.QuerySelector("td:nth-of-type(2) > div:last-child").TextContent.Trim());
|
||||
if (dateMatch.Success)
|
||||
release.PublishDate = DateTime.ParseExact(dateMatch.Value, "yyyy-MM-dd hh:mm tt", CultureInfo.InvariantCulture);
|
||||
|
||||
release.Size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-of-type(5)").TextContent.Trim());
|
||||
release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(7)").TextContent.Trim());
|
||||
release.Peers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(8)").TextContent.Trim()) + release.Seeders;
|
||||
|
||||
var catLink = row.QuerySelector("td:nth-of-type(1) a").GetAttribute("href");
|
||||
var catSplit = catLink.IndexOf("category=");
|
||||
if (catSplit > -1)
|
||||
catLink = catLink.Substring(catSplit + 9);
|
||||
|
||||
release.Category = MapTrackerCatToNewznab(catLink);
|
||||
var categoryLink = row.QuerySelector("td:nth-of-type(1) a").GetAttribute("href");
|
||||
var cat = ParseUtil.GetArgumentFromQueryString(categoryLink, "category");
|
||||
release.Category = MapTrackerCatToNewznab(cat);
|
||||
|
||||
var grabs = row.QuerySelector("td:nth-child(6)").TextContent;
|
||||
release.Grabs = ParseUtil.CoerceInt(grabs);
|
||||
|
||||
var cover = row.QuerySelector("td:nth-of-type(2) > div > img[src]")?.GetAttribute("src")?.Trim();
|
||||
release.Poster = !string.IsNullOrEmpty(cover) && cover.StartsWith("/") ? new Uri(SiteLink + cover.TrimStart('/')) : null;
|
||||
|
||||
if (row.QuerySelector("img[title^=\"Free Torrent\"]") != null)
|
||||
release.DownloadVolumeFactor = 0;
|
||||
else if (row.QuerySelector("img[title^=\"Silver Torrent\"]") != null)
|
||||
@@ -215,10 +214,7 @@ namespace Jackett.Common.Indexers
|
||||
else
|
||||
release.DownloadVolumeFactor = 1;
|
||||
|
||||
if (row.QuerySelector("img[title^=\"x2 Torrent\"]") != null)
|
||||
release.UploadVolumeFactor = 2;
|
||||
else
|
||||
release.UploadVolumeFactor = 1;
|
||||
release.UploadVolumeFactor = row.QuerySelector("img[title^=\"x2 Torrent\"]") != null ? 2 : 1;
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
|
@@ -49,9 +49,9 @@ namespace Jackett.Common.Indexers
|
||||
}
|
||||
};
|
||||
|
||||
private new ConfigurationDataBasicLogin configData
|
||||
private new ConfigurationDataBasicLoginWith2FA configData
|
||||
{
|
||||
get => (ConfigurationDataBasicLogin)base.configData;
|
||||
get => (ConfigurationDataBasicLoginWith2FA)base.configData;
|
||||
set => base.configData = value;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Jackett.Common.Indexers
|
||||
logger: l,
|
||||
p: ps,
|
||||
cacheService: cs,
|
||||
configData: new ConfigurationDataBasicLogin())
|
||||
configData: new ConfigurationDataBasicLoginWith2FA())
|
||||
{
|
||||
Encoding = Encoding.UTF8;
|
||||
Language = "en-US";
|
||||
@@ -93,26 +93,24 @@ namespace Jackett.Common.Indexers
|
||||
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
LoadValuesFromJson(configJson);
|
||||
|
||||
var pairs = new Dictionary<string, string>
|
||||
{
|
||||
{"username", configData.Username.Value},
|
||||
{"password", configData.Password.Value},
|
||||
{"keeplogged", "1"},
|
||||
{"login", "Login"}
|
||||
};
|
||||
{
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value },
|
||||
{ "code", configData.TwoFactorAuth.Value },
|
||||
{ "keeplogged", "1" },
|
||||
{ "login", "Login" }
|
||||
};
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SearchUrl, LandingUrl, true);
|
||||
await ConfigureIfOK(result.Cookies, result.ContentString?.Contains("logout.php") == true,
|
||||
() =>
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(result.ContentString);
|
||||
var warningNode = dom.QuerySelector("#loginform > .warning");
|
||||
var errorMessage = warningNode?.TextContent.Trim().Replace("\n\t", " ");
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
});
|
||||
await ConfigureIfOK(result.Cookies, result.ContentString?.Contains("logout.php") == true, () =>
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(result.ContentString);
|
||||
var errorMessage = dom.QuerySelector("#loginform > .warning")?.TextContent.Trim();
|
||||
|
||||
throw new Exception(errorMessage ?? "Login failed.");
|
||||
});
|
||||
|
||||
SaveConfig();
|
||||
|
||||
@@ -126,61 +124,64 @@ namespace Jackett.Common.Indexers
|
||||
var searchString = query.GetQueryString();
|
||||
var searchUrl = SearchUrl;
|
||||
|
||||
var searchParams = new Dictionary<string, string> { };
|
||||
var queryCollection = new NameValueCollection { };
|
||||
var queryCollection = new NameValueCollection
|
||||
{
|
||||
{ "order_by", "time" },
|
||||
{ "order_way", "desc" }
|
||||
};
|
||||
|
||||
// Search String
|
||||
if (!string.IsNullOrWhiteSpace(query.ImdbID))
|
||||
queryCollection.Add("cataloguenumber", query.ImdbID);
|
||||
queryCollection.Set("cataloguenumber", query.ImdbID);
|
||||
else if (!string.IsNullOrWhiteSpace(searchString))
|
||||
queryCollection.Add("searchstr", searchString);
|
||||
|
||||
queryCollection.Set("searchstr", searchString);
|
||||
|
||||
// Filter Categories
|
||||
if (query.HasSpecifiedCategories)
|
||||
{
|
||||
foreach (var cat in MapTorznabCapsToTrackers(query))
|
||||
{
|
||||
queryCollection.Add("filter_cat[" + cat.ToString() + "]", "1");
|
||||
}
|
||||
}
|
||||
queryCollection.Set($"filter_cat[{cat}]", "1");
|
||||
|
||||
if (query.Artist != null)
|
||||
queryCollection.Add("artistname", query.Artist);
|
||||
queryCollection.Set("artistname", query.Artist);
|
||||
|
||||
if (query.Label != null)
|
||||
queryCollection.Add("recordlabel", query.Label);
|
||||
queryCollection.Set("recordlabel", query.Label);
|
||||
|
||||
if (query.Year != null)
|
||||
queryCollection.Add("year", query.Year.ToString());
|
||||
queryCollection.Set("year", query.Year.ToString());
|
||||
|
||||
if (query.Album != null)
|
||||
queryCollection.Add("groupname", query.Album);
|
||||
queryCollection.Set("groupname", query.Album);
|
||||
|
||||
if (query.IsGenreQuery)
|
||||
queryCollection.Add("taglist", query.Genre);
|
||||
{
|
||||
queryCollection.Set("taglist", query.Genre);
|
||||
queryCollection.Set("tags_type", "0");
|
||||
}
|
||||
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
var searchPage = await RequestWithCookiesAndRetryAsync(searchUrl, method: RequestType.POST, data: searchParams);
|
||||
var searchPage = await RequestWithCookiesAndRetryAsync(searchUrl);
|
||||
|
||||
// Occasionally the cookies become invalid, login again if that happens
|
||||
if (searchPage.IsRedirect)
|
||||
{
|
||||
await ApplyConfiguration(null);
|
||||
searchPage = await RequestWithCookiesAndRetryAsync(searchUrl, method: RequestType.POST, data: searchParams);
|
||||
searchPage = await RequestWithCookiesAndRetryAsync(searchUrl);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(searchPage.ContentString);
|
||||
var albumRows = dom.QuerySelectorAll("table#torrent_table > tbody > tr:has(strong > a[href*=\"torrents.php?id=\"])");
|
||||
|
||||
var albumRows = dom.QuerySelectorAll("table#torrent_table > tbody > tr.group:has(strong > a[href*=\"torrents.php?id=\"])");
|
||||
foreach (var row in albumRows)
|
||||
{
|
||||
var releaseGroupRegex = new Regex(@"torrents\.php\?id=([0-9]+)");
|
||||
var releaseYearRegex = new Regex(@"\[(\d{4})\]$");
|
||||
|
||||
var albumNameNode = row.QuerySelector("strong > a[href*=\"torrents.php?id=\"]");
|
||||
var albumNameNode = row.QuerySelector("strong > a[href^=\"torrents.php?id=\"]");
|
||||
var artistsNameNodes = row.QuerySelectorAll("strong > a[href*=\"artist.php?id=\"]");
|
||||
var albumYearNode = row.QuerySelector("strong:has(a[href*=\"torrents.php?id=\"])");
|
||||
var categoryNode = row.QuerySelector(".cats_col > div");
|
||||
@@ -196,15 +197,8 @@ namespace Jackett.Common.Indexers
|
||||
}
|
||||
|
||||
var releaseArtist = "Various Artists";
|
||||
if (artistsNameNodes.Count() > 0)
|
||||
{
|
||||
var aristNames = new List<string>();
|
||||
foreach (var aristNode in artistsNameNodes)
|
||||
{
|
||||
aristNames.Add(aristNode.TextContent.Trim());
|
||||
}
|
||||
releaseArtist = string.Join(", ", aristNames);
|
||||
}
|
||||
if (artistsNameNodes.Any())
|
||||
releaseArtist = string.Join(", ", artistsNameNodes.Select(artist => artist.TextContent.Trim()).ToList());
|
||||
|
||||
var releaseAlbumName = albumNameNode.TextContent.Trim();
|
||||
var releaseGroupId = ParseUtil.CoerceInt(releaseGroupRegex.Match(albumNameNode.GetAttribute("href")).Groups[1].ToString());
|
||||
@@ -226,86 +220,63 @@ namespace Jackett.Common.Indexers
|
||||
}
|
||||
}
|
||||
|
||||
var releaseRows = dom.QuerySelectorAll(String.Format(".group_torrent.groupid_{0}", releaseGroupId));
|
||||
|
||||
string lastEdition = null;
|
||||
var releaseRows = dom.QuerySelectorAll($"table#torrent_table > tbody > tr.group_torrent.groupid_{releaseGroupId}:has(a[href*=\"torrents.php?id=\"])");
|
||||
foreach (var releaseDetails in releaseRows)
|
||||
{
|
||||
var editionInfoDetails = releaseDetails.QuerySelector(".edition_info");
|
||||
// https://libble.me/torrents.php?id=51694&torrentid=89758
|
||||
var release = new ReleaseInfo();
|
||||
|
||||
// Process as release details
|
||||
if (editionInfoDetails != null)
|
||||
var releaseMediaDetails = releaseDetails.Children[0].Children[1];
|
||||
var releaseMediaType = releaseMediaDetails.TextContent;
|
||||
|
||||
release.Link = new Uri(SiteLink + releaseDetails.QuerySelector("a[href^=\"torrents.php?action=download&id=\"]").GetAttribute("href"));
|
||||
release.Guid = release.Link;
|
||||
release.Details = new Uri(SiteLink + albumNameNode.GetAttribute("href"));
|
||||
|
||||
// Aug 31 2020, 15:50
|
||||
try
|
||||
{
|
||||
lastEdition = editionInfoDetails.QuerySelector("strong").TextContent;
|
||||
var dateAdded = releaseDetails.QuerySelector("td:nth-child(3) > span[title]").GetAttribute("title").Trim();
|
||||
release.PublishDate = DateTime.ParseExact(dateAdded, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
}
|
||||
// Process as torrent
|
||||
else
|
||||
catch (Exception)
|
||||
{
|
||||
// https://libble.me/torrents.php?id=51694&torrentid=89758
|
||||
var release = new ReleaseInfo();
|
||||
|
||||
var releaseMediaDetails = releaseDetails.Children[0].Children[1];
|
||||
var releaseFileCountDetails = releaseDetails.Children[1];
|
||||
var releaseDateDetails = releaseDetails.Children[2].Children[0];
|
||||
var releaseSizeDetails = releaseDetails.Children[3];
|
||||
var releaseGrabsDetails = releaseDetails.Children[4];
|
||||
var releaseSeedsCountDetails = releaseDetails.Children[5];
|
||||
var releasePeersCountDetails = releaseDetails.Children[6];
|
||||
var releaseDownloadDetails = releaseDetails.QuerySelector("a[href*=\"action=download\"]");
|
||||
var releaseMediaType = releaseMediaDetails.TextContent;
|
||||
|
||||
release.Link = new Uri(SiteLink + releaseDownloadDetails.GetAttribute("href"));
|
||||
release.Guid = release.Link;
|
||||
release.Details = new Uri(SiteLink + albumNameNode.GetAttribute("href"));
|
||||
|
||||
// Aug 31 2020, 15:50
|
||||
try
|
||||
{
|
||||
release.PublishDate = DateTime.ParseExact(
|
||||
releaseDateDetails.GetAttribute("title").Trim(),
|
||||
"MMM dd yyyy, HH:mm",
|
||||
CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.AssumeUniversal
|
||||
);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
release.Files = ParseUtil.CoerceInt(releaseFileCountDetails.TextContent.Trim());
|
||||
release.Grabs = ParseUtil.CoerceInt(releaseGrabsDetails.TextContent.Trim());
|
||||
release.Seeders = ParseUtil.CoerceInt(releaseSeedsCountDetails.TextContent.Trim());
|
||||
release.Peers = release.Seeders + ParseUtil.CoerceInt(releasePeersCountDetails.TextContent.Trim());
|
||||
release.Size = ReleaseInfo.GetBytes(releaseSizeDetails.TextContent.Trim());
|
||||
release.Poster = releaseThumbnailUri;
|
||||
release.Category = releaseNewznabCategory;
|
||||
release.MinimumSeedTime = 259200; // 72 hours
|
||||
|
||||
// Attempt to find volume factor tag
|
||||
release.DownloadVolumeFactor = 1;
|
||||
release.UploadVolumeFactor = 1;
|
||||
var releaseTags = releaseMediaType.Split('/').Select(tag => tag.Trim()).ToList();
|
||||
for (var i = releaseTags.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var releaseTag = releaseTags[i];
|
||||
if (VolumeTagMappings.ContainsKey(releaseTag))
|
||||
{
|
||||
var volumeFactor = VolumeTagMappings[releaseTag];
|
||||
release.DownloadVolumeFactor = volumeFactor.DownloadVolumeFactor;
|
||||
release.UploadVolumeFactor = volumeFactor.UploadVolumeFactor;
|
||||
releaseTags.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Set title (with volume factor tags stripped)
|
||||
var releaseTagsString = string.Join(" / ", releaseTags);
|
||||
release.Title = String.Format("{0} - {1} {2} {3}", releaseArtist, releaseAlbumName, releaseAlbumYear, releaseTagsString);
|
||||
|
||||
release.Description = releaseDescription;
|
||||
release.Genres = releaseGenres;
|
||||
|
||||
releases.Add(release);
|
||||
release.PublishDate = DateTimeUtil.FromTimeAgo(releaseDetails.QuerySelector("td:nth-child(3)")?.TextContent.Trim());
|
||||
}
|
||||
|
||||
release.Files = ParseUtil.CoerceInt(releaseDetails.QuerySelector("td:nth-child(2)").TextContent);
|
||||
release.Grabs = ParseUtil.CoerceInt(releaseDetails.QuerySelector("td:nth-child(5)").TextContent);
|
||||
release.Seeders = ParseUtil.CoerceInt(releaseDetails.QuerySelector("td:nth-child(6)").TextContent);
|
||||
release.Peers = release.Seeders + ParseUtil.CoerceInt(releaseDetails.QuerySelector("td:nth-child(7)").TextContent);
|
||||
release.Size = ReleaseInfo.GetBytes(releaseDetails.QuerySelector("td:nth-child(4)").TextContent.Trim());
|
||||
release.Poster = releaseThumbnailUri;
|
||||
release.Category = releaseNewznabCategory;
|
||||
release.MinimumSeedTime = 259200; // 72 hours
|
||||
|
||||
// Attempt to find volume factor tag
|
||||
release.DownloadVolumeFactor = 1;
|
||||
release.UploadVolumeFactor = 1;
|
||||
var releaseTags = releaseMediaType.Split('/').Select(tag => tag.Trim()).ToList();
|
||||
for (var i = releaseTags.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var releaseTag = releaseTags[i];
|
||||
if (VolumeTagMappings.ContainsKey(releaseTag))
|
||||
{
|
||||
var volumeFactor = VolumeTagMappings[releaseTag];
|
||||
release.DownloadVolumeFactor = volumeFactor.DownloadVolumeFactor;
|
||||
release.UploadVolumeFactor = volumeFactor.UploadVolumeFactor;
|
||||
releaseTags.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Set title (with volume factor tags stripped)
|
||||
var releaseTagsString = string.Join(" / ", releaseTags);
|
||||
release.Title = $"{releaseArtist} - {releaseAlbumName} {releaseAlbumYear} {releaseTagsString}".Trim(' ', '-');
|
||||
|
||||
release.Description = releaseDescription;
|
||||
release.Genres = releaseGenres;
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -421,10 +421,12 @@ namespace Jackett.Common.Indexers
|
||||
// Eg. Doctor.Who.2005.(Доктор.Кто).S02E08
|
||||
|
||||
// the season/episode part is already parsed by Jackett
|
||||
// query.GetQueryString = Doctor.Who.2005.(Доктор.Кто).
|
||||
// query.GetQueryString = Doctor.Who.2005.(Доктор.Кто).S02E08
|
||||
// query.Season = 2
|
||||
// query.Episode = 8
|
||||
var searchTerm = query.GetQueryString();
|
||||
// remove the season/episode from the query as MejorTorrent only wants the series name
|
||||
searchTerm = Regex.Replace(searchTerm, @"[S|s]\d+[E|e]\d+", "");
|
||||
|
||||
// Server returns a 500 error if a UTF character higher than \u00FF (ÿ) is included,
|
||||
// so we need to strip them
|
||||
|
@@ -5,13 +5,13 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.IndexerConfig.Bespoke;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Jackett.Common.Utils.Clients;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
|
||||
@@ -169,26 +169,32 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var limit = query.Limit > 0 ? query.Limit : 100;
|
||||
var offset = query.Offset > 0 ? query.Offset : 0;
|
||||
|
||||
var qParams = new NameValueCollection
|
||||
{
|
||||
{"tor[text]", query.GetQueryString()},
|
||||
{"tor[searchType]", configData.SearchType.Value},
|
||||
{"tor[srchIn][title]", "true"},
|
||||
{"tor[srchIn][author]", "true"},
|
||||
{"tor[searchType]", configData.ExcludeVip?.Value == true ? "nVIP" : "all"}, // exclude VIP torrents
|
||||
{"tor[srchIn][narrator]", "true"},
|
||||
{"tor[searchIn]", "torrents"},
|
||||
{"tor[hash]", ""},
|
||||
{"tor[sortType]", "default"},
|
||||
{"tor[startNumber]", "0"},
|
||||
{"tor[perpage]", limit.ToString()},
|
||||
{"tor[startNumber]", offset.ToString()},
|
||||
{"thumbnails", "1"}, // gives links for thumbnail sized versions of their posters
|
||||
//{ "posterLink", "1"}, // gives links for a full sized poster
|
||||
//{ "dlLink", "1"}, // include the url to download the torrent
|
||||
{"description", "1"} // include the description
|
||||
//{"bookmarks", "0"} // include if the item is bookmarked or not
|
||||
};
|
||||
|
||||
// Exclude VIP torrents
|
||||
if (configData.SearchInDescription.Value)
|
||||
qParams.Add("tor[srchIn][description]", "true");
|
||||
|
||||
if (configData.SearchInSeries.Value)
|
||||
qParams.Add("tor[srchIn][series]", "true");
|
||||
|
||||
if (configData.SearchInFilenames.Value)
|
||||
qParams.Add("tor[srchIn][filenames]", "true");
|
||||
|
||||
var catList = MapTorznabCapsToTrackers(query);
|
||||
if (catList.Any())
|
||||
@@ -207,10 +213,17 @@ namespace Jackett.Common.Indexers
|
||||
if (qParams.Count > 0)
|
||||
urlSearch += $"?{qParams.GetQueryString()}";
|
||||
|
||||
var response = await RequestWithCookiesAndRetryAsync(urlSearch);
|
||||
var response = await RequestWithCookiesAndRetryAsync(
|
||||
urlSearch,
|
||||
headers: new Dictionary<string, string>
|
||||
{
|
||||
{"Accept", "application/json"}
|
||||
});
|
||||
if (response.ContentString.StartsWith("Error"))
|
||||
throw new Exception(response.ContentString);
|
||||
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
try
|
||||
{
|
||||
var jsonContent = JObject.Parse(response.ContentString);
|
||||
@@ -222,30 +235,46 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
foreach (var item in jsonContent.Value<JArray>("data"))
|
||||
{
|
||||
//TODO shift to ReleaseInfo object initializer for consistency
|
||||
var release = new ReleaseInfo();
|
||||
|
||||
var id = item.Value<long>("id");
|
||||
release.Title = item.Value<string>("title");
|
||||
var link = new Uri(sitelink, "/tor/download.php?tid=" + id);
|
||||
var details = new Uri(sitelink, "/t/" + id);
|
||||
|
||||
release.Description = item.Value<string>("description");
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
Guid = details,
|
||||
Title = item.Value<string>("title").Trim(),
|
||||
Description = item.Value<string>("description").Trim(),
|
||||
Link = link,
|
||||
Details = details,
|
||||
Category = MapTrackerCatToNewznab(item.Value<string>("category")),
|
||||
PublishDate = DateTime.ParseExact(item.Value<string>("added"), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(),
|
||||
Grabs = item.Value<long>("times_completed"),
|
||||
Files = item.Value<long>("numfiles"),
|
||||
Seeders = item.Value<int>("seeders"),
|
||||
Peers = item.Value<int>("seeders") + item.Value<int>("leechers"),
|
||||
Size = ReleaseInfo.GetBytes(item.Value<string>("size")),
|
||||
DownloadVolumeFactor = item.Value<bool>("free") ? 0 : 1,
|
||||
UploadVolumeFactor = 1,
|
||||
|
||||
// MinimumRatio = 1, // global MR is 1.0 but torrents must be seeded for 3 days regardless of ratio
|
||||
MinimumSeedTime = 259200 // 72 hours
|
||||
};
|
||||
|
||||
var authorInfo = item.Value<string>("author_info");
|
||||
string author = null;
|
||||
if (!string.IsNullOrWhiteSpace(authorInfo))
|
||||
if (authorInfo != null)
|
||||
try
|
||||
{
|
||||
authorInfo = Regex.Unescape(authorInfo);
|
||||
var authorInfoJson = JObject.Parse(authorInfo);
|
||||
author = authorInfoJson.First.Last.Value<string>();
|
||||
var authorInfoList = JsonConvert.DeserializeObject<Dictionary<string, string>>(authorInfo);
|
||||
var author = authorInfoList?.Take(5).Select(v => v.Value).ToList();
|
||||
|
||||
if (author != null && author.Any())
|
||||
release.Title += " by " + string.Join(", ", author);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// the JSON on author_info field can be malformed due to double quotes
|
||||
logger.Warn($"{DisplayName} error parsing author_info: {authorInfo}");
|
||||
}
|
||||
if (author != null)
|
||||
release.Title += " by " + author;
|
||||
|
||||
var flags = new List<string>();
|
||||
|
||||
@@ -255,38 +284,14 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
var filetype = item.Value<string>("filetype");
|
||||
if (!string.IsNullOrEmpty(filetype))
|
||||
flags.Add(filetype);
|
||||
flags.Add(filetype.ToUpper());
|
||||
|
||||
if (flags.Count > 0)
|
||||
release.Title += " [" + string.Join(" / ", flags) + "]";
|
||||
|
||||
if (item.Value<int>("vip") == 1)
|
||||
if (item.Value<bool>("vip"))
|
||||
release.Title += " [VIP]";
|
||||
|
||||
var category = item.Value<string>("category");
|
||||
release.Category = MapTrackerCatToNewznab(category);
|
||||
|
||||
release.Link = new Uri(sitelink, "/tor/download.php?tid=" + id);
|
||||
release.Details = new Uri(sitelink, "/t/" + id);
|
||||
release.Guid = release.Details;
|
||||
|
||||
var dateStr = item.Value<string>("added");
|
||||
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||||
release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime();
|
||||
|
||||
release.Grabs = item.Value<long>("times_completed");
|
||||
release.Files = item.Value<long>("numfiles");
|
||||
release.Seeders = item.Value<int>("seeders");
|
||||
release.Peers = item.Value<int>("leechers") + release.Seeders;
|
||||
var size = item.Value<string>("size");
|
||||
release.Size = ReleaseInfo.GetBytes(size);
|
||||
|
||||
release.DownloadVolumeFactor = item.Value<int>("free") == 1 ? 0 : 1;
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
// release.MinimumRatio = 1; // global MR is 1.0 but torrents must be seeded for 3 days regardless of ratio
|
||||
release.MinimumSeedTime = 259200; // 72 hours
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
|
@@ -103,12 +103,14 @@ namespace Jackett.Common.Indexers
|
||||
request["method"] = method;
|
||||
request["params"] = parameters;
|
||||
request["id"] = Guid.NewGuid().ToString().Substring(0, 8);
|
||||
|
||||
return request.ToString();
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var ValidList = new List<string>() {
|
||||
var validList = new List<string>
|
||||
{
|
||||
"action",
|
||||
"adventure",
|
||||
"children",
|
||||
@@ -138,7 +140,8 @@ namespace Jackett.Common.Indexers
|
||||
"war",
|
||||
"western"
|
||||
};
|
||||
var ValidCats = new List<string>() {
|
||||
var validCats = new List<string>
|
||||
{
|
||||
"sd",
|
||||
"hd",
|
||||
"uhd",
|
||||
@@ -150,17 +153,15 @@ namespace Jackett.Common.Indexers
|
||||
"2160p"
|
||||
};
|
||||
|
||||
var searchParam = new JObject();
|
||||
var searchString = query.GetQueryString();
|
||||
var searchParam = new JObject
|
||||
{
|
||||
["age"] = ">0"
|
||||
};
|
||||
|
||||
var searchString = query.GetQueryString();
|
||||
if (!string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
searchParam["name"] = "%" + Regex.Replace(searchString, @"[ -._]", "%").Trim() + "%";
|
||||
}
|
||||
else
|
||||
{
|
||||
searchParam["name"] = "%";
|
||||
}
|
||||
searchParam["name"] = "%" + Regex.Replace(searchString, @"[ -._]+", "%").Trim() + "%";
|
||||
|
||||
if (query.IsGenreQuery)
|
||||
{
|
||||
var genre = new JArray
|
||||
@@ -169,11 +170,11 @@ namespace Jackett.Common.Indexers
|
||||
};
|
||||
searchParam["tags"] = genre;
|
||||
}
|
||||
|
||||
var limit = query.Limit;
|
||||
if (limit == 0)
|
||||
limit = (int)TorznabCaps.LimitsDefault;
|
||||
var offset = query.Offset;
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
var parameters = new JArray
|
||||
{
|
||||
@@ -192,47 +193,56 @@ namespace Jackett.Common.Indexers
|
||||
}, rawbody: JsonRPCRequest("getTorrents", parameters), emulateBrowser: false);
|
||||
|
||||
if (response.ContentString != null && response.ContentString.Contains("Invalid params"))
|
||||
throw new Exception($"Invalid API Key configured");
|
||||
throw new Exception("Invalid API Key configured");
|
||||
|
||||
char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' };
|
||||
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
try
|
||||
{
|
||||
var json = JObject.Parse(response.ContentString);
|
||||
foreach (var r in json["result"]["items"].Cast<JObject>())
|
||||
var jsonContent = JObject.Parse(response.ContentString);
|
||||
|
||||
foreach (var item in jsonContent.Value<JObject>("result").Value<JArray>("items"))
|
||||
{
|
||||
var link = new Uri(item.Value<string>("download"));
|
||||
var details = new Uri($"{SiteLink}torrents.php?id={item.Value<string>("group_id")}");
|
||||
|
||||
var descriptions = new List<string>();
|
||||
if (!string.IsNullOrWhiteSpace((string)r["group_name"]))
|
||||
descriptions.Add("Group Name: " + (string)r["group_name"]);
|
||||
var link = new Uri((string)r["download"]);
|
||||
var details = new Uri($"{SiteLink}torrents.php?id={(string)r["group_id"]}");
|
||||
var publishDate = DateTime.ParseExact((string)r["rls_utc"] + " +00:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture);
|
||||
var tags = string.Join(",", r["tags"]);
|
||||
char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' };
|
||||
var releaseGenres = ValidList.Intersect(tags.ToLower().Split(delimiters, System.StringSplitOptions.RemoveEmptyEntries)).ToList();
|
||||
if (!string.IsNullOrWhiteSpace(item.Value<string>("group_name")))
|
||||
descriptions.Add("Group Name: " + item.Value<string>("group_name"));
|
||||
var tags = string.Join(",", item.Value<JArray>("tags"));
|
||||
var releaseGenres = validList.Intersect(tags.ToLower().Split(delimiters, StringSplitOptions.RemoveEmptyEntries)).ToList();
|
||||
descriptions.Add("Tags: " + string.Join(",", releaseGenres));
|
||||
var releaseCats = ValidCats.Intersect(tags.ToLower().Split(delimiters, System.StringSplitOptions.RemoveEmptyEntries)).ToList();
|
||||
var releaseCats = validCats.Intersect(tags.ToLower().Split(delimiters, StringSplitOptions.RemoveEmptyEntries)).ToList();
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
Title = (string)r["rls_name"],
|
||||
Category = MapTrackerCatToNewznab(releaseCats.Any() ? releaseCats.First() : "TV"),
|
||||
Details = details,
|
||||
Guid = link,
|
||||
Link = link,
|
||||
PublishDate = publishDate,
|
||||
Seeders = (int)r["seed"],
|
||||
Peers = (int)r["seed"] + (int)r["leech"],
|
||||
Size = (long)r["size"],
|
||||
Grabs = (int)r["snatch"],
|
||||
UploadVolumeFactor = 1,
|
||||
Details = details,
|
||||
Title = item.Value<string>("rls_name").Trim(),
|
||||
Category = MapTrackerCatToNewznab(releaseCats.Any() ? releaseCats.First() : "TV"),
|
||||
PublishDate = DateTime.Parse(item.Value<string>("rls_utc"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal),
|
||||
Seeders = item.Value<int>("seed"),
|
||||
Peers = item.Value<int>("seed") + item.Value<int>("leech"),
|
||||
Size = item.Value<long>("size"),
|
||||
Files = item.Value<JArray>("file_list").Count,
|
||||
Grabs = item.Value<int>("snatch"),
|
||||
DownloadVolumeFactor = 0, // ratioless
|
||||
UploadVolumeFactor = 1,
|
||||
MinimumRatio = 0, // ratioless
|
||||
MinimumSeedTime = 86400, // 24 hours
|
||||
MinimumSeedTime = item.Value<string>("cat").ToLower() == "season" ? 432000 : 86400, // 120 hours for seasons and 24 hours for episodes
|
||||
Description = string.Join("<br />\n", descriptions)
|
||||
};
|
||||
|
||||
if (release.Genres == null)
|
||||
release.Genres = new List<string>();
|
||||
release.Genres = releaseGenres;
|
||||
var banner = (string)r["series_banner"];
|
||||
if ((!string.IsNullOrEmpty(banner)) && (!banner.Contains("noimage.png")))
|
||||
release.Poster = new Uri((string)r["series_banner"]);
|
||||
|
||||
var banner = item.Value<string>("series_banner");
|
||||
if (!string.IsNullOrEmpty(banner) && !banner.Contains("noimage.png"))
|
||||
release.Poster = new Uri(banner);
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
@@ -241,6 +251,7 @@ namespace Jackett.Common.Indexers
|
||||
{
|
||||
OnParseError(response.ContentString, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
|
@@ -27,8 +27,6 @@ namespace Jackett.Common.Indexers
|
||||
private string LoginUrl => SiteLink + "login.php";
|
||||
private string LoginCheckUrl => SiteLink + "takelogin.php";
|
||||
private string SearchUrl => SiteLink + "browse.php";
|
||||
private string TorrentDetailsUrl => SiteLink + "details.php?id={id}";
|
||||
private string TorrentDownloadUrl => SiteLink + "download.php?id={id}&passkey={passkey}";
|
||||
|
||||
private ConfigurationDataNorbits ConfigData => (ConfigurationDataNorbits)configData;
|
||||
|
||||
@@ -218,14 +216,14 @@ namespace Jackett.Common.Indexers
|
||||
// Check login before performing a query
|
||||
await CheckLoginAsync();
|
||||
|
||||
var SearchTerms = new List<string> { exactSearchTerm };
|
||||
var searchTerms = new List<string> { exactSearchTerm };
|
||||
|
||||
// duplicate search without diacritics
|
||||
var baseSearchTerm = StringUtil.RemoveDiacritics(exactSearchTerm);
|
||||
if (baseSearchTerm != exactSearchTerm)
|
||||
SearchTerms.Add(baseSearchTerm);
|
||||
searchTerms.Add(baseSearchTerm);
|
||||
|
||||
foreach (var searchTerm in SearchTerms)
|
||||
foreach (var searchTerm in searchTerms)
|
||||
{
|
||||
// Build our query
|
||||
var request = BuildQuery(searchTerm, query, searchUrl);
|
||||
@@ -259,49 +257,38 @@ namespace Jackett.Common.Indexers
|
||||
logger.Info("\nNorBits - Found " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !");
|
||||
logger.Info("\nNorBits - There are " + firstPageRows.Length + " results on the first page !");
|
||||
|
||||
// Loop on results
|
||||
|
||||
foreach (var row in firstPageRows)
|
||||
{
|
||||
var id = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("href").Split('=').Last(); // ID
|
||||
var name = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("title"); // Release Name
|
||||
var categoryName = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("title"); // Category
|
||||
var mainCat = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("href").Split('?').Last();
|
||||
var qSubCat2 = row.QuerySelector("td:nth-of-type(1) > div > a[href^=\"/browse.php?sub2_cat[]=\"]");
|
||||
var cat = mainCat;
|
||||
if (qSubCat2 != null)
|
||||
cat += '&' + qSubCat2.GetAttribute("href").Split('?').Last();
|
||||
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent); // Seeders
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent); // Leechers
|
||||
var regexObj = new Regex(@"[^\d]"); // Completed
|
||||
var completed2 = row.QuerySelector("td:nth-of-type(8)").TextContent;
|
||||
var completed = ParseUtil.CoerceLong(regexObj.Replace(completed2, ""));
|
||||
var qFiles = row.QuerySelector("td:nth-of-type(3) > a"); // Files
|
||||
var files = qFiles != null ? ParseUtil.CoerceInt(Regex.Match(qFiles.TextContent, @"\d+").Value) : 1;
|
||||
var humanSize = row.QuerySelector("td:nth-of-type(7)").TextContent.ToLowerInvariant(); // Size
|
||||
var size = ReleaseInfo.GetBytes(humanSize); // Date
|
||||
var dateTimeOrig = row.QuerySelector("td:nth-of-type(5)").TextContent;
|
||||
var dateTime = Regex.Replace(dateTimeOrig, @"<[^>]+>| ", "").Trim();
|
||||
var date = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime();
|
||||
var details = new Uri(TorrentDetailsUrl.Replace("{id}", id.ToString())); // Description Link
|
||||
var passkey = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(2)").GetAttribute("href"); // Download Link
|
||||
var key = Regex.Match(passkey, "(?<=passkey\\=)([a-zA-z0-9]*)");
|
||||
var downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{passkey}", key.ToString()));
|
||||
var link = new Uri(SiteLink + row.QuerySelector("td:nth-of-type(2) > a[href*=\"download.php?id=\"]")?.GetAttribute("href").TrimStart('/'));
|
||||
var qDetails = row.QuerySelector("td:nth-of-type(2) > a[href*=\"details.php?id=\"]");
|
||||
|
||||
var title = qDetails?.GetAttribute("title").Trim();
|
||||
var details = new Uri(SiteLink + qDetails?.GetAttribute("href").TrimStart('/'));
|
||||
|
||||
var mainCategory = row.QuerySelector("td:nth-of-type(1) > div > a[href*=\"main_cat[]\"]")?.GetAttribute("href")?.Split('?').Last();
|
||||
var secondCategory = row.QuerySelector("td:nth-of-type(1) > div > a[href*=\"sub2_cat[]\"]")?.GetAttribute("href")?.Split('?').Last();
|
||||
|
||||
var categoryList = new[] { mainCategory, secondCategory };
|
||||
var cat = string.Join("&", categoryList.Where(c => !string.IsNullOrWhiteSpace(c)));
|
||||
|
||||
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent);
|
||||
|
||||
// Building release infos
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
Category = MapTrackerCatToNewznab(cat),
|
||||
Title = name,
|
||||
Seeders = seeders,
|
||||
Peers = seeders + leechers,
|
||||
PublishDate = date,
|
||||
Size = size,
|
||||
Files = files,
|
||||
Grabs = completed,
|
||||
Guid = details,
|
||||
Details = details,
|
||||
Link = downloadLink,
|
||||
Link = link,
|
||||
Title = title,
|
||||
Category = MapTrackerCatToNewznab(cat),
|
||||
Size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-of-type(7)").TextContent),
|
||||
Files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(3) > a")?.TextContent.Trim()),
|
||||
Grabs = ParseUtil.CoerceLong(row.QuerySelector("td:nth-of-type(8)")?.FirstChild?.TextContent.Trim()),
|
||||
Seeders = seeders,
|
||||
Peers = seeders + leechers,
|
||||
PublishDate = DateTime.ParseExact(row.QuerySelector("td:nth-of-type(5)")?.TextContent.Trim(), "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture),
|
||||
DownloadVolumeFactor = 1,
|
||||
UploadVolumeFactor = 1,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 172800 // 48 hours
|
||||
};
|
||||
@@ -311,8 +298,7 @@ namespace Jackett.Common.Indexers
|
||||
{
|
||||
genres = genres.Trim().Replace("\xA0", " ").Replace("(", "").Replace(")", "").Replace(" | ", ",");
|
||||
release.Description = genres;
|
||||
if (release.Genres == null)
|
||||
release.Genres = new List<string>();
|
||||
release.Genres ??= new List<string>();
|
||||
release.Genres = release.Genres.Union(genres.Split(',')).ToList();
|
||||
}
|
||||
|
||||
@@ -326,10 +312,6 @@ namespace Jackett.Common.Indexers
|
||||
release.DownloadVolumeFactor = 0.5;
|
||||
else if (row.QuerySelector("img[title=\"90% Freeleech\"]") != null)
|
||||
release.DownloadVolumeFactor = 0.1;
|
||||
else
|
||||
release.DownloadVolumeFactor = 1;
|
||||
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
@@ -348,29 +330,26 @@ namespace Jackett.Common.Indexers
|
||||
/// </summary>
|
||||
/// <param name="term">Term to search</param>
|
||||
/// <param name="query">Torznab Query for categories mapping</param>
|
||||
/// <param name="url">Search url for provider</param>
|
||||
/// <param name="searchUrl">Search url for provider</param>
|
||||
/// <param name="page">Page number to request</param>
|
||||
/// <returns>URL to query for parsing and processing results</returns>
|
||||
private string BuildQuery(string term, TorznabQuery query, string url, int page = 0)
|
||||
private string BuildQuery(string term, TorznabQuery query, string searchUrl, int page = 0)
|
||||
{
|
||||
var parameters = new NameValueCollection();
|
||||
var categoriesList = MapTorznabCapsToTrackers(query);
|
||||
var searchterm = term;
|
||||
|
||||
// Building our tracker query
|
||||
parameters.Add("incldead", "1");
|
||||
parameters.Add("fullsearch", ConfigData.UseFullSearch.Value ? "1" : "0");
|
||||
parameters.Add("scenerelease", "0");
|
||||
var parameters = new NameValueCollection
|
||||
{
|
||||
{ "incldead", "1" },
|
||||
{ "fullsearch", ConfigData.UseFullSearch.Value ? "1" : "0" },
|
||||
{ "scenerelease", "0" }
|
||||
};
|
||||
|
||||
// If search term provided
|
||||
if (!string.IsNullOrWhiteSpace(query.ImdbID))
|
||||
{
|
||||
searchterm = "imdbsearch=" + query.ImdbID;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(term))
|
||||
{
|
||||
searchterm = "search=" + WebUtilityHelpers.UrlEncode(term, Encoding.GetEncoding(28591));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Showing all torrents (just for output function)
|
||||
@@ -378,17 +357,16 @@ namespace Jackett.Common.Indexers
|
||||
term = "all";
|
||||
}
|
||||
|
||||
var CatQryStr = "";
|
||||
foreach (var cat in categoriesList)
|
||||
CatQryStr += "&" + cat;
|
||||
|
||||
// Building our query
|
||||
url += "?" + searchterm + "&" + parameters.GetQueryString() + "&" + CatQryStr;
|
||||
searchUrl += "?" + searchterm + "&" + parameters.GetQueryString();
|
||||
|
||||
logger.Info("\nBuilded query for \"" + term + "\"... " + url);
|
||||
var categoriesList = MapTorznabCapsToTrackers(query);
|
||||
if (categoriesList.Any())
|
||||
searchUrl += "&" + string.Join("&", categoriesList);
|
||||
|
||||
// Return our search url
|
||||
return url;
|
||||
logger.Info("\nBuilded query for \"" + term + "\"... " + searchUrl);
|
||||
|
||||
return searchUrl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -175,7 +175,8 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
// get results and follow redirect
|
||||
results = await RequestWithCookiesAsync(searchUrl, referer: SearchUrl, headers: header);
|
||||
|
||||
if (results.ContentString.Contains("Internal server error"))
|
||||
throw new Exception("Partis is offline, returning an Internal server error");
|
||||
// parse results
|
||||
try
|
||||
{
|
||||
|
@@ -24,7 +24,7 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
protected string cap_sid = null;
|
||||
protected string cap_code_field = null;
|
||||
private static readonly Regex s_StripRussianRegex = new Regex(@"(\([А-Яа-яЁё\W]+\))|(^[А-Яа-яЁё\W\d]+\/ )|([а-яА-ЯЁё \-]+,+)|([а-яА-ЯЁё]+)");
|
||||
private static readonly Regex s_StripRussianRegex = new Regex(@"(\([\p{IsCyrillic}\W]+\))|(^[\p{IsCyrillic}\W\d]+\/ )|([\p{IsCyrillic} \-]+,+)|([\p{IsCyrillic}]+)");
|
||||
|
||||
private new ConfigurationDataPornolab configData
|
||||
{
|
||||
@@ -238,11 +238,13 @@ namespace Jackett.Common.Indexers
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, CookieHeader, true, null, LoginUrl, true);
|
||||
await ConfigureIfOK(result.Cookies, result.ContentString != null && result.ContentString.Contains("Вы зашли как:"), () =>
|
||||
{
|
||||
logger.Debug(result.ContentString);
|
||||
var errorMessage = "Unknown error message, please report";
|
||||
var LoginResultParser = new HtmlParser();
|
||||
var LoginResultDocument = LoginResultParser.ParseDocument(result.ContentString);
|
||||
var errormsg = LoginResultDocument.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]");
|
||||
var errormsg = LoginResultDocument.QuerySelector("div");
|
||||
if (errormsg != null && errormsg.TextContent.Contains("Форум временно отключен"))
|
||||
errorMessage = errormsg.TextContent;
|
||||
errormsg = LoginResultDocument.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]");
|
||||
if (errormsg != null)
|
||||
errorMessage = errormsg.TextContent;
|
||||
|
||||
@@ -286,36 +288,34 @@ namespace Jackett.Common.Indexers
|
||||
}
|
||||
try
|
||||
{
|
||||
var RowsSelector = "table#tor-tbl > tbody > tr";
|
||||
var searchResultParser = new HtmlParser();
|
||||
var searchResultDocument = searchResultParser.ParseDocument(results.ContentString);
|
||||
|
||||
var SearchResultParser = new HtmlParser();
|
||||
var SearchResultDocument = SearchResultParser.ParseDocument(results.ContentString);
|
||||
var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector);
|
||||
foreach (var Row in Rows)
|
||||
var rows = searchResultDocument.QuerySelectorAll("table#tor-tbl > tbody > tr");
|
||||
foreach (var row in rows)
|
||||
{
|
||||
try
|
||||
{
|
||||
var qDownloadLink = Row.QuerySelector("a.tr-dl");
|
||||
var qDownloadLink = row.QuerySelector("a.tr-dl");
|
||||
if (qDownloadLink == null) // Expects moderation
|
||||
continue;
|
||||
|
||||
var qForumLink = Row.QuerySelector("a.f");
|
||||
var qDetailsLink = Row.QuerySelector("a.tLink");
|
||||
var qSize = Row.QuerySelector("td:nth-child(6) u");
|
||||
var qForumLink = row.QuerySelector("a.f");
|
||||
var qDetailsLink = row.QuerySelector("a.tLink");
|
||||
var qSize = row.QuerySelector("td:nth-child(6) u");
|
||||
var link = new Uri(SiteLink + "forum/" + qDetailsLink.GetAttribute("href"));
|
||||
var seederString = Row.QuerySelector("td:nth-child(7) b").TextContent;
|
||||
var seederString = row.QuerySelector("td:nth-child(7) b").TextContent;
|
||||
var seeders = string.IsNullOrWhiteSpace(seederString) ? 0 : ParseUtil.CoerceInt(seederString);
|
||||
|
||||
var timestr = Row.QuerySelector("td:nth-child(11) u").TextContent;
|
||||
var forum = qForumLink;
|
||||
var forumid = forum.GetAttribute("href").Split('=')[1];
|
||||
var forumid = ParseUtil.GetArgumentFromQueryString(qForumLink?.GetAttribute("href"), "f");
|
||||
var title = configData.StripRussianLetters.Value
|
||||
? s_StripRussianRegex.Replace(qDetailsLink.TextContent, "")
|
||||
: qDetailsLink.TextContent;
|
||||
var size = ReleaseInfo.GetBytes(qSize.TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(Row.QuerySelector("td:nth-child(8)").TextContent);
|
||||
var grabs = ParseUtil.CoerceLong(Row.QuerySelector("td:nth-child(9)").TextContent);
|
||||
var publishDate = DateTimeUtil.UnixTimestampToDateTime(long.Parse(timestr));
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent);
|
||||
var grabs = ParseUtil.CoerceLong(row.QuerySelector("td:nth-child(9)").TextContent);
|
||||
var publishDate = DateTimeUtil.UnixTimestampToDateTime(long.Parse(row.QuerySelector("td:nth-child(11) u").TextContent));
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
MinimumRatio = 1,
|
||||
@@ -338,7 +338,7 @@ namespace Jackett.Common.Indexers
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", Id, Row.OuterHtml, ex));
|
||||
logger.Error($"{Id}: Error while parsing row '{row.OuterHtml}':\n\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -160,14 +160,20 @@ namespace Jackett.Common.Indexers
|
||||
// Send Post
|
||||
var result = await RequestWithCookiesAsync(LoginUrl, loginPage.Cookies, RequestType.POST, data: pairs);
|
||||
if (result.RedirectingTo == null)
|
||||
throw new ExceptionWithConfigData("Login failed. Did you use the PIN number that pretome emailed you?", configData);
|
||||
throw new ExceptionWithConfigData("Login failed. Did you use the PIN number that PreToMe emailed you?", configData);
|
||||
|
||||
// Get result from redirect
|
||||
var loginCookies = result.Cookies;
|
||||
await FollowIfRedirect(result, LoginUrl, null, loginCookies);
|
||||
|
||||
await ConfigureIfOK(loginCookies, result.ContentString?.Contains("logout.php") == true,
|
||||
() => throw new ExceptionWithConfigData("Login failed", configData));
|
||||
await ConfigureIfOK(loginCookies, result.ContentString?.Contains("logout.php") == true, () =>
|
||||
{
|
||||
var loginResultParser = new HtmlParser();
|
||||
var loginResultDocument = loginResultParser.ParseDocument(result.ContentString);
|
||||
var errorMessage = loginResultDocument.QuerySelector("table.body_table font[color~=\"red\"]")?.TextContent.Trim();
|
||||
|
||||
throw new ExceptionWithConfigData(errorMessage ?? "Login failed", configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
@@ -236,27 +242,26 @@ namespace Jackett.Common.Indexers
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(response.ContentString);
|
||||
|
||||
var rows = dom.QuerySelectorAll("table > tbody > tr.browse");
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var qLink = row.Children[1].QuerySelector("a");
|
||||
var title = qLink.GetAttribute("title");
|
||||
if (qLink.QuerySelectorAll("span").Length == 1 && title.StartsWith("NEW! |"))
|
||||
title = title.Substring(6).Trim();
|
||||
var qDetails = row.QuerySelector("a[href^=\"details.php?id=\"]");
|
||||
var title = qDetails?.GetAttribute("title");
|
||||
|
||||
if (!query.MatchQueryStringAND(title))
|
||||
continue; // we have to skip bad titles due to tags + any word search
|
||||
|
||||
var details = new Uri(SiteLink + qLink.GetAttribute("href"));
|
||||
var link = new Uri(SiteLink + row.Children[2].QuerySelector("a").GetAttribute("href"));
|
||||
var dateStr = Regex.Replace(row.Children[5].InnerHtml, @"\<br[\s]{0,1}[\/]{0,1}\>", " ");
|
||||
var details = new Uri(SiteLink + qDetails.GetAttribute("href"));
|
||||
var link = new Uri(SiteLink + row.QuerySelector("a[href^=\"download.php\"]")?.GetAttribute("href"));
|
||||
|
||||
var dateStr = Regex.Replace(row.QuerySelector("td:nth-of-type(6)").InnerHtml, @"\<br[\s]{0,1}[\/]{0,1}\>", " ").Trim();
|
||||
var publishDate = DateTimeUtil.FromTimeAgo(dateStr);
|
||||
var files = ParseUtil.CoerceInt(row.Children[3].TextContent);
|
||||
var size = ReleaseInfo.GetBytes(row.Children[7].TextContent);
|
||||
var grabs = ParseUtil.CoerceInt(row.Children[8].TextContent);
|
||||
var seeders = ParseUtil.CoerceInt(row.Children[9].TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(row.Children[10].TextContent);
|
||||
var cat = row.FirstElementChild.FirstElementChild.GetAttribute("href").Replace("browse.php?", string.Empty);
|
||||
|
||||
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)")?.TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(11)")?.TextContent);
|
||||
|
||||
var cat = row.QuerySelector("td:nth-of-type(1) a[href^=\"browse.php\"]")?.GetAttribute("href")?.Split('?').Last();
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
@@ -265,10 +270,10 @@ namespace Jackett.Common.Indexers
|
||||
Guid = details,
|
||||
Link = link,
|
||||
PublishDate = publishDate,
|
||||
Size = size,
|
||||
Size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-of-type(8)")?.TextContent),
|
||||
Category = MapTrackerCatToNewznab(cat),
|
||||
Files = files,
|
||||
Grabs = grabs,
|
||||
Files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(4)")?.TextContent),
|
||||
Grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)")?.TextContent),
|
||||
Seeders = seeders,
|
||||
Peers = leechers + seeders,
|
||||
MinimumRatio = 0.75,
|
||||
|
@@ -22,24 +22,21 @@ namespace Jackett.Common.Indexers
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class RuTracker : BaseWebIndexer
|
||||
{
|
||||
public override string[] AlternativeSiteLinks { get; protected set; } = {
|
||||
"https://rutracker.org/",
|
||||
"https://rutracker.net/",
|
||||
"https://rutracker.nl/"
|
||||
};
|
||||
private new ConfigurationDataRutracker configData => (ConfigurationDataRutracker)base.configData;
|
||||
|
||||
private readonly TitleParser _titleParser = new TitleParser();
|
||||
private string LoginUrl => SiteLink + "forum/login.php";
|
||||
private string SearchUrl => SiteLink + "forum/tracker.php";
|
||||
|
||||
private string _capSid;
|
||||
private string _capCodeField;
|
||||
|
||||
private new ConfigurationDataRutracker configData => (ConfigurationDataRutracker)base.configData;
|
||||
|
||||
public override string[] AlternativeSiteLinks { get; protected set; } = {
|
||||
"https://rutracker.org/",
|
||||
"https://rutracker.net/",
|
||||
"https://rutracker.nl/"
|
||||
};
|
||||
|
||||
private Regex _regexToFindTagsInReleaseTitle = new Regex(@"\[[^\[]+\]|\([^(]+\)");
|
||||
|
||||
public RuTracker(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps,
|
||||
ICacheService cs)
|
||||
public RuTracker(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps, ICacheService cs)
|
||||
: base(id: "rutracker",
|
||||
name: "RuTracker",
|
||||
description: "RuTracker is a Semi-Private Russian torrent site with a thriving file-sharing community",
|
||||
@@ -74,6 +71,7 @@ namespace Jackett.Common.Indexers
|
||||
Encoding = Encoding.GetEncoding("windows-1251");
|
||||
Language = "ru-RU";
|
||||
Type = "semi-private";
|
||||
|
||||
// note: when refreshing the categories use the tracker.php page and NOT the search.php page!
|
||||
AddCategoryMapping(22, TorznabCatType.Movies, "Наше кино");
|
||||
AddCategoryMapping(941, TorznabCatType.Movies, "|- Кино СССР");
|
||||
@@ -147,6 +145,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(816, TorznabCatType.TVHD, "|- Мультсериалы (DVD Video)");
|
||||
AddCategoryMapping(1460, TorznabCatType.TVHD, "|- Мультсериалы (HD Video)");
|
||||
AddCategoryMapping(33, TorznabCatType.TVAnime, "Аниме");
|
||||
AddCategoryMapping(1106, TorznabCatType.TVAnime, "|- Онгоинги (HD Video)");
|
||||
AddCategoryMapping(1105, TorznabCatType.TVAnime, "|- Аниме (HD Video)");
|
||||
AddCategoryMapping(599, TorznabCatType.TVAnime, "|- Аниме (DVD)");
|
||||
AddCategoryMapping(1389, TorznabCatType.TVAnime, "|- Аниме (основной подраздел)");
|
||||
@@ -164,15 +163,15 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(9, TorznabCatType.TV, "Русские сериалы");
|
||||
AddCategoryMapping(81, TorznabCatType.TVHD, "|- Русские сериалы (HD Video)");
|
||||
AddCategoryMapping(920, TorznabCatType.TVSD, "|- Русские сериалы (DVD Video)");
|
||||
AddCategoryMapping(80, TorznabCatType.TV, "|- Возвращение Мухтара");
|
||||
AddCategoryMapping(1535, TorznabCatType.TV, "|- Воронины");
|
||||
AddCategoryMapping(188, TorznabCatType.TV, "|- Чернобыль: Зона отчуждения");
|
||||
AddCategoryMapping(91, TorznabCatType.TV, "|- Кухня / Отель Элеон");
|
||||
AddCategoryMapping(80, TorznabCatType.TV, "|- Сельский детектив");
|
||||
AddCategoryMapping(1535, TorznabCatType.TV, "|- По законам военного времени");
|
||||
AddCategoryMapping(188, TorznabCatType.TV, "|- Московские тайны");
|
||||
AddCategoryMapping(91, TorznabCatType.TV, "|- Я знаю твои секреты");
|
||||
AddCategoryMapping(990, TorznabCatType.TV, "|- Универ / Универ. Новая общага / СашаТаня");
|
||||
AddCategoryMapping(1408, TorznabCatType.TV, "|- Ольга / Физрук");
|
||||
AddCategoryMapping(1408, TorznabCatType.TV, "|- Женская версия");
|
||||
AddCategoryMapping(175, TorznabCatType.TV, "|- След");
|
||||
AddCategoryMapping(79, TorznabCatType.TV, "|- Солдаты и пр.");
|
||||
AddCategoryMapping(104, TorznabCatType.TV, "|- Тайны следствия");
|
||||
AddCategoryMapping(79, TorznabCatType.TV, "|- Некрасивая подружка");
|
||||
AddCategoryMapping(104, TorznabCatType.TV, "|- Психология преступления");
|
||||
AddCategoryMapping(189, TorznabCatType.TVForeign, "Зарубежные сериалы");
|
||||
AddCategoryMapping(842, TorznabCatType.TVForeign, "|- Новинки и сериалы в стадии показа");
|
||||
AddCategoryMapping(235, TorznabCatType.TVForeign, "|- Сериалы США и Канады");
|
||||
@@ -241,18 +240,18 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(1537, TorznabCatType.TVForeign, "|- Для некондиционных раздач");
|
||||
AddCategoryMapping(2100, TorznabCatType.TVForeign, "Азиатские сериалы");
|
||||
AddCategoryMapping(820, TorznabCatType.TVForeign, "|- Азиатские сериалы (UHD Video)");
|
||||
AddCategoryMapping(915, TorznabCatType.TVForeign, "|- Корейские сериалы с озвучкой");
|
||||
AddCategoryMapping(1242, TorznabCatType.TVForeign, "|- Корейские сериалы с субтитрами");
|
||||
AddCategoryMapping(717, TorznabCatType.TVForeign, "|- Китайские сериалы с субтитрами");
|
||||
AddCategoryMapping(1939, TorznabCatType.TVForeign, "|- Японские сериалы с озвучкой");
|
||||
AddCategoryMapping(2412, TorznabCatType.TVForeign, "|- Прочие азиатские сериалы с озвучкой");
|
||||
AddCategoryMapping(915, TorznabCatType.TVForeign, "|- Корейские сериалы");
|
||||
AddCategoryMapping(1242, TorznabCatType.TVForeign, "|- Корейские сериалы (HD Video)");
|
||||
AddCategoryMapping(717, TorznabCatType.TVForeign, "|- Китайские сериалы");
|
||||
AddCategoryMapping(1939, TorznabCatType.TVForeign, "|- Японские сериалы");
|
||||
AddCategoryMapping(2412, TorznabCatType.TVForeign, "|- Сериалы Таиланда, Индонезии, Сингапура");
|
||||
AddCategoryMapping(2102, TorznabCatType.TVForeign, "|- VMV и др. ролики");
|
||||
AddCategoryMapping(19, TorznabCatType.TVDocumentary, "СМИ");
|
||||
AddCategoryMapping(670, TorznabCatType.TVDocumentary, "Вера и религия");
|
||||
AddCategoryMapping(1475, TorznabCatType.TVDocumentary, "|- [Видео Религия] Христианство");
|
||||
AddCategoryMapping(2107, TorznabCatType.TVDocumentary, "|- [Видео Религия] Ислам");
|
||||
AddCategoryMapping(294, TorznabCatType.TVDocumentary, "|- [Видео Религия] Религии Индии, Тибета и Восточной Азии");
|
||||
AddCategoryMapping(1453, TorznabCatType.TVDocumentary, "|- [Видео Религия] Культы и новые религиозные движения");
|
||||
AddCategoryMapping(294, TorznabCatType.TVDocumentary, "|- [Видео Религия] Религии Индии, Тибета и Восточной Азии");
|
||||
AddCategoryMapping(46, TorznabCatType.TVDocumentary, "Документальные фильмы и телепередачи");
|
||||
AddCategoryMapping(103, TorznabCatType.TVDocumentary, "|- Документальные (DVD)");
|
||||
AddCategoryMapping(671, TorznabCatType.TVDocumentary, "|- [Док] Биографии. Личности и кумиры");
|
||||
@@ -295,7 +294,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(979, TorznabCatType.TVDocumentary, "|- Путешествия и туризм (HD Video)");
|
||||
AddCategoryMapping(2169, TorznabCatType.TVDocumentary, "|- Флора и фауна (HD Video)");
|
||||
AddCategoryMapping(2166, TorznabCatType.TVDocumentary, "|- История (HD Video)");
|
||||
AddCategoryMapping(2164, TorznabCatType.TVDocumentary, "|- BBC, Discovery, National Geographic, History Channel (HD Video)");
|
||||
AddCategoryMapping(2164, TorznabCatType.TVDocumentary, "|- BBC, Discovery, National Geographic, History Channel, Netflix (HD Video)");
|
||||
AddCategoryMapping(2163, TorznabCatType.TVDocumentary, "|- Криминальная документалистика (HD Video)");
|
||||
AddCategoryMapping(85, TorznabCatType.TVDocumentary, "|- Некондиционное видео - Документальные (HD Video)");
|
||||
AddCategoryMapping(24, TorznabCatType.TVDocumentary, "Развлекательные телепередачи и шоу, приколы и юмор");
|
||||
@@ -346,8 +345,8 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(255, TorznabCatType.TVSport, "Спортивные турниры, фильмы и передачи");
|
||||
AddCategoryMapping(256, TorznabCatType.TVSport, "|- Автоспорт");
|
||||
AddCategoryMapping(1986, TorznabCatType.TVSport, "|- Мотоспорт");
|
||||
AddCategoryMapping(660, TorznabCatType.TVSport, "|- Формула-1 (2021)");
|
||||
AddCategoryMapping(1551, TorznabCatType.TVSport, "|- Формула-1 (2012-2020)");
|
||||
AddCategoryMapping(660, TorznabCatType.TVSport, "|- Формула-1 (2022)");
|
||||
AddCategoryMapping(1551, TorznabCatType.TVSport, "|- Формула-1 (2012-2021)");
|
||||
AddCategoryMapping(626, TorznabCatType.TVSport, "|- Формула 1 (до 2011 вкл.)");
|
||||
AddCategoryMapping(262, TorznabCatType.TVSport, "|- Велоспорт");
|
||||
AddCategoryMapping(1326, TorznabCatType.TVSport, "|- Волейбол/Гандбол");
|
||||
@@ -371,17 +370,16 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(1319, TorznabCatType.TVSport, "|- Спорт (видео)");
|
||||
AddCategoryMapping(1608, TorznabCatType.TVSport, "⚽ Футбол");
|
||||
AddCategoryMapping(2294, TorznabCatType.TVSport, "|- UHDTV");
|
||||
AddCategoryMapping(1229, TorznabCatType.TVSport, "|- Чемпионат Мира 2022 (финальный турнир)] (финальный турнир)");
|
||||
AddCategoryMapping(1229, TorznabCatType.TVSport, "|- Чемпионат Мира 2022 (финальный турнир)");
|
||||
AddCategoryMapping(1693, TorznabCatType.TVSport, "|- Чемпионат Мира 2022 (отбор)");
|
||||
AddCategoryMapping(2532, TorznabCatType.TVSport, "|- Чемпионат Европы 2020 [2021] (финальный турнир)");
|
||||
AddCategoryMapping(136, TorznabCatType.TVSport, "|- Чемпионат Европы 2020 [2021] (отбор)");
|
||||
AddCategoryMapping(592, TorznabCatType.TVSport, "|- Лига Наций");
|
||||
AddCategoryMapping(1693, TorznabCatType.TVSport, "|- Чемпионат Мира 2022 (отбор)");
|
||||
AddCategoryMapping(2533, TorznabCatType.TVSport, "|- Чемпионат Мира 2018 (игры)");
|
||||
AddCategoryMapping(1952, TorznabCatType.TVSport, "|- Чемпионат Мира 2018 (обзорные передачи, документалистика)");
|
||||
AddCategoryMapping(1621, TorznabCatType.TVSport, "|- Чемпионаты Мира");
|
||||
AddCategoryMapping(2075, TorznabCatType.TVSport, "|- Россия 2022-2023");
|
||||
AddCategoryMapping(1668, TorznabCatType.TVSport, "|- Россия 2021-2022");
|
||||
AddCategoryMapping(2075, TorznabCatType.TVSport, "|- Россия 2020-2021");
|
||||
AddCategoryMapping(1613, TorznabCatType.TVSport, "|- Россия/СССР");
|
||||
AddCategoryMapping(1614, TorznabCatType.TVSport, "|- Англия");
|
||||
AddCategoryMapping(1623, TorznabCatType.TVSport, "|- Испания");
|
||||
@@ -397,7 +395,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(1617, TorznabCatType.TVSport, "|- Еврокубки");
|
||||
AddCategoryMapping(1620, TorznabCatType.TVSport, "|- Чемпионаты Европы");
|
||||
AddCategoryMapping(1998, TorznabCatType.TVSport, "|- Товарищеские турниры и матчи");
|
||||
AddCategoryMapping(1343, TorznabCatType.TVSport, "|- Обзорные и аналитические передачи 2018-2021");
|
||||
AddCategoryMapping(1343, TorznabCatType.TVSport, "|- Обзорные и аналитические передачи 2018-2022");
|
||||
AddCategoryMapping(751, TorznabCatType.TVSport, "|- Обзорные и аналитические передачи");
|
||||
AddCategoryMapping(497, TorznabCatType.TVSport, "|- Документальные фильмы (футбол)");
|
||||
AddCategoryMapping(1697, TorznabCatType.TVSport, "|- Мини-футбол/Пляжный футбол");
|
||||
@@ -405,7 +403,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(2001, TorznabCatType.TVSport, "|- Международные соревнования");
|
||||
AddCategoryMapping(2002, TorznabCatType.TVSport, "|- NBA / NCAA (до 2000 г.)");
|
||||
AddCategoryMapping(283, TorznabCatType.TVSport, "|- NBA / NCAA (2000-2010 гг.)");
|
||||
AddCategoryMapping(1997, TorznabCatType.TVSport, "|- NBA / NCAA (2010-2022 гг.)");
|
||||
AddCategoryMapping(1997, TorznabCatType.TVSport, "|- NBA / NCAA (2010-2023 гг.)");
|
||||
AddCategoryMapping(2003, TorznabCatType.TVSport, "|- Европейский клубный баскетбол");
|
||||
AddCategoryMapping(2009, TorznabCatType.TVSport, "🏒 Хоккей");
|
||||
AddCategoryMapping(2010, TorznabCatType.TVSport, "|- Хоккей с мячом / Бенди");
|
||||
@@ -799,7 +797,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(2430, TorznabCatType.AudioLossless, "|- Этническая музыка Индии (lossless)");
|
||||
AddCategoryMapping(1283, TorznabCatType.AudioMP3, "|- Этническая музыка Африки и Ближнего Востока (lossy)");
|
||||
AddCategoryMapping(2085, TorznabCatType.AudioLossless, "|- Этническая музыка Африки и Ближнего Востока (lossless)");
|
||||
AddCategoryMapping(1282, TorznabCatType.Audio, "|- Фольклорная, Народная, Эстрадная музыка Кавказа и Закавказья (lossless)");
|
||||
AddCategoryMapping(1282, TorznabCatType.Audio, "|- Фольклорная, Народная, Эстрадная музыка Кавказа и Закавказья (lossy и lossless)");
|
||||
AddCategoryMapping(1284, TorznabCatType.AudioMP3, "|- Этническая музыка Северной и Южной Америки (lossy)");
|
||||
AddCategoryMapping(1285, TorznabCatType.AudioLossless, "|- Этническая музыка Северной и Южной Америки (lossless)");
|
||||
AddCategoryMapping(1138, TorznabCatType.Audio, "|- Этническая музыка Австралии, Тихого и Индийского океанов (lossy и lossless)");
|
||||
@@ -963,8 +961,8 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(202, TorznabCatType.AudioMP3, "|- Indie Rock, Indie Pop, Dream Pop, Brit-Pop (lossy)");
|
||||
AddCategoryMapping(172, TorznabCatType.AudioLossless, "|- Post-Punk, Shoegaze, Garage Rock, Noise Rock (lossless)");
|
||||
AddCategoryMapping(236, TorznabCatType.AudioMP3, "|- Post-Punk, Shoegaze, Garage Rock, Noise Rock (lossy)");
|
||||
AddCategoryMapping(1742, TorznabCatType.AudioLossless, "|- Indie, Post-Rock & Post-Punk (lossless)");
|
||||
AddCategoryMapping(1743, TorznabCatType.AudioMP3, "|- Indie, Post-Rock & Post-Punk (lossy)");
|
||||
AddCategoryMapping(1742, TorznabCatType.AudioLossless, "|- Post-Rock (lossless)");
|
||||
AddCategoryMapping(1743, TorznabCatType.AudioMP3, "|- Post-Rock (lossy)");
|
||||
AddCategoryMapping(1744, TorznabCatType.AudioLossless, "|- Industrial & Post-industrial (lossless)");
|
||||
AddCategoryMapping(1745, TorznabCatType.AudioMP3, "|- Industrial & Post-industrial (lossy)");
|
||||
AddCategoryMapping(1746, TorznabCatType.AudioLossless, "|- Emocore, Post-hardcore, Metalcore (lossless)");
|
||||
@@ -1122,8 +1120,8 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(1886, TorznabCatType.AudioVideo, "|- Электронная музыка (DVD Video)");
|
||||
AddCategoryMapping(2509, TorznabCatType.AudioVideo, "|- Документальные фильмы о музыке и музыкантах (DVD Video)");
|
||||
AddCategoryMapping(2507, TorznabCatType.AudioVideo, "Неофициальные DVD видео");
|
||||
AddCategoryMapping(2263, TorznabCatType.AudioVideo, "Классическая музыка, Опера, Балет, Мюзикл (Неофициальные DVD Video)");
|
||||
AddCategoryMapping(2511, TorznabCatType.AudioVideo, "Шансон, Авторская песня, Сборные концерты, МДЖ (Неофициальные DVD Video)");
|
||||
AddCategoryMapping(2263, TorznabCatType.AudioVideo, "|- Классическая музыка, Опера, Балет, Мюзикл (Неофициальные DVD Video)");
|
||||
AddCategoryMapping(2511, TorznabCatType.AudioVideo, "|- Шансон, Авторская песня, Сборные концерты, МДЖ (Неофициальные DVD Video)");
|
||||
AddCategoryMapping(2264, TorznabCatType.AudioVideo, "|- Зарубежная и Отечественная Поп-музыка (Неофициальные DVD Video)");
|
||||
AddCategoryMapping(2262, TorznabCatType.AudioVideo, "|- Джаз и Блюз (Неофициальные DVD Video)");
|
||||
AddCategoryMapping(2261, TorznabCatType.AudioVideo, "|- Зарубежная и Отечественная Рок-музыка (Неофициальные DVD Video)");
|
||||
@@ -1244,7 +1242,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(1041, TorznabCatType.PC, "|- Изменение интерфейса ОС Windows");
|
||||
AddCategoryMapping(1636, TorznabCatType.PC, "|- Скринсейверы");
|
||||
AddCategoryMapping(1042, TorznabCatType.PC, "|- Разное (Системные программы под Windows)");
|
||||
AddCategoryMapping(1059, TorznabCatType.PC, "Архив (Разрегистрированные раздачи)");
|
||||
AddCategoryMapping(1059, TorznabCatType.PC, "|- Архив (Разрегистрированные раздачи)");
|
||||
AddCategoryMapping(1014, TorznabCatType.PC, "Системы для бизнеса, офиса, научной и проектной работы");
|
||||
AddCategoryMapping(2134, TorznabCatType.PC, "|- Медицина - интерактивный софт");
|
||||
AddCategoryMapping(1060, TorznabCatType.PC, "|- Всё для дома: кройка, шитьё, кулинария");
|
||||
@@ -1290,7 +1288,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(1357, TorznabCatType.OtherMisc, "|- Авторские работы");
|
||||
AddCategoryMapping(890, TorznabCatType.OtherMisc, "|- Официальные сборники векторных клипартов");
|
||||
AddCategoryMapping(830, TorznabCatType.OtherMisc, "|- Прочие векторные клипарты");
|
||||
AddCategoryMapping(1290, TorznabCatType.OtherMisc, "|- Photostoсks");
|
||||
AddCategoryMapping(1290, TorznabCatType.OtherMisc, "|- Photostocks");
|
||||
AddCategoryMapping(1962, TorznabCatType.OtherMisc, "|- Дополнения для программ компоузинга и постобработки");
|
||||
AddCategoryMapping(831, TorznabCatType.OtherMisc, "|- Рамки, шаблоны, текстуры и фоны");
|
||||
AddCategoryMapping(829, TorznabCatType.OtherMisc, "|- Прочие растровые клипарты");
|
||||
@@ -1378,7 +1376,7 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping(147, TorznabCatType.Books, "|- Публикации и учебные материалы (тексты)");
|
||||
AddCategoryMapping(847, TorznabCatType.MoviesOther, "|- Трейлеры и дополнительные материалы к фильмам");
|
||||
AddCategoryMapping(1167, TorznabCatType.TVOther, "|- Любительские видеоклипы");
|
||||
AddCategoryMapping(321, TorznabCatType.Other, "Место встречи изменить - Отчеты о встречах");
|
||||
AddCategoryMapping(321, TorznabCatType.Other, "|- Отчеты о встречах");
|
||||
}
|
||||
|
||||
public override async Task<ConfigurationData> GetConfigurationForSetup()
|
||||
@@ -1389,17 +1387,15 @@ namespace Jackett.Common.Indexers
|
||||
var response = await RequestWithCookiesAsync(LoginUrl);
|
||||
var parser = new HtmlParser();
|
||||
var doc = parser.ParseDocument(response.ContentString);
|
||||
var captchaimg = doc.QuerySelector("img[src^=\"https://static.t-ru.org/captcha/\"]");
|
||||
var captchaimg = doc.QuerySelector("img[src^=\"https://static.rutracker.cc/captcha/\"]");
|
||||
|
||||
if (captchaimg != null)
|
||||
{
|
||||
var captchaImage = await RequestWithCookiesAsync(captchaimg.GetAttribute("src"));
|
||||
configData.CaptchaImage.Value = captchaImage.ContentBytes;
|
||||
|
||||
var codefield = doc.QuerySelector("input[name^=\"cap_code_\"]");
|
||||
_capCodeField = codefield.GetAttribute("name");
|
||||
|
||||
var sidfield = doc.QuerySelector("input[name=\"cap_sid\"]");
|
||||
_capSid = sidfield.GetAttribute("value");
|
||||
_capCodeField = doc.QuerySelector("input[name^=\"cap_code_\"]")?.GetAttribute("name");
|
||||
_capSid = doc.QuerySelector("input[name=\"cap_sid\"]")?.GetAttribute("value");
|
||||
}
|
||||
else
|
||||
configData.CaptchaImage.Value = null;
|
||||
@@ -1435,11 +1431,13 @@ namespace Jackett.Common.Indexers
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, CookieHeader, true, null, LoginUrl, true);
|
||||
await ConfigureIfOK(result.Cookies, result.ContentString != null && result.ContentString.Contains("id=\"logged-in-username\""), () =>
|
||||
{
|
||||
logger.Debug(result.ContentString);
|
||||
var errorMessage = "Unknown error message, please report";
|
||||
var parser = new HtmlParser();
|
||||
var doc = parser.ParseDocument(result.ContentString);
|
||||
var errormsg = doc.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]");
|
||||
var errormsg = doc.QuerySelector("div.msg-main");
|
||||
if (errormsg != null)
|
||||
errorMessage = errormsg.TextContent;
|
||||
errormsg = doc.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]");
|
||||
if (errormsg != null)
|
||||
errorMessage = errormsg.TextContent;
|
||||
|
||||
@@ -1515,6 +1513,7 @@ namespace Jackett.Common.Indexers
|
||||
queryCollection.Add("f", string.Join(",", MapTorznabCapsToTrackers(query)));
|
||||
|
||||
var searchUrl = SearchUrl + "?" + queryCollection.GetQueryString();
|
||||
|
||||
return searchUrl;
|
||||
}
|
||||
|
||||
@@ -1539,6 +1538,7 @@ namespace Jackett.Common.Indexers
|
||||
var qDetailsLink = row.QuerySelector("td.t-title-col > div.t-title > a.tLink");
|
||||
var details = new Uri(SiteLink + "forum/" + qDetailsLink.GetAttribute("href"));
|
||||
|
||||
var title = qDetailsLink.TextContent.Trim();
|
||||
var category = GetCategoryOfRelease(row);
|
||||
|
||||
var size = GetSizeOfRelease(row);
|
||||
@@ -1554,7 +1554,14 @@ namespace Jackett.Common.Indexers
|
||||
{
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 0,
|
||||
Title = qDetailsLink.TextContent,
|
||||
Title = _titleParser.Parse(
|
||||
title,
|
||||
category,
|
||||
configData.StripRussianLetters.Value,
|
||||
configData.MoveAllTagsToEndOfReleaseTitle.Value,
|
||||
configData.MoveFirstTagsToEndOfReleaseTitle.Value
|
||||
),
|
||||
Description = title,
|
||||
Details = details,
|
||||
Link = link,
|
||||
Guid = details,
|
||||
@@ -1568,60 +1575,6 @@ namespace Jackett.Common.Indexers
|
||||
UploadVolumeFactor = 1
|
||||
};
|
||||
|
||||
// TODO finish extracting release variables to simplify release initialization
|
||||
if (IsAnyTvCategory(release.Category))
|
||||
{
|
||||
// extract season and episodes
|
||||
var regex = new Regex(".+\\/\\s([^а-яА-я\\/]+)\\s\\/.+Сезон\\s*[:]*\\s+(\\d+).+(?:Серии|Эпизод)+\\s*[:]*\\s+(\\d+-*\\d*).+,\\s+(.+)\\][\\s]?(.*)");
|
||||
|
||||
//replace double 4K quality in title
|
||||
release.Title = release.Title.Replace(", 4K]", "]");
|
||||
|
||||
var title = regex.Replace(release.Title, "$1 - S$2E$3 - rus $4 $5");
|
||||
title = Regex.Replace(title, "-Rip", "Rip", RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, "WEB-DLRip", "WEBDL", RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, "WEB-DL", "WEBDL", RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, "HDTVRip", "HDTV", RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, "Кураж-Бамбей", "kurazh", RegexOptions.IgnoreCase);
|
||||
|
||||
release.Title = title;
|
||||
}
|
||||
else if (IsAnyMovieCategory(release.Category))
|
||||
{
|
||||
// remove director's name from title
|
||||
// rutracker movies titles look like: russian name / english name (russian director / english director) other stuff
|
||||
// Ирландец / The Irishman (Мартин Скорсезе / Martin Scorsese) [2019, США, криминал, драма, биография, WEB-DL 1080p] Dub (Пифагор) + MVO (Jaskier) + AVO (Юрий Сербин) + Sub Rus, Eng + Original Eng
|
||||
// this part should be removed: (Мартин Скорсезе / Martin Scorsese)
|
||||
var director = new Regex(@"(\([А-Яа-яЁё\W]+)\s/\s(.+?)\)");
|
||||
release.Title = director.Replace(release.Title, "");
|
||||
|
||||
// Bluray quality fix: radarr parse Blu-ray Disc as Bluray-1080p but should be BR-DISK
|
||||
release.Title = Regex.Replace(release.Title, "Blu-ray Disc", "BR-DISK", RegexOptions.IgnoreCase);
|
||||
// language fix: all rutracker releases contains russian track
|
||||
if (release.Title.IndexOf("rus", StringComparison.OrdinalIgnoreCase) < 0)
|
||||
release.Title += " rus";
|
||||
}
|
||||
|
||||
if (configData.StripRussianLetters.Value)
|
||||
{
|
||||
var regex = new Regex(@"(\([А-Яа-яЁё\W]+\))|(^[А-Яа-яЁё\W\d]+\/ )|([а-яА-ЯЁё \-]+,+)|([а-яА-ЯЁё]+)");
|
||||
release.Title = regex.Replace(release.Title, "");
|
||||
}
|
||||
|
||||
if (configData.MoveAllTagsToEndOfReleaseTitle.Value)
|
||||
{
|
||||
release.Title = MoveAllTagsToEndOfReleaseTitle(release.Title);
|
||||
}
|
||||
else if (configData.MoveFirstTagsToEndOfReleaseTitle.Value)
|
||||
{
|
||||
release.Title = MoveFirstTagsToEndOfReleaseTitle(release.Title);
|
||||
}
|
||||
|
||||
if (release.Category.Contains(TorznabCatType.Audio.ID))
|
||||
{
|
||||
release.Title = DetectRereleaseInReleaseTitle(release.Title);
|
||||
}
|
||||
|
||||
return release;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1637,7 +1590,7 @@ namespace Jackett.Common.Indexers
|
||||
var qSeeders = row.QuerySelector("td:nth-child(7)");
|
||||
if (qSeeders != null && !qSeeders.TextContent.Contains("дн"))
|
||||
{
|
||||
var seedersString = qSeeders.QuerySelector("b").TextContent;
|
||||
var seedersString = qSeeders.QuerySelector("b")?.TextContent.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(seedersString))
|
||||
seeders = ParseUtil.CoerceInt(seedersString);
|
||||
}
|
||||
@@ -1646,107 +1599,186 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
private ICollection<int> GetCategoryOfRelease(in IElement row)
|
||||
{
|
||||
var forum = row.QuerySelector("td.f-name-col > div.f-name > a");
|
||||
var forumid = forum.GetAttribute("href").Split('=')[1];
|
||||
return MapTrackerCatToNewznab(forumid);
|
||||
var forum = row.QuerySelector("td.f-name-col > div.f-name > a")?.GetAttribute("href");
|
||||
var cat = ParseUtil.GetArgumentFromQueryString(forum, "f");
|
||||
|
||||
return MapTrackerCatToNewznab(cat);
|
||||
}
|
||||
|
||||
private long GetSizeOfRelease(in IElement row)
|
||||
{
|
||||
var qSize = row.QuerySelector("td.tor-size");
|
||||
var size = ReleaseInfo.GetBytes(qSize.GetAttribute("data-ts_text"));
|
||||
return size;
|
||||
}
|
||||
private long GetSizeOfRelease(in IElement row) => ReleaseInfo.GetBytes(row.QuerySelector("td.tor-size")?.GetAttribute("data-ts_text"));
|
||||
|
||||
private DateTime GetPublishDateOfRelease(in IElement row)
|
||||
{
|
||||
var timestr = row.QuerySelector("td:nth-child(10)").GetAttribute("data-ts_text");
|
||||
var publishDate = DateTimeUtil.UnixTimestampToDateTime(long.Parse(timestr));
|
||||
return publishDate;
|
||||
}
|
||||
private DateTime GetPublishDateOfRelease(in IElement row) => DateTimeUtil.UnixTimestampToDateTime(long.Parse(row.QuerySelector("td:nth-child(10)")?.GetAttribute("data-ts_text")));
|
||||
|
||||
private bool IsAnyTvCategory(ICollection<int> category)
|
||||
public class TitleParser
|
||||
{
|
||||
return category.Contains(TorznabCatType.TV.ID)
|
||||
|| TorznabCatType.TV.SubCategories.Any(subCat => category.Contains(subCat.ID));
|
||||
}
|
||||
|
||||
private bool IsAnyMovieCategory(ICollection<int> category)
|
||||
{
|
||||
return category.Contains(TorznabCatType.Movies.ID)
|
||||
|| TorznabCatType.Movies.SubCategories.Any(subCat => category.Contains(subCat.ID));
|
||||
}
|
||||
|
||||
private string MoveAllTagsToEndOfReleaseTitle(string input)
|
||||
{
|
||||
var output = input + " ";
|
||||
foreach (Match match in _regexToFindTagsInReleaseTitle.Matches(input))
|
||||
private static readonly List<Regex> _FindTagsInTitlesRegexList = new List<Regex>
|
||||
{
|
||||
var tag = match.ToString();
|
||||
output = output.Replace(tag, "") + tag;
|
||||
}
|
||||
output = output.Trim();
|
||||
return output;
|
||||
}
|
||||
new Regex(@"\((?>\((?<c>)|[^()]+|\)(?<-c>))*(?(c)(?!))\)"),
|
||||
new Regex(@"\[(?>\[(?<c>)|[^\[\]]+|\](?<-c>))*(?(c)(?!))\]")
|
||||
};
|
||||
|
||||
private string MoveFirstTagsToEndOfReleaseTitle(string input)
|
||||
{
|
||||
var output = input + " ";
|
||||
var expectedIndex = 0;
|
||||
foreach (Match match in _regexToFindTagsInReleaseTitle.Matches(input))
|
||||
private readonly Regex _stripCyrillicRegex = new Regex(@"(\([\p{IsCyrillic}\W]+\))|(^[\p{IsCyrillic}\W\d]+\/ )|([\p{IsCyrillic} \-]+,+)|([\p{IsCyrillic}]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly Regex _tvTitleCommaRegex = new Regex(@"\s(\d+),(\d+)", RegexOptions.Compiled);
|
||||
private readonly Regex _tvTitleCyrillicXRegex = new Regex(@"([\s-])Х+([\s\)\]])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly Regex _tvTitleRusSeasonEpisodeOfRegex = new Regex(@"Сезон\s*[:]*\s+(\d+).+(?:Серии|Эпизод|Выпуски)+\s*[:]*\s+(\d+(?:-\d+)?)\s*из\s*([\w?])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleRusSeasonEpisodeRegex = new Regex(@"Сезон\s*[:]*\s+(\d+).+(?:Серии|Эпизод|Выпуски)+\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleRusSeasonRegex = new Regex(@"Сезон\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleRusEpisodeOfRegex = new Regex(@"(?:Серии|Эпизод|Выпуски)+\s*[:]*\s+(\d+(?:-\d+)?)\s*из\s*([\w?])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleRusEpisodeRegex = new Regex(@"(?:Серии|Эпизод|Выпуски)+\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public string Parse(string title, ICollection<int> category, bool stripCyrillicLetters = true, bool moveAllTagsToEndOfReleaseTitle = false, bool moveFirstTagsToEndOfReleaseTitle = false)
|
||||
{
|
||||
if (match.Index > expectedIndex)
|
||||
// https://www.fileformat.info/info/unicode/category/Pd/list.htm
|
||||
title = Regex.Replace(title, @"\p{Pd}", "-", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
// replace double 4K quality in title
|
||||
title = Regex.Replace(title, @"\b(2160p), 4K\b", "$1", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
if (IsAnyTvCategory(category))
|
||||
{
|
||||
var substring = input.Substring(expectedIndex, match.Index - expectedIndex);
|
||||
if (string.IsNullOrWhiteSpace(substring))
|
||||
expectedIndex = match.Index;
|
||||
else
|
||||
break;
|
||||
title = _tvTitleCommaRegex.Replace(title, " $1-$2");
|
||||
title = _tvTitleCyrillicXRegex.Replace(title, "$1XX$2");
|
||||
|
||||
title = _tvTitleRusSeasonEpisodeOfRegex.Replace(title, "S$1E$2 of $3");
|
||||
title = _tvTitleRusSeasonEpisodeRegex.Replace(title, "S$1E$2");
|
||||
title = _tvTitleRusSeasonRegex.Replace(title, "S$1");
|
||||
title = _tvTitleRusEpisodeOfRegex.Replace(title, "E$1 of $2");
|
||||
title = _tvTitleRusEpisodeRegex.Replace(title, "E$1");
|
||||
}
|
||||
var tag = match.ToString();
|
||||
output = output.Replace(tag, "") + tag;
|
||||
expectedIndex += tag.Length;
|
||||
else if (IsAnyMovieCategory(category))
|
||||
{
|
||||
// remove director's name from title
|
||||
// rutracker movies titles look like: russian name / english name (russian director / english director) other stuff
|
||||
// Ирландец / The Irishman (Мартин Скорсезе / Martin Scorsese) [2019, США, криминал, драма, биография, WEB-DL 1080p] Dub (Пифагор) + MVO (Jaskier) + AVO (Юрий Сербин) + Sub Rus, Eng + Original Eng
|
||||
// this part should be removed: (Мартин Скорсезе / Martin Scorsese)
|
||||
title = Regex.Replace(title, @"(\([\p{IsCyrillic}\W]+)\s/\s(.+?)\)", string.Empty, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
// Bluray quality fix: radarr parse Blu-ray Disc as Bluray-1080p but should be BR-DISK
|
||||
title = Regex.Replace(title, @"\bBlu-ray Disc\b", "BR-DISK", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
// language fix: all rutracker releases contains russian track
|
||||
if (title.IndexOf("rus", StringComparison.OrdinalIgnoreCase) < 0)
|
||||
title += " rus";
|
||||
}
|
||||
|
||||
if (stripCyrillicLetters)
|
||||
title = _stripCyrillicRegex.Replace(title, string.Empty).Trim(' ', '-');
|
||||
|
||||
if (moveAllTagsToEndOfReleaseTitle)
|
||||
title = MoveAllTagsToEndOfReleaseTitle(title);
|
||||
else if (moveFirstTagsToEndOfReleaseTitle)
|
||||
title = MoveFirstTagsToEndOfReleaseTitle(title);
|
||||
|
||||
if (IsAnyAudioCategory(category))
|
||||
title = DetectRereleaseInReleaseTitle(title);
|
||||
|
||||
title = Regex.Replace(title, @"\b-Rip\b", "Rip", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bHDTVRip\b", "HDTV", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bWEB-DLRip\b", "WEB-DL", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bWEBDLRip\b", "WEB-DL", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bWEBDL\b", "WEB-DL", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bКураж-Бамбей\b", "kurazh", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
title = Regex.Replace(title, @"\(\s*\/\s*", "(", RegexOptions.Compiled);
|
||||
title = Regex.Replace(title, @"\s*\/\s*\)", ")", RegexOptions.Compiled);
|
||||
|
||||
title = Regex.Replace(title, @"[\[\(]\s*[\)\]]", "", RegexOptions.Compiled);
|
||||
|
||||
title = title.Trim(' ', '&', ',', '.', '!', '?', '+', '-', '_', '|', '/', '\\', ':');
|
||||
|
||||
// replace multiple spaces with a single space
|
||||
title = Regex.Replace(title, @"\s+", " ");
|
||||
|
||||
return title.Trim();
|
||||
}
|
||||
output = output.Trim();
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the release title to find a 'year1/year2' pattern that would indicate that this is a re-release of an old music album.
|
||||
/// If the release is found to be a re-release, this is added to the title as a new tag.
|
||||
/// Not to be confused with discographies; they mostly follow the 'year1-year2' pattern.
|
||||
/// </summary>
|
||||
private string DetectRereleaseInReleaseTitle(string input)
|
||||
{
|
||||
var fullTitle = input;
|
||||
private static bool IsAnyTvCategory(ICollection<int> category) => category.Contains(TorznabCatType.TV.ID) || TorznabCatType.TV.SubCategories.Any(subCat => category.Contains(subCat.ID));
|
||||
|
||||
var squareBracketTags = input.FindSubstringsBetween('[', ']', includeOpeningAndClosing: true);
|
||||
input = input.RemoveSubstrings(squareBracketTags);
|
||||
private static bool IsAnyMovieCategory(ICollection<int> category) => category.Contains(TorznabCatType.Movies.ID) || TorznabCatType.Movies.SubCategories.Any(subCat => category.Contains(subCat.ID));
|
||||
|
||||
var roundBracketTags = input.FindSubstringsBetween('(', ')', includeOpeningAndClosing: true);
|
||||
input = input.RemoveSubstrings(roundBracketTags);
|
||||
private static bool IsAnyAudioCategory(ICollection<int> category) => category.Contains(TorznabCatType.Audio.ID) || TorznabCatType.Audio.SubCategories.Any(subCat => category.Contains(subCat.ID));
|
||||
|
||||
var regex = new Regex(@"\d{4}");
|
||||
var yearsInTitle = regex.Matches(input);
|
||||
|
||||
if (yearsInTitle == null || yearsInTitle.Count < 2)
|
||||
private static string MoveAllTagsToEndOfReleaseTitle(string input)
|
||||
{
|
||||
//Can only be a re-release if there's at least 2 years in the title.
|
||||
return fullTitle;
|
||||
var output = input;
|
||||
foreach (var findTagsRegex in _FindTagsInTitlesRegexList)
|
||||
{
|
||||
foreach (Match match in findTagsRegex.Matches(input))
|
||||
{
|
||||
var tag = match.ToString();
|
||||
output = $"{output.Replace(tag, "")} {tag}".Trim();
|
||||
}
|
||||
}
|
||||
|
||||
return output.Trim();
|
||||
}
|
||||
|
||||
regex = new Regex(@"(\d{4}) *\/ *(\d{4})");
|
||||
var regexMatch = regex.Match(input);
|
||||
if (!regexMatch.Success)
|
||||
private static string MoveFirstTagsToEndOfReleaseTitle(string input)
|
||||
{
|
||||
//Not in the expected format. Return the unaltered title.
|
||||
return fullTitle;
|
||||
var output = input;
|
||||
foreach (var findTagsRegex in _FindTagsInTitlesRegexList)
|
||||
{
|
||||
var expectedIndex = 0;
|
||||
foreach (Match match in findTagsRegex.Matches(output))
|
||||
{
|
||||
if (match.Index > expectedIndex)
|
||||
{
|
||||
var substring = output.Substring(expectedIndex, match.Index - expectedIndex);
|
||||
if (string.IsNullOrWhiteSpace(substring))
|
||||
expectedIndex = match.Index;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
var tag = match.ToString();
|
||||
var regex = new Regex(Regex.Escape(tag));
|
||||
output = $"{regex.Replace(output, string.Empty, 1)} {tag}".Trim();
|
||||
expectedIndex += tag.Length;
|
||||
}
|
||||
}
|
||||
|
||||
return output.Trim();
|
||||
}
|
||||
|
||||
var originalYear = regexMatch.Groups[1].ToString();
|
||||
fullTitle = fullTitle.Replace(regexMatch.ToString(), originalYear);
|
||||
/// <summary>
|
||||
/// Searches the release title to find a 'year1/year2' pattern that would indicate that this is a re-release of an old music album.
|
||||
/// If the release is found to be a re-release, this is added to the title as a new tag.
|
||||
/// Not to be confused with discographies; they mostly follow the 'year1-year2' pattern.
|
||||
/// </summary>
|
||||
private static string DetectRereleaseInReleaseTitle(string input)
|
||||
{
|
||||
var fullTitle = input;
|
||||
|
||||
return fullTitle + "(Re-release)";
|
||||
var squareBracketTags = input.FindSubstringsBetween('[', ']', includeOpeningAndClosing: true);
|
||||
input = input.RemoveSubstrings(squareBracketTags);
|
||||
|
||||
var roundBracketTags = input.FindSubstringsBetween('(', ')', includeOpeningAndClosing: true);
|
||||
input = input.RemoveSubstrings(roundBracketTags);
|
||||
|
||||
var regex = new Regex(@"\d{4}");
|
||||
var yearsInTitle = regex.Matches(input);
|
||||
|
||||
if (yearsInTitle == null || yearsInTitle.Count < 2)
|
||||
{
|
||||
//Can only be a re-release if there's at least 2 years in the title.
|
||||
return fullTitle;
|
||||
}
|
||||
|
||||
regex = new Regex(@"(\d{4}) *\/ *(\d{4})");
|
||||
var regexMatch = regex.Match(input);
|
||||
if (!regexMatch.Success)
|
||||
{
|
||||
//Not in the expected format. Return the unaltered title.
|
||||
return fullTitle;
|
||||
}
|
||||
|
||||
var originalYear = regexMatch.Groups[1].ToString();
|
||||
fullTitle = fullTitle.Replace(regexMatch.ToString(), originalYear);
|
||||
|
||||
return fullTitle + "(Re-release)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Html.Parser;
|
||||
using Jackett.Common.Models;
|
||||
@@ -57,7 +57,7 @@ namespace Jackett.Common.Indexers
|
||||
cacheService: cs,
|
||||
configData: new ConfigurationDataSceneTime())
|
||||
{
|
||||
Encoding = Encoding.GetEncoding("iso-8859-1");
|
||||
Encoding = Encoding.UTF8;
|
||||
Language = "en-US";
|
||||
Type = "private";
|
||||
|
||||
@@ -119,14 +119,14 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
var catList = MapTorznabCapsToTrackers(query);
|
||||
foreach (var cat in catList)
|
||||
qParams.Add("c" + cat, "1");
|
||||
qParams.Set($"c{cat}", "1");
|
||||
|
||||
if (!string.IsNullOrEmpty(query.SanitizedSearchTerm))
|
||||
qParams.Add("search", query.GetQueryString());
|
||||
qParams.Set("search", query.GetQueryString());
|
||||
|
||||
// If Only Freeleech Enabled
|
||||
if (configData.Freeleech.Value)
|
||||
qParams.Add("freeleech", "on");
|
||||
qParams.Set("freeleech", "on");
|
||||
|
||||
var searchUrl = SearchUrl + "?" + qParams.GetQueryString();
|
||||
var results = await RequestWithCookiesAsync(searchUrl);
|
||||
@@ -161,8 +161,7 @@ namespace Jackett.Common.Indexers
|
||||
if (table == null)
|
||||
return releases; // no results
|
||||
|
||||
var headerColumns = table.QuerySelectorAll("tbody > tr > td.cat_Head")
|
||||
.Select(x => x.TextContent).ToList();
|
||||
var headerColumns = table.QuerySelectorAll("tbody > tr > td.cat_Head").Select(x => x.TextContent).ToList();
|
||||
var categoryIndex = headerColumns.FindIndex(x => x.Equals("Type"));
|
||||
var nameIndex = headerColumns.FindIndex(x => x.Equals("Name"));
|
||||
var sizeIndex = headerColumns.FindIndex(x => x.Equals("Size"));
|
||||
@@ -172,44 +171,44 @@ namespace Jackett.Common.Indexers
|
||||
var rows = dom.QuerySelectorAll("tr.browse");
|
||||
foreach (var row in rows)
|
||||
{
|
||||
// TODO convert to initializer
|
||||
var qDescCol = row.Children[nameIndex];
|
||||
var qLink = qDescCol.QuerySelector("a");
|
||||
var title = qLink.TextContent;
|
||||
|
||||
if (!query.MatchQueryStringAND(title))
|
||||
continue;
|
||||
|
||||
var details = new Uri(SiteLink + "/" + qLink.GetAttribute("href"));
|
||||
var torrentId = ParseUtil.GetArgumentFromQueryString(qLink.GetAttribute("href"), "id");
|
||||
var link = new Uri(string.Format(DownloadUrl, torrentId));
|
||||
|
||||
var categoryLink = row.Children[categoryIndex].QuerySelector("a")?.GetAttribute("href");
|
||||
var cat = categoryLink != null ? ParseUtil.GetArgumentFromQueryString(categoryLink, "cat") : "82"; // default
|
||||
|
||||
var seeders = ParseUtil.CoerceInt(row.Children[seedersIndex].TextContent.Trim());
|
||||
|
||||
var dateAdded = qDescCol.QuerySelector("span[class=\"elapsedDate\"]").GetAttribute("title").Trim();
|
||||
var publishDate = DateTime.TryParseExact(dateAdded, "dddd, MMMM d, yyyy \\a\\t h:mmtt", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var date)
|
||||
? date
|
||||
: DateTimeUtil.FromTimeAgo(qDescCol.QuerySelector("span[class=\"elapsedDate\"]").TextContent.Trim());
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
Guid = details,
|
||||
Details = details,
|
||||
Link = link,
|
||||
Title = title,
|
||||
Category = MapTrackerCatToNewznab(cat),
|
||||
PublishDate = publishDate,
|
||||
Size = ReleaseInfo.GetBytes(row.Children[sizeIndex].TextContent),
|
||||
Seeders = seeders,
|
||||
Peers = ParseUtil.CoerceInt(row.Children[leechersIndex].TextContent.Trim()) + seeders,
|
||||
DownloadVolumeFactor = row.QuerySelector("font > b:contains(Freeleech)") != null ? 0 : 1,
|
||||
UploadVolumeFactor = 1,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 259200 // 72 hours
|
||||
};
|
||||
|
||||
var catId = "82"; // default
|
||||
var qCatLink = row.Children[categoryIndex].QuerySelector("a");
|
||||
if (qCatLink != null)
|
||||
{
|
||||
catId = new Regex(@"\?cat=(\d*)").Match(qCatLink.GetAttribute("href")).Groups[1].ToString().Trim();
|
||||
}
|
||||
release.Category = MapTrackerCatToNewznab(catId);
|
||||
|
||||
var qDescCol = row.Children[nameIndex];
|
||||
var qLink = qDescCol.QuerySelector("a");
|
||||
release.Title = qLink.TextContent;
|
||||
if (!query.MatchQueryStringAND(release.Title))
|
||||
continue;
|
||||
|
||||
release.Details = new Uri(SiteLink + "/" + qLink.GetAttribute("href"));
|
||||
release.Guid = release.Details;
|
||||
|
||||
var torrentId = qLink.GetAttribute("href").Split('=')[1];
|
||||
release.Link = new Uri(string.Format(DownloadUrl, torrentId));
|
||||
|
||||
release.PublishDate = DateTimeUtil.FromTimeAgo(qDescCol.ChildNodes.Last().TextContent);
|
||||
|
||||
var sizeStr = row.Children[sizeIndex].TextContent;
|
||||
release.Size = ReleaseInfo.GetBytes(sizeStr);
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(row.Children[seedersIndex].TextContent.Trim());
|
||||
release.Peers = ParseUtil.CoerceInt(row.Children[leechersIndex].TextContent.Trim()) + release.Seeders;
|
||||
|
||||
release.DownloadVolumeFactor = row.QuerySelector("font > b:contains(Freeleech)") != null ? 0 : 1;
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
||||
using AngleSharp.Html.Parser;
|
||||
using Jackett.Common.Helpers;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.IndexerConfig;
|
||||
using Jackett.Common.Models.IndexerConfig.Bespoke;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Jackett.Common.Utils.Clients;
|
||||
@@ -31,7 +31,7 @@ namespace Jackett.Common.Indexers
|
||||
"https://speeders.me/"
|
||||
};
|
||||
|
||||
private new ConfigurationDataBasicLogin configData => (ConfigurationDataBasicLogin)base.configData;
|
||||
private new ConfigurationDataSpeedCD configData => (ConfigurationDataSpeedCD)base.configData;
|
||||
|
||||
public SpeedCD(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps,
|
||||
ICacheService cs)
|
||||
@@ -63,7 +63,7 @@ namespace Jackett.Common.Indexers
|
||||
logger: l,
|
||||
p: ps,
|
||||
cacheService: cs,
|
||||
configData: new ConfigurationDataBasicLogin(
|
||||
configData: new ConfigurationDataSpeedCD(
|
||||
@"Speed.Cd have increased their security. If you are having problems please check the security tab
|
||||
in your Speed.Cd profile. Eg. Geo Locking, your seedbox may be in a different country to the one where you login via your
|
||||
web browser.<br><br>For best results, change the 'Torrents per page' setting to 100 in 'Profile Settings > Torrents'."))
|
||||
@@ -116,7 +116,8 @@ namespace Jackett.Common.Indexers
|
||||
private async Task DoLogin()
|
||||
{
|
||||
// first request with username
|
||||
var pairs = new Dictionary<string, string> {
|
||||
var pairs = new Dictionary<string, string>
|
||||
{
|
||||
{ "username", configData.Username.Value }
|
||||
};
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl1, pairs, null, true, null, SiteLink);
|
||||
@@ -127,7 +128,8 @@ namespace Jackett.Common.Indexers
|
||||
var token = matches.Groups[1].Value;
|
||||
|
||||
// second request with token and password
|
||||
pairs = new Dictionary<string, string> {
|
||||
pairs = new Dictionary<string, string>
|
||||
{
|
||||
{ "pwd", configData.Password.Value },
|
||||
{ "a", token }
|
||||
};
|
||||
@@ -138,9 +140,11 @@ namespace Jackett.Common.Indexers
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(result.ContentString);
|
||||
var errorMessage = dom.QuerySelector("h5")?.TextContent;
|
||||
|
||||
if (result.ContentString.Contains("Wrong Captcha!"))
|
||||
errorMessage = "Captcha required due to a failed login attempt. Login via a browser to whitelist your IP and then reconfigure Jackett.";
|
||||
throw new Exception(errorMessage);
|
||||
|
||||
throw new Exception(errorMessage ?? "Login failed.");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -155,20 +159,42 @@ namespace Jackett.Common.Indexers
|
||||
foreach (var cat in catList)
|
||||
qc.Add(cat);
|
||||
|
||||
if (configData.Freeleech.Value)
|
||||
qc.Add("freeleech");
|
||||
|
||||
if (configData.ExcludeArchives.Value)
|
||||
qc.Add("norar");
|
||||
|
||||
if (query.IsImdbQuery)
|
||||
{
|
||||
var term = query.ImdbID;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.GetEpisodeSearchString()))
|
||||
{
|
||||
term += $" {query.GetEpisodeSearchString()}";
|
||||
|
||||
if (query.Season > 0 && string.IsNullOrEmpty(query.Episode))
|
||||
term += "*";
|
||||
}
|
||||
|
||||
qc.Add("deep");
|
||||
qc.Add("q");
|
||||
qc.Add(query.ImdbID);
|
||||
qc.Add(WebUtilityHelpers.UrlEncode(term.Trim(), Encoding));
|
||||
}
|
||||
else
|
||||
{
|
||||
var term = query.GetQueryString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.GetEpisodeSearchString()) && query.Season > 0 && string.IsNullOrEmpty(query.Episode))
|
||||
term += "*";
|
||||
|
||||
qc.Add("q");
|
||||
qc.Add(WebUtilityHelpers.UrlEncode(query.GetQueryString(), Encoding));
|
||||
qc.Add(WebUtilityHelpers.UrlEncode(term.Trim(), Encoding));
|
||||
}
|
||||
|
||||
var searchUrl = SearchUrl + string.Join("/", qc);
|
||||
var response = await RequestWithCookiesAndRetryAsync(searchUrl);
|
||||
|
||||
if (!response.ContentString.Contains("/logout.php")) // re-login
|
||||
{
|
||||
await DoLogin();
|
||||
@@ -179,42 +205,35 @@ namespace Jackett.Common.Indexers
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(response.ContentString);
|
||||
var rows = dom.QuerySelectorAll("div.boxContent > table > tbody > tr");
|
||||
|
||||
var rows = dom.QuerySelectorAll("div.boxContent > table > tbody > tr");
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var cells = row.QuerySelectorAll("td");
|
||||
|
||||
var title = row.QuerySelector("td[class='lft'] > div > a").TextContent.Trim();
|
||||
var link = new Uri(SiteLink + row.QuerySelector("img[title='Download']").ParentElement.GetAttribute("href").TrimStart('/'));
|
||||
var details = new Uri(SiteLink + row.QuerySelector("td[class='lft'] > div > a").GetAttribute("href").TrimStart('/'));
|
||||
var size = ReleaseInfo.GetBytes(cells[5].TextContent);
|
||||
var grabs = ParseUtil.CoerceInt(cells[6].TextContent);
|
||||
var seeders = ParseUtil.CoerceInt(cells[7].TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(cells[8].TextContent);
|
||||
|
||||
var pubDateStr = row.QuerySelector("span[class^='elapsedDate']").GetAttribute("title").Replace(" at", "");
|
||||
var publishDate = DateTime.ParseExact(pubDateStr, "dddd, MMMM d, yyyy h:mmtt", CultureInfo.InvariantCulture);
|
||||
|
||||
var cat = row.QuerySelector("a").GetAttribute("href").Split('/').Last();
|
||||
var downloadVolumeFactor = row.QuerySelector("span:contains(\"[Freeleech]\")") != null ? 0 : 1;
|
||||
var title = CleanTitle(row.QuerySelector("td:nth-child(2) > div > a[href^=\"/t/\"]")?.TextContent);
|
||||
var link = new Uri(SiteLink + row.QuerySelector("td:nth-child(4) a[href^=\"/download/\"]")?.GetAttribute("href")?.TrimStart('/'));
|
||||
var details = new Uri(SiteLink + row.QuerySelector("td:nth-child(2) > div > a[href^=\"/t/\"]")?.GetAttribute("href")?.TrimStart('/'));
|
||||
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)")?.TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(9)")?.TextContent);
|
||||
var pubDateStr = row.QuerySelector("td:nth-child(2) span[class^=\"elapsedDate\"]")?.GetAttribute("title")?.Replace(" at", "");
|
||||
var cat = row.QuerySelector("td:nth-child(1) a")?.GetAttribute("href")?.Split('/').Last();
|
||||
var downloadVolumeFactor = row.QuerySelector("td:nth-child(2) span:contains(\"[Freeleech]\")") != null ? 0 : 1;
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
Title = title,
|
||||
Link = link,
|
||||
Guid = link,
|
||||
Link = link,
|
||||
Details = details,
|
||||
PublishDate = publishDate,
|
||||
Title = title,
|
||||
Category = MapTrackerCatToNewznab(cat),
|
||||
Size = size,
|
||||
Grabs = grabs,
|
||||
PublishDate = DateTime.ParseExact(pubDateStr, "dddd, MMMM d, yyyy h:mmtt", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal),
|
||||
Size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-child(6)")?.TextContent),
|
||||
Grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)")?.TextContent),
|
||||
Seeders = seeders,
|
||||
Peers = seeders + leechers,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 259200, // 72 hours
|
||||
DownloadVolumeFactor = downloadVolumeFactor,
|
||||
UploadVolumeFactor = 1
|
||||
UploadVolumeFactor = 1,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 259200 // 72 hours
|
||||
};
|
||||
|
||||
releases.Add(release);
|
||||
@@ -226,5 +245,12 @@ namespace Jackett.Common.Indexers
|
||||
}
|
||||
return releases;
|
||||
}
|
||||
|
||||
private static string CleanTitle(string title)
|
||||
{
|
||||
title = Regex.Replace(title, @"\[REQ(UEST)?\]", string.Empty, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
return title.Trim(' ', '.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
@@ -9,29 +10,26 @@ using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.IndexerConfig.Bespoke;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Jackett.Common.Utils.Clients;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using WebClient = Jackett.Common.Utils.Clients.WebClient;
|
||||
|
||||
namespace Jackett.Common.Indexers
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class Toloka : BaseWebIndexer
|
||||
{
|
||||
private string LoginUrl => SiteLink + "/login.php";
|
||||
private string SearchUrl => SiteLink + "/tracker.php";
|
||||
|
||||
protected string cap_sid = null;
|
||||
protected string cap_code_field = null;
|
||||
|
||||
private new ConfigurationDataToloka configData
|
||||
{
|
||||
get => (ConfigurationDataToloka)base.configData;
|
||||
set => base.configData = value;
|
||||
}
|
||||
|
||||
public Toloka(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps,
|
||||
ICacheService cs)
|
||||
private readonly TitleParser _titleParser = new TitleParser();
|
||||
private string LoginUrl => SiteLink + "login.php";
|
||||
private string SearchUrl => SiteLink + "tracker.php";
|
||||
|
||||
public Toloka(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps, ICacheService cs)
|
||||
: base(id: "toloka",
|
||||
name: "Toloka.to",
|
||||
description: "Toloka is a Semi-Private Ukrainian torrent site with a thriving file-sharing community",
|
||||
@@ -209,6 +207,7 @@ namespace Jackett.Common.Indexers
|
||||
{ "password", configData.Password.Value },
|
||||
{ "autologin", "on" },
|
||||
{ "ssl", "on" },
|
||||
{ "redirect", "" },
|
||||
{ "login", "Вхід" }
|
||||
};
|
||||
|
||||
@@ -216,15 +215,14 @@ namespace Jackett.Common.Indexers
|
||||
await ConfigureIfOK(result.Cookies, result.ContentString != null && result.ContentString.Contains("logout=true"), () =>
|
||||
{
|
||||
logger.Debug(result.ContentString);
|
||||
var errorMessage = "Unknown error message, please report";
|
||||
var LoginResultParser = new HtmlParser();
|
||||
var LoginResultDocument = LoginResultParser.ParseDocument(result.ContentString);
|
||||
var errormsg = LoginResultDocument.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]");
|
||||
if (errormsg != null)
|
||||
errorMessage = errormsg.TextContent;
|
||||
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
var loginResultParser = new HtmlParser();
|
||||
var loginResultDocument = loginResultParser.ParseDocument(result.ContentString);
|
||||
var errorMessage = loginResultDocument.QuerySelector("table.forumline table span.gen")?.FirstChild?.TextContent;
|
||||
|
||||
throw new ExceptionWithConfigData(errorMessage ?? "Unknown error message, please report.", configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
@@ -241,16 +239,12 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
// if the search string is empty use the getnew view
|
||||
if (string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
qc.Add("nm", searchString);
|
||||
}
|
||||
else // use the normal search
|
||||
{
|
||||
searchString = searchString.Replace("-", " ");
|
||||
if (query.Season != 0)
|
||||
{
|
||||
searchString += " Сезон " + query.Season;
|
||||
}
|
||||
qc.Add("nm", searchString);
|
||||
}
|
||||
|
||||
@@ -259,81 +253,63 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
var searchUrl = SearchUrl + "?" + qc.GetQueryString();
|
||||
var results = await RequestWithCookiesAsync(searchUrl);
|
||||
|
||||
if (!results.ContentString.Contains("logout=true"))
|
||||
{
|
||||
// re login
|
||||
await ApplyConfiguration(null);
|
||||
results = await RequestWithCookiesAsync(searchUrl);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var RowsSelector = "table.forumline > tbody > tr[class*=prow]";
|
||||
var searchResultParser = new HtmlParser();
|
||||
var searchResultDocument = searchResultParser.ParseDocument(results.ContentString);
|
||||
var rows = searchResultDocument.QuerySelectorAll("table.forumline > tbody > tr[class*=\"prow\"]");
|
||||
|
||||
var SearchResultParser = new HtmlParser();
|
||||
var SearchResultDocument = SearchResultParser.ParseDocument(results.ContentString);
|
||||
var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector);
|
||||
foreach (var Row in Rows)
|
||||
foreach (var row in rows)
|
||||
{
|
||||
try
|
||||
{
|
||||
var qDownloadLink = Row.QuerySelector("td:nth-child(6) > a");
|
||||
var qDownloadLink = row.QuerySelector("td:nth-child(6) > a");
|
||||
if (qDownloadLink == null) // Expects moderation
|
||||
continue;
|
||||
|
||||
var qDetailsLink = Row.QuerySelector("td:nth-child(3) > a");
|
||||
var qSize = Row.QuerySelector("td:nth-child(7)");
|
||||
var seedersStr = Row.QuerySelector("td:nth-child(10) > b").TextContent;
|
||||
var seeders = string.IsNullOrWhiteSpace(seedersStr) ? 0 : ParseUtil.CoerceInt(seedersStr);
|
||||
var timestr = Row.QuerySelector("td:nth-child(13)").TextContent;
|
||||
var forum = Row.QuerySelector("td:nth-child(2) > a");
|
||||
var forumid = forum.GetAttribute("href").Split('=')[1];
|
||||
var qDetailsLink = row.QuerySelector("td:nth-child(3) > a");
|
||||
var details = new Uri(SiteLink + qDetailsLink.GetAttribute("href"));
|
||||
var title = qDetailsLink.TextContent.Trim();
|
||||
var link = new Uri(SiteLink + qDownloadLink.GetAttribute("href"));
|
||||
var size = ReleaseInfo.GetBytes(qSize.TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(Row.QuerySelector("td:nth-child(11) > b").TextContent);
|
||||
var publishDate = DateTimeUtil.FromFuzzyTime(timestr);
|
||||
var forumLink = row.QuerySelector("td:nth-child(2) > a").GetAttribute("href");
|
||||
var forumId = ParseUtil.GetArgumentFromQueryString(forumLink, "f");
|
||||
var category = MapTrackerCatToNewznab(forumId);
|
||||
var seedersStr = row.QuerySelector("td:nth-child(10) > b").TextContent;
|
||||
var seeders = string.IsNullOrWhiteSpace(seedersStr) ? 0 : ParseUtil.CoerceInt(seedersStr);
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(11) > b").TextContent);
|
||||
|
||||
var release = new ReleaseInfo
|
||||
{
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 0,
|
||||
Title = qDetailsLink.TextContent,
|
||||
Guid = details,
|
||||
Details = details,
|
||||
Link = link,
|
||||
Guid = details,
|
||||
Size = size,
|
||||
Title = _titleParser.Parse(title, category, configData.StripCyrillicLetters.Value),
|
||||
Description = title,
|
||||
Category = category,
|
||||
Size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-child(7)").TextContent),
|
||||
Seeders = seeders,
|
||||
Peers = leechers + seeders,
|
||||
Grabs = 0, //ParseUtil.CoerceLong(Row.QuerySelector("td:nth-child(9)").TextContent);
|
||||
PublishDate = publishDate,
|
||||
Category = MapTrackerCatToNewznab(forumid),
|
||||
PublishDate = DateTimeUtil.FromFuzzyTime(row.QuerySelector("td:nth-child(13)").TextContent),
|
||||
DownloadVolumeFactor = 1,
|
||||
UploadVolumeFactor = 1
|
||||
UploadVolumeFactor = 1,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 0
|
||||
};
|
||||
|
||||
// TODO cleanup
|
||||
if (release.Category.Contains(TorznabCatType.TV.ID))
|
||||
{
|
||||
// extract season and episodes
|
||||
var regex = new Regex(".+\\/\\s([^а-яА-я\\/]+)\\s\\/.+Сезон\\s*[:]*\\s+(\\d+).+(?:Серії|Епізод)+\\s*[:]*\\s+(\\d+-*\\d*).+,\\s+(.+)\\]\\s(.+)");
|
||||
var title = regex.Replace(release.Title, "$1 - S$2E$3 - rus $4 $5");
|
||||
title = Regex.Replace(title, "-Rip", "Rip", RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, "WEB-DLRip", "WEBDL", RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, "WEB-DL", "WEBDL", RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, "HDTVRip", "HDTV", RegexOptions.IgnoreCase);
|
||||
|
||||
release.Title = title;
|
||||
}
|
||||
else if (configData.StripCyrillicLetters.Value)
|
||||
{
|
||||
var regex = new Regex(@"(\([А-Яа-яіІєЄїЇ\W]+\))|(^[А-Яа-яіІєЄїЇ\W\d]+\/ )|([а-яА-ЯіІєЄїЇ \-]+,+)|([а-яА-ЯіІєЄїЇ]+)");
|
||||
release.Title = regex.Replace(release.Title, "");
|
||||
}
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", Id, Row.OuterHtml, ex));
|
||||
logger.Error($"{Id}: Error while parsing row '{row.OuterHtml}':\n\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,5 +320,112 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
return releases;
|
||||
}
|
||||
|
||||
public class TitleParser
|
||||
{
|
||||
private static readonly List<Regex> _FindTagsInTitlesRegexList = new List<Regex>
|
||||
{
|
||||
new Regex(@"\((?>\((?<c>)|[^()]+|\)(?<-c>))*(?(c)(?!))\)"),
|
||||
new Regex(@"\[(?>\[(?<c>)|[^\[\]]+|\](?<-c>))*(?(c)(?!))\]")
|
||||
};
|
||||
|
||||
private readonly Regex _tvTitleCommaRegex = new Regex(@"\s(\d+),(\d+)", RegexOptions.Compiled);
|
||||
private readonly Regex _tvTitleCyrillicXRegex = new Regex(@"([\s-])Х+([\)\]])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly Regex _tvTitleMultipleSeasonsRegex = new Regex(@"(?:Сезон|Seasons?)\s*[:]*\s+(\d+-\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly Regex _tvTitleUkrSeasonEpisodeOfRegex = new Regex(@"Сезон\s*[:]*\s+(\d+).+(?:Серії|Серія|Серій|Епізод)+\s*[:]*\s+(\d+(?:-\d+)?)\s*з\s*([\w?])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleUkrSeasonEpisodeRegex = new Regex(@"Сезон\s*[:]*\s+(\d+).+(?:Серії|Серія|Серій|Епізод)+\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleUkrSeasonRegex = new Regex(@"Сезон\s*[:]*\s+(\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleUkrEpisodeOfRegex = new Regex(@"(?:Серії|Серія|Серій|Епізод)+\s*[:]*\s+(\d+(?:-\d+)?)\s*з\s*([\w?])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleUkrEpisodeRegex = new Regex(@"(?:Серії|Серія|Серій|Епізод)+\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly Regex _tvTitleEngSeasonEpisodeOfRegex = new Regex(@"Season\s*[:]*\s+(\d+).+(?:Episodes?)+\s*[:]*\s+(\d+(?:-\d+)?)\s*of\s*([\w?])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleEngSeasonEpisodeRegex = new Regex(@"Season\s*[:]*\s+(\d+).+(?:Episodes?)+\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleEngSeasonRegex = new Regex(@"Season\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleEngEpisodeOfRegex = new Regex(@"(?:Episodes?)+\s*[:]*\s+(\d+(?:-\d+)?)\s*of\s*([\w?])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex _tvTitleEngEpisodeRegex = new Regex(@"(?:Episodes?)+\s*[:]+\s*[:]*\s+(\d+(?:-\d+)?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly Regex _stripCyrillicRegex = new Regex(@"(\([\p{IsCyrillic}\W]+\))|(^[\p{IsCyrillic}\W\d]+\/ )|([\p{IsCyrillic} \-]+,+)|([\p{IsCyrillic}]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public string Parse(string title, ICollection<int> category, bool stripCyrillicLetters = true)
|
||||
{
|
||||
// https://www.fileformat.info/info/unicode/category/Pd/list.htm
|
||||
title = Regex.Replace(title, @"\p{Pd}", "-", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
if (IsAnyTvCategory(category))
|
||||
{
|
||||
title = _tvTitleCommaRegex.Replace(title, " $1-$2");
|
||||
title = _tvTitleCyrillicXRegex.Replace(title, "$1XX$2");
|
||||
|
||||
// special case for multiple seasons
|
||||
title = _tvTitleMultipleSeasonsRegex.Replace(title, "S$1");
|
||||
|
||||
title = _tvTitleUkrSeasonEpisodeOfRegex.Replace(title, "S$1E$2 of $3");
|
||||
title = _tvTitleUkrSeasonEpisodeRegex.Replace(title, "S$1E$2");
|
||||
title = _tvTitleUkrSeasonRegex.Replace(title, "S$1");
|
||||
title = _tvTitleUkrEpisodeOfRegex.Replace(title, "E$1 of $2");
|
||||
title = _tvTitleUkrEpisodeRegex.Replace(title, "E$1");
|
||||
|
||||
title = _tvTitleEngSeasonEpisodeOfRegex.Replace(title, "S$1E$2 of $3");
|
||||
title = _tvTitleEngSeasonEpisodeRegex.Replace(title, "S$1E$2");
|
||||
title = _tvTitleEngSeasonRegex.Replace(title, "S$1");
|
||||
title = _tvTitleEngEpisodeOfRegex.Replace(title, "E$1 of $2");
|
||||
title = _tvTitleEngEpisodeRegex.Replace(title, "E$1");
|
||||
}
|
||||
|
||||
if (stripCyrillicLetters)
|
||||
title = _stripCyrillicRegex.Replace(title, string.Empty).Trim(' ', '-');
|
||||
|
||||
title = Regex.Replace(title, @"\b-Rip\b", "Rip", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bHDTVRip\b", "HDTV", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bWEB-DLRip\b", "WEB-DL", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bWEBDLRip\b", "WEB-DL", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
title = Regex.Replace(title, @"\bWEBDL\b", "WEB-DL", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
title = MoveFirstTagsToEndOfReleaseTitle(title);
|
||||
|
||||
title = Regex.Replace(title, @"\(\s*\/\s*", "(", RegexOptions.Compiled);
|
||||
title = Regex.Replace(title, @"\s*\/\s*\)", ")", RegexOptions.Compiled);
|
||||
|
||||
title = Regex.Replace(title, @"[\[\(]\s*[\)\]]", "", RegexOptions.Compiled);
|
||||
|
||||
title = title.Trim(' ', '&', ',', '.', '!', '?', '+', '-', '_', '|', '/', '\\', ':');
|
||||
|
||||
// replace multiple spaces with a single space
|
||||
title = Regex.Replace(title, @"\s+", " ");
|
||||
|
||||
return title.Trim();
|
||||
}
|
||||
|
||||
private static bool IsAnyTvCategory(ICollection<int> category) => category.Contains(TorznabCatType.TV.ID) || TorznabCatType.TV.SubCategories.Any(subCat => category.Contains(subCat.ID));
|
||||
|
||||
private static string MoveFirstTagsToEndOfReleaseTitle(string input)
|
||||
{
|
||||
var output = input;
|
||||
foreach (var findTagsRegex in _FindTagsInTitlesRegexList)
|
||||
{
|
||||
var expectedIndex = 0;
|
||||
foreach (Match match in findTagsRegex.Matches(output))
|
||||
{
|
||||
if (match.Index > expectedIndex)
|
||||
{
|
||||
var substring = output.Substring(expectedIndex, match.Index - expectedIndex);
|
||||
if (string.IsNullOrWhiteSpace(substring))
|
||||
expectedIndex = match.Index;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
var tag = match.ToString();
|
||||
var regex = new Regex(Regex.Escape(tag));
|
||||
output = $"{regex.Replace(output, string.Empty, 1)} {tag}".Trim();
|
||||
expectedIndex += tag.Length;
|
||||
}
|
||||
}
|
||||
|
||||
return output.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,8 +25,7 @@ namespace Jackett.Common.Indexers
|
||||
private string LoginUrl => SiteLink + "takelogin.php";
|
||||
private string GetRSSKeyUrl => SiteLink + "getrss.php";
|
||||
private string SearchUrl => SiteLink + "browse.php";
|
||||
private readonly Regex _dateMatchRegex = new Regex(
|
||||
@"\d{2}-\d{2}-\d{4} \d{2}:\d{2}", RegexOptions.Compiled);
|
||||
private readonly Regex _dateMatchRegex = new Regex(@"\d{2}-\d{2}-\d{4} \d{2}:\d{2}", RegexOptions.Compiled);
|
||||
|
||||
private new ConfigurationDataBasicLoginWithRSSAndDisplay configData =>
|
||||
(ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData;
|
||||
@@ -143,8 +142,35 @@ namespace Jackett.Common.Indexers
|
||||
AddCategoryMapping("Wii Games", TorznabCatType.ConsoleWii);
|
||||
AddCategoryMapping("Wrestling", TorznabCatType.TVSport);
|
||||
AddCategoryMapping("Xbox Games", TorznabCatType.ConsoleXBox);
|
||||
|
||||
// Configure the sort selects
|
||||
var sortBySelect = new SingleSelectConfigurationItem(
|
||||
"Sort by",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "added", "created" },
|
||||
{ "seeders", "seeders" },
|
||||
{ "size", "size" },
|
||||
{ "name", "title" }
|
||||
})
|
||||
{ Value = "added" };
|
||||
configData.AddDynamic("sortrequestedfromsite", sortBySelect);
|
||||
|
||||
var orderSelect = new SingleSelectConfigurationItem(
|
||||
"Order",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "desc", "descending" },
|
||||
{ "asc", "ascending" }
|
||||
})
|
||||
{ Value = "desc" };
|
||||
configData.AddDynamic("orderrequestedfromsite", orderSelect);
|
||||
}
|
||||
|
||||
private string GetSortBy => ((SingleSelectConfigurationItem)configData.GetDynamic("sortrequestedfromsite")).Value;
|
||||
|
||||
private string GetOrder => ((SingleSelectConfigurationItem)configData.GetDynamic("orderrequestedfromsite")).Value;
|
||||
|
||||
public override async Task<ConfigurationData> GetConfigurationForSetup()
|
||||
{
|
||||
var loginPage = await RequestWithCookiesAsync(LandingUrl);
|
||||
@@ -171,12 +197,11 @@ namespace Jackett.Common.Indexers
|
||||
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
LoadValuesFromJson(configJson);
|
||||
|
||||
var pairs = new Dictionary<string, string>
|
||||
{
|
||||
{"username", configData.Username.Value},
|
||||
{"password", configData.Password.Value}
|
||||
};
|
||||
{
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value }
|
||||
};
|
||||
|
||||
var captchaText = (StringConfigurationItem)configData.GetDynamic("CaptchaText");
|
||||
if (captchaText != null)
|
||||
@@ -184,26 +209,26 @@ namespace Jackett.Common.Indexers
|
||||
|
||||
//var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink, true);
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SearchUrl, LandingUrl, true);
|
||||
await ConfigureIfOK(result.Cookies, result.ContentString?.Contains("logout.php") == true,
|
||||
() =>
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(result.ContentString);
|
||||
var errorMessage = dom.QuerySelector(".left_side table:nth-of-type(1) tr:nth-of-type(2)")?.TextContent.Trim().Replace("\n\t", " ");
|
||||
if (string.IsNullOrWhiteSpace(errorMessage))
|
||||
errorMessage = dom.QuerySelector("div.notification-body").TextContent.Trim().Replace("\n\t", " ");
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
});
|
||||
await ConfigureIfOK(result.Cookies, result.ContentString?.Contains("logout.php") == true, () =>
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(result.ContentString);
|
||||
var errorMessage = dom.QuerySelector(".left_side table:nth-of-type(1) tr:nth-of-type(2)")?.TextContent.Trim().Replace("\n\t", " ");
|
||||
if (string.IsNullOrWhiteSpace(errorMessage))
|
||||
errorMessage = dom.QuerySelector("div.notification-body")?.TextContent.Trim().Replace("\n\t", " ");
|
||||
|
||||
throw new ExceptionWithConfigData(errorMessage ?? "Login failed.", configData);
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
// Get RSS key
|
||||
var rssParams = new Dictionary<string, string>
|
||||
{
|
||||
{"feedtype", "download"},
|
||||
{"timezone", "0"},
|
||||
{"showrows", "50"}
|
||||
};
|
||||
{
|
||||
{ "feedtype", "download" },
|
||||
{ "timezone", "0" },
|
||||
{ "showrows", "50" }
|
||||
};
|
||||
var rssPage = await RequestWithCookiesAsync(
|
||||
GetRSSKeyUrl, result.Cookies, RequestType.POST, data: rssParams);
|
||||
var match = Regex.Match(rssPage.ContentString, "(?<=secret_key\\=)([a-zA-z0-9]*)");
|
||||
@@ -217,19 +242,24 @@ namespace Jackett.Common.Indexers
|
||||
IsConfigured = false;
|
||||
throw;
|
||||
}
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
var searchString = query.GetQueryString();
|
||||
var prevCook = CookieHeader + "";
|
||||
|
||||
var searchParams = new Dictionary<string, string> {
|
||||
var categoryMapping = MapTorznabCapsToTrackers(query);
|
||||
|
||||
var searchParams = new Dictionary<string, string>
|
||||
{
|
||||
{ "do", "search" },
|
||||
{ "category", "0" },
|
||||
{ "include_dead_torrents", "no" }
|
||||
{ "category", categoryMapping.FirstIfSingleOrDefault("0") }, // multi category search not supported
|
||||
{ "include_dead_torrents", "yes" },
|
||||
{ "sort", GetSortBy },
|
||||
{ "order", GetOrder }
|
||||
};
|
||||
|
||||
if (query.IsImdbQuery)
|
||||
@@ -243,16 +273,16 @@ namespace Jackett.Common.Indexers
|
||||
searchParams.Add("search_type", "t_name");
|
||||
}
|
||||
|
||||
var searchPage = await RequestWithCookiesAndRetryAsync(
|
||||
SearchUrl, CookieHeader, RequestType.POST, null, searchParams);
|
||||
var searchPage = await RequestWithCookiesAndRetryAsync(SearchUrl, CookieHeader, RequestType.POST, null, searchParams);
|
||||
// Occasionally the cookies become invalid, login again if that happens
|
||||
if (searchPage.IsRedirect)
|
||||
{
|
||||
await ApplyConfiguration(null);
|
||||
searchPage = await RequestWithCookiesAndRetryAsync(
|
||||
SearchUrl, CookieHeader, RequestType.POST, null, searchParams);
|
||||
searchPage = await RequestWithCookiesAndRetryAsync(SearchUrl, CookieHeader, RequestType.POST, null, searchParams);
|
||||
}
|
||||
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
try
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
@@ -270,13 +300,13 @@ namespace Jackett.Common.Indexers
|
||||
release.Guid = new Uri(row.QuerySelector("td:nth-of-type(3) a").GetAttribute("href"));
|
||||
release.Link = release.Guid;
|
||||
release.Details = new Uri(qDetails.GetAttribute("href"));
|
||||
//08-08-2015 12:51
|
||||
|
||||
// 08-08-2015 12:51
|
||||
// requests can be 'Pre Release Time: 25-04-2021 15:00 Uploaded: 3 Weeks, 2 Days, 23 Hours, 53 Minutes, 39 Seconds after Pre'
|
||||
var dateMatch = _dateMatchRegex.Match(row.QuerySelectorAll("td:nth-of-type(2) div").Last().TextContent.Trim());
|
||||
var dateMatch = _dateMatchRegex.Match(row.QuerySelector("td:nth-of-type(2) > div:last-child").TextContent.Trim());
|
||||
if (dateMatch.Success)
|
||||
release.PublishDate = DateTime.ParseExact(dateMatch.Value
|
||||
, "dd-MM-yyyy H:mm",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
release.PublishDate = DateTime.ParseExact(dateMatch.Value, "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture);
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(7)").TextContent);
|
||||
release.Peers = release.Seeders + ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(8)").TextContent.Trim());
|
||||
release.Size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-of-type(5)").TextContent.Trim());
|
||||
@@ -285,15 +315,16 @@ namespace Jackett.Common.Indexers
|
||||
if (qPoster != null)
|
||||
release.Poster = new Uri(qPoster.GetAttribute("src"));
|
||||
|
||||
var cat = row.QuerySelector("td:nth-of-type(1) a").GetAttribute("href");
|
||||
var catSplit = cat.LastIndexOf('=');
|
||||
if (catSplit > -1)
|
||||
cat = cat.Substring(catSplit + 1);
|
||||
var categoryLink = row.QuerySelector("td:nth-of-type(1) a").GetAttribute("href");
|
||||
var cat = ParseUtil.GetArgumentFromQueryString(categoryLink, "category");
|
||||
release.Category = MapTrackerCatToNewznab(cat);
|
||||
|
||||
var grabs = row.QuerySelector("td:nth-child(6)").TextContent;
|
||||
release.Grabs = ParseUtil.CoerceInt(grabs);
|
||||
|
||||
var cover = row.QuerySelector("td:nth-of-type(2) > div > img[src]")?.GetAttribute("src")?.Trim();
|
||||
release.Poster = !string.IsNullOrEmpty(cover) && cover.StartsWith("http") ? new Uri(cover) : null;
|
||||
|
||||
if (row.QuerySelector("img[alt^=\"Free Torrent\"]") != null)
|
||||
release.DownloadVolumeFactor = 0;
|
||||
else if (row.QuerySelector("img[alt^=\"Silver Torrent\"]") != null)
|
||||
|
@@ -5,13 +5,13 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal class ConfigurationDataFileList : ConfigurationDataUserPasskey
|
||||
{
|
||||
public BoolConfigurationItem IncludeRomanianReleases { get; private set; }
|
||||
public DisplayInfoConfigurationItem CatWarning { get; private set; }
|
||||
public BoolConfigurationItem Freeleech { get; set; }
|
||||
public DisplayInfoConfigurationItem CatWarning { get; set; }
|
||||
|
||||
public ConfigurationDataFileList()
|
||||
: base("Note this is <b>not</b> your <i>password</i>.<ul><li>Login to the FileList Website</li><li>Click on the <b>Profile</b> link</li><li>Scroll down to the <b>Reset Passkey</b> section</li><li>Copy the <b>passkey</b>.</li><li>Also be aware of not leaving a trailing blank at the end of the passkey after pasting it here.</li></ul>")
|
||||
{
|
||||
IncludeRomanianReleases = new BoolConfigurationItem("IncludeRomanianReleases") { Value = false };
|
||||
Freeleech = new BoolConfigurationItem("Search freeleech only") { Value = false };
|
||||
CatWarning = new DisplayInfoConfigurationItem("CatWarning", "When mapping TV ensure you add category 5000 in addition to 5030, 5040.");
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jackett.Common.Models.IndexerConfig.Bespoke
|
||||
@@ -7,16 +8,30 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke
|
||||
{
|
||||
public StringConfigurationItem MamId { get; private set; }
|
||||
public DisplayInfoConfigurationItem MamIdHint { get; private set; }
|
||||
public BoolConfigurationItem ExcludeVip { get; private set; }
|
||||
public DisplayInfoConfigurationItem Instructions { get; private set; }
|
||||
public SingleSelectConfigurationItem SearchType { get; private set; }
|
||||
public BoolConfigurationItem SearchInDescription { get; private set; }
|
||||
public BoolConfigurationItem SearchInSeries { get; private set; }
|
||||
public BoolConfigurationItem SearchInFilenames { get; private set; }
|
||||
|
||||
public ConfigurationDataMyAnonamouse()
|
||||
{
|
||||
MamId = new StringConfigurationItem("mam_id");
|
||||
MamIdHint = new DisplayInfoConfigurationItem("mam_id instructions", "Go to your <a href=\"https://www.myanonamouse.net/preferences/index.php?view=security\" target=\"_blank\">security preferences</a> and create a new session for the IP used by the Jackett server. Then paste the resulting mam_id value into the mam_id field here.");
|
||||
ExcludeVip = new BoolConfigurationItem("Exclude VIP torrents");
|
||||
Instructions = new DisplayInfoConfigurationItem("", "For best results, change the 'Torrents per page' setting to 100 in your Profile => Torrent tab.");
|
||||
SearchType = new SingleSelectConfigurationItem(
|
||||
"Search Type",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "all", "All torrents" },
|
||||
{ "active", "Only active" },
|
||||
{ "fl", "Freeleech" },
|
||||
{ "fl-VIP", "Freeleech or VIP" },
|
||||
{ "VIP", "VIP torrents" },
|
||||
{ "nVIP", "Torrents not VIP" },
|
||||
})
|
||||
{ Value = "all" };
|
||||
SearchInDescription = new BoolConfigurationItem("Also search text in the description") { Value = false };
|
||||
SearchInSeries = new BoolConfigurationItem("Also search text in the series") { Value = false };
|
||||
SearchInFilenames = new BoolConfigurationItem("Also search text in the filenames") { Value = false };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,18 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jackett.Common.Models.IndexerConfig.Bespoke
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ConfigurationDataSpeedCD : ConfigurationDataBasicLogin
|
||||
{
|
||||
public BoolConfigurationItem Freeleech { get; set; }
|
||||
public BoolConfigurationItem ExcludeArchives { get; set; }
|
||||
|
||||
public ConfigurationDataSpeedCD(string instructionMessageOptional = null)
|
||||
: base(instructionMessageOptional)
|
||||
{
|
||||
Freeleech = new BoolConfigurationItem("Search freeleech only") { Value = false };
|
||||
ExcludeArchives = new BoolConfigurationItem("Exclude torrents with RAR files") { Value = false };
|
||||
}
|
||||
}
|
||||
}
|
52
src/Jackett.Test/Common/Indexers/RuTracker/RuTrackerTests.cs
Normal file
52
src/Jackett.Test/Common/Indexers/RuTracker/RuTrackerTests.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Jackett.Common.Models;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Jackett.Test.Common.Indexers.RuTracker
|
||||
{
|
||||
[TestFixture]
|
||||
public class RuTrackerTests
|
||||
{
|
||||
[TestCaseSource(typeof(TitleParserTestData), nameof(TitleParserTestData.TestCases))]
|
||||
public string TestTitleParsing(string title, ICollection<int> category, bool stripCyrillicLetters, bool moveAllTagsToEndOfReleaseTitle, bool moveFirstTagsToEndOfReleaseTitle)
|
||||
{
|
||||
var titleParser = new Jackett.Common.Indexers.RuTracker.TitleParser();
|
||||
|
||||
return titleParser.Parse(title, category, stripCyrillicLetters, moveAllTagsToEndOfReleaseTitle, moveFirstTagsToEndOfReleaseTitle);
|
||||
}
|
||||
}
|
||||
|
||||
public class TitleParserTestData
|
||||
{
|
||||
public static IEnumerable TestCases
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Терапия / Shrinking / Сезон: 1 / серии: 1-2 из 10 (Джеймс Понсольдт) [2023, США, комедия, WEB-DLRip] Dub (Iyuno-SDI Group) + Original + Sub Rus", new List<int> { TorznabCatType.TVSD.ID }, false, false, false).Returns("Терапия / Shrinking / S1E1-2 of 10 (Джеймс Понсольдт) [2023, США, комедия, WEB-DL] Dub (Iyuno-SDI Group) + Original + Sub Rus");
|
||||
yield return new TestCaseData("Новичок / Новобранец / The Rookie / сезон: 5 / Серии: 1-14 из ?? (Майкл Гои, Билл Роу) [2022, США, боевик, драма, криминал, WEB-DLRip] MVO (LostFilm) + Original", new List<int> { TorznabCatType.TVForeign.ID }, false, false, false).Returns("Новичок / Новобранец / The Rookie / S5E1-14 of ?? (Майкл Гои, Билл Роу) [2022, США, боевик, драма, криминал, WEB-DL] MVO (LostFilm) + Original");
|
||||
yield return new TestCaseData("Красный яр / Сезон: 1-8 (Михаил Вассербаум) [2022, детектив, WEBRip-AVC]", new List<int> { TorznabCatType.TVOther.ID }, false, false, false).Returns("Красный яр / S1-8 (Михаил Вассербаум) [2022, детектив, WEBRip-AVC]");
|
||||
yield return new TestCaseData("Просто Михалыч / Эпизод: 1-5 из ХХ (Евгений Корчагин) [2022, комедия, WEBRip 720p]", new List<int> { TorznabCatType.TVHD.ID }, false, false, false).Returns("Просто Михалыч / E1-5 of XX (Евгений Корчагин) [2022, комедия, WEBRip 720p]");
|
||||
yield return new TestCaseData("Открывай, полиция! / Выпуски: 1,2 (Сергей Гинзбург) [2022, комедия, WEBRip]", new List<int> { TorznabCatType.TV.ID }, false, false, false).Returns("Открывай, полиция! / E1-2 (Сергей Гинзбург) [2022, комедия, WEBRip]");
|
||||
|
||||
yield return new TestCaseData("Терапия / Shrinking / Сезон: 1 / серии: 1-2 из 10 (Джеймс Понсольдт) [2023, США, комедия, WEB-DLRip] Dub (Iyuno-SDI Group) + Original + Sub Rus", new List<int> { TorznabCatType.TVHD.ID }, true, false, false).Returns("Shrinking / S1E1-2 of 10 [2023, WEB-DL] Dub (Iyuno-SDI Group) + Original + Sub Rus");
|
||||
yield return new TestCaseData("Новичок / Новобранец / The Rookie / сезон: 5 / Серии: 1-14 из ?? (Майкл Гои, Билл Роу) [2022, США, боевик, драма, криминал, WEB-DLRip] MVO (LostFilm) + Original", new List<int> { TorznabCatType.TVForeign.ID }, true, false, false).Returns("The Rookie / S5E1-14 of ?? [2022, WEB-DL] MVO (LostFilm) + Original");
|
||||
yield return new TestCaseData("Красный яр / Сезон: 1-8 (Михаил Вассербаум) [2022, детектив, WEBRip-AVC]", new List<int> { TorznabCatType.TVOther.ID }, true, false, false).Returns("S1-8 [2022, WEBRip-AVC]");
|
||||
yield return new TestCaseData("Просто Михалыч / Эпизод: 1-5 из ХХ (Евгений Корчагин) [2022, комедия, WEBRip 720p]", new List<int> { TorznabCatType.TVHD.ID }, true, false, false).Returns("E1-5 of XX [2022, WEBRip 720p]");
|
||||
yield return new TestCaseData("Открывай, полиция! / Выпуски: 1,2 (Сергей Гинзбург) [2022, комедия, WEBRip]", new List<int> { TorznabCatType.TV.ID }, true, false, false).Returns("E1-2 [2022, WEBRip]");
|
||||
|
||||
yield return new TestCaseData("Терапия / Shrinking / Сезон: 1 / Серии: 1-2 из 10 (Джеймс Понсольдт) [2023, США, комедия, WEB-DLRip] Dub (Iyuno-SDI Group) + Original + Sub Rus", new List<int> { TorznabCatType.TVUHD.ID }, true, false, true).Returns("Shrinking / S1E1-2 of 10 [2023, WEB-DL] Dub (Iyuno-SDI Group) + Original + Sub Rus");
|
||||
yield return new TestCaseData("Новичок / Новобранец / The Rookie / Сезон: 5 / Серии: 1-14 из ?? (Майкл Гои, Билл Роу) [2022, США, боевик, драма, криминал, WEB-DLRip] MVO (LostFilm) + Original", new List<int> { TorznabCatType.TVSport.ID }, true, false, true).Returns("The Rookie / S5E1-14 of ?? [2022, WEB-DL] MVO (LostFilm) + Original");
|
||||
|
||||
yield return new TestCaseData("Терапия / Shrinking / Сезон: 1 / Серии: 1-2 из 10 (Джеймс Понсольдт) [2023, США, комедия, WEB-DLRip] Dub (Iyuno-SDI Group) + Original + Sub Rus", new List<int> { TorznabCatType.TVAnime.ID }, true, true, false).Returns("Shrinking / S1E1-2 of 10 Dub + Original + Sub Rus (Iyuno-SDI Group) [2023, WEB-DL]");
|
||||
yield return new TestCaseData("Новичок / Новобранец / The Rookie / Сезон: 5 / Серии: 1-14 из ХХ (Майкл Гои, Билл Роу) [2022, США, боевик, драма, криминал, WEB-DLRip] MVO (LostFilm) + Original", new List<int> { TorznabCatType.TVDocumentary.ID }, true, true, false).Returns("The Rookie / S5E1-14 of XX MVO + Original (LostFilm) [2022, WEB-DL]");
|
||||
|
||||
yield return new TestCaseData("Терапия / Shrinking / Сезон: 1 / Серии: 1-2 из 10 (Джеймс Понсольдт) [2023, США, комедия, WEB-DLRip] Dub (Iyuno-SDI Group) + Original + Sub Rus", new List<int> { TorznabCatType.TVAnime.ID }, true, true, true).Returns("Shrinking / S1E1-2 of 10 Dub + Original + Sub Rus (Iyuno-SDI Group) [2023, WEB-DL]");
|
||||
yield return new TestCaseData("Новичок / Новобранец / The Rookie / Сезон: 5 / Серии: 1,14 из ?? (Майкл Гои, Билл Роу) [2022, США, боевик, драма, криминал, WEB-DLRip] MVO (LostFilm) + Original", new List<int> { TorznabCatType.TVDocumentary.ID }, true, true, true).Returns("The Rookie / S5E1-14 of ?? MVO + Original (LostFilm) [2022, WEB-DL]");
|
||||
|
||||
yield return new TestCaseData("Терапия / Shrinking / Сезон: 1 / Серии: 1-2 из 10 (Джеймс Понсольдт) [2023, США, комедия, WEB-DLRip] Dub (Iyuno-SDI Group) + Original + Sub Rus", new List<int> { TorznabCatType.TVHD.ID }, false, true, false).Returns("Терапия / Shrinking / S1E1-2 of 10 Dub + Original + Sub Rus (Джеймс Понсольдт) (Iyuno-SDI Group) [2023, США, комедия, WEB-DL]");
|
||||
yield return new TestCaseData("Новичок / Новобранец / The Rookie / Сезон: 5 / Серии: 1,14 из ХХ (Майкл Гои, Билл Роу) [2022, США, боевик, драма, криминал, WEB-DLRip] MVO (LostFilm) + Original", new List<int> { TorznabCatType.TVForeign.ID }, false, true, false).Returns("Новичок / Новобранец / The Rookie / S5E1-14 of XX MVO + Original (Майкл Гои, Билл Роу) (LostFilm) [2022, США, боевик, драма, криминал, WEB-DL]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
src/Jackett.Test/Common/Indexers/Toloka/TolokaTests.cs
Normal file
38
src/Jackett.Test/Common/Indexers/Toloka/TolokaTests.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Jackett.Common.Models;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Jackett.Test.Common.Indexers.Toloka
|
||||
{
|
||||
[TestFixture]
|
||||
public class TolokaTests
|
||||
{
|
||||
[TestCaseSource(typeof(TitleParserTestData), nameof(TitleParserTestData.TestCases))]
|
||||
public string TestTitleParsing(string title, ICollection<int> category, bool stripCyrillicLetters)
|
||||
{
|
||||
var titleParser = new Jackett.Common.Indexers.Toloka.TitleParser();
|
||||
|
||||
return titleParser.Parse(title, category, stripCyrillicLetters);
|
||||
}
|
||||
}
|
||||
|
||||
public class TitleParserTestData
|
||||
{
|
||||
public static IEnumerable TestCases
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Правдива терапія (Сезон 1, серії 1-2) / Shrinking (Season 1, episodes 1-2) (2023) WEBRip 1080p Ukr/Eng", new List<int> { TorznabCatType.TV.ID }, true).Returns("Shrinking (S1E1-2) (2023) WEBRip 1080p Ukr/Eng (S1E1-2)");
|
||||
yield return new TestCaseData("Ші-Ра та принцеси могутності (сезон 1-2, серій 14 з 20) / She-Ra and the Princesses of Power (seasons 1-2, episodes 14 of 20) (2018) WEBRip 1080p", new List<int> { TorznabCatType.TVHD.ID }, true).Returns("She-Ra and the Princesses of Power (S1-2, E14 of 20) (2018) WEBRip 1080p (S1-2, E14 of 20)");
|
||||
yield return new TestCaseData("А інші сгорять у пеклі (Сезон 1, Серія 3) / Everyone Else Burns (Season 1, Episode 3) (2023) WEB-DL 1080p Ukr/Eng | Sub Ukr/Eng", new List<int> { TorznabCatType.TVOther.ID }, true).Returns("Everyone Else Burns (S1E3) (2023) WEB-DL 1080p Ukr/Eng | Sub Ukr/Eng (S1E3)");
|
||||
yield return new TestCaseData("У тілі (Сезон 2, Епізод 1,2 з ХХ) / In the flesh (Season 2, episodes 1,2 of XX) (2014) 1080p BDRip Eng | sub Ukr", new List<int> { TorznabCatType.TVSport.ID }, true).Returns("In the flesh (S2E1-2 of XX) (2014) 1080p BDRip Eng | sub Ukr (S2E1-2 of XX)");
|
||||
|
||||
yield return new TestCaseData("Правдива терапія (Сезон 1, серії 1-2) / Shrinking (Season 1, episodes 1-2) (2023) WEBRip 1080p Ukr/Eng", new List<int> { TorznabCatType.TVHD.ID }, false).Returns("Правдива терапія (S1E1-2) / Shrinking (S1E1-2) (2023) WEBRip 1080p Ukr/Eng");
|
||||
yield return new TestCaseData("Ші-Ра та принцеси могутності (сезон 1-2, серій 14 з 20) / She-Ra and the Princesses of Power (seasons 1-2, episodes 14 of 20) (2018) WEBRip 1080p", new List<int> { TorznabCatType.TVAnime.ID }, false).Returns("Ші-Ра та принцеси могутності (S1-2, E14 of 20) / She-Ra and the Princesses of Power (S1-2, E14 of 20) (2018) WEBRip 1080p");
|
||||
yield return new TestCaseData("А інші сгорять у пеклі (Сезон 1, Серія 3) / Everyone Else Burns (Season 1, Episode 3) (2023) WEB-DL 1080p Ukr/Eng | Sub Ukr/Eng", new List<int> { TorznabCatType.TVDocumentary.ID }, false).Returns("А інші сгорять у пеклі (S1E3) / Everyone Else Burns (S1E3) (2023) WEB-DL 1080p Ukr/Eng | Sub Ukr/Eng");
|
||||
yield return new TestCaseData("У тілі (Сезон 2, Епізод 1,2 з ХХ) / In the flesh (Season 2, episodes 1,2 of XX) (2014) 1080p BDRip Eng | sub Ukr", new List<int> { TorznabCatType.TV.ID }, false).Returns("У тілі (S2E1-2 of XX) / In the flesh (S2E1-2 of XX) (2014) 1080p BDRip Eng | sub Ukr");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -256,6 +256,7 @@ namespace Jackett.Updater
|
||||
"Definitions/01torrent.yml",
|
||||
"Definitions/24rolika.yml",
|
||||
"Definitions/32pages.yml",
|
||||
"Definitions/3evils.yml",
|
||||
"Definitions/3evils-api.yml",
|
||||
"Definitions/420files.yml",
|
||||
"Definitions/7torrents.yml",
|
||||
|
Reference in New Issue
Block a user