Compare commits

...

84 Commits

Author SHA1 Message Date
kaso17
3538fdfaf7 Synthesiz3r: removed (dead) 2018-06-15 11:58:29 +02:00
kaso17
3468e7d404 improve BEncode error handling 2018-06-15 11:12:03 +02:00
kaso17
ec4afda184 Audiobook Torrents: improve compatibility 2018-06-15 10:44:26 +02:00
kaso17
67b1835264 Bit-City Reloaded: fix login 2018-06-15 10:30:43 +02:00
kaso17
aee64aa589 Shareisland: update URL 2018-06-14 19:28:51 +02:00
kaso17
687e6e237f TorrentWTF: removed (dead) 2018-06-14 19:28:36 +02:00
kaso17
b48dd5e930 cpasbien: URL update 2018-06-14 18:38:07 +02:00
kaso17
5ee6833610 NCore: fix else 2018-06-14 17:53:46 +02:00
morpheus133
c998ba3762 Additional fix for #1450 (#3227)
* Additional fix for #1450
Sonarr is search for a tilte if the result title is different it reject it.
So it is not enough that Jackett give the result it must give with the same language.

Workaround create a new title from the original one and from the title.
It also make some fine tunning:
if title not contains the language we add it from category

* Make decision safer
2018-06-14 17:44:22 +02:00
kaso17
2d4f7ab0e9 Waffles: fix category parsing 2018-06-14 17:39:16 +02:00
kaso17
676d03eb88 mono: redirect workaround 2018-06-14 17:28:57 +02:00
garfield69
6f7ecbfb7b Yggtorrent: domain changed, fixes #3228 2018-06-13 13:01:32 +12:00
Raphael Barreiros
c4aa49eb32 Update BJ-Share to new domain name (#3225)
* Update BJ-Share to new domain name

BJ-Share changed its domain from bj-share.me to bj-share.info

* Added LegacySiteLinks method
2018-06-13 07:44:42 +12:00
garfield69
32aae44ffc Btbit: fix slash in wrong place #3902 2018-06-13 07:04:35 +12:00
garfield69
7883534c5e Btbit: apply sort for all results #3209 2018-06-13 06:49:10 +12:00
kaso17
b58c9fb718 HDHome: try to fix search 2018-06-11 18:31:27 +02:00
kaso17
99d8f63f9e HDChina: try to fix search 2018-06-11 18:31:10 +02:00
la55u
635e8240d2 RevTT: added files count (#3213) 2018-06-11 17:36:29 +02:00
R91g
117a670aa3 Update readme (add HD-Spain tracker) (#3223)
Add new private tracker HD-Spain
2018-06-11 17:33:49 +02:00
R91g
f49c58a1fa HD-Spain: add indexer (#3222)
Add Spanish Private HD tracker https://www.hd-spain.com/
Based on Albvadi's code from HD-Spain forum all credit to him, I only added some changes for better search, ISO correct and spain flag detection
2018-06-11 17:33:26 +02:00
kaso17
2492f1b797 NCore: add comment 2018-06-11 17:31:46 +02:00
kaso17
d6781f67b2 NCore: improve search fix 2018-06-11 17:28:24 +02:00
morpheus133
2e0c22eb6d NCore: fix for #1450 (#3220)
Some workoround to "Ncore - not forward all search results to Sonarr, Radarr"
In case of TV shows if nothing is founded, retry the search without SxxExx after the show name.
This will list all torrent also if their title or description are changed.
Than add the result only if it contains the skipped SxxExx
2018-06-11 17:15:21 +02:00
flightlevel
f7bf4060ea Don't publish experimental artifacts 2018-06-11 17:21:34 +10:00
flightlevel
8c953bbf01 Avoid Engine for AspNetCore 2018-06-11 17:17:56 +10:00
aurelien
4e91761fdf Elite Tracker: Add HTTPS tracker option (#3217)
* Add option for Elite Tracker (FR) for download torrent using https for tracker URL.

* change return type.
clean code.

* use the SiteLink variable instead of hard coding
2018-06-11 06:42:21 +02:00
kaso17
53f8465e67 Demonoid: change to public 2018-06-10 15:55:51 +02:00
flightlevel
e8bc2816ef Update migration logging 2018-06-10 12:51:34 +10:00
flightlevel
28ed7cc8a5 BJShare: Remove unused variable
Remove warning in build
2018-06-10 12:40:02 +10:00
flightlevel
089d9f2e3d Ignore launchSettings.json 2018-06-10 12:38:32 +10:00
garfield69
b4eda2ed54 Ettv: sort by created for rss, test and no-keyword search #3209 2018-06-09 08:01:24 +12:00
garfield69
4d8d21a815 Btbit: sort by created for rss, test, and no-keyword searches #3209 2018-06-09 07:39:08 +12:00
kaso17
f3290800d8 bloackhole: fix magnet links 2018-06-08 16:04:54 +02:00
kaso17
22a858c076 SceneTime: fix search 2018-06-07 18:33:44 +02:00
kaso17
823419c032 Shareisland: fix legacylinks 2018-06-07 18:19:57 +02:00
Jorman
908d3f64f4 Added Audiobook category (#3203) 2018-06-06 12:44:49 +12:00
flightlevel
4b599f391c Mono 5.8 is the minimum supported runtime
#3181 fix. Can get away without using RuntimeInformation and didn't
consider public trackers without a password
2018-06-05 21:47:20 +10:00
kaso17
6d8239caab Demonoid: improve download debugging 2018-06-05 13:34:54 +02:00
Jorman
dae37f273a ilcorsaroblu: Update url (#3202) 2018-06-05 13:21:37 +02:00
kaso17
1615bff2d0 handle RuntimeInformation exception 2018-06-05 13:14:32 +02:00
kaso17
b303befbb9 SceneTime: fix indexer 2018-06-05 13:09:07 +02:00
kaso17
e243c11cc0 update mono reference 2018-06-05 07:24:05 +02:00
Travis Boss
c860bca320 changed log button from btn-danger to btn-success, less scary (#3196) 2018-06-04 14:59:16 +12:00
flightlevel
a60c1fca36 .NET 4.6.1 or Mono 5.4 is now the minimum supported runtime 2018-06-03 21:27:47 +10:00
la55u
5ad2c7a371 RevTT: Minor fixes (#3193)
* fixed RevTT pc/iso category

* added grabs count to RevTT
2018-06-03 01:11:42 +02:00
Jorman
3df0218347 Changed link after site fix (#3188) 2018-06-02 17:43:46 +10:00
flightlevel
601783aef6 .NET Core preparation 2 2018-06-02 17:42:01 +10:00
flightlevel
ac5af81344 .NET Core preparation (#3177)
The DPAPI won't be present, will be using AspNetCore DataProtection
instead
2018-05-30 21:28:20 +10:00
Celedhrim
823563c84f downloadville: fix typo (#3175)
Fix typo if MULTI replacement is check
2018-05-29 22:07:31 +02:00
Celedhrim
47410c5eb6 yggtorrent: fix typo (#3174)
Fix typo if multi language replacement is activate
2018-05-29 22:07:05 +02:00
kaso17
af135f4ae9 Torrent9: update links 2018-05-29 14:41:08 +02:00
kaso17
3eeced3a04 Racing4Everyone: update links 2018-05-29 14:40:56 +02:00
kaso17
8ea99b548d PolishSource: add login detection 2018-05-29 14:09:47 +02:00
kaso17
ae73e8188d Torrent.LT: update categories
fixes #2279
2018-05-29 13:48:07 +02:00
kaso17
9c5cda72da Demonoid: fix download handling 2018-05-29 13:26:35 +02:00
Jonas Stendahl
fb1e24799d TorrentBytes: Don't use truncated release names (#3168) 2018-05-29 12:24:13 +02:00
bpikap
5721948434 torrent-turk: add indexer (#3161)
* Add tracker torrent-turk

* Add torrent-turk to readme
2018-05-29 12:23:39 +02:00
Jorman
d7b6f413be README: Update for Girotorrent (#3159)
Added new girotorrent
2018-05-29 12:23:01 +02:00
Jorman
959ec4667d Girotorrent:_ add indexer (#3158)
Italian Private Tracker
2018-05-29 12:22:45 +02:00
kaso17
20433db169 RevolutionTT: remove debug output 2018-05-24 16:28:14 +02:00
kaso17
54465798e9 GazelleGames: add relogin detection 2018-05-24 16:13:13 +02:00
kaso17
313147d224 Demonoid: add redirect error detection 2018-05-24 16:05:45 +02:00
kaso17
84bd947eca ICE Torrent: update definition 2018-05-24 16:05:23 +02:00
kaso17
366abc4431 Mega-Bliz: fix and improve definition 2018-05-24 15:45:23 +02:00
DarkSupremo
2f7fa2f063 Bjshare: fix broken regex (#3137) 2018-05-23 15:40:23 +02:00
Celedhrim
205f6cac12 Yggtorrent and downloadville: Better MULTI replace (#3135) 2018-05-23 14:11:22 +02:00
Jorman
f602b3db24 README: add Il Corsaro Blu (#3132)
Update file to adding new traker file
2018-05-23 14:10:34 +02:00
Jorman
0d72f1f228 add tracker Il Corsaro Blu (#3131) 2018-05-23 14:10:13 +02:00
kaso17
508125e68f RGU: fix AND search 2018-05-22 18:52:47 +02:00
kaso17
cfb714e13c TorrentSeeds: add andmatch 2018-05-22 18:30:49 +02:00
kaso17
b9dcfd1b02 Torlock: add andmatch 2018-05-22 18:30:29 +02:00
kaso17
a1b2dc67b8 Elit Tracker: add andmatch 2018-05-22 18:30:10 +02:00
Celedhrim
2207c5a961 yggtorrents and downloadville: support multi to french title rewriting (#3130) 2018-05-22 18:07:15 +02:00
kaso17
2caa09bb1e fix bee 2018-05-21 15:51:07 +02:00
kaso17
68906f6e40 readme: fix link 2018-05-21 12:26:02 +02:00
kaso17
2cf3cf15e3 README: add Roslyn note 2018-05-21 12:24:39 +02:00
Jorman
88202c1f7f Isohunt2: fix size parsing (#3127)
Sometimes when parsing, the size of the rel was not enough to have Gb instead Mb or Kb to Mb or whatever
So the size in row is for example 1.015.22 Mb (less than 1024)
So in this case the parser return error

I searched a way to replace this, I found a solution, hope that works in a log way
2018-05-20 21:08:22 +02:00
DarkSupremo
6293c787e7 Bj share: improve search results (#3126)
* Improved anime search and speed-share resolution detection

* - Code Refactored to new standards
- Removed publish date from search mode, since the tracker does not provide that information, it was based on the serie year (but it does provide it on last 24h page, that's still prssent)
- Code clean
- Added season to all animes but One Piece (every anime that i searched in this tracker have the correct season and episode numbering, except One Piece that have an incorrect season set and episode is in absolute format, its added automatically on every new release, so must be the source from where they get that info that is wrong, since its an popular show, added it as an workaround and explained on code as comment)
2018-05-20 21:07:00 +02:00
flightlevel
f67fda3bf4 Add detail to build steps and remove Bountysource 2018-05-20 21:56:50 +10:00
kaso17
c81dd24fe7 RevolutionTT: add time debug output 2018-05-20 10:10:30 +02:00
kaso17
af94dd2757 TVChaosUK: fix parse error 2018-05-20 09:51:18 +02:00
kaso17
0a07738c5b HDME: fix passkey 2018-05-19 06:33:11 +02:00
kaso17
e05783a25a Cardigann: add support for .Config.sitelink 2018-05-19 06:32:16 +02:00
kaso17
27d4ab3967 TorrentBytes: support hidden userbars 2018-05-18 18:10:32 +02:00
61 changed files with 1295 additions and 438 deletions

1
.gitignore vendored
View File

@@ -200,3 +200,4 @@ FakesAssemblies/
/TestResults /TestResults
*.DS_Store *.DS_Store
.idea/ .idea/
launchSettings.json

View File

@@ -2,7 +2,6 @@
[![GitHub issues](https://img.shields.io/github/issues/Jackett/Jackett.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/issues) [![GitHub issues](https://img.shields.io/github/issues/Jackett/Jackett.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/issues)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/Jackett/Jackett.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/pulls) [![GitHub pull requests](https://img.shields.io/github/issues-pr/Jackett/Jackett.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/pulls)
[![Bountysource](https://img.shields.io/bountysource/team/jackett/activity.svg?style=flat-square)](https://www.bountysource.com/teams/jackett)
[![Build status](https://ci.appveyor.com/api/projects/status/gaybh5mvyx418nsp/branch/master?svg=true)](https://ci.appveyor.com/project/Jackett/jackett) [![Build status](https://ci.appveyor.com/api/projects/status/gaybh5mvyx418nsp/branch/master?svg=true)](https://ci.appveyor.com/project/Jackett/jackett)
[![Github Releases](https://img.shields.io/github/downloads/Jackett/Jackett/total.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/releases/latest) [![Github Releases](https://img.shields.io/github/downloads/Jackett/Jackett/total.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/releases/latest)
[![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/jackett.svg?maxAge=60&style=flat-square)](https://hub.docker.com/r/linuxserver/jackett/) [![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/jackett.svg?maxAge=60&style=flat-square)](https://hub.docker.com/r/linuxserver/jackett/)
@@ -17,8 +16,8 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
#### Supported Systems #### Supported Systems
* Windows using .NET 4.5.2 [Download here](https://www.microsoft.com/net/framework/versions/net452). * Windows using .NET 4.6.1 or above [Download here](https://www.microsoft.com/net/framework/versions/net461).
* Linux and macOS using Mono 4.6.0 and above. [Download here](http://www.mono-project.com/download/). Earlier versions of mono may work but some trackers may fail to negotiate SSL correctly, and others may cause Jackett to crash when used. * Linux and macOS using Mono 5.8 or above. [Download here](http://www.mono-project.com/download/). Earlier versions of mono may work, but some trackers may fail to negotiate SSL correctly, and others may cause Jackett to crash when used.
### Supported Public Trackers ### Supported Public Trackers
* 1337x * 1337x
@@ -37,6 +36,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* Horrible Subs * Horrible Subs
* Idope * Idope
* Il Corsaro Nero <!-- maintained by bonny1992 --> * Il Corsaro Nero <!-- maintained by bonny1992 -->
* Il Corsaro Blu
* Isohunt2 * Isohunt2
* KickAssTorrent * KickAssTorrent
* KickAssTorrent (thekat.se clone) * KickAssTorrent (thekat.se clone)
@@ -163,6 +163,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* GFXPeers * GFXPeers
* GigaTorrents * GigaTorrents
* GimmePeers <!-- maintained by jamesb2147 --> * GimmePeers <!-- maintained by jamesb2147 -->
* Girotottent
* GODS [![(invite needed)][inviteneeded]](#) * GODS [![(invite needed)][inviteneeded]](#)
* Greek Team * Greek Team
* HacheDe * HacheDe
@@ -170,6 +171,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* HD-Forever * HD-Forever
* HD-Only * HD-Only
* HD-Space * HD-Space
* HD-Spain
* HD-Torrents * HD-Torrents
* HD-Bits.com * HD-Bits.com
* HDBits * HDBits
@@ -239,7 +241,6 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* SportsCult * SportsCult
* SportHD * SportHD
* Superbits * Superbits
* Synthesiz3r
* Tasmanit * Tasmanit
* TBPlus * TBPlus
* TenYardTracker * TenYardTracker
@@ -269,7 +270,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* Torrents.Md * Torrents.Md
* TorrentSeeds * TorrentSeeds
* Torrent-Syndikat * Torrent-Syndikat
* TorrentWTF * TOrrent-tuRK (TORK)
* TorViet * TorViet
* ToTheGlory * ToTheGlory
* TranceTraffic * TranceTraffic
@@ -317,7 +318,7 @@ When installed as a service the tray icon acts as a way to open/start/stop Jacke
Jackett can also be run from the command line if you would like to see log messages (Ensure the server isn't already running from the tray/service). This can be done by using "JackettConsole.exe" (for Command Prompt), found in the Jackett data folder: "%ProgramData%\Jackett". Jackett can also be run from the command line if you would like to see log messages (Ensure the server isn't already running from the tray/service). This can be done by using "JackettConsole.exe" (for Command Prompt), found in the Jackett data folder: "%ProgramData%\Jackett".
## Installation on Linux ## Installation on Linux
1. Install [Mono 4.6](http://www.mono-project.com/download/#download-lin) or better (using the latest stable release for your distribution is recommended) 1. Install [Mono 5.8](http://www.mono-project.com/download/#download-lin) or better (using the latest stable release is recommended)
* Follow the instructions on the mono website and install the `mono-devel` and the `ca-certificates-mono` packages. * Follow the instructions on the mono website and install the `mono-devel` and the `ca-certificates-mono` packages.
* On Red Hat/CentOS/openSUSE/Fedora the `mono-locale-extras` package is also required. * On Red Hat/CentOS/openSUSE/Fedora the `mono-locale-extras` package is also required.
2. Install libcurl: 2. Install libcurl:
@@ -330,6 +331,8 @@ Detailed instructions for [Ubuntu 14.x](http://www.htpcguides.com/install-jacket
If you want to run it with a user without a /home directory you need to add `Environment=XDG_CONFIG_HOME=/path/to/folder` to your systemd file, this folder will be used to store your config files. If you want to run it with a user without a /home directory you need to add `Environment=XDG_CONFIG_HOME=/path/to/folder` to your systemd file, this folder will be used to store your config files.
Mono must be compiled with the Roslyn compiler (default), using MCS will cause "An error has occurred." errors (See https://github.com/Jackett/Jackett/issues/2704).
## Installation on macOS ## Installation on macOS
### Prerequisites ### Prerequisites
@@ -399,7 +402,8 @@ All contributions are welcome just send a pull request. Jackett's framework all
## Building from source ## Building from source
### Windows ### Windows
* Open the Jackett solution in Visual Studio 2017 * Open the Jackett solution in Visual Studio 2017 (version 15.7 or above)
* Right click on the Jackett solution and click 'Rebuild Solution' to restore nuget packages
* Select Jackett.Console as startup project * Select Jackett.Console as startup project
* Build/Start the project * Build/Start the project
@@ -418,4 +422,4 @@ mono Jackett.Console/bin/Debug/JackettConsole.exe # run jackett
![screenshot](https://i.imgur.com/0d1nl7g.png "screenshot") ![screenshot](https://i.imgur.com/0d1nl7g.png "screenshot")
[inviteneeded]: https://raw.githubusercontent.com/Jackett/Jackett/master/.github/label-inviteneeded.png [inviteneeded]: https://raw.githubusercontent.com/Jackett/Jackett/master/.github/label-inviteneeded.png

View File

@@ -27,6 +27,7 @@ deploy:
description: $(release_description) description: $(release_description)
auth_token: auth_token:
secure: hOg+16YTIbq4kO9u4D1YVOTbWDqgCX6mAQYMbnmBBSw2CiUsZh7OKbupoUb3FtWa secure: hOg+16YTIbq4kO9u4D1YVOTbWDqgCX6mAQYMbnmBBSw2CiUsZh7OKbupoUb3FtWa
artifact: /^(?:(?![Ee]xperimental).)*$/
draft: true draft: true
on: on:
branch: master branch: master

View File

@@ -98,7 +98,7 @@
<button id="change-jackett-port" class="btn btn-primary btn-sm"> <button id="change-jackett-port" class="btn btn-primary btn-sm">
<i class="fa fa-wrench"></i> Apply server settings <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span> <i class="fa fa-wrench"></i> Apply server settings <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
</button> </button>
<button id="view-jackett-logs" class="btn btn-danger btn-sm"> <button id="view-jackett-logs" class="btn btn-success btn-sm">
<i class="fa fa-rss"></i> View logs <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span> <i class="fa fa-rss"></i> View logs <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
</button> </button>
<button id="trigger-updater" class="btn btn-warning btn-sm"> <button id="trigger-updater" class="btn btn-warning btn-sm">

View File

@@ -72,7 +72,7 @@
rows: rows:
selector: tr.browse_color, tr.freeleech_color, tr[id^="kdescr"] selector: tr.browse_color, tr.freeleech_color, tr[id^="kdescr"]
after: 1 after: 1
fields: fields: # some users (rank specific?) have an extra column (td:nth-child(4)) with bookmark features
banner: banner:
selector: a[href^="details.php?id="][onmouseover] selector: a[href^="details.php?id="][onmouseover]
attribute: onmouseover attribute: onmouseover
@@ -98,20 +98,20 @@
selector: a[href^="download.php"] selector: a[href^="download.php"]
attribute: href attribute: href
files: files:
selector: td:nth-child(4) selector: a[href^="filelist.php"]
size: size:
selector: td:nth-child(7) selector: td:nth-last-child(6)
grabs: grabs:
selector: td:nth-child(8) selector: td:nth-last-child(5)
filters: filters:
- name: regexp - name: regexp
args: ([\d,]+) args: ([\d,]+)
seeders: seeders:
selector: td:nth-child(9) selector: td:nth-last-child(4)
leechers: leechers:
selector: td:nth-child(10) selector: td:nth-last-child(3)
date: date:
selector: td:nth-child(6) selector: td:nth-last-child(7)
downloadvolumefactor: downloadvolumefactor:
case: case:
"a.info > b:contains(\"[FREE]\")": "0" "a.info > b:contains(\"[FREE]\")": "0"

View File

@@ -28,7 +28,7 @@
search: search:
paths: paths:
- path: "list/{{if .Keywords}}{{.Keywords}}{{else}}movie{{end}}.html" - path: "list/{{if .Keywords}}{{.Keywords}}{{else}}movie{{end}}/1-1-0.html"
rows: rows:
selector: .rs selector: .rs
fields: fields:

View File

@@ -6,8 +6,9 @@
type: public type: public
encoding: UTF-8 encoding: UTF-8
links: links:
- http://www.cpabien.cm/ - http://www.cpasbiens.cc/
legacylinks: legacylinks:
- http://www.cpabien.cm/
- http://cpabien.cm/ - http://cpabien.cm/
- http://cpasbiens1.com/ - http://cpasbiens1.com/
- http://cpabien.mx/ - http://cpabien.mx/

View File

@@ -128,7 +128,18 @@
"2" : "Argent (Silver)" "2" : "Argent (Silver)"
"3" : "Or (Gold)" "3" : "Or (Gold)"
"4" : "Argent & Or (Both)" "4" : "Argent & Or (Both)"
- name: multilang
type: checkbox
label: Replace MULTI by another language in release name
default: false
- name: multilanguage
type: select
label: Replace MULTI by this language
default: FRENCH
options:
FRENCH : "FRENCH"
MULTI.FRENCH : "MULTI.FRENCH"
ENGLISH: "ENGLISH"
login: login:
path: tracker/index.php?page=login path: tracker/index.php?page=login
method: post method: post
@@ -168,8 +179,15 @@
rows: rows:
selector: table > tbody > tr > td > table.lista > tbody > tr:has(td[onmouseover="this.className='post'"]) selector: table > tbody > tr > td > table.lista > tbody > tr:has(td[onmouseover="this.className='post'"])
fields: fields:
title: title_phase1:
selector: a[onmouseover][href^="index.php?page=torrent-details&id="] selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
title_multilang:
text: "{{ .Result.title_phase1 }}"
filters:
- name: re_replace
args: ["[\\.\\s\\[\\-][Mm][Uu][Ll][Tt][Ii][\\.\\s\\]\\-]", ".{{ .Config.multilanguage }}."]
title:
text: "{{if .Config.multilang }}{{ .Result.title_multilang }}{{else}}{{ .Result.title_phase1 }}{{end}}"
details: details:
selector: a[onmouseover][href^="index.php?page=torrent-details&id="] selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
attribute: href attribute: href

View File

@@ -115,6 +115,8 @@
rows: rows:
selector: table > tbody > tr:has(img[src*="/pic/categories/"]) selector: table > tbody > tr:has(img[src*="/pic/categories/"])
filters:
- name: andmatch
fields: fields:
title: title:
# using attribute title from td(3) because the text from td(2) a(2) can be abbreviated # using attribute title from td(3) because the text from td(2) a(2) can be abbreviated

View File

@@ -69,6 +69,8 @@
inputs: inputs:
$raw: "{{range .Categories}}c{{.}}=1&{{end}}" $raw: "{{range .Categories}}c{{.}}=1&{{end}}"
search: "{{ .Keywords }}" search: "{{ .Keywords }}"
sort: "id"
order: "desc"
incldead: "1" incldead: "1"
keywordsfilters: keywordsfilters:
- name: replace - name: replace
@@ -110,4 +112,4 @@
downloadvolumefactor: downloadvolumefactor:
text: "0" text: "0"
uploadvolumefactor: uploadvolumefactor:
text: "1" text: "1"

View File

@@ -0,0 +1,225 @@
---
site: girotorrent
name: Girotorrent
description: "Girotorrent is an ITALIAN Private site for TV / MOVIES / GENERAL"
language: it-it
type: private
encoding: UTF-8
links:
- http://girotorrent.org/
caps:
categorymappings:
# LIBREDICOLA
- {id: 13, cat: Books, desc: "Giornali e Riviste"}
- {id: 15, cat: Books, desc: "Ebook"}
- {id: 16, cat: Books, desc: "Fumetti"}
- {id: 70, cat: Books, desc: "Manuali e Guide"}
- {id: 72, cat: Audio/Audiobook, desc: "Audiolibri"}
# CINEMA
- {id: 17, cat: Movies/Other, desc: "Movie Cam-Ts"}
- {id: 18, cat: Movies/Other, desc: "Movie Screener"}
- {id: 61, cat: Movies/Other, desc: "Movie R5-R6"}
- {id: 19, cat: Movies/Other, desc: "Movie DVDRip"}
- {id: 20, cat: Movies/Other, desc: "Movie BDRip"}
- {id: 60, cat: Movies/Other, desc: "Movie BluRay"}
- {id: 63, cat: Movies/Other, desc: "Movie WEBDLRip"}
# VIDEOTECA
- {id: 22, cat: Movies/SD, desc: "Movie BDRip"}
- {id: 23, cat: Movies/SD, desc: "Movie DvdRip"}
- {id: 23, cat: Movies/SD, desc: "Movie WEBRip"}
- {id: 24, cat: Movies/DVD, desc: "Movie DVD-R 5"}
- {id: 25, cat: Movies/DVD, desc: "Movie DVD-R 9"}
- {id: 26, cat: Movies/HD, desc: "Movie Blu-Ray HD"}
- {id: 27, cat: Movies/3D, desc: "Movie 3D-SBS"}
- {id: 96, cat: Movies/HD, desc: "Movie x265 HEVC"}
- {id: 28, cat: Movies/Foreign, desc: "Movie Subbet-ita"}
- {id: 73, cat: Movies/SD, desc: "Movie MP4"}
- {id: 29, cat: Movies/Foreign, desc: "Movie Ligua Originale"}
# ANIMAZIONE
- {id: 32, cat: TV/Anime, desc: "Anime Disney"}
- {id: 33, cat: TV/Anime, desc: "Anime"}
- {id: 34, cat: TV/Anime, desc: "Anime Altri Cartoni"}
# TELEVISIONE
- {id: 36, cat: TV, desc: "TV Serie TV"}
- {id: 77, cat: TV, desc: "TV Reality"}
- {id: 37, cat: TV, desc: "TV Film TV"}
- {id: 59, cat: TV, desc: "TV Sport"}
- {id: 38, cat: TV, desc: "TV Concerti-Spettacoli"}
- {id: 39, cat: TV, desc: "TV Teatro-Cabaret"}
- {id: 40, cat: TV/Documentary, desc: "Tv Documentario"}
# MUSICA
- {id: 42, cat: Audio, desc: "Musica CD Singoli"}
- {id: 43, cat: Audio, desc: "Musica Italiana"}
- {id: 44, cat: Audio, desc: "Musica Straniera"}
- {id: 45, cat: Audio, desc: "Musica Compilation"}
- {id: 46, cat: Audio, desc: "Musica Video Clip"}
- {id: 58, cat: Audio, desc: "Musica Discografie"}
# SALA GIOCHI
- {id: 47, cat: PC/Games, desc: "PC Games"}
- {id: 48, cat: PC/Games, desc: "PC Giochi PS2-PS3"}
- {id: 49, cat: PC/Games, desc: "PC Giochi Nintendo Wii"}
- {id: 50, cat: PC/Games, desc: "PC Giochi Xbox"}
- {id: 52, cat: PC/Games, desc: "PC Giochi DS-DS3"}
# SOFTWARE
- {id: 54, cat: PC, desc: "PC Programmi Windows"}
- {id: 55, cat: PC/Mac, desc: "PC Mac"}
- {id: 69, cat: PC, desc: "PC Portable"}
- {id: 56, cat: PC, desc: "PC Linux"}
# CELLULARI-PALMARI
- {id: 71, cat: PC/Phone-Android, desc: "Android APP"}
- {id: 74, cat: Other, desc: "Varie"}
- {id: 75, cat: Other, desc: "Immagini Wallpaper"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
login:
path: /index.php?page=login
method: post
inputs:
uid: "{{ .Config.username }}"
pwd: "{{ .Config.password }}"
error:
- selector: div.error
test:
path: /index.php
selector: a[href="logout.php"]
download:
before:
path: "thanks.php"
method: "post"
inputs:
infohash: "{{ .DownloadUri.Query.id }}"
thanks: "1"
rndval: "1487013827343"
selector: a[href^="download.php?id="]
search:
paths:
- path: /index.php
keywordsfilters:
- name: re_replace
args: ["S[0-9]{2}([^E]|$)", ""] # remove season tag without episode (search doesn't support it)
- name: diacritics
args: replace
# most ITA TV torrents are in XXxYY format, so we search without S/E prefixes and filter later
- name: re_replace
args: ["S0?(\\d{1,2})", " $1 "]
- name: re_replace
args: ["E(\\d{2,3})", " $1 "]
inputs:
search: "{{ .Keywords }}"
category: "{{range .Categories}}{{.}};{{end}}"
page: "torrents"
active: 0
rows:
selector: div.b-content > table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="])
#http://girotorrent.org/index.php?page=torrent-details&id=73d93dccf84ea3a8b614a3113acfd9eea186d730
fields:
download:
selector: a[href^="index.php?page=downloadcheck&id="]
attribute: href
title: # shortened title?
selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
# normalize to SXXEYY format
filters:
- name: re_replace # replace special characters with " " (space)
args: ["[^a-zA-Z0-9]|\\.", " "]
# normalize to SXXEYY format
- name: re_replace
args: ["(\\d{2})x(\\d{2})", "S$1E$2"]
- name: re_replace
args: ["(\\d{1})x(\\d{2})", "S0$1E$2"]
- name: re_replace #Stagione X --> S0X
args: ["Stagione (\\d{0,1}\\s)", "S0$1"]
- name: re_replace #Stagione XX --> SXX
args: ["Stagione (\\d{2}\\s)", "S$1"]
- name: re_replace #/ Episodio [YY-YY --> EYY-YY
args: ["(\\s\\/\\sEpisodio|\\s\\/\\sEpisodi|\\sEpisodio|\\s\\|\\sEpisodio|\\sEpisodi)\\s\\[", "E"]
- name: re_replace #/ Completa [episodi YY-YY --> EYY-YY
args: ["(\\s\\/\\sCompleta\\s\\[episodi\\s)", "E"]
- name: re_replace #remove di YY] | remove /YY]
args: ["(\\sdi\\s\\d{1,2}|\\/\\d{1,2})\\]", " "]
- name: re_replace #remove various
args: ["(Serie completa|Completa|\\[in pausa\\])", ""]
# fine prova
title: # long titles?
optional: true
selector: a[title][href^="index.php?page=torrent-details"]
attribute: title
filters:
- name: replace
args: ["Vedi Dettagli: ", ""]
# inizio prova
- name: re_replace # replace special characters with " " (space)
args: ["[^a-zA-Z0-9]|\\.", " "]
# normalize to SXXEYY format
- name: re_replace
args: ["(\\d{2})x(\\d{2})", "S$1E$2"]
- name: re_replace
args: ["(\\d{1})x(\\d{2})", "S0$1E$2"]
- name: re_replace #Stagione X --> S0X
args: ["Stagione (\\d{0,1}\\s)", "S0$1"]
- name: re_replace #Stagione XX --> SXX
args: ["Stagione (\\d{2}\\s)", "S$1"]
- name: re_replace #/ Episodio [YY-YY --> EYY-YY
args: ["(\\s\\/\\sEpisodio|\\s\\/\\sEpisodi|\\sEpisodio|\\s\\|\\sEpisodio|\\sEpisodi)\\s\\[", "E"]
- name: re_replace #/ Completa [episodi YY-YY --> EYY-YY
args: ["(\\s\\/\\sCompleta\\s\\[episodi\\s)", "E"]
- name: re_replace #remove di YY] | remove /YY]
args: ["(\\sdi\\s\\d{1,2}|\\/\\d{1,2})\\]", " "]
- name: re_replace #remove various
args: ["(Serie completa|Completa|\\[in pausa\\])", ""]
# fine prova
category:
selector: a[href^="index.php?page=torrents&category="]
attribute: href
filters:
- name: querystring
args: category
details:
selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
attribute: href
banner:
optional: true
selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
attribute: onmouseover
filters:
- name: regexp
args: "src=(.+?) "
size:
selector: td:nth-child(11)
date:
selector: td:nth-child(6)
filters:
- name: dateparse
args: "02/01/2006"
grabs:
selector: td:nth-child(9)
filters:
- name: replace
args: ["---", "0"]
seeders:
selector: td:nth-child(7)
leechers:
selector: td:nth-child(8)
downloadvolumefactor:
case:
img[alt="Free Leech"]: "0"
img[alt="Gold 100% Free"]: "0"
img[alt="Silver 50% Free"]: "0.5"
img[alt="Bronze 25% Free"]: "0.75"
"*": "1"
uploadvolumefactor:
text: "1"
uploadvolumefactor:
optional: true
selector: img[alt$="x Upload Multiplier"]
attribute: alt
filters:
- name: replace
args: ["x Upload Multiplier", ""]

View File

@@ -61,7 +61,6 @@
search: search:
paths: paths:
- path: /torrents.php - path: /torrents.php
method: post
inputs: inputs:
$raw: "{{range .Categories}}cat{{.}}=1&{{end}}" $raw: "{{range .Categories}}cat{{.}}=1&{{end}}"
search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}"

View File

@@ -82,7 +82,6 @@
search: search:
paths: paths:
- path: /torrents.php - path: /torrents.php
method: post
inputs: inputs:
$raw: "{{range .Categories}}cat{{.}}=1&{{end}}" $raw: "{{range .Categories}}cat{{.}}=1&{{end}}"
search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}"

View File

@@ -91,6 +91,11 @@
download: download:
selector: td:nth-child(11) > a selector: td:nth-child(11) > a
attribute: href attribute: href
filters:
- name: prepend
args: "{{ .Config.sitelink }}"
- name: replace # https download links are redirected to http causing invalid cookies => invalid passkeys
args: ["https", "http"]
size: size:
selector: td:nth-child(6) selector: td:nth-child(6)
remove: br remove: br
@@ -103,3 +108,9 @@
selector: td:nth-child(8) selector: td:nth-child(8)
leechers: leechers:
selector: td:nth-child(9) selector: td:nth-child(9)
downloadvolumefactor:
case:
"font:contains(\"(FreeLeech)\")": "0"
"*": "1"
uploadvolumefactor:
text: "1"

View File

@@ -0,0 +1,142 @@
---
site: hdspain
name: HD-Spain
description: "HD-Spain is a SPANISH site for HD content"
language: es-es
type: private
encoding: ISO-8859-1
links:
- https://www.hd-spain.com/
caps:
categorymappings:
- {id: 1 , cat: Movies/HD, desc: "Películas"}
- {id: 5 , cat: Movies/HD, desc: "Pelíc. Anim."}
- {id: 4 , cat: TV/HD, desc: "Series"}
- {id: 3 , cat: TV/HD, desc: "Series Anim."}
- {id: 6 , cat: TV/Documentary, desc: "Documentales"}
- {id: 11, cat: TV/Sport, desc: "Deportes"}
- {id: 7 , cat: Audio/Video, desc: "Música/Espec."}
- {id: 9 , cat: TV/OTHER, desc: "Programas TV"}
- {id: 8 , cat: Audio/Lossless, desc: "Audios"}
- {id: 10, cat: XXX/x264, desc: "XXX"}
modes:
search: [q]
login:
path: index.php
method: form
inputs:
usuario: "{{ .Config.username }}"
contrasena: "{{ .Config.password }}"
error:
- selector: p.error
test:
path: index.php
selector: .tcabecera
search:
path: index.php
keywordsfilters:
- name: re_replace
args: ["S0?(\\d{1,2})E(\\d{1,2})", "$1x$2"]
inputs:
sec: listado
ord: 9
b: "{{ .Keywords }}"
ver: "0"
relanz: "0"
$raw: "{{range .Categories}}&cat[]={{.}}{{end}}"
rows:
selector: "table.listatorrents tr:not(:first-child)"
fields:
category:
selector: td.categorias a
attribute: href
filters:
- name: querystring
args: cat
title:
selector: td.titulo a[id]
filters:
- name: append
args: " [spanish]"
details:
selector: td.titulo a
attribute: href
size:
selector: td.tamano
seeders:
selector: td.usuarios.seeds a
leechers:
selector: td.usuarios.leechers a
grabs:
selector: td.usuarios.completados
date:
optional: true
selector: td.fecha
attribute: title
filters:
- name: replace
args: ["Lunes", "Monday"]
- name: replace
args: ["Martes", "Tuesday"]
- name: re_replace
args: ["Miércoles", "Wednesday"]
- name: replace
args: ["Jueves", "Thursday"]
- name: replace
args: ["Viernes", "Friday"]
- name: re_replace
args: ["Sábado", "Saturday"]
- name: replace
args: ["Domingo", "Sunday"]
- name: replace
args: ["Enero", "January"]
- name: replace
args: ["Febrero", "February"]
- name: replace
args: ["Marzo", "March"]
- name: replace
args: ["Abril", "April"]
- name: replace
args: ["Mayo", "May"]
- name: replace
args: ["Junio", "June"]
- name: replace
args: ["Julio", "July"]
- name: replace
args: ["Agosto", "August"]
- name: replace
args: ["Septiembre", "September"]
- name: replace
args: ["Octubre", "October"]
- name: replace
args: ["Noviembre", "November"]
- name: replace
args: ["Diciembre", "December"]
- name: dateparse
args: "Monday 2 January 2006, 15:04"
download:
selector: td.descargar a
attribute: href
downloadvolumefactor:
text: "1"
downloadvolumefactor:
optional: true
selector: td.descargar a b strong
filters:
- name: replace
args: [" X2", ""]
- name: replace
args: ["Freeleech", "0"]
uploadvolumefactor:
text: "1"
uploadvolumefactor:
optional: true
selector: td.descargar a b strong
filters:
- name: replace
args: ["Freeleech X2", "2"]

View File

@@ -114,7 +114,7 @@
selector: td:has(a[href$="filelist=1#filelist"]) selector: td:has(a[href$="filelist=1#filelist"])
remove: a remove: a
date: date:
selector: td > font:contains("Added on") selector: td > font:has(i.fa-clock-o)
remove: b remove: b
filters: filters:
- name: replace - name: replace

View File

@@ -0,0 +1,160 @@
---
site: ilcorsaroblu
name: Il Corsaro Blu
description: "Il Corsaro Blu is an ITALIAN Public site for TV / MOVIES / GENERAL"
language: it-it
type: public
encoding: UTF-8
links:
- https://www.ilcorsaroblu.info/
legacylinks:
- http://ilcorsaroblu.org/
- https://www.ilcorsaroblu.org/
caps:
categorymappings:
# Adult
- {id: 12, cat: XXX, desc: "Adult"}
# Applicazioni
- {id: 5, cat: PC/Phone-Android, desc: "Android"}
# Books
- {id: 6, cat: Books, desc: "Books"}
# Games
- {id: 3, cat: Other, desc: "Games"}
# Music
- {id: 2, cat: Audio, desc: "Music"}
# Movies
- {id: 17, cat: Movies/SD, desc: "Movie BDRip"}
- {id: 21, cat: Movies/Other, desc: "Movies - Films"}
- {id: 11, cat: Movies/DVD, desc: "DVD-R"}
- {id: 14, cat: Movies/HD, desc: "Movie 720p"}
- {id: 13, cat: Movies/HD, desc: "Movie 1080p"}
- {id: 15, cat: Movies/3D, desc: "Movie 3D"}
- {id: 24, cat: TV/OTHER, desc: "TV Show Standard"}
- {id: 19, cat: TV/HD, desc: "Tv Show 1080p"}
- {id: 20, cat: TV/HD, desc: "Tv Show 720"}
# Various
- {id: 4, cat: Other, desc: "Other"}
- {id: 7, cat: PC, desc: "Windows"}
- {id: 8, cat: Other, desc: "Linux"}
- {id: 9, cat: PC/Mac, desc: "Mac"}
- {id: 23, cat: Other, desc: "Archive"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings: []
search:
paths:
- path: /index.php
keywordsfilters:
- name: re_replace
args: ["S[0-9]{2}([^E]|$)", ""] # remove season tag without episode (search doesn't support it)
- name: diacritics
args: replace
# most ITA TV torrents are in XXxYY format, so we search without S/E prefixes and filter later
- name: re_replace
args: ["S0?(\\d{1,2})", " $1 "]
- name: re_replace
args: ["E(\\d{2,3})", " $1 "]
inputs:
search: "{{ .Keywords }}"
category: "{{range .Categories}}{{.}};{{end}}"
page: torrents
active: 0
rows:
selector: div.b-content > table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrents&category="])
fields:
title:
selector: td:nth-child(2) > a
# normalize to SXXEYY format
filters:
- name: re_replace # replace special characters with " " (space)
args: ["[^a-zA-Z0-9]|\\.", " "]
# normalize to SXXEYY format
- name: re_replace
args: ["(\\d{2})x(\\d{2})", "S$1E$2"]
- name: re_replace
args: ["(\\d{1})x(\\d{2})", "S0$1E$2"]
- name: re_replace #Stagione X --> S0X
args: ["Stagione (\\d{0,1}\\s)", "S0$1"]
- name: re_replace #Stagione XX --> SXX
args: ["Stagione (\\d{2}\\s)", "S$1"]
- name: re_replace #/ Episodio [YY-YY --> EYY-YY
args: ["(\\s\\/\\sEpisodio|\\s\\/\\sEpisodi|\\sEpisodio|\\s\\|\\sEpisodio|\\sEpisodi)\\s\\[", "E"]
- name: re_replace #/ Completa [episodi YY-YY --> EYY-YY
args: ["(\\s\\/\\sCompleta\\s\\[episodi\\s)", "E"]
- name: re_replace #remove di YY] | remove /YY]
args: ["(\\sdi\\s\\d{1,2}|\\/\\d{1,2})\\]", " "]
- name: re_replace #remove various
args: ["(Serie completa|Completa|\\[in pausa\\])", ""]
# fine prova
download: # handle torrents with normal torrent file download
optional: true
selector: a[href^="download.php?id="]
attribute: href
filters:
- name: querystring
args: id
- name: toupper
- name: prepend
args: http://itorrents.org/torrent/
- name: append
args: ".torrent"
_magnetfilename: # convert title to valid magnet filename
text: "{{ .Result.title }}"
filters:
- name: validfilename
- name: urlencode
magnet: # generate magnet link from download link
optional: true
selector: a[href^="download.php?id="]
attribute: href
filters:
- name: querystring
args: id
- name: prepend
args: "magnet:?xt=urn:btih:"
- name: append
args: "&dn={{ .Result._magnetfilename }}.torrent"
- name: append # add some well known public trackers
args: "&tr=udp://tracker.openbittorrent.com:80/announce&tr=udp://tracker.opentrackr.org:1337/announce"
magnet: # in case a direct magnet link is provided use it
optional: true
selector: a[href^="magnet:?xt="]
attribute: href
category:
selector: a[href^="index.php?page=torrents&category="]
attribute: href
filters:
- name: querystring
args: category
details:
selector: td:nth-child(2) a
attribute: href
banner:
optional: true
selector: td:nth-child(2) > a
attribute: onmouseover
filters:
- name: regexp
args: "src=(.+?) "
size:
selector: td:nth-child(9)
date:
selector: td:nth-child(5)
filters:
- name: dateparse
args: "02/01/2006"
grabs:
selector: td:nth-child(8)
filters:
- name: replace
args: ["---", "0"]
seeders:
selector: td:nth-child(6)
leechers:
selector: td:nth-child(7)

View File

@@ -77,6 +77,9 @@
attribute: href attribute: href
size: size:
selector: td.size-row selector: td.size-row
filters:
- name: re_replace
args: ["(\\d+).(?=\\d{3}(\\D|$))", "$1"]
seeders: seeders:
selector: td.sn selector: td.sn
date: date:
@@ -96,4 +99,4 @@
downloadvolumefactor: downloadvolumefactor:
text: "0" text: "0"
uploadvolumefactor: uploadvolumefactor:
text: "1" text: "1"

View File

@@ -10,53 +10,20 @@
caps: caps:
categorymappings: categorymappings:
# TV - {id: 9, cat: TV/Anime, desc: "Anime"}
- {id: 23, cat: TV, desc: "TV/HD"} - {id: 1, cat: PC/0day, desc: "Apps"}
- {id: 47, cat: TV, desc: "TV/PACKS"} - {id: 13, cat: PC/0day, desc: "Apps"}
- {id: 28, cat: TV, desc: "TV/eps"} - {id: 5, cat: TV, desc: "Episodes"}
- {id: 25, cat: TV, desc: "TV/HDRIP"} - {id: 2, cat: PC/Games, desc: "Games"}
- {id: 24, cat: TV, desc: "TV/TV-packs"} - {id: 12, cat: PC/Games, desc: "Games/PC Rips"}
- {id: 26, cat: TV/HD, desc: "TV/X264-HD"} - {id: 8, cat: Console/Other, desc: "Games/PS2"}
- {id: 27, cat: TV/SD, desc: "TV/X264-SD"} - {id: 7, cat: Console/PSP, desc: "Games/PSP"}
# Movies - {id: 3, cat: Movies, desc: "Movies"}
- {id: 10, cat: Movies, desc: "Movies/0DAY"} - {id: 11, cat: Movies/SD, desc: "Movies/HDTV"}
- {id: 56, cat: Movies/3D, desc: "Movies/3D"} - {id: 10, cat: Movies/SD, desc: "Movies/XviD"}
- {id: 16, cat: TV/Anime, desc: "Movies/ANIME"} - {id: 4, cat: Audio, desc: "Music"}
- {id: 44, cat: Movies, desc: "Movies/CAM"} - {id: 14, cat: Audio, desc: "Music"}
- {id: 18, cat: Movies/DVD, desc: "Movies/DVDR"} - {id: 6, cat: XXX, desc: "XXX"}
- {id: 49, cat: Movies/HD, desc: "Movies/hd 1080p"}
- {id: 48, cat: Movies/HD, desc: "Movies/hd 720p"}
- {id: 55, cat: Movies, desc: "Movies/Box Sets"}
- {id: 53, cat: Movies, desc: "Movies/Sports"}
- {id: 17, cat: Movies, desc: "Movies/X264"}
- {id: 57, cat: Movies, desc: "Movies/xmas"}
- {id: 15, cat: Movies/SD, desc: "Movies/XVID"}
# Music
- {id: 54, cat: Audio/Audiobook, desc: "Music/Audio Book"}
- {id: 19, cat: Audio/Lossless, desc: "Music/FLAC"}
- {id: 20, cat: Audio, desc: "Music/DVDR"}
- {id: 21, cat: Audio/MP3, desc: "Music/MP3"}
- {id: 42, cat: Audio, desc: "Music/0DAY"}
- {id: 22, cat: Audio/Video, desc: "Music/VID"}
# Apps
- {id: 9, cat: PC/0day, desc: "Apps/APPS"}
- {id: 11, cat: Books/Ebook, desc: "Apps/EBOOKS"}
- {id: 46, cat: PC/Phone-Other, desc: "Apps/IPHONE/ANDROID"}
- {id: 51, cat: PC, desc: "Apps/Linux"}
- {id: 52, cat: PC/Mac, desc: "Apps/MAC"}
# Games
- {id: 58, cat: Console/Other, desc: "Games/Android"}
- {id: 45, cat: PC/Games, desc: "Games/GAMES"}
- {id: 59, cat: Console/NDS, desc: "Games/NDS"}
- {id: 50, cat: Console, desc: "Games/PS2"}
- {id: 14, cat: Console/PS3, desc: "Games/PS3"}
- {id: 12, cat: Console/Wii, desc: "Games/WII"}
- {id: 13, cat: Console/Xbox 360, desc: "Games/XBOX360"}
# XXX
- {id: 38, cat: XXX, desc: "XXX"}
- {id: 39, cat: XXX, desc: "XXX/0DAY"}
- {id: 40, cat: XXX/Imageset, desc: "XXX/IMAGESET"}
- {id: 41, cat: XXX/Other, desc: "XXX/SITERIPS"}
modes: modes:
search: [q] search: [q]
@@ -101,13 +68,13 @@
selector: table tr td.text selector: table tr td.text
test: test:
path: browse.php path: browse.php
selector: li a[href^="logout.php?hash_please="] selector: a[href*="logout.php?hash_please="]
search: search:
paths: paths:
- path: browse.php - path: browse.php
inputs: inputs:
#$raw: "{{range .Categories}}c{{.}}=1&{{end}}" # this should work, untested $raw: "{{range .Categories}}c{{.}}=1&{{end}}"
search: "{{ .Keywords }}" search: "{{ .Keywords }}"
searchin: "title" searchin: "title"
incldead: "{{ .Config.incldead }}" incldead: "{{ .Config.incldead }}"
@@ -137,11 +104,7 @@
selector: td:nth-of-type(3) a selector: td:nth-of-type(3) a
attribute: href attribute: href
files: files:
optional: true selector: td:nth-of-type(5)
selector: td:nth-of-type(5) a
files:
optional: true
selector: td:nth-of-type(5):not(:has(a))
date: date:
selector: td:nth-of-type(7) selector: td:nth-of-type(7)
filters: filters:
@@ -155,12 +118,13 @@
- name: regexp - name: regexp
args: "([\\d]+)" args: "([\\d]+)"
seeders: seeders:
selector: td:nth-of-type(10) a font selector: td:nth-of-type(10)
leechers: leechers:
selector: td:nth-of-type(11) selector: td:nth-of-type(11)
downloadvolumefactor: downloadvolumefactor:
case: case:
"span:contains(\"Unlimited\")": "0" "img[title=\"Free Torrent\"]": "0" # torrent specific free leech (icon)?
"a.info:contains(\"Free\")": "0" # global freeleech note?
"*": "1" "*": "1"
uploadvolumefactor: uploadvolumefactor:
text: "1" text: "1"

View File

@@ -44,6 +44,7 @@
- selector: td.embedded:has(h2:contains("failed")) - selector: td.embedded:has(h2:contains("failed"))
- selector: td.embedded:has(h2:contains("Error")) - selector: td.embedded:has(h2:contains("Error"))
test: test:
selector: a[href^="logout.php"]
path: /browse.php path: /browse.php
search: search:

View File

@@ -6,6 +6,8 @@
type: private type: private
encoding: UTF-8 encoding: UTF-8
links: links:
- https://racing4everyone.eu/
legacylinks:
- https://racing4everyone.jp/ - https://racing4everyone.jp/
caps: caps:

View File

@@ -83,7 +83,9 @@
searchin: "title" searchin: "title"
incldead: "{{ .Config.incldead }}" incldead: "{{ .Config.incldead }}"
"only_free": "{{ if .Config.onlyfree }}1{{else}}0{{end}}" "only_free": "{{ if .Config.onlyfree }}1{{else}}0{{end}}"
keywordsfilters:
- name: re_replace
args: ["(\\w+)", " +$1"] # prepend + to each word
rows: rows:
selector: tr.browse_color, tr[id^="kdescr"] selector: tr.browse_color, tr[id^="kdescr"]
after: 1 after: 1
@@ -141,7 +143,10 @@
args: ["\n", "<br>\n"] args: ["\n", "<br>\n"]
downloadvolumefactor: downloadvolumefactor:
case: case:
"b:contains(\"[Free and Double]\")": "0"
"img[alt=\"Free Torrent\"]": "0" "img[alt=\"Free Torrent\"]": "0"
"*": "1" "*": "1"
uploadvolumefactor: uploadvolumefactor:
text: "1" case:
"b:contains(\"[Free and Double]\")": "2"
"*": "1"

View File

@@ -6,10 +6,10 @@
type: private type: private
encoding: UTF-8 encoding: UTF-8
links: links:
- http://www.shareisland.org/
legacylinks:
- https://shareisland.org/ - https://shareisland.org/
- http://shareisland.org/ legacylinks:
- http://shareisland.org/
- http://www.shareisland.org/
caps: caps:
categorymappings: categorymappings:
@@ -28,6 +28,7 @@
- {id: 41, cat: Books, desc: "Quotidiani"} - {id: 41, cat: Books, desc: "Quotidiani"}
- {id: 59, cat: Books, desc: "Fumetti"} - {id: 59, cat: Books, desc: "Fumetti"}
- {id: 60, cat: Books, desc: "Riviste"} - {id: 60, cat: Books, desc: "Riviste"}
- {id: 61, cat: Books, desc: "Audiolibri"}
# Games # Games
- {id: 47, cat: PC/Games, desc: "Games PC"} - {id: 47, cat: PC/Games, desc: "Games PC"}
- {id: 22, cat: Console/Other, desc: "Nintendo"} - {id: 22, cat: Console/Other, desc: "Nintendo"}

View File

@@ -60,6 +60,8 @@
args: ["[^a-zA-Z0-9]+", "-"] args: ["[^a-zA-Z0-9]+", "-"]
rows: rows:
selector: table > tbody > tr:has(td:has(div:has(a[href^="/torrent/"]))) selector: table > tbody > tr:has(td:has(div:has(a[href^="/torrent/"])))
filters:
- name: andmatch
fields: fields:
title: title:
selector: td:nth-child(1) > div > a selector: td:nth-child(1) > div > a

View File

@@ -0,0 +1,111 @@
---
site: torrent-turk
name: TOrrent-tuRK
description: "TOrrent-tuRK (TORK) is a Turkish Private Torrent Tracker for HD MOVIES / TV / GENERAL"
language: tr-TR
type: private
encoding: UTF-8
links:
- https://torrent-turk.org/
caps:
categorymappings:
- {id: 149, cat: Movies, desc: "Movies/Turkish"}
- {id: 151, cat: Movies/HD, desc: "Movies/Turkish/1080p"}
- {id: 152, cat: Movies/HD, desc: "Movies/Turkish/720p"}
- {id: 156, cat: Movies, desc: "Movies/Foreign"}
- {id: 157, cat: Movies/UHD, desc: "Movies/Foreign/4K"}
- {id: 159, cat: Movies/HD, desc: "Movies/Foreign/1080p"}
- {id: 160, cat: Movies/HD, desc: "Movies/Foreign/720p"}
- {id: 164, cat: TV, desc: "TV"}
- {id: 165, cat: TV, desc: "TV/Turkish"}
- {id: 166, cat: TV, desc: "TV/Foreign"}
- {id: 171, cat: Audio, desc: "Music"}
- {id: 172, cat: Audio, desc: "Music/Turkish"}
- {id: 173, cat: Audio, desc: "Music/Foreign"}
modes:
search: [q]
tv-search: [q]
movie-search: [q]
login:
path: /?p=home&pid=1
method: form
form: form#loginbox_form
submitpath: /ajax/login.php
inputs:
action: "login"
loginbox_membername: "{{ .Config.username }}"
loginbox_password: "{{ .Config.password }}"
loginbox_remember: "true"
selectorinputs:
securitytoken:
selector: "script:contains(\"stKey: \")"
filters:
- name: regexp
args: "stKey: \"(.+?)\","
error:
- selector: ":contains(\"-ERROR-\")"
test:
path: /?p=torrents&type=bookmarks&pid=508
selector: a#logout
search:
paths:
- path: /
keywordsfilters:
- name: re_replace
args: ["[^a-zA-Z0-9]+", "%25"]
inputs:
p: "torrents"
pid: "32"
$raw: "{{range .Categories}}cid[]={{.}}&{{end}}"
keywords: "{{ .Keywords }}"
search_type: "name"
searchin: "title"
error:
- selector: div.error:not(:contains("Hiçbir sonuç bulunamadı."))
rows:
selector: table#torrents_table_classic > tbody > tr:has(td.torrent_name)
fields:
title:
selector: a[href*="?p=torrents&pid=10&action=details"]
category:
selector: div.category_image > a
attribute: href
filters:
- name: querystring
args: cid
details:
selector: a[href*="?p=torrents&pid=10&action=details"]
attribute: href
download:
selector: a[href*="?p=torrents&pid=10&action=download"]
attribute: href
size:
selector: a[rel="torrent_size"]
seeders:
selector: a[rel="torrent_seeders"]
leechers:
selector: a[rel="torrent_leechers"]
grabs:
selector: a[rel="times_completed"]
banner:
selector: a[rel="fancybox"]
optional: true
attribute: href
downloadvolumefactor:
case:
"img[title=\"FREE!\"]": "0"
"*": "1"
uploadvolumefactor:
case:
"*": "1"
date:
selector: td.torrent_name > abbr.timeago
optional: true
attribute: data-time

View File

@@ -6,8 +6,9 @@
type: public type: public
encoding: UTF-8 encoding: UTF-8
links: links:
- http://www.torrent9.red/ - http://www.torrent9.ec/
legacylinks: legacylinks:
- http://www.torrent9.red/
- http://www.torrent9.bz/ - http://www.torrent9.bz/
- http://www.torrents9.pe/ - http://www.torrents9.pe/
- http://www.torrent9.cc/ - http://www.torrent9.cc/

View File

@@ -55,6 +55,7 @@
- {id: 71, cat: XXX/Packs, desc: "pr0n / pack"} - {id: 71, cat: XXX/Packs, desc: "pr0n / pack"}
- {id: 30, cat: Other, desc: "Kita"} - {id: 30, cat: Other, desc: "Kita"}
- {id: 41, cat: Books, desc: "E-Books"} - {id: 41, cat: Books, desc: "E-Books"}
- {id: 76, cat: TV, desc: "Animacija / LT"}
modes: modes:
search: [q] search: [q]

View File

@@ -115,6 +115,8 @@
rows: rows:
selector: tr.browse_color, tr[id^="kdescr"] selector: tr.browse_color, tr[id^="kdescr"]
after: 1 after: 1
filters:
- name: andmatch
fields: fields:
category: category:
selector: td:nth-of-type(1) a selector: td:nth-of-type(1) a

View File

@@ -1,111 +0,0 @@
---
site: torrentwtf
name: Torrentwtf
description: "Torrentwtf is a Czech Private site for TV / MOVIES / GENERAL"
language: cs-cz
type: private
encoding: UTF-8
links:
- https://torrent.wtf/
caps:
categorymappings:
- {id: 1, cat: Movies, desc: "Filmy"}
- {id: 2, cat: TV, desc: "Seriály"}
- {id: 3, cat: Audio, desc: "Hudba"}
- {id: 5, cat: PC/Games, desc: "Hry"}
- {id: 6, cat: Books, desc: "Knihy"}
- {id: 8, cat: PC, desc: "Software"}
- {id: 9, cat: XXX, desc: "xXx"}
- {id: 10, cat: Other, desc: "Ostatní"}
modes:
search: [q]
tv-search: [q, season, ep, imdbid]
movie-search: [q, imdbid]
login:
path: /login
method: form
inputs:
username: "{{ .Config.username }}"
password: "{{ .Config.password }}"
error:
- selector: table.main:contains("Tieto poverenia sa nezhodujú s našimi záznamami.")
test:
path: /torrents
search:
paths:
- path: /filter
inputs:
$raw: "{{range .Categories}}categories[]={{.}}&{{end}}"
search: "{{if .Query.IMDBID}}{{else}}{{ .Keywords }}{{end}}"
imdb: "{{ .Query.IMDBIDShort }}"
tvdb: ""
tmdb: ""
sorting: created_at
direction: desc
qty: 100
preprocessingfilters:
- name: jsonjoinarray
args: ["$.result", ""]
- name: prepend
args: "<table>"
- name: append
args: "</table>"
rows:
selector: tr
fields:
category:
selector: a[href*="/categories/"]
attribute: href
filters:
- name: regexp
args: "/categories/.*?\\.(\\d+)"
title:
selector: a.view-torrent
filters:
- name: re_replace
args: [".*? / ", ""]
download:
selector: a[href*="/download_check/"]
attribute: href
filters:
- name: replace
args: ["/download_check/", "/download/"]
details:
selector: a.view-torrent
attribute: href
imdb:
optional: true
selector: a[href*="://www.imdb.com/title/"]
attribute: href
size:
selector: td:nth-child(5)
seeders:
selector: td:nth-child(7)
leechers:
selector: td:nth-child(8)
grabs:
selector: td:nth-child(6)
filters:
- name: regexp
args: ([\d\.]+)
date:
selector: time
attribute: datetime
filters:
- name: append
args: " +00:00"
- name: dateparse
args: "2006-01-02 15:04:05 -07:00"
downloadvolumefactor:
case:
"i[data-original-title=\"100% Free\"]": "0"
"i[data-original-title=\"Global FreeLeech\"]": "0"
"*": "1"
uploadvolumefactor:
case:
"i[data-original-title=\"Double upload\"]": "2"
"*": "1"

View File

@@ -120,7 +120,7 @@
selector: table#browsetable > tbody > tr:has(a[href^="/details.php?id="]) selector: table#browsetable > tbody > tr:has(a[href^="/details.php?id="])
fields: fields:
category: category:
selector: a[href^="/browse.php?q="] selector: a[href^="/browse.php"]
attribute: href attribute: href
filters: filters:
- name: querystring - name: querystring

View File

@@ -6,8 +6,9 @@
type: semi-private type: semi-private
encoding: UTF-8 encoding: UTF-8
links: links:
- https://yggtorrent.is/ - https://ww1.yggtorrent.is/
legacylinks: legacylinks:
- https://yggtorrent.is/
- https://yggtorrent.com/ - https://yggtorrent.com/
- https://ww1.yggtorrent.com/ - https://ww1.yggtorrent.com/
@@ -96,7 +97,18 @@
type: checkbox type: checkbox
label: Try to normalize releases names by moving year after the title label: Try to normalize releases names by moving year after the title
default: false default: false
- name: multilang
type: checkbox
label: Replace MULTI by another language in release name
default: false
- name: multilanguage
type: select
label: Replace MULTI by this language
default: FRENCH
options:
FRENCH : "FRENCH"
MULTI.FRENCH: "MULTI.FRENCH"
ENGLISH: "ENGLISH"
login: login:
method: form method: form
path: / path: /
@@ -140,8 +152,15 @@
- name: re_replace - name: re_replace
args: ["(\\s{2,5})", " "] args: ["(\\s{2,5})", " "]
- name: trim - name: trim
title: title_phase1:
text: "{{if .Config.filter_title }}{{ .Result.title_filtered }}{{else}}{{ .Result.title_normal }}{{end}}" text: "{{if .Config.filter_title }}{{ .Result.title_filtered }}{{else}}{{ .Result.title_normal }}{{end}}"
title_multilang:
text: "{{ .Result.title_phase1 }}"
filters:
- name: re_replace
args: ["[\\.\\s\\[\\-][Mm][Uu][Ll][Tt][Ii][\\.\\s\\]\\-]", ".{{ .Config.multilanguage }}."]
title:
text: "{{if .Config.multilang }}{{ .Result.title_multilang }}{{else}}{{ .Result.title_phase1 }}{{end}}"
details: details:
selector: ":nth-child(2) > a" selector: ":nth-child(2) > a"
attribute: href attribute: href
@@ -238,4 +257,4 @@
downloadvolumefactor: downloadvolumefactor:
text: "1" text: "1"
uploadvolumefactor: uploadvolumefactor:
text: "1" text: "1"

View File

@@ -20,21 +20,29 @@ namespace Jackett.Common.Indexers
{ {
public class BJShare : BaseWebIndexer public class BJShare : BaseWebIndexer
{ {
private string LoginUrl { get { return SiteLink + "login.php"; } } private string LoginUrl => SiteLink + "login.php";
private string BrowseUrl { get { return SiteLink + "torrents.php"; } } private string BrowseUrl => SiteLink + "torrents.php";
private string TodayUrl { get { return SiteLink + "torrents.php?action=today"; } } private string TodayUrl => SiteLink + "torrents.php?action=today";
private char[] digits = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; private readonly char[] _digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
private readonly Dictionary<string, string> _commonSearchTerms = new Dictionary<string, string>
private new ConfigurationDataBasicLoginWithRSSAndDisplay configData
{ {
get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } { "agents of shield", "Agents of S.H.I.E.L.D."}
set { base.configData = value; } };
public override string[] LegacySiteLinks { get; protected set; } = new string[] {
"https://bj-share.me/"
};
private ConfigurationDataBasicLoginWithRSSAndDisplay ConfigData
{
get => (ConfigurationDataBasicLoginWithRSSAndDisplay)configData;
set => configData = value;
} }
public BJShare(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps) public BJShare(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps)
: base(name: "BJ-Share", : base("BJ-Share",
description: "A brazilian tracker.", description: "A brazilian tracker.",
link: "https://bj-share.me/", link: "https://bj-share.info/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(), caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
configService: configService, configService: configService,
client: wc, client: wc,
@@ -76,8 +84,8 @@ namespace Jackett.Common.Indexers
var pairs = new Dictionary<string, string> var pairs = new Dictionary<string, string>
{ {
{ "username", configData.Username.Value }, { "username", ConfigData.Username.Value },
{ "password", configData.Password.Value }, { "password", ConfigData.Password.Value },
{ "keeplogged", "1" } { "keeplogged", "1" }
}; };
@@ -85,7 +93,7 @@ namespace Jackett.Common.Indexers
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
{ {
var errorMessage = result.Content; var errorMessage = result.Content;
throw new ExceptionWithConfigData(errorMessage, configData); throw new ExceptionWithConfigData(errorMessage, ConfigData);
}); });
return IndexerConfigurationStatus.RequiresTesting; return IndexerConfigurationStatus.RequiresTesting;
} }
@@ -94,13 +102,24 @@ namespace Jackett.Common.Indexers
{ {
// Search does not support searching with episode numbers so strip it if we have one // Search does not support searching with episode numbers so strip it if we have one
// Ww AND filter the result later to archive the proper result // Ww AND filter the result later to archive the proper result
if (isAnime) return isAnime ? term.TrimEnd(_digits) : Regex.Replace(term, @"[S|E]\d\d", string.Empty).Trim();
{ }
return term.TrimEnd(digits);
} private static string FixAbsoluteNumbering(string title)
{
var ret = Regex.Replace(term, @"[S|E]\d\d", string.Empty).Trim(); // if result is One piece, convert title from SXXEXX to EXX
return ret.Replace("Agents of SHIELD", "Agents of S.H.I.E.L.D."); // One piece is the only anime that i'm aware that is in "absolute" numbering, the problem is that they include
// the season (wrong season) and episode as absolute, eg: One Piece - S08E836
// 836 is the latest episode in absolute numbering, that is correct, but S08 is not the current season...
// So for this show, i don't see a other way to make it work...
//
// All others animes that i tested is with correct season and episode set, so i can't remove the season from all
// or will break everything else
//
// In this indexer, it looks that it is added "automatically", so all current and new releases will be broken
// until they or the source from where they get that info fix it...
return title.Contains("One Piece") ? Regex.Replace(title, @"(Ep[\.]?[ ]?)|([S]\d\d[Ee])", "E") : title;
} }
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
@@ -113,51 +132,53 @@ namespace Jackett.Common.Indexers
var results = await RequestStringWithCookies(TodayUrl); var results = await RequestStringWithCookies(TodayUrl);
try try
{ {
string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; const string rowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)";
var SearchResultParser = new HtmlParser(); var searchResultParser = new HtmlParser();
var SearchResultDocument = SearchResultParser.Parse(results.Content); var searchResultDocument = searchResultParser.Parse(results.Content);
var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); var rows = searchResultDocument.QuerySelectorAll(rowsSelector);
foreach (var Row in Rows) foreach (var row in rows)
{ {
try try
{ {
var release = new ReleaseInfo(); var release = new ReleaseInfo
{
MinimumRatio = 1,
MinimumSeedTime = 0
};
release.MinimumRatio = 1;
release.MinimumSeedTime = 0;
var qDetailsLink = Row.QuerySelector("a.BJinfoBox");
var qTitle = qDetailsLink.QuerySelector("font");
release.Title = qTitle.TextContent;
var qDetailsLink = row.QuerySelector("a.BJinfoBox");
var qBJinfoBox = qDetailsLink.QuerySelector("span"); var qBJinfoBox = qDetailsLink.QuerySelector("span");
var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); var qCatLink = row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]");
var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); var qDlLink = row.QuerySelector("a[href^=\"torrents.php?action=download\"]");
var qSeeders = Row.QuerySelector("td:nth-child(4)"); var qSeeders = row.QuerySelector("td:nth-child(4)");
var qLeechers = Row.QuerySelector("td:nth-child(5)"); var qLeechers = row.QuerySelector("td:nth-child(5)");
var qQuality = Row.QuerySelector("font[color=\"red\"]"); var qQuality = row.QuerySelector("font[color=\"red\"]");
var qFreeLeech = Row.QuerySelector("font[color=\"green\"]:contains(Free)"); var qFreeLeech = row.QuerySelector("font[color=\"green\"]:contains(Free)");
var qTitle = qDetailsLink.QuerySelector("font");
// Get international title if available, or use the full title if not
release.Title = Regex.Replace(qTitle.TextContent, @".* \[(.*?)\](.*)", "$1$2");
release.Description = ""; release.Description = "";
foreach (var Child in qBJinfoBox.ChildNodes) foreach (var child in qBJinfoBox.ChildNodes)
{ {
var type = Child.NodeType; var type = child.NodeType;
if (type != NodeType.Text) if (type != NodeType.Text)
continue; continue;
var line = Child.TextContent; var line = child.TextContent;
if (line.StartsWith("Tamanho:")) if (line.StartsWith("Tamanho:"))
{ {
string Size = line.Substring("Tamanho: ".Length); ; var size = line.Substring("Tamanho: ".Length); ;
release.Size = ReleaseInfo.GetBytes(Size); release.Size = ReleaseInfo.GetBytes(size);
} }
else if (line.StartsWith("Lançado em: ")) else if (line.StartsWith("Lançado em: "))
{ {
string PublishDateStr = line.Substring("Lançado em: ".Length).Replace("às ", ""); var publishDateStr = line.Substring("Lançado em: ".Length).Replace("às ", "");
PublishDateStr += " +0"; publishDateStr += " +0";
var PublishDate = DateTime.SpecifyKind(DateTime.ParseExact(PublishDateStr, "dd/MM/yyyy HH:mm z", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); var publishDate = DateTime.SpecifyKind(DateTime.ParseExact(publishDateStr, "dd/MM/yyyy HH:mm z", CultureInfo.InvariantCulture), DateTimeKind.Unspecified);
release.PublishDate = PublishDate.ToLocalTime(); release.PublishDate = publishDate.ToLocalTime();
} }
else else
{ {
@@ -166,39 +187,36 @@ namespace Jackett.Common.Indexers
} }
var catStr = qCatLink.GetAttribute("href").Split('=')[1]; var catStr = qCatLink.GetAttribute("href").Split('=')[1];
// if result is an anime, convert title from SXXEXX to EXX release.Title = FixAbsoluteNumbering(release.Title);
if (catStr == "14")
var quality = qQuality.TextContent;
switch (quality)
{ {
release.Title = Regex.Replace(release.Title, @"(Ep[\.]?[ ]?)|([S]\d\d[Ee])", "E"); case "Full HD":
release.Title += " 1080p";
break;
case "HD":
release.Title += " 720p";
break;
default:
release.Title += " 480p";
break;
} }
var Quality = qQuality.TextContent;
if (Quality == "Full HD")
release.Title += " 1080p";
else if(Quality == "HD")
release.Title += " 720p";
release.Category = MapTrackerCatToNewznab(catStr); release.Category = MapTrackerCatToNewznab(catStr);
release.Link = new Uri(SiteLink + qDlLink.GetAttribute("href"));
release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href"));
release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href"));
release.Guid = release.Link; release.Guid = release.Link;
release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent);
release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders;
release.DownloadVolumeFactor = qFreeLeech != null ? 0 : 1;
if (qFreeLeech != null)
release.DownloadVolumeFactor = 0;
else
release.DownloadVolumeFactor = 1;
release.UploadVolumeFactor = 1; release.UploadVolumeFactor = 1;
releases.Add(release); releases.Add(release);
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); logger.Error($"{ID}: Error while parsing row '{row.OuterHtml}': {ex.Message}");
} }
} }
} }
@@ -211,10 +229,13 @@ namespace Jackett.Common.Indexers
{ {
var searchUrl = BrowseUrl; var searchUrl = BrowseUrl;
var isSearchAnime = query.Categories.Any(s => s == TorznabCatType.TVAnime.ID); var isSearchAnime = query.Categories.Any(s => s == TorznabCatType.TVAnime.ID);
query.SearchTerm = query.SearchTerm.Replace("Agents of SHIELD", "Agents of S.H.I.E.L.D.");
var searchString = query.GetQueryString();
foreach (var searchTerm in _commonSearchTerms)
{
query.SearchTerm = query.SearchTerm.ToLower().Replace(searchTerm.Key.ToLower(), searchTerm.Value);
}
var searchString = query.GetQueryString();
var queryCollection = new NameValueCollection var queryCollection = new NameValueCollection
{ {
{"searchstr", StripSearchString(searchString, isSearchAnime)}, {"searchstr", StripSearchString(searchString, isSearchAnime)},
@@ -235,132 +256,134 @@ namespace Jackett.Common.Indexers
var results = await RequestStringWithCookies(searchUrl); var results = await RequestStringWithCookies(searchUrl);
try try
{ {
string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; const string rowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)";
var SearchResultParser = new HtmlParser(); var searchResultParser = new HtmlParser();
var SearchResultDocument = SearchResultParser.Parse(results.Content); var searchResultDocument = searchResultParser.Parse(results.Content);
var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); var rows = searchResultDocument.QuerySelectorAll(rowsSelector);
ICollection<int> GroupCategory = null; ICollection<int> groupCategory = null;
string GroupTitle = null; string groupTitle = null;
string GroupYearStr = null; string groupYearStr = null;
Nullable<DateTime> GroupPublishDate = null; var categoryStr = "";
foreach (var Row in Rows) foreach (var row in rows)
{ {
try try
{ {
var qDetailsLink = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); var qDetailsLink = row.QuerySelector("a[href^=\"torrents.php?id=\"]");
string Title = qDetailsLink.TextContent; var title = qDetailsLink.TextContent;
ICollection<int> Category = null; ICollection<int> category = null;
string YearStr = null; string yearStr = null;
Nullable<DateTime> YearPublishDate = null;
string CategoryStr = "";
if (Row.ClassList.Contains("group") || Row.ClassList.Contains("torrent")) // group/ungrouped headers if (row.ClassList.Contains("group") || row.ClassList.Contains("torrent")) // group/ungrouped headers
{ {
var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); var qCatLink = row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]");
CategoryStr = qCatLink.GetAttribute("href").Split('=')[1].Split('&')[0]; categoryStr = qCatLink.GetAttribute("href").Split('=')[1].Split('&')[0];
Category = MapTrackerCatToNewznab(CategoryStr); category = MapTrackerCatToNewznab(categoryStr);
YearStr = qDetailsLink.NextSibling.TextContent.Trim().TrimStart('[').TrimEnd(']'); yearStr = qDetailsLink.NextSibling.TextContent.Trim().TrimStart('[').TrimEnd(']');
YearPublishDate = DateTime.SpecifyKind(DateTime.ParseExact(YearStr, "yyyy", CultureInfo.InvariantCulture), DateTimeKind.Unspecified);
// if result is an anime, convert title from SXXEXX to EXX title = FixAbsoluteNumbering(title);
if (CategoryStr == "14")
{
Title = Regex.Replace(Title, @"(Ep[\.]?[ ]?)|([S]\d\d[Ee])", "E");
}
if (Row.ClassList.Contains("group")) // group headers if (row.ClassList.Contains("group")) // group headers
{ {
GroupCategory = Category; groupCategory = category;
GroupTitle = Title; groupTitle = title;
GroupYearStr = YearStr; groupYearStr = yearStr;
GroupPublishDate = YearPublishDate;
continue; continue;
} }
} }
var release = new ReleaseInfo(); var release = new ReleaseInfo
release.MinimumRatio = 1;
release.MinimumSeedTime = 0;
var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]");
var qSize = Row.QuerySelector("td:nth-last-child(4)");
var qGrabs = Row.QuerySelector("td:nth-last-child(3)");
var qSeeders = Row.QuerySelector("td:nth-last-child(2)");
var qLeechers = Row.QuerySelector("td:nth-last-child(1)");
var qFreeLeech = Row.QuerySelector("strong[title=\"Free\"]");
if (Row.ClassList.Contains("group_torrent")) // torrents belonging to a group
{ {
release.Description = qDetailsLink.TextContent; MinimumRatio = 1,
MinimumSeedTime = 0
};
string cleanTitle = Regex.Replace(GroupTitle, @" - S?(?<season>\d{1,2})?E?(?<episode>\d{1,4})?", ""); var qDlLink = row.QuerySelector("a[href^=\"torrents.php?action=download\"]");
string seasonEp = Regex.Replace(GroupTitle, @"^(.*?) - (S?(\d{1,2})?E?(\d{1,4})?)?", "$2"); var qSize = row.QuerySelector("td:nth-last-child(4)");
release.Title = CategoryStr == "14" ? GroupTitle : cleanTitle + " " + GroupYearStr + " " + seasonEp; var qGrabs = row.QuerySelector("td:nth-last-child(3)");
var qSeeders = row.QuerySelector("td:nth-last-child(2)");
var qLeechers = row.QuerySelector("td:nth-last-child(1)");
var qFreeLeech = row.QuerySelector("strong[title=\"Free\"]");
release.PublishDate = GroupPublishDate.Value; if (row.ClassList.Contains("group_torrent")) // torrents belonging to a group
release.Category = GroupCategory; {
var description = Regex.Replace(qDetailsLink.TextContent.Trim(), @"\s+", " ");
description = Regex.Replace(description, @"((S\d{2})(E\d{2,4})?) (.*)", "$4");
release.Description = description;
var cleanTitle = Regex.Replace(groupTitle, @" - ((S(\d{2}))?E(\d{1,4}))", "");
title = Regex.Replace(title.Trim(), @"\s+", " ");
var seasonEp = Regex.Replace(title, @"((S\d{2})?(E\d{2,4})?) .*", "$1");
// do not include year to animes
if (categoryStr == "14")
{
release.Title = cleanTitle + " " + seasonEp;
}
else
{
release.Title = cleanTitle + " " + groupYearStr + " " + seasonEp;
}
release.Category = groupCategory;
} }
else if (Row.ClassList.Contains("torrent")) // standalone/un grouped torrents else if (row.ClassList.Contains("torrent")) // standalone/un grouped torrents
{ {
var qDescription = Row.QuerySelector("div.torrent_info"); var qDescription = row.QuerySelector("div.torrent_info");
release.Description = qDescription.TextContent; release.Description = qDescription.TextContent;
string cleanTitle = Regex.Replace(Title, @" - ((S(\d{1,2}))?E(\d{1,4}))", ""); var cleanTitle = Regex.Replace(title, @" - ((S\d{2})?(E\d{2,4})?)", "");
string seasonEp = Regex.Replace(Title, @"^(.*?) - ((S(\d{1,2}))?E(\d{1,4}))", "$2"); var seasonEp = Regex.Replace(title, @"^(.*?) - ((S\d{2})?(E\d{2,4})?)", "$2");
release.Title = CategoryStr == "14" ? Title : cleanTitle + " " + YearStr + " " + seasonEp;
release.PublishDate = YearPublishDate.Value; // do not include year to animes
release.Category = Category; if (categoryStr == "14")
{
release.Title = cleanTitle + " " + seasonEp;
}
else
{
release.Title = cleanTitle + " " + yearStr + " " + seasonEp;
}
release.Category = category;
} }
release.Description = release.Description.Replace(" / Free", ""); // Remove Free Tag release.Description = release.Description.Replace(" / Free", ""); // Remove Free Tag
release.Description = release.Description.Replace("Full HD", "1080p"); release.Description = release.Description.Replace("Full HD", "1080p");
release.Description = release.Description.Replace("/ HD / ", "/ 720p /"); release.Description = release.Description.Replace("/ HD / ", "/ 720p /");
release.Description = release.Description.Replace(" / HD]", " / 720p]"); release.Description = release.Description.Replace(" / HD]", " / 720p]");
release.Description = release.Description.Replace("4K", "2160p"); release.Description = release.Description.Replace("4K", "2160p");
int nBarra = release.Title.IndexOf("["); // Get international title if available, or use the full title if not
if (nBarra != -1) release.Title = Regex.Replace(release.Title, @".* \[(.*?)\](.*)", "$1$2");
{
release.Title = release.Title.Substring(nBarra + 1);
release.Title = release.Title.Replace("]", "");
}
release.Title += " " + release.Description; // add year and Description to the release Title to add some meaning to it release.Title += " " + release.Description; // add year and Description to the release Title to add some meaning to it
// This tracker does not provide an publish date to search terms (only on last 24h page)
release.PublishDate = DateTime.Today;
// check for previously stripped search terms // check for previously stripped search terms
if (!query.MatchQueryStringAND(release.Title)) if (!query.MatchQueryStringAND(release.Title))
continue; continue;
var Size = qSize.TextContent; var size = qSize.TextContent;
release.Size = ReleaseInfo.GetBytes(Size); release.Size = ReleaseInfo.GetBytes(size);
release.Link = new Uri(SiteLink + qDlLink.GetAttribute("href"));
release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href"));
release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href"));
release.Guid = release.Link; release.Guid = release.Link;
release.Grabs = ParseUtil.CoerceLong(qGrabs.TextContent); release.Grabs = ParseUtil.CoerceLong(qGrabs.TextContent);
release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent);
release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders;
release.DownloadVolumeFactor = qFreeLeech != null ? 0 : 1;
if (qFreeLeech != null)
release.DownloadVolumeFactor = 0;
else
release.DownloadVolumeFactor = 1;
release.UploadVolumeFactor = 1; release.UploadVolumeFactor = 1;
releases.Add(release); releases.Add(release);
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); logger.Error($"{ID}: Error while parsing row '{row.OuterHtml}': {ex.Message}");
} }
} }
} }

View File

@@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper; using AutoMapper;
@@ -32,6 +34,9 @@ namespace Jackett.Common.Indexers
public string Type { get; protected set; } public string Type { get; protected set; }
public virtual string ID { get { return GetIndexerID(GetType()); } } public virtual string ID { get { return GetIndexerID(GetType()); } }
[JsonConverter(typeof(EncodingJsonConverter))]
public Encoding Encoding { get; protected set; }
public virtual bool IsConfigured { get; protected set; } public virtual bool IsConfigured { get; protected set; }
protected Logger logger; protected Logger logger;
protected IIndexerConfigurationService configurationService; protected IIndexerConfigurationService configurationService;
@@ -154,8 +159,11 @@ namespace Jackett.Common.Indexers
{ {
if (jsonConfig is JArray) if (jsonConfig is JArray)
{ {
LoadValuesFromJson(jsonConfig, true); if (!MigratedFromDPAPI(jsonConfig))
IsConfigured = true; {
LoadValuesFromJson(jsonConfig, true);
IsConfigured = true;
}
} }
// read and upgrade old settings file format // read and upgrade old settings file format
else if (jsonConfig is Object) else if (jsonConfig is Object)
@@ -166,6 +174,81 @@ namespace Jackett.Common.Indexers
} }
} }
//TODO: Remove this section once users have moved off DPAPI
private bool MigratedFromDPAPI(JToken jsonConfig)
{
if (EnvironmentUtil.IsRunningLegacyOwin)
{
//Still running legacy Owin and using the DPAPI, we don't want to migrate
logger.Debug(ID + " - Running Owin, no need to migrate from DPAPI");
return false;
}
Version dotNetVersion = Microsoft.Extensions.PlatformAbstractions.PlatformServices.Default.Application.RuntimeFramework.Version;
bool isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT;
if (!isWindows && dotNetVersion.Major < 4)
{
// User isn't running Windows, but is running on .NET Core framework, no access to the DPAPI, so don't bother trying to migrate
return false;
}
LoadValuesFromJson(jsonConfig, false);
object passwordPropertyValue = null;
string passwordValue = "";
try
{
passwordPropertyValue = configData.GetType().GetProperty("Password").GetValue(configData, null);
passwordValue = passwordPropertyValue.GetType().GetProperty("Value").GetValue(passwordPropertyValue, null).ToString();
}
catch (Exception)
{
logger.Debug($"Unable to source password for [{ID}] while attempting migration, likely a public tracker");
return false;
}
if (!string.IsNullOrEmpty(passwordValue))
{
try
{
protectionService.UnProtect(passwordValue);
//Password successfully unprotected using Microsoft.AspNetCore.DataProtection, no further action needed as we've already converted the password previously
return false;
}
catch (Exception ex)
{
if (ex.Message != "The provided payload cannot be decrypted because it was not protected with this protection provider.")
{
logger.Info($"Password could not be unprotected using Microsoft.AspNetCore.DataProtection - {ID} : " + ex);
}
logger.Info($"Attempting legacy Unprotect - {ID} : ");
try
{
string unprotectedPassword = protectionService.LegacyUnProtect(passwordValue);
//Password successfully unprotected using Windows/Mono DPAPI
passwordPropertyValue.GetType().GetProperty("Value").SetValue(passwordPropertyValue, unprotectedPassword);
SaveConfig();
IsConfigured = true;
logger.Info($"Password successfully migrated for {ID}");
return true;
}
catch (Exception exception)
{
logger.Info($"Password could not be unprotected using legacy DPAPI - {ID} : " + exception);
}
}
}
return false;
}
protected async Task ConfigureIfOK(string cookies, bool isLoggedin, Func<Task> onError) protected async Task ConfigureIfOK(string cookies, bool isLoggedin, Func<Task> onError)
{ {
if (isLoggedin) if (isLoggedin)
@@ -755,8 +838,6 @@ namespace Jackett.Common.Indexers
public override TorznabCapabilities TorznabCaps { get; protected set; } public override TorznabCapabilities TorznabCaps { get; protected set; }
[JsonConverter(typeof(EncodingJsonConverter))]
public Encoding Encoding { get; protected set; }
private List<CategoryMapping> categoryMapping = new List<CategoryMapping>(); private List<CategoryMapping> categoryMapping = new List<CategoryMapping>();
protected WebClient webclient; protected WebClient webclient;

View File

@@ -17,7 +17,7 @@ namespace Jackett.Common.Indexers
{ {
public class BitCityReloaded : BaseWebIndexer public class BitCityReloaded : BaseWebIndexer
{ {
private string LoginUrl { get { return SiteLink + "login.php"; } } private string LoginUrl { get { return SiteLink + "login/index.php"; } }
private string BrowseUrl { get { return SiteLink + "uebersicht.php"; } } private string BrowseUrl { get { return SiteLink + "uebersicht.php"; } }
private TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "W. Europe Standard Time", "W. Europe Standard Time"); private TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "W. Europe Standard Time", "W. Europe Standard Time");

View File

@@ -197,6 +197,7 @@ namespace Jackett.Common.Indexers
{ {
Dictionary<string, object> variables = new Dictionary<string, object>(); Dictionary<string, object> variables = new Dictionary<string, object>();
variables[".Config.sitelink"] = SiteLink;
foreach (settingsField Setting in Definition.Settings) foreach (settingsField Setting in Definition.Settings)
{ {
string value; string value;

View File

@@ -40,7 +40,7 @@ namespace Jackett.Common.Indexers
{ {
Encoding = Encoding.UTF8; Encoding = Encoding.UTF8;
Language = "en-us"; Language = "en-us";
Type = "private"; Type = "public";
AddCategoryMapping(5, TorznabCatType.PC0day, "Applications"); AddCategoryMapping(5, TorznabCatType.PC0day, "Applications");
AddCategoryMapping(17, TorznabCatType.AudioAudiobook, "Audio Books"); AddCategoryMapping(17, TorznabCatType.AudioAudiobook, "Audio Books");
@@ -135,6 +135,11 @@ namespace Jackett.Common.Indexers
var episodeSearchUrl = string.Format(SearchUrl, cat, WebUtility.UrlEncode(query.GetQueryString())); var episodeSearchUrl = string.Format(SearchUrl, cat, WebUtility.UrlEncode(query.GetQueryString()));
var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl); var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl);
if (results.IsRedirect)
{
throw new ExceptionWithConfigData("Unexpected redirect to " + results.RedirectingTo + ". Check your credentials.", configData);
}
if (results.Content.Contains("No torrents found")) if (results.Content.Contains("No torrents found"))
{ {
return releases; return releases;
@@ -199,17 +204,15 @@ namespace Jackett.Common.Indexers
release.Comments = new Uri(new Uri(SiteLink), qLink.Attr("href")); release.Comments = new Uri(new Uri(SiteLink), qLink.Attr("href"));
release.Guid = release.Comments; release.Guid = release.Comments;
release.Link = release.Comments; // indirect download see Download() method
var qDownload = rowB.ChildElements.ElementAt(2).ChildElements.ElementAt(0).Cq(); var sizeStr = rowB.ChildElements.ElementAt(2).Cq().Text();
release.Link = new Uri(qDownload.Attr("href"));
var sizeStr = rowB.ChildElements.ElementAt(3).Cq().Text();
release.Size = ReleaseInfo.GetBytes(sizeStr); release.Size = ReleaseInfo.GetBytes(sizeStr);
release.Seeders = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()); release.Seeders = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(5).Cq().Text());
release.Peers = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()) + release.Seeders; release.Peers = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()) + release.Seeders;
var grabs = rowB.Cq().Find("td:nth-child(6)").Text(); var grabs = rowB.Cq().Find("td:nth-child(5)").Text();
release.Grabs = ParseUtil.CoerceInt(grabs); release.Grabs = ParseUtil.CoerceInt(grabs);
release.DownloadVolumeFactor = 0; // ratioless release.DownloadVolumeFactor = 0; // ratioless
@@ -224,5 +227,19 @@ namespace Jackett.Common.Indexers
} }
return releases; return releases;
} }
public override async Task<byte[]> Download(Uri link)
{
var results = await RequestStringWithCookies(link.AbsoluteUri);
//await FollowIfRedirect(results); // manual follow for better debugging (string)
if (results.IsRedirect)
results = await RequestStringWithCookies(results.RedirectingTo);
CQ dom = results.Content;
var dl = dom.Find("a:has(font:contains(\"Download torrent file\"))");
link = new Uri(dl.Attr("href"));
return await base.Download(link);
}
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using AngleSharp.Parser.Html; using AngleSharp.Parser.Html;
using Jackett.Common.Models.IndexerConfig.Bespoke;
using Jackett.Common.Models; using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig; using Jackett.Common.Models.IndexerConfig;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
@@ -22,10 +23,11 @@ namespace Jackett.Common.Indexers
{ get { return SiteLink + "takelogin.php"; } } { get { return SiteLink + "takelogin.php"; } }
private string BrowseUrl private string BrowseUrl
{ get { return SiteLink + "browse.php"; } } { get { return SiteLink + "browse.php"; } }
private bool TorrentHTTPSMode => configData.TorrentHTTPSMode.Value;
private new ConfigurationDataBasicLogin configData private new ConfigurationDataEliteTracker configData
{ {
get { return (ConfigurationDataBasicLogin)base.configData; } get { return (ConfigurationDataEliteTracker)base.configData; }
set { base.configData = value; } set { base.configData = value; }
} }
@@ -37,10 +39,10 @@ namespace Jackett.Common.Indexers
logger: logger, logger: logger,
p: protectionService, p: protectionService,
client: webClient, client: webClient,
configData: new ConfigurationDataBasicLogin() configData: new ConfigurationDataEliteTracker()
) )
{ {
Encoding = Encoding.UTF8; Encoding = Encoding.UTF8;
Language = "fr-fr"; Language = "fr-fr";
Type = "private"; Type = "private";
@@ -206,6 +208,13 @@ Encoding = Encoding.UTF8;
release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders;
release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent); release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent);
if (TorrentHTTPSMode)
{
var linkHttps = Row.QuerySelector("td:nth-child(4)").QuerySelector("a").GetAttribute("href");
var idTorrent = ParseUtil.GetArgumentFromQueryString(linkHttps, "id");
release.Link = new Uri($"{SiteLink}download.php?id={idTorrent}&type=ssl");
}
if (added.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null) if (added.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null)
release.DownloadVolumeFactor = 0; release.DownloadVolumeFactor = 0;
else if (added.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null) else if (added.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null)

View File

@@ -219,6 +219,11 @@ namespace Jackett.Common.Indexers
searchUrl += "?" + queryCollection.GetQueryString(); searchUrl += "?" + queryCollection.GetQueryString();
var results = await RequestStringWithCookies(searchUrl); var results = await RequestStringWithCookies(searchUrl);
if (results.IsRedirect && results.RedirectingTo.EndsWith("login.php"))
{
throw new Exception("relogin needed, please update your cookie");
}
try try
{ {
string RowsSelector = ".torrent_table > tbody > tr"; string RowsSelector = ".torrent_table > tbody > tr";

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jackett.Common.Models; using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig; using Jackett.Common.Models.IndexerConfig;
@@ -30,6 +31,7 @@ namespace Jackett.Common.Indexers
string Language { get; } string Language { get; }
string LastError { get; set; } string LastError { get; set; }
string ID { get; } string ID { get; }
Encoding Encoding { get; }
TorznabCapabilities TorznabCaps { get; } TorznabCapabilities TorznabCaps { get; }

View File

@@ -117,12 +117,17 @@ namespace Jackett.Common.Indexers
return IndexerConfigurationStatus.RequiresTesting; return IndexerConfigurationStatus.RequiresTesting;
} }
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) protected async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, String seasonep)
{ {
var releases = new List<ReleaseInfo>(); var releases = new List<ReleaseInfo>();
var searchString = query.GetQueryString(); var searchString = query.GetQueryString();
var pairs = new List<KeyValuePair<string, string>>(); var pairs = new List<KeyValuePair<string, string>>();
if (seasonep != null)
{
searchString = query.SanitizedSearchTerm;
}
pairs.Add(new KeyValuePair<string, string>("nyit_sorozat_resz", "true")); pairs.Add(new KeyValuePair<string, string>("nyit_sorozat_resz", "true"));
pairs.Add(new KeyValuePair<string, string>("miben", "name")); pairs.Add(new KeyValuePair<string, string>("miben", "name"));
pairs.Add(new KeyValuePair<string, string>("tipus", "kivalasztottak_kozott")); pairs.Add(new KeyValuePair<string, string>("tipus", "kivalasztottak_kozott"));
@@ -198,8 +203,46 @@ namespace Jackett.Common.Indexers
string catlink = qRow.Find("a:has(img[class='categ_link'])").First().Attr("href"); string catlink = qRow.Find("a:has(img[class='categ_link'])").First().Attr("href");
string cat = ParseUtil.GetArgumentFromQueryString(catlink, "tipus"); string cat = ParseUtil.GetArgumentFromQueryString(catlink, "tipus");
release.Category = MapTrackerCatToNewznab(cat); release.Category = MapTrackerCatToNewznab(cat);
if (seasonep == null)
releases.Add(release);
else
{
if (query.MatchQueryStringAND(release.Title, null, seasonep))
{
/* For sonnar if the search querry was english the title must be english also so we need to change the Description and Title */
var temp = release.Title;
// releasedata everithing after Name.S0Xe0X
String releasedata =release.Title.Split(new[] { seasonep }, StringSplitOptions.None)[1].Trim();
/* if the release name not contains the language we add it because it is know from category */
if (cat.Contains("hun") && !releasedata.Contains("hun"))
releasedata += ".hun";
// release description contains [imdb: ****] but we only need the data before it for title
String[] description = {release.Description, ""};
if (release.Description.Contains("[imdb:"))
{
description = release.Description.Split('[');
description[1] = "[" + description[1];
}
else
release.Title = (description[0].Trim() + "." + seasonep.Trim() + "." + releasedata.Trim('.')).Replace(' ', '.');
// if search is done for S0X than we dont want to put . between S0X and E0X
Match match = Regex.Match(releasedata, @"^E\d\d?");
if (seasonep.Length==3 && match.Success)
release.Title = (description[0].Trim() + "." + seasonep.Trim() + releasedata.Trim('.')).Replace(' ', '.');
// add back imdb points to the description [imdb: 8.7]
release.Description = temp+" "+ description[1];
release.Description = release.Description.Trim();
releases.Add(release);
}
}
releases.Add(release);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -209,5 +252,16 @@ namespace Jackett.Common.Indexers
return releases; return releases;
} }
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var results = await PerformQuery(query, null);
if (results.Count()==0 && query.IsTVSearch) // if we search for a localized title ncore can't handle any extra S/E information, search without it and AND filter the results. See #1450
{
results = await PerformQuery(query,query.GetEpisodeSearchString());
}
return results;
}
} }
} }

View File

@@ -116,7 +116,7 @@ namespace Jackett.Common.Indexers
//AddCategoryMapping("cat_id", TorznabCatType.AudioForeign); //AddCategoryMapping("cat_id", TorznabCatType.AudioForeign);
AddCategoryMapping("21", TorznabCatType.PC); AddCategoryMapping("21", TorznabCatType.PC);
AddCategoryMapping("22", TorznabCatType.PC0day); AddCategoryMapping("22", TorznabCatType.PC0day);
AddCategoryMapping("4", TorznabCatType.PCISO); AddCategoryMapping("1", TorznabCatType.PCISO);
AddCategoryMapping("2", TorznabCatType.PCMac); AddCategoryMapping("2", TorznabCatType.PCMac);
//AddCategoryMapping("cat_id", TorznabCatType.PCPhoneOther); //AddCategoryMapping("cat_id", TorznabCatType.PCPhoneOther);
//Games/PC-ISO, Games/PC-Rips //Games/PC-ISO, Games/PC-Rips
@@ -155,7 +155,7 @@ namespace Jackett.Common.Indexers
// RSS Textual categories // RSS Textual categories
AddCategoryMapping("Anime", TorznabCatType.TVAnime); AddCategoryMapping("Anime", TorznabCatType.TVAnime);
AddCategoryMapping("Appz/Misc", TorznabCatType.PC0day); AddCategoryMapping("Appz/Misc", TorznabCatType.PC0day);
AddCategoryMapping("Appz/PC-ISO", TorznabCatType.Books); AddCategoryMapping("Appz/PC-ISO", TorznabCatType.PCISO);
AddCategoryMapping("E-Book", TorznabCatType.BooksEbook); AddCategoryMapping("E-Book", TorznabCatType.BooksEbook);
AddCategoryMapping("Games/PC-ISO", TorznabCatType.PCGames); AddCategoryMapping("Games/PC-ISO", TorznabCatType.PCGames);
AddCategoryMapping("Games/PC-Rips", TorznabCatType.PCGames); AddCategoryMapping("Games/PC-Rips", TorznabCatType.PCGames);
@@ -265,6 +265,10 @@ namespace Jackett.Common.Indexers
imdbID = l; imdbID = l;
} }
} }
var Now = DateTime.Now;
var PublishDate = DateTime.ParseExact(date, "ddd, dd MMM yyyy HH:mm:ss zz00", CultureInfo.InvariantCulture);
var PublishDateLocal = PublishDate.ToLocalTime();
var diff = Now - PublishDateLocal;
var release = new ReleaseInfo() var release = new ReleaseInfo()
{ {
@@ -273,7 +277,7 @@ namespace Jackett.Common.Indexers
Guid = new Uri(string.Format(DetailsURL, torrentId)), Guid = new Uri(string.Format(DetailsURL, torrentId)),
Comments = new Uri(string.Format(DetailsURL, torrentId)), Comments = new Uri(string.Format(DetailsURL, torrentId)),
//PublishDate = DateTime.ParseExact(infoMatch.Groups["added"].Value, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture), //2015-08-08 21:20:31 TODO: correct timezone (always -4) //PublishDate = DateTime.ParseExact(infoMatch.Groups["added"].Value, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture), //2015-08-08 21:20:31 TODO: correct timezone (always -4)
PublishDate = DateTime.ParseExact(date, "ddd, dd MMM yyyy HH:mm:ss zz00", CultureInfo.InvariantCulture).ToLocalTime(), PublishDate = PublishDateLocal,
Link = new Uri(link), Link = new Uri(link),
Seeders = ParseUtil.CoerceInt(infoMatch.Groups["seeders"].Value == "no" ? "0" : infoMatch.Groups["seeders"].Value), Seeders = ParseUtil.CoerceInt(infoMatch.Groups["seeders"].Value == "no" ? "0" : infoMatch.Groups["seeders"].Value),
Peers = ParseUtil.CoerceInt(infoMatch.Groups["leechers"].Value == "no" ? "0" : infoMatch.Groups["leechers"].Value), Peers = ParseUtil.CoerceInt(infoMatch.Groups["leechers"].Value == "no" ? "0" : infoMatch.Groups["leechers"].Value),
@@ -345,6 +349,12 @@ namespace Jackett.Common.Indexers
release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:nth-child(9)").Text()); release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:nth-child(9)").Text());
release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:nth-child(10)").Text()); release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:nth-child(10)").Text());
var grabsStr = qRow.Find("td:nth-child(8)").Text();
release.Grabs = ParseUtil.GetLongFromString(grabsStr);
var filesStr = qRow.Find("td:nth-child(7) > a").Text();
release.Files = ParseUtil.GetLongFromString(filesStr);
var category = qRow.Find(".br_type > a").Attr("href").Replace("browse.php?cat=", string.Empty); var category = qRow.Find(".br_type > a").Attr("href").Replace("browse.php?cat=", string.Empty);
release.Category = MapTrackerCatToNewznab(category); release.Category = MapTrackerCatToNewznab(category);
} }
@@ -360,4 +370,4 @@ namespace Jackett.Common.Indexers
return releases; return releases;
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@@ -19,7 +20,7 @@ namespace Jackett.Common.Indexers
{ {
private string StartPageUrl { get { return SiteLink + "login.php"; } } private string StartPageUrl { get { return SiteLink + "login.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } } private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
private string SearchUrl { get { return SiteLink + "browse_API.php"; } } private string SearchUrl { get { return SiteLink + "browse.php"; } }
private string DownloadUrl { get { return SiteLink + "download.php/{0}/download.torrent"; } } private string DownloadUrl { get { return SiteLink + "download.php/{0}/download.torrent"; } }
private new ConfigurationDataRecaptchaLogin configData private new ConfigurationDataRecaptchaLogin configData
@@ -53,25 +54,27 @@ namespace Jackett.Common.Indexers
AddCategoryMapping(59, TorznabCatType.MoviesHD, "Movies/HD"); AddCategoryMapping(59, TorznabCatType.MoviesHD, "Movies/HD");
AddCategoryMapping(61, TorznabCatType.Movies, "Movies/Classic"); AddCategoryMapping(61, TorznabCatType.Movies, "Movies/Classic");
AddCategoryMapping(64, TorznabCatType.Movies3D, "Movies/3D"); AddCategoryMapping(64, TorznabCatType.Movies3D, "Movies/3D");
AddCategoryMapping(78, TorznabCatType.XXX, "0day/XxX");
AddCategoryMapping(80, TorznabCatType.MoviesForeign, "Movies/Non-English"); AddCategoryMapping(80, TorznabCatType.MoviesForeign, "Movies/Non-English");
AddCategoryMapping(81, TorznabCatType.MoviesBluRay, "Movies/BluRay"); AddCategoryMapping(81, TorznabCatType.MoviesBluRay, "Movies/BluRay");
AddCategoryMapping(82, TorznabCatType.MoviesOther, "Movies/CAM-TS"); AddCategoryMapping(82, TorznabCatType.MoviesOther, "Movies/CAM-TS");
AddCategoryMapping(102, TorznabCatType.MoviesOther, "Movies/Remux"); AddCategoryMapping(102, TorznabCatType.MoviesOther, "Movies/Remux");
AddCategoryMapping(103, TorznabCatType.MoviesWEBDL, "Movies/Web-Rip"); AddCategoryMapping(103, TorznabCatType.MoviesWEBDL, "Movies/Web-Rip");
AddCategoryMapping(105, TorznabCatType.Movies, "Movies/Kids"); AddCategoryMapping(105, TorznabCatType.Movies, "Movies/Kids");
AddCategoryMapping(16, TorznabCatType.MoviesUHD, "Movies/4K");
AddCategoryMapping(17, TorznabCatType.MoviesBluRay, "Movies/4K bluray");
//TV //TV
AddCategoryMapping(2, TorznabCatType.TVSD, "TV/XviD"); AddCategoryMapping(2, TorznabCatType.TVSD, "TV/XviD");
AddCategoryMapping(43, TorznabCatType.TV, "TV/Packs"); AddCategoryMapping(43, TorznabCatType.TV, "TV/Packs");
AddCategoryMapping(9, TorznabCatType.TVHD, "TV-HD"); AddCategoryMapping(9, TorznabCatType.TVHD, "TV-HD");
AddCategoryMapping(19, TorznabCatType.TVHD, "TV-HD HEVC/x265");
AddCategoryMapping(63, TorznabCatType.TV, "TV/Classic"); AddCategoryMapping(63, TorznabCatType.TV, "TV/Classic");
AddCategoryMapping(77, TorznabCatType.TVSD, "TV/SD"); AddCategoryMapping(77, TorznabCatType.TVSD, "TV/SD");
AddCategoryMapping(79, TorznabCatType.TVSport, "Sports"); AddCategoryMapping(79, TorznabCatType.TVSport, "Sports");
AddCategoryMapping(100, TorznabCatType.TVFOREIGN, "TV/Non-English"); AddCategoryMapping(100, TorznabCatType.TVFOREIGN, "TV/Non-English");
AddCategoryMapping(83, TorznabCatType.TVWEBDL, "TV/Web-Rip"); AddCategoryMapping(83, TorznabCatType.TVWEBDL, "TV/Web-Rip");
AddCategoryMapping(8, TorznabCatType.TVOTHER, "TV-Mobile"); AddCategoryMapping(8, TorznabCatType.TVOTHER, "TV-Mobile");
AddCategoryMapping(18, TorznabCatType.TVAnime, "TV/Anime");
AddCategoryMapping(19, TorznabCatType.TVHD, "TV-x265");
// Games // Games
AddCategoryMapping(6, TorznabCatType.PCGames, "Games/PC ISO"); AddCategoryMapping(6, TorznabCatType.PCGames, "Games/PC ISO");
@@ -165,7 +168,7 @@ namespace Jackett.Common.Indexers
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{ {
Dictionary<string, string> qParams = new Dictionary<string, string>(); var qParams = new NameValueCollection();
qParams.Add("cata", "yes"); qParams.Add("cata", "yes");
qParams.Add("sec", "jax"); qParams.Add("sec", "jax");
@@ -180,7 +183,9 @@ namespace Jackett.Common.Indexers
qParams.Add("search", query.GetQueryString()); qParams.Add("search", query.GetQueryString());
} }
var results = await PostDataWithCookiesAndRetry(SearchUrl, qParams); var searchUrl = SearchUrl + "?" + qParams.GetQueryString();
var results = await RequestStringWithCookies(searchUrl);
List<ReleaseInfo> releases = ParseResponse(query, results.Content); List<ReleaseInfo> releases = ParseResponse(query, results.Content);
return releases; return releases;

View File

@@ -1,36 +0,0 @@
using System.Collections.Generic;
using Jackett.Common.Indexers.Abstract;
using Jackett.Common.Models;
using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils.Clients;
using NLog;
namespace Jackett.Common.Indexers
{
public class Synthesiz3r : GazelleTracker
{
public Synthesiz3r(IIndexerConfigurationService configService, WebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "Synthesiz3r",
desc: "Synthesiz3r (ST3) is a Private Torrent Tracker for ELECTRONIC MUSIC",
link: "https://synthesiz3r.com/",
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient,
supportsFreeleechTokens: true
)
{
Language = "en-us";
Type = "private";
TorznabCaps.SupportedMusicSearchParamsList = new List<string>() { "q", "album", "artist", "label", "year" };
AddCategoryMapping(1, TorznabCatType.Audio, "Music");
AddCategoryMapping(2, TorznabCatType.PC, "Applications");
AddCategoryMapping(3, TorznabCatType.Books, "E-Books");
AddCategoryMapping(4, TorznabCatType.AudioAudiobook, "Audiobooks");
AddCategoryMapping(5, TorznabCatType.Movies, "E-Learning Videos");
AddCategoryMapping(6, TorznabCatType.TV, "Comedy");
AddCategoryMapping(7, TorznabCatType.Books, "Comics");
}
}
}

View File

@@ -12,6 +12,7 @@ using Jackett.Common.Models.IndexerConfig;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils; using Jackett.Common.Utils;
using Jackett.Common.Utils.Clients; using Jackett.Common.Utils.Clients;
using static Jackett.Common.Utils.ParseUtil;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NLog; using NLog;
@@ -195,6 +196,7 @@ namespace Jackett.Common.Indexers
if (query.IsTest || string.IsNullOrWhiteSpace(searchString)) if (query.IsTest || string.IsNullOrWhiteSpace(searchString))
{ {
var rssPage = await RequestStringWithCookiesAndRetry(string.Format(RSSUrl, configData.RSSKey.Value)); var rssPage = await RequestStringWithCookiesAndRetry(string.Format(RSSUrl, configData.RSSKey.Value));
rssPage.Content = RemoveInvalidXmlChars(rssPage.Content);
var rssDoc = XDocument.Parse(rssPage.Content); var rssDoc = XDocument.Parse(rssPage.Content);
foreach (var item in rssDoc.Descendants("item")) foreach (var item in rssDoc.Descendants("item"))

View File

@@ -90,7 +90,7 @@ namespace Jackett.Common.Indexers
var loginPage = await RequestStringWithCookies(SiteLink, string.Empty); var loginPage = await RequestStringWithCookies(SiteLink, string.Empty);
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, SiteLink, SiteLink); var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, SiteLink, SiteLink);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("my.php"), () =>
{ {
CQ dom = result.Content; CQ dom = result.Content;
var messageEl = dom["td.embedded"].First(); var messageEl = dom["td.embedded"].First();
@@ -156,7 +156,14 @@ namespace Jackett.Common.Indexers
var link = row.Cq().Find("td:eq(1) a:eq(1)").First(); var link = row.Cq().Find("td:eq(1) a:eq(1)").First();
release.Guid = new Uri(SiteLink + link.Attr("href")); release.Guid = new Uri(SiteLink + link.Attr("href"));
release.Comments = release.Guid; release.Comments = release.Guid;
release.Title = link.Get(0).FirstChild.ToString(); release.Title = link.Attr("title");
// There isn't a title attribute if the release name isn't truncated.
if (string.IsNullOrWhiteSpace(release.Title))
{
release.Title = link.Get(0).FirstChild.ToString();
}
release.Description = release.Title; release.Description = release.Title;
// If we search an get no results, we still get a table just with no info. // If we search an get no results, we still get a table just with no info.

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;net452</TargetFrameworks> <TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
@@ -114,16 +114,17 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AngleSharp" Version="0.9.9.2" /> <PackageReference Include="AngleSharp" Version="0.9.9.2" />
<PackageReference Include="Autofac" Version="4.6.2" /> <PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="AutoMapper" Version="6.2.2" /> <PackageReference Include="AutoMapper" Version="6.2.2" />
<PackageReference Include="BencodeNET" Version="2.2.24" /> <PackageReference Include="BencodeNET" Version="2.2.24" />
<PackageReference Include="CloudFlareUtilities" Version="1.2.0" /> <PackageReference Include="CloudFlareUtilities" Version="1.2.0" />
<PackageReference Include="CommandLineParser" Version="2.2.1" /> <PackageReference Include="CommandLineParser" Version="2.2.1" />
<PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" /> <PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.4.1" /> <PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
<PackageReference Include="MimeMapping" Version="1.0.1.12" /> <PackageReference Include="MimeMapping" Version="1.0.1.12" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NLog" Version="4.5.0-rc07" /> <PackageReference Include="NLog" Version="4.5.6" />
<PackageReference Include="YamlDotNet" Version="4.3.2-pre0473" /> <PackageReference Include="YamlDotNet" Version="4.3.2-pre0473" />
</ItemGroup> </ItemGroup>

View File

@@ -1,4 +1,5 @@
using CommandLine; using CommandLine;
using Jackett.Common.Utils;
using System; using System;
namespace Jackett.Common.Models.Config namespace Jackett.Common.Models.Config
@@ -83,7 +84,16 @@ namespace Jackett.Common.Models.Config
if (options.ListenPublic && options.ListenPrivate) if (options.ListenPublic && options.ListenPrivate)
{ {
Console.WriteLine("You can only use listen private OR listen publicly."); Console.WriteLine("You can only use listen private OR listen publicly.");
Engine.Exit(1);
//TODO: Remove once off Owin
if (EnvironmentUtil.IsRunningLegacyOwin)
{
Engine.Exit(1);
}
else
{
Environment.Exit(1);
}
} }
// SSL Fix // SSL Fix

View File

@@ -0,0 +1,13 @@
namespace Jackett.Common.Models.IndexerConfig.Bespoke
{
class ConfigurationDataEliteTracker : ConfigurationDataBasicLogin
{
public BoolItem TorrentHTTPSMode { get; private set; }
public ConfigurationDataEliteTracker()
: base()
{
TorrentHTTPSMode = new BoolItem { Name = "Use https for tracker URL (Experimental)", Value = false };
}
}
}

View File

@@ -83,7 +83,11 @@ namespace Jackett.Common.Plumbing
private void RegisterWebClient<WebClientType>(ContainerBuilder builder) private void RegisterWebClient<WebClientType>(ContainerBuilder builder)
{ {
Engine.WebClientType = typeof(WebClientType); //TODO: Remove once off Owin
if (EnvironmentUtil.IsRunningLegacyOwin)
{
Engine.WebClientType = typeof(WebClientType);
}
builder.RegisterType<WebClientType>().As<WebClient>(); builder.RegisterType<WebClientType>().As<WebClient>();
} }

View File

@@ -4,5 +4,7 @@
{ {
string Protect(string plainText); string Protect(string plainText);
string UnProtect(string plainText); string UnProtect(string plainText);
string LegacyProtect(string plainText);
string LegacyUnProtect(string plainText);
} }
} }

View File

@@ -12,8 +12,10 @@ using System.Threading.Tasks;
using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar; using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip;
using Jackett.Common.Models.Config;
using Jackett.Common.Models.GitHub; using Jackett.Common.Models.GitHub;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils;
using Jackett.Common.Utils.Clients; using Jackett.Common.Utils.Clients;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
@@ -28,14 +30,16 @@ namespace Jackett.Common.Services
IConfigurationService configService; IConfigurationService configService;
ManualResetEvent locker = new ManualResetEvent(false); ManualResetEvent locker = new ManualResetEvent(false);
ITrayLockService lockService; ITrayLockService lockService;
private ServerConfig serverConfig;
bool forceupdatecheck = false; bool forceupdatecheck = false;
public UpdateService(Logger l, WebClient c, IConfigurationService cfg, ITrayLockService ls) public UpdateService(Logger l, WebClient c, IConfigurationService cfg, ITrayLockService ls, ServerConfig sc)
{ {
logger = l; logger = l;
client = c; client = c;
configService = cfg; configService = cfg;
lockService = ls; lockService = ls;
serverConfig = sc;
} }
private string ExePath() private string ExePath()
@@ -74,13 +78,12 @@ namespace Jackett.Common.Services
private async Task CheckForUpdates() private async Task CheckForUpdates()
{ {
var config = Engine.ServerConfig; if (serverConfig.RuntimeSettings.NoUpdates)
if (config.RuntimeSettings.NoUpdates)
{ {
logger.Info($"Updates are disabled via --NoUpdates."); logger.Info($"Updates are disabled via --NoUpdates.");
return; return;
} }
if (config.UpdateDisabled && !forceupdatecheck) if (serverConfig.UpdateDisabled && !forceupdatecheck)
{ {
logger.Info($"Skipping update check as it is disabled."); logger.Info($"Skipping update check as it is disabled.");
return; return;
@@ -112,7 +115,7 @@ namespace Jackett.Common.Services
var releases = JsonConvert.DeserializeObject<List<Release>>(response.Content); var releases = JsonConvert.DeserializeObject<List<Release>>(response.Content);
if (!config.UpdatePrerelease) if (!serverConfig.UpdatePrerelease)
{ {
releases = releases.Where(r => !r.Prerelease).ToList(); releases = releases.Where(r => !r.Prerelease).ToList();
} }
@@ -132,7 +135,7 @@ namespace Jackett.Common.Services
var installDir = Path.GetDirectoryName(ExePath()); var installDir = Path.GetDirectoryName(ExePath());
var updaterPath = Path.Combine(tempDir, "Jackett", "JackettUpdater.exe"); var updaterPath = Path.Combine(tempDir, "Jackett", "JackettUpdater.exe");
if (updaterPath != null) if (updaterPath != null)
StartUpdate(updaterPath, installDir, isWindows, config.RuntimeSettings.NoRestart); StartUpdate(updaterPath, installDir, isWindows, serverConfig.RuntimeSettings.NoRestart);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -304,7 +307,15 @@ namespace Jackett.Common.Services
{ {
logger.Info("Exiting Jackett.."); logger.Info("Exiting Jackett..");
lockService.Signal(); lockService.Signal();
Engine.Exit(0); //TODO: Remove once off Owin
if (EnvironmentUtil.IsRunningLegacyOwin)
{
Engine.Exit(0);
}
else
{
Environment.Exit(0);
}
} }
} }
} }

View File

@@ -13,6 +13,7 @@ using CloudFlareUtilities;
using Jackett.Common.Models.Config; using Jackett.Common.Models.Config;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
using NLog; using NLog;
using Jackett.Common.Helpers;
namespace Jackett.Common.Utils.Clients namespace Jackett.Common.Utils.Clients
{ {
@@ -257,7 +258,10 @@ namespace Jackett.Common.Utils.Clients
// See issue #1200 // See issue #1200
if (result.RedirectingTo != null && result.RedirectingTo.StartsWith("file://")) if (result.RedirectingTo != null && result.RedirectingTo.StartsWith("file://"))
{ {
var newRedirectingTo = result.RedirectingTo.Replace("file://", request.RequestUri.Scheme + "://" + request.RequestUri.Host); // URL decoding apparently is needed to, without it e.g. Demonoid download is broken
// TODO: is it always needed (not just for relative redirects)?
var newRedirectingTo = WebUtilityHelpers.UrlDecode(result.RedirectingTo, webRequest.Encoding);
newRedirectingTo = newRedirectingTo.Replace("file://", request.RequestUri.Scheme + "://" + request.RequestUri.Host);
logger.Debug("[MONO relative redirect bug] Rewriting relative redirect URL from " + result.RedirectingTo + " to " + newRedirectingTo); logger.Debug("[MONO relative redirect bug] Rewriting relative redirect URL from " + result.RedirectingTo + " to " + newRedirectingTo);
result.RedirectingTo = newRedirectingTo; result.RedirectingTo = newRedirectingTo;
} }

View File

@@ -13,6 +13,7 @@ using CloudFlareUtilities;
using Jackett.Common.Models.Config; using Jackett.Common.Models.Config;
using Jackett.Common.Services.Interfaces; using Jackett.Common.Services.Interfaces;
using NLog; using NLog;
using Jackett.Common.Helpers;
namespace Jackett.Common.Utils.Clients namespace Jackett.Common.Utils.Clients
{ {
@@ -277,7 +278,10 @@ namespace Jackett.Common.Utils.Clients
// See issue #1200 // See issue #1200
if (result.RedirectingTo != null && result.RedirectingTo.StartsWith("file://")) if (result.RedirectingTo != null && result.RedirectingTo.StartsWith("file://"))
{ {
var newRedirectingTo = result.RedirectingTo.Replace("file://", request.RequestUri.Scheme + "://" + request.RequestUri.Host); // URL decoding apparently is needed to, without it e.g. Demonoid download is broken
// TODO: is it always needed (not just for relative redirects)?
var newRedirectingTo = WebUtilityHelpers.UrlDecode(result.RedirectingTo, webRequest.Encoding);
newRedirectingTo = newRedirectingTo.Replace("file://", request.RequestUri.Scheme + "://" + request.RequestUri.Host);
logger.Debug("[MONO relative redirect bug] Rewriting relative redirect URL from " + result.RedirectingTo + " to " + newRedirectingTo); logger.Debug("[MONO relative redirect bug] Rewriting relative redirect URL from " + result.RedirectingTo + " to " + newRedirectingTo);
result.RedirectingTo = newRedirectingTo; result.RedirectingTo = newRedirectingTo;
} }

View File

@@ -1,4 +1,6 @@
using System; using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection; using System.Reflection;
namespace Jackett.Common.Utils namespace Jackett.Common.Utils
@@ -22,6 +24,33 @@ namespace Jackett.Common.Utils
} }
} }
public static bool IsRunningLegacyOwin
{
get
{
bool runningOwin;
try
{
var currentAssembly = Assembly.GetExecutingAssembly();
bool aspNetCorePresent = new StackTrace().GetFrames()
.Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
.Where(x => x.GetReferencedAssemblies().Any(y => y.FullName == currentAssembly.FullName))
.Where(x => x.ManifestModule.Name == "JackettConsole.exe").Select(x => x.CustomAttributes)
.FirstOrDefault()
.Where(x => x.AttributeType.Assembly.FullName.StartsWith("Microsoft.AspNetCore", StringComparison.OrdinalIgnoreCase))
.Any();
runningOwin = !aspNetCorePresent;
}
catch
{
runningOwin = true;
}
return runningOwin;
}
}
} }
} }

View File

@@ -118,4 +118,4 @@ namespace Jackett.Common.Utils
return "tt" + ((int)imdbid).ToString("D7"); return "tt" + ((int)imdbid).ToString("D7");
} }
} }
} }

View File

@@ -15,7 +15,7 @@
<EmbeddedResource Include="Util\Invalid-RSS.xml" /> <EmbeddedResource Include="Util\Invalid-RSS.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Autofac" Version="4.6.2" /> <PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="FluentAssertions" Version="5.2.0" /> <PackageReference Include="FluentAssertions" Version="5.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0" /> <PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />

View File

@@ -206,6 +206,7 @@ namespace Jackett.Updater
"Definitions/rockhardlossless.yml", "Definitions/rockhardlossless.yml",
"Definitions/oxtorrent.yml", "Definitions/oxtorrent.yml",
"Definitions/tehconnection.yml", "Definitions/tehconnection.yml",
"Definitions/torrentwtf.yml",
}; };
foreach (var oldFIle in oldFiles) foreach (var oldFIle in oldFiles)

View File

@@ -71,9 +71,19 @@ namespace Jackett.Controllers
} }
// This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr. // This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr.
var parser = new BencodeParser(); byte[] sortedDownloadBytes = null;
var torrentDictionary = parser.Parse(downloadBytes); try
byte[] sortedDownloadBytes = torrentDictionary.EncodeAsBytes(); {
var parser = new BencodeParser();
var torrentDictionary = parser.Parse(downloadBytes);
sortedDownloadBytes = torrentDictionary.EncodeAsBytes();
}
catch (Exception e)
{
var content = indexer.Encoding.GetString(downloadBytes);
logger.Error(content);
throw new Exception("BencodeParser failed", e);
}
var result = new HttpResponseMessage(HttpStatusCode.OK); var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(sortedDownloadBytes); result.Content = new ByteArrayContent(sortedDownloadBytes);

View File

@@ -467,8 +467,13 @@ namespace Jackett.Controllers
var link = result.Link; var link = result.Link;
var file = StringUtil.MakeValidFileName(result.Title, '_', false); var file = StringUtil.MakeValidFileName(result.Title, '_', false);
result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file); result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file);
if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir)) if (!string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir))
result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file); {
if (result.Link != null)
result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file);
else if (result.MagnetUri != null)
result.BlackholeLink = serverService.ConvertToProxyLink(result.MagnetUri, serverUrl, result.TrackerId, "bh", file);
}
} }
} }

View File

@@ -57,6 +57,16 @@ namespace Jackett.Services
} }
} }
public string LegacyProtect(string plainText)
{
return Protect(plainText);
}
public string LegacyUnProtect(string plainText)
{
return UnProtect(plainText);
}
private string ProtectDefaultMethod(string plainText) private string ProtectDefaultMethod(string plainText)
{ {
if (string.IsNullOrEmpty(plainText)) if (string.IsNullOrEmpty(plainText))

View File

@@ -61,7 +61,7 @@ namespace Jackett.Services
public Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t") public Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t")
{ {
if (link == null || (link.IsAbsoluteUri && link.Scheme == "magnet")) if (link == null || (link.IsAbsoluteUri && link.Scheme == "magnet" && action != "bh")) // no need to convert a magnet link to a proxy link unless it's a blackhole link
return link; return link;
var encryptedLink = _protectionService.Protect(link.ToString()); var encryptedLink = _protectionService.Protect(link.ToString());
@@ -153,6 +153,13 @@ namespace Jackett.Services
logger.Error(notice); logger.Error(notice);
} }
if (monoVersionO.Major < 5 || (monoVersionO.Major == 5 && monoVersionO.Minor < 8))
{
string notice = "A minimum Mono version of 5.8 is required. Please update to the latest version from http://www.mono-project.com/download/";
_notices.Add(notice);
logger.Error(notice);
}
try try
{ {
// Check for mono-devel // Check for mono-devel