2020-02-09 02:35:16 +00:00
using System ;
2016-09-22 10:27:35 +00:00
using System.Collections.Generic ;
2017-04-15 08:45:10 +00:00
using System.Collections.Specialized ;
2017-10-29 06:50:47 +00:00
using System.Globalization ;
2017-04-15 08:45:10 +00:00
using System.Linq ;
2017-10-29 06:50:47 +00:00
using System.Text ;
2017-04-15 08:45:10 +00:00
using System.Text.RegularExpressions ;
2017-10-29 06:50:47 +00:00
using System.Threading.Tasks ;
using CsQuery ;
2018-03-10 08:05:56 +00:00
using Jackett.Common.Models ;
using Jackett.Common.Models.IndexerConfig ;
using Jackett.Common.Services.Interfaces ;
using Jackett.Common.Utils ;
using Jackett.Common.Utils.Clients ;
2017-10-29 06:50:47 +00:00
using Newtonsoft.Json.Linq ;
using NLog ;
2017-04-15 08:45:10 +00:00
2018-03-10 08:05:56 +00:00
namespace Jackett.Common.Indexers
2016-09-22 10:27:35 +00:00
{
2017-07-10 20:58:44 +00:00
public class TorrentHeaven : BaseWebIndexer
2016-09-22 10:27:35 +00:00
{
2020-02-09 02:35:16 +00:00
public override string [ ] LegacySiteLinks { get ; protected set ; } = new string [ ] {
"https://torrentheaven.myfqdn.info/" ,
} ;
2019-04-13 13:52:00 +00:00
2017-10-29 06:50:47 +00:00
private string IndexUrl { get { return SiteLink + "index.php" ; } }
private string LoginCompleteUrl { get { return SiteLink + "index.php?strWebValue=account&strWebAction=login_complete&ancestry=verify" ; } }
2016-09-22 10:27:35 +00:00
2017-10-29 06:50:47 +00:00
private new ConfigurationDataCaptchaLogin configData
2016-09-22 10:27:35 +00:00
{
get { return ( ConfigurationDataCaptchaLogin ) base . configData ; }
set { base . configData = value ; }
}
2017-11-05 09:42:03 +00:00
public TorrentHeaven ( IIndexerConfigurationService configService , WebClient wc , Logger l , IProtectionService ps )
2016-09-22 10:27:35 +00:00
: base ( name : "TorrentHeaven" ,
description : "A German general tracker." ,
2018-09-29 09:22:37 +00:00
link : "https://newheaven.nl/" ,
2016-09-22 10:27:35 +00:00
caps : TorznabUtil . CreateDefaultTorznabTVCaps ( ) ,
2017-07-10 20:58:44 +00:00
configService : configService ,
2016-09-22 10:27:35 +00:00
client : wc ,
logger : l ,
p : ps ,
configData : new ConfigurationDataCaptchaLogin ( ) )
2017-04-15 08:45:10 +00:00
{
2016-12-06 13:56:47 +00:00
Encoding = Encoding . GetEncoding ( "iso-8859-1" ) ;
2016-12-09 17:20:58 +00:00
Language = "de-de" ;
2017-01-27 15:57:32 +00:00
Type = "private" ;
2016-12-06 13:56:47 +00:00
2019-04-13 13:52:00 +00:00
wc . AddTrustedCertificate ( new Uri ( SiteLink ) . Host , "cbf23ac75b07255ad7548a87567a839d23f31576" ) ; // incomplete CA chain
2018-03-05 12:34:55 +00:00
AddCategoryMapping ( 1 , TorznabCatType . PCGames , "GAMES/PC" ) ;
AddCategoryMapping ( 3 , TorznabCatType . Console , "GAMES/Sonstige" ) ;
AddCategoryMapping ( 59 , TorznabCatType . ConsolePS4 , "GAMES/PlayStation" ) ;
AddCategoryMapping ( 60 , TorznabCatType . ConsolePSP , "GAMES/PSP" ) ;
AddCategoryMapping ( 63 , TorznabCatType . ConsoleWii , "GAMES/Wii" ) ;
AddCategoryMapping ( 67 , TorznabCatType . ConsoleXbox360 , "GAMES/XBOX 360" ) ;
AddCategoryMapping ( 68 , TorznabCatType . PCPhoneOther , "GAMES/PDA / Handy" ) ;
AddCategoryMapping ( 72 , TorznabCatType . ConsoleNDS , "GAMES/NDS" ) ;
2017-07-10 20:58:44 +00:00
2018-03-05 12:34:55 +00:00
AddCategoryMapping ( 7 , TorznabCatType . MoviesDVD , "MOVIES/DVD" ) ;
AddCategoryMapping ( 8 , TorznabCatType . MoviesSD , "MOVIES/SD" ) ;
AddCategoryMapping ( 37 , TorznabCatType . MoviesDVD , "MOVIES/DVD Spezial" ) ;
AddCategoryMapping ( 41 , TorznabCatType . MoviesForeign , "MOVIES/International" ) ;
AddCategoryMapping ( 101 , TorznabCatType . MoviesHD , "MOVIES/720p" ) ;
AddCategoryMapping ( 102 , TorznabCatType . MoviesHD , "MOVIES/1080p" ) ;
AddCategoryMapping ( 103 , TorznabCatType . MoviesHD , "MOVIES/AVCHD" ) ;
AddCategoryMapping ( 104 , TorznabCatType . MoviesBluRay , "MOVIES/Bluray" ) ;
AddCategoryMapping ( 106 , TorznabCatType . Movies3D , "MOVIES/3D" ) ;
AddCategoryMapping ( 109 , TorznabCatType . MoviesUHD , "MOVIES/4K" ) ;
2017-04-15 08:45:10 +00:00
2018-03-05 12:34:55 +00:00
AddCategoryMapping ( 14 , TorznabCatType . Audio , "AUDIO/Musik" ) ;
AddCategoryMapping ( 15 , TorznabCatType . AudioAudiobook , "AUDIO/Hörbücher" ) ;
AddCategoryMapping ( 16 , TorznabCatType . AudioAudiobook , "AUDIO/Hörspiele" ) ;
AddCategoryMapping ( 36 , TorznabCatType . AudioLossless , "AUDIO/Flac" ) ;
AddCategoryMapping ( 42 , TorznabCatType . AudioOther , "AUDIO/Soundtracks" ) ;
AddCategoryMapping ( 58 , TorznabCatType . AudioVideo , "AUDIO/Musikvideos" ) ;
2017-07-10 20:58:44 +00:00
2018-03-05 12:34:55 +00:00
AddCategoryMapping ( 18 , TorznabCatType . TVSD , "TV/Serien SD" ) ;
AddCategoryMapping ( 19 , TorznabCatType . TVHD , "TV/Serien HD 720p" ) ;
AddCategoryMapping ( 20 , TorznabCatType . TVHD , "TV/Serien HD 1080p" ) ;
AddCategoryMapping ( 49 , TorznabCatType . TVSD , "TV/Serien DVD" ) ;
AddCategoryMapping ( 51 , TorznabCatType . TVDocumentary , "TV/Doku SD" ) ;
AddCategoryMapping ( 52 , TorznabCatType . TVDocumentary , "TV/Doku HD" ) ;
AddCategoryMapping ( 53 , TorznabCatType . TV , "TV/Serien Complete Packs" ) ;
AddCategoryMapping ( 54 , TorznabCatType . TVSport , "TV/Sport" ) ;
AddCategoryMapping ( 66 , TorznabCatType . TVFOREIGN , "TV/International" ) ;
2017-07-10 20:58:44 +00:00
2018-03-05 12:34:55 +00:00
AddCategoryMapping ( 22 , TorznabCatType . Books , "MISC/EBooks" ) ;
AddCategoryMapping ( 24 , TorznabCatType . Other , "MISC/Sonstiges" ) ;
AddCategoryMapping ( 25 , TorznabCatType . Other , "MISC/Tonspuren" ) ;
AddCategoryMapping ( 108 , TorznabCatType . TVAnime , "MISC/Anime" ) ;
2017-04-15 08:45:10 +00:00
2018-03-05 12:34:55 +00:00
AddCategoryMapping ( 28 , TorznabCatType . PC , "APPLICATIONS/PC" ) ;
AddCategoryMapping ( 29 , TorznabCatType . PCPhoneOther , "APPLICATIONS/Mobile" ) ;
AddCategoryMapping ( 30 , TorznabCatType . PC , "APPLICATIONS/Sonstige" ) ;
AddCategoryMapping ( 70 , TorznabCatType . PC , "APPLICATIONS/Linux" ) ;
AddCategoryMapping ( 71 , TorznabCatType . PCMac , "APPLICATIONS/Mac" ) ;
2017-02-28 19:05:57 +00:00
}
2016-09-22 10:27:35 +00:00
public override async Task < ConfigurationData > GetConfigurationForSetup ( )
2017-04-15 08:45:10 +00:00
{
var loginPage = await RequestStringWithCookies ( IndexUrl , string . Empty ) ;
CQ dom = loginPage . Content ;
CQ qCaptchaImg = dom . Find ( "td.tablea > img" ) . First ( ) ;
2017-07-10 20:58:44 +00:00
if ( qCaptchaImg . Length = = 1 )
{
2016-09-22 10:27:35 +00:00
var CaptchaUrl = SiteLink + qCaptchaImg . Attr ( "src" ) ;
var captchaImage = await RequestBytesWithCookies ( CaptchaUrl , loginPage . Cookies ) ;
2017-04-15 08:45:10 +00:00
configData . CaptchaImage . Value = captchaImage . Content ;
2016-09-22 10:27:35 +00:00
}
2017-04-15 08:45:10 +00:00
else
{
configData . CaptchaImage . Value = new byte [ 0 ] ;
2016-11-17 06:06:47 +00:00
}
2016-09-22 10:27:35 +00:00
configData . CaptchaCookie . Value = loginPage . Cookies ;
return configData ;
}
2017-06-28 05:31:38 +00:00
public override async Task < IndexerConfigurationStatus > ApplyConfiguration ( JToken configJson )
2016-09-22 10:27:35 +00:00
{
2017-01-02 20:39:28 +00:00
LoadValuesFromJson ( configJson ) ;
2017-07-10 20:58:44 +00:00
2016-09-22 10:27:35 +00:00
var pairs = new Dictionary < string , string >
{
{ "strWebAction" , "login" } ,
{ "strWebValue" , "account" } ,
{ "jsenabled" , "1" } ,
{ "screenwidth" , "2560" } ,
{ "username" , configData . Username . Value } ,
{ "password" , configData . Password . Value }
} ;
2017-04-15 08:45:10 +00:00
if ( ! string . IsNullOrWhiteSpace ( configData . CaptchaText . Value ) )
{
pairs . Add ( "proofcode" , configData . CaptchaText . Value ) ;
2016-09-22 10:27:35 +00:00
}
var result = await RequestLoginAndFollowRedirect ( IndexUrl , pairs , configData . CaptchaCookie . Value , true , null , IndexUrl , true ) ;
2017-04-15 08:45:10 +00:00
if ( result . Content = = null | | ( ! result . Content . Contains ( "login_complete" ) & & ! result . Content . Contains ( "index.php?strWebValue=account&strWebAction=logout" ) ) )
{
CQ dom = result . Content ;
var errorMessage = dom [ "table > tbody > tr > td[valign=top][width=100%]" ] . Html ( ) ;
2017-07-10 20:58:44 +00:00
if ( errorMessage . Length = = 0 )
2017-04-15 08:45:10 +00:00
errorMessage = result . Content ;
throw new ExceptionWithConfigData ( errorMessage , configData ) ;
2016-09-22 10:27:35 +00:00
}
var result2 = await RequestStringWithCookies ( LoginCompleteUrl , result . Cookies ) ;
await ConfigureIfOK ( result2 . Cookies , result2 . Cookies ! = null & & result2 . Cookies . Contains ( "pass" ) , ( ) = >
{
var errorMessage = "Didn't get a user/pass cookie" ;
throw new ExceptionWithConfigData ( errorMessage , configData ) ;
} ) ;
return IndexerConfigurationStatus . RequiresTesting ;
}
2017-07-03 05:15:47 +00:00
protected override async Task < IEnumerable < ReleaseInfo > > PerformQuery ( TorznabQuery query )
2016-09-22 10:27:35 +00:00
{
2017-04-15 08:45:10 +00:00
TimeZoneInfo . TransitionTime startTransition = TimeZoneInfo . TransitionTime . CreateFloatingDateRule ( new DateTime ( 1 , 1 , 1 , 3 , 0 , 0 ) , 3 , 5 , DayOfWeek . Sunday ) ;
TimeZoneInfo . TransitionTime endTransition = TimeZoneInfo . TransitionTime . CreateFloatingDateRule ( new DateTime ( 1 , 1 , 1 , 4 , 0 , 0 ) , 10 , 5 , DayOfWeek . Sunday ) ;
TimeSpan delta = new TimeSpan ( 1 , 0 , 0 ) ;
TimeZoneInfo . AdjustmentRule adjustment = TimeZoneInfo . AdjustmentRule . CreateAdjustmentRule ( new DateTime ( 1999 , 10 , 1 ) , DateTime . MaxValue . Date , delta , startTransition , endTransition ) ;
TimeZoneInfo . AdjustmentRule [ ] adjustments = { adjustment } ;
2016-09-22 10:27:35 +00:00
TimeZoneInfo germanyTz = TimeZoneInfo . CreateCustomTimeZone ( "W. Europe Standard Time" , new TimeSpan ( 1 , 0 , 0 ) , "(GMT+01:00) W. Europe Standard Time" , "W. Europe Standard Time" , "W. Europe DST Time" , adjustments ) ;
var releases = new List < ReleaseInfo > ( ) ;
2017-07-10 20:58:44 +00:00
2017-04-15 08:45:10 +00:00
var searchString = query . GetQueryString ( ) ;
var searchUrl = IndexUrl ;
var queryCollection = new NameValueCollection ( ) ;
queryCollection . Add ( "strWebValue" , "torrent" ) ;
queryCollection . Add ( "strWebAction" , "search" ) ;
queryCollection . Add ( "sort" , "torrent_added" ) ;
queryCollection . Add ( "by" , "d" ) ;
queryCollection . Add ( "type" , "0" ) ;
queryCollection . Add ( "do_search" , "suchen" ) ;
queryCollection . Add ( "time" , "0" ) ;
queryCollection . Add ( "details" , "title" ) ;
if ( ! string . IsNullOrWhiteSpace ( searchString ) )
{
queryCollection . Add ( "searchstring" , searchString ) ;
}
foreach ( var cat in MapTorznabCapsToTrackers ( query ) )
{
queryCollection . Add ( "dirs" + cat , "1" ) ;
}
2016-09-22 10:27:35 +00:00
searchUrl + = "?" + queryCollection . GetQueryString ( ) ;
2016-11-16 08:05:23 +00:00
2016-12-06 13:56:47 +00:00
var response = await RequestStringWithCookies ( searchUrl ) ;
var results = response . Content ;
2016-11-16 08:05:23 +00:00
var TitleRegexp = new Regex ( @"^return buildTable\('(.*?)',\s+" ) ;
2016-09-22 10:27:35 +00:00
try
{
CQ dom = results ;
var rows = dom [ "table.torrenttable > tbody > tr" ] ;
foreach ( var row in rows . Skip ( 1 ) )
{
var release = new ReleaseInfo ( ) ;
2017-04-15 08:45:10 +00:00
release . MinimumRatio = 0.8 ;
2016-09-22 10:27:35 +00:00
release . MinimumSeedTime = 0 ;
2017-04-15 08:45:10 +00:00
var qRow = row . Cq ( ) ;
var qDetailsLink = qRow . Find ( "a[href^=index.php?strWebValue=torrent&strWebAction=details]" ) . First ( ) ;
release . Title = TitleRegexp . Match ( qDetailsLink . Attr ( "onmouseover" ) ) . Groups [ 1 ] . Value ;
var qCatLink = qRow . Find ( "a[href^=index.php?strWebValue=torrent&strWebAction=search&dir=]" ) . First ( ) ;
var qDLLink = qRow . Find ( "a[href^=index.php?strWebValue=torrent&strWebAction=download&id=]" ) . First ( ) ;
var qSeeders = qRow . Find ( "td.column1:eq(3)" ) ;
var qLeechers = qRow . Find ( "td.column2:eq(3)" ) ;
var qDateStr = qRow . Find ( "font:has(a)" ) . First ( ) ;
var qSize = qRow . Find ( "td.column2[align=center]" ) . First ( ) ;
var catStr = qCatLink . Attr ( "href" ) . Split ( '=' ) [ 3 ] . Split ( '#' ) [ 0 ] ;
release . Category = MapTrackerCatToNewznab ( catStr ) ;
release . Link = new Uri ( SiteLink + qDLLink . Attr ( "href" ) ) ;
release . Comments = new Uri ( SiteLink + qDetailsLink . Attr ( "href" ) ) ;
release . Guid = release . Link ;
var sizeStr = qSize . Text ( ) ;
release . Size = ReleaseInfo . GetBytes ( sizeStr ) ;
release . Seeders = ParseUtil . CoerceInt ( qSeeders . Text ( ) ) ;
2016-09-22 10:27:35 +00:00
release . Peers = ParseUtil . CoerceInt ( qLeechers . Text ( ) ) + release . Seeders ;
var dateStr = qDateStr . Text ( ) . Trim ( ) ;
var dateStrParts = dateStr . Split ( ) ;
2017-04-15 08:45:10 +00:00
DateTime dateGerman ;
if ( dateStrParts [ 0 ] = = "Heute" )
dateGerman = DateTime . SpecifyKind ( DateTime . UtcNow . Date , DateTimeKind . Unspecified ) + TimeSpan . Parse ( dateStrParts [ 1 ] ) ;
else if ( dateStrParts [ 0 ] = = "Gestern" )
dateGerman = DateTime . SpecifyKind ( DateTime . UtcNow . Date , DateTimeKind . Unspecified ) + TimeSpan . Parse ( dateStrParts [ 1 ] ) - TimeSpan . FromDays ( 1 ) ;
else
2017-07-10 20:58:44 +00:00
dateGerman = DateTime . SpecifyKind ( DateTime . ParseExact ( dateStrParts [ 0 ] + dateStrParts [ 1 ] , "dd.MM.yyyyHH:mm" , CultureInfo . InvariantCulture ) , DateTimeKind . Unspecified ) ;
2017-04-15 08:45:10 +00:00
DateTime pubDateUtc = TimeZoneInfo . ConvertTimeToUtc ( dateGerman , germanyTz ) ;
2016-09-22 10:27:35 +00:00
release . PublishDate = pubDateUtc . ToLocalTime ( ) ;
2016-10-27 07:35:31 +00:00
var grabs = qRow . Find ( "td:nth-child(7)" ) . Text ( ) ;
2017-04-15 08:45:10 +00:00
release . Grabs = ParseUtil . CoerceInt ( grabs ) ;
if ( qRow . Find ( "img[src=\"themes/images/freeleech.png\"]" ) . Length > = 1 )
2016-10-27 07:35:31 +00:00
release . DownloadVolumeFactor = 0 ;
2017-04-15 08:45:10 +00:00
else if ( qRow . Find ( "img[src=\"themes/images/DL50.png\"]" ) . Length > = 1 )
release . DownloadVolumeFactor = 0.5 ;
2016-10-27 07:35:31 +00:00
else
2017-04-15 08:45:10 +00:00
release . DownloadVolumeFactor = 1 ;
2016-10-27 07:35:31 +00:00
release . UploadVolumeFactor = 1 ;
2016-09-22 10:27:35 +00:00
releases . Add ( release ) ;
}
}
catch ( Exception ex )
{
OnParseError ( results , ex ) ;
}
return releases ;
}
}
}