[Bit-Titan] C# Implementation (#12329) resolves #10281

This commit is contained in:
montana123
2021-09-24 21:59:58 +02:00
committed by GitHub
parent 2a48c53510
commit 8b6fb88033
3 changed files with 235 additions and 241 deletions

View File

@@ -1,241 +0,0 @@
---
id: bit-titan
name: BiT-TiTAN
description: "BiT-TiTAN is a GERMAN Private Torrent Tracker for MOVIES / TV / GENERAL"
language: de-DE
type: private
encoding: iso-8859-1
links:
- https://bit-titan.net/
caps:
categorymappings:
- {id: 1010, cat: Movies/UHD, desc: "Movies 2160p"}
- {id: 1020, cat: Movies/HD, desc: "Movies 1080p"}
- {id: 1030, cat: Movies/HD, desc: "Movies 720p"}
- {id: 1040, cat: Movies/HD, desc: "Movies x264"}
- {id: 1050, cat: Movies/HD, desc: "Movies x265"}
- {id: 1060, cat: Movies/SD, desc: "Movies XviD"}
- {id: 1070, cat: Movies/3D, desc: "Movies 3D"}
- {id: 1080, cat: Movies/DVD, desc: "Movies DVD"}
- {id: 1090, cat: Movies/BluRay, desc: "Movies BluRay"}
- {id: 1100, cat: Movies/DVD, desc: "Movies HD2DVD"}
- {id: 1110, cat: Movies/Foreign, desc: "Movies International"}
- {id: 1120, cat: Movies/HD, desc: "Movies HD Packs"}
- {id: 1130, cat: Movies/SD, desc: "Movies SD Packs"}
- {id: 2010, cat: TV/UHD, desc: "TV 2160p"}
- {id: 2020, cat: TV/HD, desc: "TV 1080p"}
- {id: 2030, cat: TV/HD, desc: "TV 720p"}
- {id: 2040, cat: TV/HD, desc: "TV x264"}
- {id: 2050, cat: TV/HD, desc: "TV x265"}
- {id: 2060, cat: TV/SD, desc: "TV XviD"}
- {id: 2070, cat: TV/HD, desc: "TV HD Packs"}
- {id: 2080, cat: TV/SD, desc: "TV SD Packs"}
- {id: 2090, cat: TV/Foreign, desc: "TV International"}
- {id: 3010, cat: TV/Documentary, desc: "Docu 2160p"}
- {id: 3020, cat: TV/Documentary, desc: "Docu 1080p"}
- {id: 3030, cat: TV/Documentary, desc: "Docu 720p"}
- {id: 3040, cat: TV/Documentary, desc: "Docu x264"}
- {id: 3050, cat: TV/Documentary, desc: "Docu x265"}
- {id: 3060, cat: TV/Documentary, desc: "Docu XviD"}
- {id: 3070, cat: TV/Documentary, desc: "Docu HD Packs"}
- {id: 3080, cat: TV/Documentary, desc: "Docu SD Packs"}
- {id: 3090, cat: TV/Documentary, desc: "Docu International"}
- {id: 4010, cat: TV/Sport, desc: "Sport 2160p"}
- {id: 4020, cat: TV/Sport, desc: "Sport 1080p"}
- {id: 4030, cat: TV/Sport, desc: "Sport 720p"}
- {id: 4040, cat: TV/Sport, desc: "Sport SD Sport"}
- {id: 4050, cat: TV/Sport, desc: "Sport HD Packs"}
- {id: 4060, cat: TV/Sport, desc: "Sport SD Packs"}
- {id: 5010, cat: XXX, desc: "XXX 2160p"}
- {id: 5020, cat: XXX, desc: "XXX 1080p"}
- {id: 5030, cat: XXX, desc: "XXX 720p"}
- {id: 5040, cat: XXX, desc: "XXX x264"}
- {id: 5050, cat: XXX, desc: "XXX x265"}
- {id: 5060, cat: XXX, desc: "XXX XviD"}
- {id: 5070, cat: XXX, desc: "XXX HD Packs"}
- {id: 5080, cat: XXX, desc: "XXX SD Packs"}
- {id: 5090, cat: XXX, desc: "XXX Sonstiges"}
- {id: 6010, cat: PC/Games, desc: "Games Windows"}
- {id: 6020, cat: Console, desc: "Games Linux"}
- {id: 6030, cat: PC/Mac, desc: "Games MacOS"}
- {id: 6040, cat: PC/Mobile-Android, desc: "Games Android"}
- {id: 6050, cat: Console/XBox, desc: "Games Xbox"}
- {id: 6060, cat: Console/PSP, desc: "Games PlayStation"}
- {id: 6070, cat: Console/NDS, desc: "Games Nintendo"}
- {id: 6080, cat: Console, desc: "Games Sonstige"}
- {id: 7010, cat: PC/0day, desc: "Software Windows"}
- {id: 7020, cat: PC, desc: "Software Linux"}
- {id: 7030, cat: PC/Mac, desc: "Software MacOS"}
- {id: 7040, cat: PC/Mobile-Android, desc: "Software Android"}
- {id: 8010, cat: Audio/MP3, desc: "Music MP3-Album"}
- {id: 8020, cat: Audio/MP3, desc: "Music MP3-Charts"}
- {id: 8030, cat: Audio/MP3, desc: "Music MP3-Sampler"}
- {id: 8040, cat: Audio/MP3, desc: "Music MP3-Single"}
- {id: 8050, cat: Audio/Lossless, desc: "Music FLAC-Album"}
- {id: 8060, cat: Audio/Lossless, desc: "Music FLAC-Charts"}
- {id: 8070, cat: Audio/Lossless, desc: "Music FLAC-Sampler"}
- {id: 8080, cat: Audio/Lossless, desc: "Music FLAC-Single"}
- {id: 8090, cat: Audio/Video, desc: "Music Video"}
- {id: 9010, cat: Audio/Audiobook, desc: "Books A-Book"}
- {id: 9020, cat: Books/EBook, desc: "Books E-Book"}
- {id: 9030, cat: Books, desc: "Books E-Paper"}
- {id: 9040, cat: Books, desc: "Books E-Learning"}
- {id: 9060, cat: TV/Anime, desc: "Anime HD"}
- {id: 9070, cat: TV/Anime, desc: "Anime SD"}
- {id: 9080, cat: TV/Anime, desc: "Anime Pack"}
- {id: 9999, cat: Other, desc: "unsort"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
music-search: [q]
book-search: [q]
settings:
- name: username
type: text
label: Username
- name: password
type: password
label: Password
- name: freeleech
type: checkbox
label: Search freeleech only
default: false
- name: sort
type: select
label: Sort requested from site
default: 1
options:
1: created
2: seeders
5: size
9: title
- name: type
type: select
label: Order requested from site
default: 1
options:
1: desc
2: asc
login:
path: login.php
method: form
form: form[action$="login.php"]
cookies: ["JAVA=OK"] # avoid jscheck redirect
captcha:
type: image
selector: img[src*="captcha_math.php"]
input: stringCaptcha
inputs:
username: "{{ .Config.username }}"
password: "{{ .Config.password }}"
error:
- selector: div#login_error
test:
path: index.php
# selector: a[href="logout.php"] # ajax does not return a full page so cant test this.
search:
paths:
- path: ajax_browse.php
method: post
inputs:
# allCats=1000&categories[]=1010&categories[]=1020&search=&limit=1&searchIn=0&orderBy=1&order=1
$raw: "{{ if .Categories }}{{ range .Categories }}categories[]={{.}}&{{end}}{{ else }}{{ end }}"
# cat: (empty) all, 1000 film, 2000 tv, 3000 docs, 4000 sport, 5000 xxx, 6000 games, 7000 apps, 8000 music, 9000 other
allCats: ""
search: "{{ .Keywords }}"
# 1 25, 2 50, 3 75, 4 100
limit: 4
# searchin: 0 all, 1 active, 2 dead, 3 highlights, 4 bookmarks, 5 uploads, 10 bots, 11 onlyupload, 12 multiplier, 13 %download, 14 freeleech
# note: freeleech on this site means download and upload is not counted, whereas OU means download is free and upload is counted
# 14 yields no freeleech, but 11 returns results
searchin: "{{ if .Config.freeleech }}11{{ else }}0{{ end }}"
orderBy: "{{ .Config.sort }}"
order: "{{ .Config.type }}"
headers:
x-requested-with: ["XMLHttpRequest"]
rows:
selector: table.tableinborder tr:has(.catPic)
fields:
category:
selector: td.catPic > img
attribute: src
filters:
- name: regexp
args: (\d+).png$
title:
selector: a[href^="details.php?id="]
details:
selector: a[href^="details.php?id="]
attribute: href
download:
# a[onlick="downloadTorrent(383718);"] --> a[href="download.php?torrent=383559"]
selector: td.tdl > a
attribute: onclick
filters:
- name: regexp
args: (\d+)
- name: prepend
args: "download.php?torrent="
poster:
selector: div[data-image]
attribute: data-image
seeders:
selector: td.peers:has(i[title="Seeders"])
leechers:
selector: td.peers:has(i[title="Leechers"])
grabs:
selector: td.peers:has(i[title="Snatchers"])
# 2 flavours of dates
date:
#  Heute 13:30:04
#  Gestern 22:44:23
selector: td.added:not(:contains("."))
optional: true
filters:
- name: replace
args: ["\u00a0", ""]
- name: replace
args: ["Heute", "Today"]
- name: replace
args: ["Gestern", "Yesterday"]
- name: append
args: " +01:00" # CET
- name: fuzzytime
date:
#  24.05.2019 20:15:38
selector: td.added:contains(".")
optional: true
filters:
- name: append
args: " +01:00" # CET
- name: dateparse
args: "02.01.2006 15:04:05 -07:00"
size:
selector: td.size
downloadvolumefactor:
case:
"span:contains(\"OU\")": 0 # only upload is counted
"span:contains(\"FL\")": 0 # freeleech neither dl or ul is counted (identity unconfirmed)
"span:contains(\"%25\")": .25 # 75% free
"span:contains(\"%50\")": .5 # 50% free
"span:contains(\"%75\")": .75 # 25% free
"*": 1
uploadvolumefactor:
case:
"span:contains(\"x2\")": 2
"span:contains(\"x5\")": 5
"span:contains(\"x10\")": 10
"span:contains(\"FL\")": 0 # freeleech neither dl or ul is counted
"*": 1
minimumseedtime:
# 2 day (as seconds = 2 x 24 x 60 x 60)
text: 172800
# engine n/a

View File

@@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig;
using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils;
using Jackett.Common.Utils.Clients;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using static Jackett.Common.Models.IndexerConfig.ConfigurationData;
namespace Jackett.Common.Indexers
{
[ExcludeFromCodeCoverage]
public class BitTitan : BaseWebIndexer
{
private string APIBASE => SiteLink + "api.php";
private string DETAILS => SiteLink + "details.php";
private new ConfigurationDataAPIKey configData => (ConfigurationDataAPIKey)base.configData;
public BitTitan(IIndexerConfigurationService configService, WebClient wc, Logger l,
IProtectionService ps, ICacheService cs)
: base(id: "bit-titan",
name: "BiT-TiTAN",
description: "BiT-TiTAN is a GERMAN Private Torrent Tracker for MOVIES / TV / GENERAL",
link: "https://bit-titan.net/",
caps: new TorznabCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
},
configService: configService,
client: wc,
logger: l,
p: ps,
cacheService: cs,
configData: new ConfigurationDataAPIKey())
{
Encoding = Encoding.UTF8;
Language = "de-DE";
Type = "private";
configData.AddDynamic("keyInfo", new DisplayInfoConfigurationItem(String.Empty, "Find or Generate a new key <a href=\"https://bit-titan.net/api_cp.php\" target =_blank>here</a>."));
configData.AddDynamic("freeleech", new BoolConfigurationItem("Search freeleech only") { Value = false });
// Configure the category mappings
AddCategoryMapping(1010, TorznabCatType.MoviesUHD, "Movies 2160p");
AddCategoryMapping(1020, TorznabCatType.MoviesHD, "Movies 1080p");
AddCategoryMapping(1030, TorznabCatType.MoviesHD, "Movies 720p");
AddCategoryMapping(1040, TorznabCatType.MoviesHD, "Movies x264");
AddCategoryMapping(1050, TorznabCatType.MoviesHD, "Movies x265");
AddCategoryMapping(1060, TorznabCatType.MoviesSD, "Movies XviD");
AddCategoryMapping(1070, TorznabCatType.Movies3D, "Movies 3D");
AddCategoryMapping(1080, TorznabCatType.MoviesDVD, "Movies DVD");
AddCategoryMapping(1090, TorznabCatType.MoviesBluRay, "Movies BluRay");
AddCategoryMapping(1100, TorznabCatType.MoviesDVD, "Movies HD2DVD");
AddCategoryMapping(1110, TorznabCatType.MoviesForeign, "Movies International");
AddCategoryMapping(1120, TorznabCatType.MoviesHD, "Movies HD Packs");
AddCategoryMapping(1130, TorznabCatType.MoviesSD, "Movies SD Packs");
AddCategoryMapping(2010, TorznabCatType.TVUHD, "TV 2160p");
AddCategoryMapping(2020, TorznabCatType.TVHD, "TV 1080p");
AddCategoryMapping(2030, TorznabCatType.TVHD, "TV 720p");
AddCategoryMapping(2040, TorznabCatType.TVHD, "TV x264");
AddCategoryMapping(2050, TorznabCatType.TVHD, "TV x265");
AddCategoryMapping(2060, TorznabCatType.TVSD, "TV XviD");
AddCategoryMapping(2070, TorznabCatType.TVHD, "TV HD Packs");
AddCategoryMapping(2080, TorznabCatType.TVSD, "TV SD Packs");
AddCategoryMapping(2090, TorznabCatType.TVForeign, "TV International");
AddCategoryMapping(3010, TorznabCatType.TVDocumentary, "Docu 2160p");
AddCategoryMapping(3020, TorznabCatType.TVDocumentary, "Docu 1080p");
AddCategoryMapping(3030, TorznabCatType.TVDocumentary, "Docu 720p");
AddCategoryMapping(3040, TorznabCatType.TVDocumentary, "Docu x264");
AddCategoryMapping(3050, TorznabCatType.TVDocumentary, "Docu x265");
AddCategoryMapping(3060, TorznabCatType.TVDocumentary, "Docu XviD");
AddCategoryMapping(3070, TorznabCatType.TVDocumentary, "Docu HD Packs");
AddCategoryMapping(3080, TorznabCatType.TVDocumentary, "Docu SD Packs");
AddCategoryMapping(3090, TorznabCatType.TVDocumentary, "Docu International");
AddCategoryMapping(4010, TorznabCatType.TVSport, "Sport 2160p");
AddCategoryMapping(4020, TorznabCatType.TVSport, "Sport 1080p");
AddCategoryMapping(4030, TorznabCatType.TVSport, "Sport 720p");
AddCategoryMapping(4040, TorznabCatType.TVSport, "Sport SD Sport");
AddCategoryMapping(4050, TorznabCatType.TVSport, "Sport HD Packs");
AddCategoryMapping(4060, TorznabCatType.TVSport, "Sport SD Packs");
AddCategoryMapping(5010, TorznabCatType.XXX, "XXX 2160p");
AddCategoryMapping(5020, TorznabCatType.XXX, "XXX 1080p");
AddCategoryMapping(5030, TorznabCatType.XXX, "XXX 720p");
AddCategoryMapping(5040, TorznabCatType.XXX, "XXX x264");
AddCategoryMapping(5050, TorznabCatType.XXX, "XXX x265");
AddCategoryMapping(5060, TorznabCatType.XXX, "XXX XviD");
AddCategoryMapping(5070, TorznabCatType.XXX, "XXX HD Packs");
AddCategoryMapping(5080, TorznabCatType.XXX, "XXX SD Packs");
AddCategoryMapping(5090, TorznabCatType.XXX, "XXX Sonstiges");
AddCategoryMapping(6010, TorznabCatType.PCGames, "Games Windows");
AddCategoryMapping(6020, TorznabCatType.Console, "Games Linux");
AddCategoryMapping(6030, TorznabCatType.PCMac, "Games MacOS");
AddCategoryMapping(6040, TorznabCatType.PCMobileAndroid, "Games Android");
AddCategoryMapping(6050, TorznabCatType.ConsoleXBox, "Games Xbox");
AddCategoryMapping(6060, TorznabCatType.ConsolePSP, "Games PlayStation");
AddCategoryMapping(6070, TorznabCatType.ConsoleNDS, "Games Nintendo");
AddCategoryMapping(6080, TorznabCatType.Console, "Games Sonstige");
AddCategoryMapping(7010, TorznabCatType.PC0day, "Software Windows");
AddCategoryMapping(7020, TorznabCatType.PC, "Software Linux");
AddCategoryMapping(7030, TorznabCatType.PCMac, "Software MacOS");
AddCategoryMapping(7040, TorznabCatType.PCMobileAndroid, "Software Android");
AddCategoryMapping(8010, TorznabCatType.AudioMP3, "Music MP3-Album");
AddCategoryMapping(8020, TorznabCatType.AudioMP3, "Music MP3-Charts");
AddCategoryMapping(8030, TorznabCatType.AudioMP3, "Music MP3-Sampler");
AddCategoryMapping(8040, TorznabCatType.AudioMP3, "Music MP3-Single");
AddCategoryMapping(8050, TorznabCatType.AudioLossless, "Music FLAC-Album");
AddCategoryMapping(8060, TorznabCatType.AudioLossless, "Music FLAC-Charts");
AddCategoryMapping(8070, TorznabCatType.AudioLossless, "Music FLAC-Sampler");
AddCategoryMapping(8080, TorznabCatType.AudioLossless, "Music FLAC-Single");
AddCategoryMapping(8090, TorznabCatType.AudioVideo, "Music Video");
AddCategoryMapping(9010, TorznabCatType.AudioAudiobook, "Books A-Book");
AddCategoryMapping(9020, TorznabCatType.BooksEBook, "Books E-Book");
AddCategoryMapping(9030, TorznabCatType.Books, "Books E-Paper");
AddCategoryMapping(9040, TorznabCatType.Books, "Books E-Learning");
AddCategoryMapping(9060, TorznabCatType.TVAnime, "Anime HD");
AddCategoryMapping(9070, TorznabCatType.TVAnime, "Anime SD");
AddCategoryMapping(9080, TorznabCatType.TVAnime, "Anime Pack");
AddCategoryMapping(9999, TorznabCatType.Other, "unsort");
}
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
LoadValuesFromJson(configJson);
IsConfigured = false;
try
{
var results = await PerformQuery(new TorznabQuery());
if (results.Count() == 0)
throw new Exception("Testing returned no results!");
IsConfigured = true;
SaveConfig();
}
catch (Exception e)
{
throw new ExceptionWithConfigData(e.Message, configData);
}
return IndexerConfigurationStatus.Completed;
}
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var apiKey = configData.Key.Value;
var searchUrl = $"{APIBASE}?apiKey={apiKey}";
var cats = MapTorznabCapsToTrackers(query);
if (cats.Count > 0)
searchUrl += "&categories=" + string.Join(",", cats);
searchUrl += "&search=" + query.SanitizedSearchTerm;
searchUrl += "&downloadLink=1";
searchUrl += "&limit=4";
if (((BoolConfigurationItem)configData.GetDynamic("freeleech")).Value)
searchUrl += "&searchIn=9";
var results = await RequestWithCookiesAndRetryAsync(searchUrl);
try
{
var rows = (JArray)((JObject)JsonConvert.DeserializeObject(results.ContentString))["results"];
foreach (var row in rows)
{
var title = row["name"].ToString();
if (!query.MatchQueryStringAND(title))
continue;
var torrentId = row["id"].ToString();
var details = new Uri(DETAILS + "?id=" + torrentId);
var link = new Uri(row["download"].ToString());
var publishDate = DateTime.Parse(row["added"].ToString());
var seeders = (int)row["seeds"];
var cat = MapTrackerCatToNewznab(row["category"].ToString());
var release = new ReleaseInfo
{
Title = title,
Details = details,
Guid = details,
Link = link,
PublishDate = publishDate,
Category = cat,
Size = (long)row["size"],
Grabs = (int)row["snatchers"],
Seeders = seeders,
Peers = seeders + (int)row["leechers"],
Imdb = null,
UploadVolumeFactor = (int)row["uploadFactor"],
DownloadVolumeFactor = (int)row["downloadFactor"],
MinimumRatio = 1,
MinimumSeedTime = 172800 // 2 days
};
releases.Add(release);
}
}
catch (Exception ex)
{
OnParseError(results.ContentString, ex);
}
return releases;
}
}
}

View File

@@ -275,6 +275,7 @@ namespace Jackett.Updater
"Definitions/bithq.yml",
"Definitions/bigtower.yml",
"Definitions/bitme.yml",
"Definitions/bit-titan.yml", // migrated to C# #10281
"Definitions/bittorrentam.yml",
"Definitions/blubits.yml",
"Definitions/brobits.yml",