2017-10-29 06:50:47 +00:00
using System ;
2015-04-26 02:32:03 +00:00
using System.Collections.Generic ;
using System.Globalization ;
2018-04-17 11:55:18 +00:00
using System.Linq ;
2017-11-05 09:42:03 +00:00
using System.Net ;
2015-04-26 02:32:03 +00:00
using System.Text ;
2018-05-13 15:42:22 +00:00
using System.Text.RegularExpressions ;
2015-04-26 02:32:03 +00:00
using System.Threading.Tasks ;
2017-10-29 06:50:47 +00:00
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 ;
2018-04-09 09:36:20 +00:00
using Newtonsoft.Json ;
2017-10-29 06:50:47 +00:00
using Newtonsoft.Json.Linq ;
using NLog ;
2015-04-26 02:32:03 +00:00
2018-03-10 08:05:56 +00:00
namespace Jackett.Common.Indexers
2015-04-26 02:32:03 +00:00
{
2017-07-10 20:58:44 +00:00
public class TorrentLeech : BaseWebIndexer
2015-04-26 02:32:03 +00:00
{
2018-04-23 16:19:50 +00:00
public override string [ ] LegacySiteLinks { get ; protected set ; } = new string [ ] {
"https://v4.torrentleech.org/" ,
} ;
2015-07-27 00:03:51 +00:00
private string LoginUrl { get { return SiteLink + "user/account/login/" ; } }
2018-04-06 08:18:58 +00:00
private string SearchUrl { get { return SiteLink + "torrents/browse/list/" ; } }
2015-04-26 02:32:03 +00:00
2018-04-17 11:55:18 +00:00
private new ConfigurationDataRecaptchaLogin configData
2015-08-03 21:38:45 +00:00
{
2018-04-17 11:55:18 +00:00
get { return ( ConfigurationDataRecaptchaLogin ) base . configData ; }
2015-08-03 21:38:45 +00:00
set { base . configData = value ; }
}
2017-11-05 09:42:03 +00:00
public TorrentLeech ( IIndexerConfigurationService configService , Utils . Clients . WebClient wc , Logger l , IProtectionService ps )
2015-07-19 23:05:30 +00:00
: base ( name : "TorrentLeech" ,
description : "This is what happens when you seed" ,
2015-10-07 23:17:54 +00:00
link : "https://www.torrentleech.org/" ,
2015-08-11 18:48:25 +00:00
caps : TorznabUtil . CreateDefaultTorznabTVCaps ( ) ,
2017-07-10 20:58:44 +00:00
configService : configService ,
2015-07-27 00:03:51 +00:00
client : wc ,
2015-08-03 21:38:45 +00:00
logger : l ,
2015-08-07 19:09:13 +00:00
p : ps ,
2015-10-07 23:17:54 +00:00
downloadBase : "https://www.torrentleech.org/download/" ,
2018-04-17 11:55:18 +00:00
configData : new ConfigurationDataRecaptchaLogin ( "For best results, change the 'Default Number of Torrents per Page' setting to the maximum in your profile on the TorrentLeech webpage." ) )
2015-04-26 02:32:03 +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 = "en-us" ;
2017-01-27 15:57:32 +00:00
Type = "private" ;
2015-08-13 21:51:49 +00:00
AddCategoryMapping ( 8 , TorznabCatType . MoviesSD ) ; // cam
AddCategoryMapping ( 9 , TorznabCatType . MoviesSD ) ; //ts
AddCategoryMapping ( 10 , TorznabCatType . MoviesSD ) ; // Sceener
AddCategoryMapping ( 11 , TorznabCatType . MoviesSD ) ;
AddCategoryMapping ( 12 , TorznabCatType . MoviesSD ) ;
AddCategoryMapping ( 13 , TorznabCatType . MoviesHD ) ;
AddCategoryMapping ( 14 , TorznabCatType . MoviesHD ) ;
AddCategoryMapping ( 15 , TorznabCatType . Movies ) ; // Boxsets
AddCategoryMapping ( 29 , TorznabCatType . TVDocumentary ) ;
2017-09-29 15:21:32 +00:00
AddCategoryMapping ( 41 , TorznabCatType . MoviesHD , "4K Upscaled" ) ;
AddCategoryMapping ( 47 , TorznabCatType . MoviesHD , "Real 4K UltraHD HDR" ) ;
2016-12-29 11:14:35 +00:00
AddCategoryMapping ( 36 , TorznabCatType . MoviesForeign ) ;
AddCategoryMapping ( 37 , TorznabCatType . MoviesWEBDL ) ;
AddCategoryMapping ( 43 , TorznabCatType . MoviesSD , "Movies/HDRip" ) ;
2015-08-13 21:51:49 +00:00
AddCategoryMapping ( 26 , TorznabCatType . TVSD ) ;
AddCategoryMapping ( 27 , TorznabCatType . TV ) ; // Boxsets
AddCategoryMapping ( 32 , TorznabCatType . TVHD ) ;
2016-12-29 11:14:35 +00:00
AddCategoryMapping ( 44 , TorznabCatType . TVFOREIGN , "TV/Foreign" ) ;
2015-08-13 21:51:49 +00:00
AddCategoryMapping ( 17 , TorznabCatType . PCGames ) ;
AddCategoryMapping ( 18 , TorznabCatType . ConsoleXbox ) ;
AddCategoryMapping ( 19 , TorznabCatType . ConsoleXbox360 ) ;
2016-12-29 11:14:35 +00:00
AddCategoryMapping ( 40 , TorznabCatType . ConsoleXbox , "Games/XBOXONE" ) ;
AddCategoryMapping ( 20 , TorznabCatType . ConsolePS3 ) ; // PS2
2015-08-13 21:51:49 +00:00
AddCategoryMapping ( 21 , TorznabCatType . ConsolePS3 ) ;
AddCategoryMapping ( 22 , TorznabCatType . ConsolePSP ) ;
AddCategoryMapping ( 28 , TorznabCatType . ConsoleWii ) ;
AddCategoryMapping ( 30 , TorznabCatType . ConsoleNDS ) ;
2016-12-29 11:14:35 +00:00
AddCategoryMapping ( 39 , TorznabCatType . ConsolePS4 ) ;
AddCategoryMapping ( 42 , TorznabCatType . PCMac , "Games/Mac" ) ;
2015-08-13 21:51:49 +00:00
AddCategoryMapping ( 16 , TorznabCatType . AudioVideo ) ;
AddCategoryMapping ( 31 , TorznabCatType . Audio ) ;
AddCategoryMapping ( 34 , TorznabCatType . TVAnime ) ;
AddCategoryMapping ( 35 , TorznabCatType . TV ) ; // Cartoons
AddCategoryMapping ( 5 , TorznabCatType . Books ) ;
2016-12-29 11:14:35 +00:00
AddCategoryMapping ( 45 , TorznabCatType . BooksEbook , "Books/EBooks" ) ;
AddCategoryMapping ( 46 , TorznabCatType . BooksComics , "Books/Comics" ) ;
2017-04-15 08:45:10 +00:00
2015-08-13 21:51:49 +00:00
AddCategoryMapping ( 23 , TorznabCatType . PCISO ) ;
AddCategoryMapping ( 24 , TorznabCatType . PCMac ) ;
AddCategoryMapping ( 25 , TorznabCatType . PCPhoneOther ) ;
AddCategoryMapping ( 33 , TorznabCatType . PC0day ) ;
2016-12-29 11:14:35 +00:00
AddCategoryMapping ( 38 , TorznabCatType . Other , "Education" ) ;
2015-04-26 02:32:03 +00:00
}
2018-04-17 11:55:18 +00:00
public override async Task < ConfigurationData > GetConfigurationForSetup ( )
{
var loginPage = await RequestStringWithCookies ( LoginUrl , string . Empty ) ;
CQ cq = loginPage . Content ;
var captcha = cq . Find ( ".g-recaptcha" ) ;
if ( captcha . Any ( ) )
{
var result = this . configData ;
result . CookieHeader . Value = loginPage . Cookies ;
result . Captcha . SiteKey = captcha . Attr ( "data-sitekey" ) ;
result . Captcha . Version = "2" ;
return result ;
}
else
{
var result = new ConfigurationDataBasicLogin ( ) ;
result . SiteLink . Value = configData . SiteLink . Value ;
result . Instructions . Value = configData . Instructions . Value ;
result . Username . Value = configData . Username . Value ;
result . Password . Value = configData . Password . Value ;
result . CookieHeader . Value = loginPage . Cookies ;
return result ;
}
}
2017-06-28 05:31:38 +00:00
public override async Task < IndexerConfigurationStatus > ApplyConfiguration ( JToken configJson )
2015-04-26 02:32:03 +00:00
{
2017-01-02 20:39:28 +00:00
LoadValuesFromJson ( configJson ) ;
2018-04-17 11:55:18 +00:00
var pairs = new Dictionary < string , string > {
{ "username" , configData . Username . Value } ,
{ "password" , configData . Password . Value } ,
{ "g-recaptcha-response" , configData . Captcha . Value }
} ;
if ( ! string . IsNullOrWhiteSpace ( configData . Captcha . Cookie ) )
{
CookieHeader = configData . Captcha . Cookie ;
try
{
var results = await PerformQuery ( new TorznabQuery ( ) ) ;
if ( results . Count ( ) = = 0 )
{
throw new Exception ( "Your cookie did not work" ) ;
}
IsConfigured = true ;
SaveConfig ( ) ;
return IndexerConfigurationStatus . Completed ;
}
catch ( Exception e )
{
IsConfigured = false ;
throw new Exception ( "Your cookie did not work: " + e . Message ) ;
}
}
2016-08-05 11:57:43 +00:00
await DoLogin ( ) ;
return IndexerConfigurationStatus . RequiresTesting ;
}
private async Task DoLogin ( )
{
2015-04-26 02:32:03 +00:00
var pairs = new Dictionary < string , string > {
2015-08-03 21:38:45 +00:00
{ "username" , configData . Username . Value } ,
2016-12-12 07:16:46 +00:00
{ "password" , configData . Password . Value }
2015-08-03 21:38:45 +00:00
} ;
2015-04-26 02:32:03 +00:00
2015-08-03 21:38:45 +00:00
var result = await RequestLoginAndFollowRedirect ( LoginUrl , pairs , null , true , null , LoginUrl ) ;
2015-08-02 17:28:59 +00:00
await ConfigureIfOK ( result . Cookies , result . Content ! = null & & result . Content . Contains ( "/user/account/logout" ) , ( ) = >
2015-04-26 02:32:03 +00:00
{
2015-07-27 00:03:51 +00:00
CQ dom = result . Content ;
2018-04-17 18:56:01 +00:00
var errorMessage = dom [ "p.text-danger:contains(\"Error:\")" ] . Text ( ) . Trim ( ) ;
2015-08-03 21:38:45 +00:00
throw new ExceptionWithConfigData ( errorMessage , configData ) ;
2015-07-27 00:03:51 +00:00
} ) ;
2015-04-26 02:32:03 +00:00
}
2017-07-03 05:15:47 +00:00
protected override async Task < IEnumerable < ReleaseInfo > > PerformQuery ( TorznabQuery query )
2015-04-26 02:32:03 +00:00
{
2015-07-28 23:10:04 +00:00
var releases = new List < ReleaseInfo > ( ) ;
2017-04-15 08:45:10 +00:00
var searchString = query . GetQueryString ( ) ;
2018-05-13 15:42:22 +00:00
searchString = Regex . Replace ( searchString , @"(^|\s)-" , " " ) ; // remove dashes at the beginning of keywords as they exclude search strings (see issue #3096)
2015-08-13 21:51:49 +00:00
var searchUrl = SearchUrl ;
if ( ! string . IsNullOrWhiteSpace ( searchString ) )
{
2017-11-05 09:42:03 +00:00
searchUrl + = "query/" + WebUtility . UrlEncode ( searchString ) + "/" ;
2015-08-13 21:51:49 +00:00
}
2017-11-05 09:42:03 +00:00
string . Format ( SearchUrl , WebUtility . UrlEncode ( searchString ) ) ;
2015-08-13 21:51:49 +00:00
var cats = MapTorznabCapsToTrackers ( query ) ;
if ( cats . Count > 0 )
{
searchUrl + = "categories/" ;
foreach ( var cat in cats )
{
if ( ! searchUrl . EndsWith ( "/" ) )
searchUrl + = "," ;
searchUrl + = cat ;
}
2017-04-15 08:45:10 +00:00
}
else
{
searchUrl + = "newfilter/2" ; // include 0day and music
2015-08-13 21:51:49 +00:00
}
var results = await RequestStringWithCookiesAndRetry ( searchUrl ) ;
2016-12-12 07:24:18 +00:00
2018-04-06 08:18:58 +00:00
if ( results . Content . Contains ( "/user/account/login" ) )
2016-12-12 07:24:18 +00:00
{
//Cookie appears to expire after a period of time or logging in to the site via browser
await DoLogin ( ) ;
results = await RequestStringWithCookiesAndRetry ( searchUrl ) ;
}
2015-07-18 20:35:02 +00:00
try
2015-04-26 02:32:03 +00:00
{
2018-04-06 08:18:58 +00:00
dynamic jsonObj = JsonConvert . DeserializeObject ( results . Content ) ;
2015-04-26 02:32:03 +00:00
2018-04-06 08:18:58 +00:00
foreach ( var torrent in jsonObj . torrentList )
2015-07-18 20:35:02 +00:00
{
var release = new ReleaseInfo ( ) ;
2015-04-26 02:32:03 +00:00
2015-07-18 20:35:02 +00:00
release . MinimumRatio = 1 ;
release . MinimumSeedTime = 172800 ;
2015-04-26 02:32:03 +00:00
2018-04-06 08:18:58 +00:00
release . Guid = new Uri ( SiteLink + "torrent/" + torrent . fid ) ;
2015-07-18 20:35:02 +00:00
release . Comments = release . Guid ;
2018-04-06 08:18:58 +00:00
release . Title = torrent . name ;
2016-12-29 11:01:42 +00:00
2017-04-15 08:45:10 +00:00
if ( ! query . MatchQueryStringAND ( release . Title ) )
2016-12-29 11:01:42 +00:00
continue ;
2015-04-26 02:32:03 +00:00
2018-04-06 08:18:58 +00:00
release . Link = new Uri ( SiteLink + "download/" + torrent . fid + "/" + torrent . filename ) ;
2015-04-26 02:32:03 +00:00
2018-04-09 09:36:20 +00:00
release . PublishDate = DateTime . ParseExact ( torrent . addedTimestamp . ToString ( ) , "yyyy-MM-dd HH:mm:ss" , CultureInfo . InvariantCulture , DateTimeStyles . AssumeLocal ) ;
2015-04-26 02:32:03 +00:00
2018-04-06 08:18:58 +00:00
release . Size = ( long ) torrent . size ;
2015-04-26 02:32:03 +00:00
2018-04-06 10:07:27 +00:00
release . Seeders = ParseUtil . CoerceInt ( torrent . seeders . ToString ( ) ) ;
release . Peers = release . Seeders + ParseUtil . CoerceInt ( torrent . leechers . ToString ( ) ) ;
2015-05-04 04:12:14 +00:00
2018-04-06 08:18:58 +00:00
release . Category = MapTrackerCatToNewznab ( torrent . categoryID . ToString ( ) ) ;
2015-08-13 21:51:49 +00:00
2018-04-06 10:07:27 +00:00
release . Grabs = ParseUtil . CoerceInt ( torrent . completed . ToString ( ) ) ;
release . Imdb = ParseUtil . GetImdbID ( torrent . imdbID . ToString ( ) ) ;
2016-10-27 07:35:31 +00:00
2017-04-15 08:45:10 +00:00
release . DownloadVolumeFactor = 1 ;
2016-10-27 07:35:31 +00:00
release . UploadVolumeFactor = 1 ;
2019-12-16 19:48:22 +00:00
// freeleech #6579 #6624
release . DownloadVolumeFactor = ParseUtil . CoerceInt ( torrent . download_multiplier . ToString ( ) ) ;
2019-12-11 07:33:27 +00:00
2015-07-18 20:35:02 +00:00
releases . Add ( release ) ;
2015-04-26 02:32:03 +00:00
}
}
2015-07-18 20:35:02 +00:00
catch ( Exception ex )
{
2015-07-27 00:03:51 +00:00
OnParseError ( results . Content , ex ) ;
2015-07-18 20:35:02 +00:00
}
2015-05-04 04:12:14 +00:00
2015-07-28 23:10:04 +00:00
return releases ;
2015-04-26 02:32:03 +00:00
}
}
}