2020-02-09 02:35:16 +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 ;
2020-02-29 19:23:09 +00:00
using AngleSharp.Html.Parser ;
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
{
2020-02-29 19:23:09 +00:00
public override string [ ] LegacySiteLinks { get ; protected set ; } =
{
2018-04-23 16:19:50 +00:00
"https://v4.torrentleech.org/" ,
} ;
2020-02-25 16:08:03 +00:00
private string LoginUrl = > SiteLink + "user/account/login/" ;
private string SearchUrl = > 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
{
2020-02-25 16:08:03 +00:00
get = > ( ConfigurationDataRecaptchaLogin ) base . configData ;
set = > base . configData = value ;
2015-08-03 21:38:45 +00:00
}
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
{
2020-02-17 21:29:32 +00:00
Encoding = Encoding . UTF8 ;
2016-12-09 17:20:58 +00:00
Language = "en-us" ;
2017-01-27 15:57:32 +00:00
Type = "private" ;
2020-02-17 21:29:32 +00:00
TorznabCaps . SupportsImdbMovieSearch = true ;
TorznabCaps . SupportsImdbTVSearch = true ;
2015-08-13 21:51:49 +00:00
2020-03-22 06:25:02 +00:00
AddCategoryMapping ( 1 , TorznabCatType . Movies , "Movies" ) ;
2020-03-09 17:52:40 +00:00
AddCategoryMapping ( 8 , TorznabCatType . MoviesSD , "Movies Cam" ) ;
AddCategoryMapping ( 9 , TorznabCatType . MoviesSD , "Movies TS/TC" ) ;
AddCategoryMapping ( 11 , TorznabCatType . MoviesSD , "Movies DVDRip/DVDScreener" ) ;
AddCategoryMapping ( 12 , TorznabCatType . MoviesDVD , "Movies DVD-R" ) ;
AddCategoryMapping ( 13 , TorznabCatType . MoviesBluRay , "Movies Bluray" ) ;
AddCategoryMapping ( 14 , TorznabCatType . MoviesHD , "Movies BlurayRip" ) ;
AddCategoryMapping ( 15 , TorznabCatType . Movies , "Movies Boxsets" ) ;
AddCategoryMapping ( 29 , TorznabCatType . TVDocumentary , "Documentaries" ) ;
AddCategoryMapping ( 47 , TorznabCatType . MoviesUHD , "Movies 4K" ) ;
AddCategoryMapping ( 36 , TorznabCatType . MoviesForeign , "Movies Foreign" ) ;
AddCategoryMapping ( 37 , TorznabCatType . MoviesWEBDL , "Movies WEBRip" ) ;
AddCategoryMapping ( 43 , TorznabCatType . MoviesHD , "Movies HDRip" ) ;
2015-08-13 21:51:49 +00:00
2020-03-22 06:25:02 +00:00
AddCategoryMapping ( 2 , TorznabCatType . TV , "TV" ) ;
2020-03-09 17:52:40 +00:00
AddCategoryMapping ( 26 , TorznabCatType . TVSD , "TV Episodes" ) ;
AddCategoryMapping ( 27 , TorznabCatType . TV , "TV Boxsets" ) ;
AddCategoryMapping ( 32 , TorznabCatType . TVHD , "TV Episodes HD" ) ;
AddCategoryMapping ( 44 , TorznabCatType . TVFOREIGN , "TV Foreign" ) ;
2015-08-13 21:51:49 +00:00
2020-03-22 06:25:02 +00:00
AddCategoryMapping ( 3 , TorznabCatType . PCGames , "Games" ) ;
2020-03-09 17:52:40 +00:00
AddCategoryMapping ( 17 , TorznabCatType . PCGames , "Games PC" ) ;
AddCategoryMapping ( 18 , TorznabCatType . ConsoleXbox , "Games XBOX" ) ;
AddCategoryMapping ( 19 , TorznabCatType . ConsoleXbox360 , "Games XBOX360" ) ;
AddCategoryMapping ( 40 , TorznabCatType . ConsoleXboxOne , "Games XBOXONE" ) ;
AddCategoryMapping ( 20 , TorznabCatType . ConsolePS3 , "Games PS2" ) ;
AddCategoryMapping ( 21 , TorznabCatType . ConsolePS3 , "Games Mac" ) ;
AddCategoryMapping ( 22 , TorznabCatType . ConsolePSP , "Games PSP" ) ;
AddCategoryMapping ( 28 , TorznabCatType . ConsoleWii , "Games Wii" ) ;
AddCategoryMapping ( 30 , TorznabCatType . ConsoleNDS , "Games Nintendo DS" ) ;
AddCategoryMapping ( 39 , TorznabCatType . ConsolePS4 , "Games PS4" ) ;
AddCategoryMapping ( 42 , TorznabCatType . PCMac , "Games Mac" ) ;
AddCategoryMapping ( 48 , TorznabCatType . ConsoleOther , "Games Nintendo Switch" ) ;
2015-08-13 21:51:49 +00:00
2020-03-22 06:25:02 +00:00
AddCategoryMapping ( 4 , TorznabCatType . Audio , "Music" ) ;
2020-03-09 17:52:40 +00:00
AddCategoryMapping ( 16 , TorznabCatType . AudioVideo , "Music videos" ) ;
AddCategoryMapping ( 31 , TorznabCatType . Audio , "Audio" ) ;
2015-08-13 21:51:49 +00:00
2020-03-22 06:25:02 +00:00
AddCategoryMapping ( 7 , TorznabCatType . TV , "Animation" ) ;
2020-03-09 17:52:40 +00:00
AddCategoryMapping ( 34 , TorznabCatType . TVAnime , "TV Anime" ) ;
AddCategoryMapping ( 35 , TorznabCatType . TV , "TV Cartoons" ) ;
2015-08-13 21:51:49 +00:00
2020-03-22 06:25:02 +00:00
AddCategoryMapping ( 5 , TorznabCatType . Books , "Books" ) ;
2020-03-09 17:52:40 +00:00
AddCategoryMapping ( 45 , TorznabCatType . BooksEbook , "Books EBooks" ) ;
AddCategoryMapping ( 46 , TorznabCatType . BooksComics , "Books Comics" ) ;
2017-04-15 08:45:10 +00:00
2020-03-22 06:25:02 +00:00
AddCategoryMapping ( 6 , TorznabCatType . PC , "Apps" ) ;
2020-03-09 17:52:40 +00:00
AddCategoryMapping ( 23 , TorznabCatType . PCISO , "PC ISO" ) ;
AddCategoryMapping ( 24 , TorznabCatType . PCMac , "PC Mac" ) ;
AddCategoryMapping ( 25 , TorznabCatType . PCPhoneOther , "PC Mobile" ) ;
AddCategoryMapping ( 33 , TorznabCatType . PC0day , "PC 0-day" ) ;
2020-03-22 06:25:02 +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 ) ;
2020-02-29 19:23:09 +00:00
var parser = new HtmlParser ( ) ;
var dom = parser . ParseDocument ( loginPage . Content ) ;
var captcha = dom . QuerySelector ( ".g-recaptcha" ) ;
if ( captcha ! = null )
2018-04-17 11:55:18 +00:00
{
2020-02-10 22:16:19 +00:00
var result = configData ;
2018-04-17 11:55:18 +00:00
result . CookieHeader . Value = loginPage . Cookies ;
2020-02-29 19:23:09 +00:00
result . Captcha . SiteKey = captcha . GetAttribute ( "data-sitekey" ) ;
2018-04-17 11:55:18 +00:00
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
if ( ! string . IsNullOrWhiteSpace ( configData . Captcha . Cookie ) )
{
CookieHeader = configData . Captcha . Cookie ;
try
{
var results = await PerformQuery ( new TorznabQuery ( ) ) ;
2020-02-29 19:23:09 +00:00
if ( ! results . Any ( ) )
2018-04-17 11:55:18 +00:00
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
{
2020-02-29 19:23:09 +00:00
var parser = new HtmlParser ( ) ;
var dom = parser . ParseDocument ( result . Content ) ;
var errorMessage = dom . QuerySelector ( "p.text-danger:contains(\"Error:\")" ) . TextContent . 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 ;
2020-02-17 21:29:32 +00:00
var imdbId = ParseUtil . GetFullImdbID ( query . ImdbID ) ;
2015-08-13 21:51:49 +00:00
2020-02-17 21:29:32 +00:00
if ( imdbId ! = null )
{
searchUrl + = "imdbID/" + imdbId + "/" ;
}
else if ( ! string . IsNullOrWhiteSpace ( searchString ) )
2015-08-13 21:51:49 +00:00
{
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 ;
2020-01-11 18:07:19 +00:00
release . MinimumSeedTime = 172800 ; // 48 hours
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 ( ) ) ;
2020-03-22 06:25:02 +00:00
release . Description = 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
release . UploadVolumeFactor = 1 ;
2020-02-29 04:00:01 +00:00
// freeleech #6579 #6624 #7367
release . DownloadVolumeFactor = string . IsNullOrEmpty ( torrent . download_multiplier . ToString ( ) ) ?
1 :
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
}
}
}