2020-02-09 02:35:16 +00:00
using System ;
2015-07-30 20:09:38 +00:00
using System.Collections.Generic ;
using System.Collections.Specialized ;
2020-05-03 23:35:52 +00:00
using System.Diagnostics.CodeAnalysis ;
2015-07-30 20:09:38 +00:00
using System.Globalization ;
using System.Text ;
using System.Threading.Tasks ;
2020-02-29 20:29:35 +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 ;
using Jackett.Common.Utils.Clients ;
2017-10-29 06:50:47 +00:00
using Newtonsoft.Json.Linq ;
using NLog ;
2015-07-30 20:09:38 +00:00
2018-03-10 08:05:56 +00:00
namespace Jackett.Common.Indexers
2015-07-30 20:09:38 +00:00
{
2020-05-03 23:35:52 +00:00
[ExcludeFromCodeCoverage]
2017-07-10 20:58:44 +00:00
public class TorrentBytes : BaseWebIndexer
2015-07-30 20:09:38 +00:00
{
2020-02-25 16:08:03 +00:00
private string LoginUrl = > SiteLink + "takelogin.php" ;
2020-03-29 20:43:37 +00:00
private string SearchUrl = > SiteLink + "browse.php" ;
2015-07-30 20:09:38 +00:00
2020-03-29 20:43:37 +00:00
private new ConfigurationDataBasicLogin configData = > ( ConfigurationDataBasicLogin ) base . configData ;
2015-08-03 21:38:45 +00:00
2020-12-11 22:14:21 +00:00
public TorrentBytes ( IIndexerConfigurationService configService , WebClient wc , Logger l , IProtectionService ps ,
ICacheService cs )
2020-05-11 19:59:28 +00:00
: base ( id : "torrentbytes" ,
name : "TorrentBytes" ,
2020-03-29 20:43:37 +00:00
description : "A decade of TorrentBytes" ,
2020-03-06 18:35:10 +00:00
link : "https://www.torrentbytes.net/" ,
2020-10-13 20:17:26 +00:00
caps : new TorznabCapabilities
{
2020-10-18 20:47:36 +00:00
TvSearchParams = new List < TvSearchParam >
{
TvSearchParam . Q , TvSearchParam . Season , TvSearchParam . Ep , TvSearchParam . ImdbId
} ,
MovieSearchParams = new List < MovieSearchParam >
{
MovieSearchParam . Q , MovieSearchParam . ImdbId
2020-10-20 00:38:27 +00:00
} ,
MusicSearchParams = new List < MusicSearchParam >
{
MusicSearchParam . Q
2020-10-18 20:47:36 +00:00
}
2020-10-13 20:17:26 +00:00
} ,
2020-03-06 18:35:10 +00:00
configService : configService ,
client : wc ,
logger : l ,
p : ps ,
2020-12-11 22:14:21 +00:00
cacheService : cs ,
2020-03-29 20:43:37 +00:00
configData : new ConfigurationDataBasicLogin ( "For best results, change the 'Torrents per page' setting to 100 in your profile on the TorrentBytes webpage." ) )
2015-07-30 20:09:38 +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-12-17 19:26:35 +00:00
Type = "private" ;
2020-03-29 20:43:37 +00:00
2018-01-14 19:47:21 +00:00
AddCategoryMapping ( 23 , TorznabCatType . TVAnime , "Anime" ) ;
AddCategoryMapping ( 52 , TorznabCatType . PCMac , "Apple/All" ) ;
AddCategoryMapping ( 22 , TorznabCatType . PC , "Apps/misc" ) ;
AddCategoryMapping ( 1 , TorznabCatType . PC , "Apps/PC" ) ;
2020-10-28 19:00:48 +00:00
AddCategoryMapping ( 28 , TorznabCatType . TVForeign , "Foreign Titles" ) ;
2018-01-14 19:47:21 +00:00
AddCategoryMapping ( 50 , TorznabCatType . Console , "Games/Consoles" ) ;
AddCategoryMapping ( 42 , TorznabCatType . PCGames , "Games/Pack" ) ;
AddCategoryMapping ( 4 , TorznabCatType . PCGames , "Games/PC" ) ;
AddCategoryMapping ( 51 , TorznabCatType . PC , "Linux/All" ) ;
AddCategoryMapping ( 31 , TorznabCatType . OtherMisc , "Misc" ) ;
AddCategoryMapping ( 20 , TorznabCatType . MoviesDVD , "Movies/DVD-R" ) ;
AddCategoryMapping ( 12 , TorznabCatType . MoviesBluRay , "Movies/Full Blu-ray" ) ;
AddCategoryMapping ( 5 , TorznabCatType . MoviesHD , "Movies/HD" ) ;
AddCategoryMapping ( 40 , TorznabCatType . Movies , "Movies/Pack" ) ;
AddCategoryMapping ( 19 , TorznabCatType . MoviesSD , "Movies/SD" ) ;
AddCategoryMapping ( 49 , TorznabCatType . MoviesUHD , "Movies/UHD" ) ;
AddCategoryMapping ( 25 , TorznabCatType . Audio , "Music/DVDR" ) ;
AddCategoryMapping ( 48 , TorznabCatType . AudioLossless , "Music/Flac" ) ;
AddCategoryMapping ( 6 , TorznabCatType . AudioMP3 , "Music/MP3" ) ;
AddCategoryMapping ( 43 , TorznabCatType . Audio , "Music/Pack" ) ;
AddCategoryMapping ( 34 , TorznabCatType . AudioVideo , "Music/Videos" ) ;
AddCategoryMapping ( 45 , TorznabCatType . MoviesBluRay , "NonScene/BRrip" ) ;
AddCategoryMapping ( 46 , TorznabCatType . MoviesHD , "NonScene/x264" ) ;
AddCategoryMapping ( 44 , TorznabCatType . MoviesSD , "NonScene/Xvid" ) ;
AddCategoryMapping ( 37 , TorznabCatType . TVHD , "TV/BRrip" ) ;
AddCategoryMapping ( 38 , TorznabCatType . TVHD , "TV/HD" ) ;
AddCategoryMapping ( 41 , TorznabCatType . TV , "TV/Pack" ) ;
AddCategoryMapping ( 33 , TorznabCatType . TVSD , "TV/SD" ) ;
AddCategoryMapping ( 32 , TorznabCatType . TVUHD , "TV/UHD" ) ;
AddCategoryMapping ( 39 , TorznabCatType . XXXx264 , "XXX/HD" ) ;
2020-10-28 19:00:48 +00:00
AddCategoryMapping ( 24 , TorznabCatType . XXXImageSet , "XXX/IMGSET" ) ;
AddCategoryMapping ( 21 , TorznabCatType . XXXPack , "XXX/Pack" ) ;
2018-01-14 19:47:21 +00:00
AddCategoryMapping ( 9 , TorznabCatType . XXXXviD , "XXX/SD" ) ;
AddCategoryMapping ( 29 , TorznabCatType . XXX , "XXX/Web" ) ;
2015-07-30 20:09:38 +00:00
}
2017-06-28 05:31:38 +00:00
public override async Task < IndexerConfigurationStatus > ApplyConfiguration ( JToken configJson )
2015-07-30 20:09:38 +00:00
{
2017-01-02 20:39:28 +00:00
LoadValuesFromJson ( configJson ) ;
2020-03-06 18:35:10 +00:00
var pairs = new Dictionary < string , string >
{
{ "username" , configData . Username . Value } ,
{ "password" , configData . Password . Value } ,
{ "returnto" , "/" } ,
{ "login" , "Log in!" }
2015-07-30 20:09:38 +00:00
} ;
2020-09-21 16:39:47 +00:00
var loginPage = await RequestWithCookiesAsync ( SiteLink , string . Empty ) ;
2015-07-30 20:09:38 +00:00
var result = await RequestLoginAndFollowRedirect ( LoginUrl , pairs , loginPage . Cookies , true , SiteLink , SiteLink ) ;
2020-03-06 18:35:10 +00:00
await ConfigureIfOK (
2020-06-09 17:36:57 +00:00
result . Cookies , result . ContentString ? . Contains ( "my.php" ) = = true , ( ) = >
2020-03-06 18:35:10 +00:00
{
var parser = new HtmlParser ( ) ;
2020-06-09 17:36:57 +00:00
var dom = parser . ParseDocument ( result . ContentString ) ;
2020-03-06 18:35:10 +00:00
var messageEl = dom . QuerySelector ( "td.embedded" ) ;
2020-06-09 17:36:57 +00:00
var errorMessage = messageEl ! = null ? messageEl . TextContent : result . ContentString ;
2020-03-06 18:35:10 +00:00
throw new ExceptionWithConfigData ( errorMessage , configData ) ;
} ) ;
2015-08-22 20:57:13 +00:00
return IndexerConfigurationStatus . RequiresTesting ;
2015-07-30 20:09:38 +00:00
}
2017-07-03 05:15:47 +00:00
protected override async Task < IEnumerable < ReleaseInfo > > PerformQuery ( TorznabQuery query )
2015-07-30 20:09:38 +00:00
{
var releases = new List < ReleaseInfo > ( ) ;
2020-03-29 20:43:37 +00:00
var qc = new NameValueCollection
2015-07-30 20:09:38 +00:00
{
2020-03-29 20:43:37 +00:00
{ "incldead" , "1" }
} ;
if ( query . IsImdbQuery )
{
qc . Add ( "search" , query . ImdbID ) ;
qc . Add ( "sc" , "2" ) ; // search in description
2015-07-30 20:09:38 +00:00
}
else
{
2020-03-29 20:43:37 +00:00
qc . Add ( "search" , query . GetQueryString ( ) ) ;
qc . Add ( "sc" , "1" ) ; // search in title
2015-07-30 20:09:38 +00:00
}
2020-03-29 20:43:37 +00:00
foreach ( var cat in MapTorznabCapsToTrackers ( query ) )
qc . Add ( "c" + cat , "1" ) ;
var searchUrl = SearchUrl + "?" + qc . GetQueryString ( ) ;
2020-06-11 15:09:27 +00:00
var response = await RequestWithCookiesAndRetryAsync ( searchUrl , referer : SearchUrl ) ;
2020-03-29 20:43:37 +00:00
if ( response . IsRedirect ) // re-login
2017-04-15 08:45:10 +00:00
{
await ApplyConfiguration ( null ) ;
2020-06-11 15:09:27 +00:00
response = await RequestWithCookiesAndRetryAsync ( searchUrl , referer : SearchUrl ) ;
2016-11-06 16:41:22 +00:00
}
2015-07-30 20:09:38 +00:00
try
{
2020-02-29 20:29:35 +00:00
var parser = new HtmlParser ( ) ;
2020-06-09 17:36:57 +00:00
var dom = parser . ParseDocument ( response . ContentString ) ;
2020-02-29 20:29:35 +00:00
var rows = dom . QuerySelectorAll ( "table > tbody:has(tr > td.colhead) > tr:not(:has(td.colhead))" ) ;
2016-10-25 07:41:30 +00:00
foreach ( var row in rows )
2015-07-30 20:09:38 +00:00
{
var release = new ReleaseInfo ( ) ;
2020-02-29 20:29:35 +00:00
var link = row . QuerySelector ( "td:nth-of-type(2) a:nth-of-type(2)" ) ;
release . Guid = new Uri ( SiteLink + link . GetAttribute ( "href" ) ) ;
2020-11-08 02:11:27 +00:00
release . Details = release . Guid ;
2020-02-29 20:29:35 +00:00
release . Title = link . GetAttribute ( "title" ) ;
2018-05-29 10:24:13 +00:00
// There isn't a title attribute if the release name isn't truncated.
if ( string . IsNullOrWhiteSpace ( release . Title ) )
2020-03-06 18:35:10 +00:00
release . Title = link . FirstChild . TextContent . Trim ( ) ;
2015-07-30 20:09:38 +00:00
release . Description = release . Title ;
// If we search an get no results, we still get a table just with no info.
if ( string . IsNullOrWhiteSpace ( release . Title ) )
break ;
2016-01-19 13:20:19 +00:00
// Check if the release has been assigned a category
2020-02-29 20:29:35 +00:00
var qCat = row . QuerySelector ( "td:nth-of-type(1) a" ) ;
if ( qCat ! = null )
2016-01-19 13:20:19 +00:00
{
2020-02-29 20:29:35 +00:00
var cat = qCat . GetAttribute ( "href" ) . Substring ( 15 ) ;
2016-01-19 13:20:19 +00:00
release . Category = MapTrackerCatToNewznab ( cat ) ;
}
2015-07-30 20:09:38 +00:00
2020-02-29 20:29:35 +00:00
var qLink = row . QuerySelector ( "td:nth-of-type(2) a" ) ;
release . Link = new Uri ( SiteLink + qLink . GetAttribute ( "href" ) ) ;
var added = row . QuerySelector ( "td:nth-of-type(5)" ) . TextContent . Trim ( ) ;
2017-08-05 00:45:38 +00:00
release . PublishDate = DateTime . ParseExact ( added , "yyyy-MM-ddHH:mm:ss" , CultureInfo . InvariantCulture ) ;
2020-02-29 20:29:35 +00:00
var sizeStr = row . QuerySelector ( "td:nth-of-type(7)" ) . TextContent . Trim ( ) ;
2015-07-30 20:09:38 +00:00
release . Size = ReleaseInfo . GetBytes ( sizeStr ) ;
2020-02-29 20:29:35 +00:00
release . Seeders = ParseUtil . CoerceInt ( row . QuerySelector ( "td:nth-of-type(9)" ) . TextContent . Trim ( ) ) ;
2020-03-06 18:35:10 +00:00
release . Peers = ParseUtil . CoerceInt ( row . QuerySelector ( "td:nth-of-type(10)" ) . TextContent . Trim ( ) ) +
release . Seeders ;
2020-02-29 20:29:35 +00:00
var files = row . QuerySelector ( "td:nth-child(3)" ) . TextContent ;
2016-10-27 07:35:31 +00:00
release . Files = ParseUtil . CoerceInt ( files ) ;
2020-02-29 20:29:35 +00:00
var grabs = row . QuerySelector ( "td:nth-child(8)" ) . TextContent ;
2016-10-27 07:35:31 +00:00
if ( grabs ! = "----" )
release . Grabs = ParseUtil . CoerceInt ( grabs ) ;
2020-03-06 18:35:10 +00:00
release . DownloadVolumeFactor =
row . QuerySelector ( "font[color=\"green\"]:contains(\"F\"):contains(\"L\")" ) ! = null ? 0 : 1 ;
2016-10-27 07:35:31 +00:00
release . UploadVolumeFactor = 1 ;
2015-07-30 20:09:38 +00:00
releases . Add ( release ) ;
}
}
catch ( Exception ex )
{
2020-06-09 17:36:57 +00:00
OnParseError ( response . ContentString , ex ) ;
2015-07-30 20:09:38 +00:00
}
2020-03-06 18:35:10 +00:00
return releases ;
2015-07-30 20:09:38 +00:00
}
}
}