2018-10-13 05:10:46 +00:00
using System ;
2017-10-29 06:21:18 +00:00
using System.Collections.Generic ;
using System.Collections.Specialized ;
using System.Globalization ;
using System.Text ;
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 ;
2015-07-11 19:27:57 +00:00
using Newtonsoft.Json.Linq ;
2015-07-19 00:27:41 +00:00
using NLog ;
2015-07-11 19:27:57 +00:00
2018-03-10 08:05:56 +00:00
namespace Jackett.Common.Indexers
2015-07-11 19:27:57 +00:00
{
2017-07-10 20:58:44 +00:00
public class HDTorrents : BaseWebIndexer
2015-07-11 19:27:57 +00:00
{
2017-01-02 20:39:28 +00:00
private string SearchUrl { get { return SiteLink + "torrents.php?" ; } }
private string LoginUrl { get { return SiteLink + "login.php" ; } }
2015-07-12 15:48:37 +00:00
private const int MAXPAGES = 3 ;
2017-08-31 08:50:47 +00:00
public override string [ ] AlternativeSiteLinks { get ; protected set ; } = new string [ ] { "https://hdts.ru/" , "https://hd-torrents.org/" , "https://hd-torrents.net/" , "https://hd-torrents.me/" } ;
2015-07-12 15:48:37 +00:00
2017-10-29 06:21:18 +00:00
private new ConfigurationDataBasicLogin configData
2015-08-03 21:38:45 +00:00
{
2017-01-02 20:39:28 +00:00
get { return ( ConfigurationDataBasicLogin ) base . configData ; }
2015-08-03 21:38:45 +00:00
set { base . configData = value ; }
}
2017-11-05 09:42:03 +00:00
public HDTorrents ( IIndexerConfigurationService configService , WebClient w , Logger l , IProtectionService ps )
2015-07-19 23:05:30 +00:00
: base ( name : "HD-Torrents" ,
description : "HD-Torrents is a private torrent website with HD torrents and strict rules on their content." ,
2016-12-20 18:45:57 +00:00
link : "https://hdts.ru/" , // Of the accessible domains the .ru seems the most reliable. https://hdts.ru | https://hd-torrents.org | https://hd-torrents.net | https://hd-torrents.me
2017-07-10 20:58:44 +00:00
configService : configService ,
2015-07-27 00:03:51 +00:00
client : w ,
2015-08-03 21:38:45 +00:00
logger : l ,
2015-08-07 19:09:13 +00:00
p : ps ,
2017-01-02 20:39:28 +00:00
configData : new ConfigurationDataBasicLogin ( ) )
2015-07-11 19:27:57 +00:00
{
2017-11-05 09:42:03 +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" ;
2016-12-06 13:56:47 +00:00
2017-01-25 13:10:28 +00:00
TorznabCaps . SupportsImdbSearch = true ;
2017-04-15 08:45:10 +00:00
TorznabCaps . Categories . Clear ( ) ;
// Movie
2018-01-02 18:12:08 +00:00
AddCategoryMapping ( "70" , TorznabCatType . MoviesUHD , "Movie/UHD/Blu-Ray" ) ;
2017-04-15 08:45:10 +00:00
AddCategoryMapping ( "1" , TorznabCatType . MoviesHD , "Movie/Blu-Ray" ) ;
2018-01-02 18:12:08 +00:00
AddCategoryMapping ( "71" , TorznabCatType . MoviesUHD , "Movie/UHD/Remux" ) ;
2017-04-15 08:45:10 +00:00
AddCategoryMapping ( "2" , TorznabCatType . MoviesHD , "Movie/Remux" ) ;
AddCategoryMapping ( "5" , TorznabCatType . MoviesHD , "Movie/1080p/i" ) ;
AddCategoryMapping ( "3" , TorznabCatType . MoviesHD , "Movie/720p" ) ;
2018-01-02 18:12:08 +00:00
AddCategoryMapping ( "64" , TorznabCatType . MoviesUHD , "Movie/2160p" ) ;
2017-04-15 08:45:10 +00:00
AddCategoryMapping ( "63" , TorznabCatType . Audio , "Movie/Audio Track" ) ;
// TV Show
2018-01-02 18:00:32 +00:00
2018-01-02 18:12:08 +00:00
AddCategoryMapping ( "72" , TorznabCatType . TVUHD , "TV Show/UHD/Blu-ray" ) ;
2017-04-15 08:45:10 +00:00
AddCategoryMapping ( "59" , TorznabCatType . TVHD , "TV Show/Blu-ray" ) ;
2018-01-02 18:12:08 +00:00
AddCategoryMapping ( "73" , TorznabCatType . TVUHD , "TV Show/UHD/Remux" ) ;
2017-04-15 08:45:10 +00:00
AddCategoryMapping ( "60" , TorznabCatType . TVHD , "TV Show/Remux" ) ;
AddCategoryMapping ( "30" , TorznabCatType . TVHD , "TV Show/1080p/i" ) ;
AddCategoryMapping ( "38" , TorznabCatType . TVHD , "TV Show/720p" ) ;
2018-01-02 18:12:08 +00:00
AddCategoryMapping ( "65" , TorznabCatType . TVUHD , "TV Show/2160p" ) ;
2017-04-15 08:45:10 +00:00
// Music
AddCategoryMapping ( "44" , TorznabCatType . Audio , "Music/Album" ) ;
AddCategoryMapping ( "61" , TorznabCatType . AudioVideo , "Music/Blu-Ray" ) ;
AddCategoryMapping ( "62" , TorznabCatType . AudioVideo , "Music/Remux" ) ;
AddCategoryMapping ( "57" , TorznabCatType . AudioVideo , "Music/1080p/i" ) ;
AddCategoryMapping ( "45" , TorznabCatType . AudioVideo , "Music/720p" ) ;
AddCategoryMapping ( "66" , TorznabCatType . AudioVideo , "Music/2160p" ) ;
// XXX
AddCategoryMapping ( "58" , TorznabCatType . XXX , "XXX/Blu-ray" ) ;
2018-01-02 18:00:32 +00:00
AddCategoryMapping ( "74" , TorznabCatType . XXX , "XXX/UHD/Blu-ray" ) ;
2017-04-15 08:45:10 +00:00
AddCategoryMapping ( "48" , TorznabCatType . XXX , "XXX/1080p/i" ) ;
AddCategoryMapping ( "47" , TorznabCatType . XXX , "XXX/720p" ) ;
AddCategoryMapping ( "67" , TorznabCatType . XXX , "XXX/2160p" ) ;
2015-07-11 19:27:57 +00:00
}
2017-06-28 05:31:38 +00:00
public override async Task < IndexerConfigurationStatus > ApplyConfiguration ( JToken configJson )
2015-07-11 19:27:57 +00:00
{
2017-01-02 20:39:28 +00:00
LoadValuesFromJson ( configJson ) ;
2016-12-20 18:45:57 +00:00
2015-07-28 19:22:23 +00:00
var loginPage = await RequestStringWithCookies ( LoginUrl , string . Empty ) ;
2015-07-12 15:48:37 +00:00
2015-07-11 19:27:57 +00:00
var pairs = new Dictionary < string , string > {
2015-08-03 21:38:45 +00:00
{ "uid" , configData . Username . Value } ,
{ "pwd" , configData . Password . Value }
2015-07-27 00:03:51 +00:00
} ;
2015-07-11 19:27:57 +00:00
2015-07-27 00:03:51 +00:00
var result = await RequestLoginAndFollowRedirect ( LoginUrl , pairs , loginPage . Cookies , true , null , LoginUrl ) ;
2015-07-11 19:27:57 +00:00
2015-08-02 17:28:59 +00:00
await ConfigureIfOK ( result . Cookies , result . Content ! = null & & result . Content . Contains ( "If your browser doesn't have javascript enabled" ) , ( ) = >
2015-07-11 19:27:57 +00:00
{
2015-07-12 15:48:37 +00:00
var errorMessage = "Couldn't login" ;
2015-08-03 21:38:45 +00:00
throw new ExceptionWithConfigData ( errorMessage , configData ) ;
2015-07-27 00:03:51 +00:00
} ) ;
2015-08-22 20:57:13 +00:00
return IndexerConfigurationStatus . RequiresTesting ;
2015-07-11 19:27:57 +00:00
}
2017-07-03 05:15:47 +00:00
protected override async Task < IEnumerable < ReleaseInfo > > PerformQuery ( TorznabQuery query )
2015-07-11 19:27:57 +00:00
{
2015-07-27 00:03:51 +00:00
var releases = new List < ReleaseInfo > ( ) ;
var searchurls = new List < string > ( ) ;
2015-08-19 21:51:16 +00:00
var searchUrl = SearchUrl ; // string.Format(SearchUrl, HttpUtility.UrlEncode()));
var queryCollection = new NameValueCollection ( ) ;
var searchString = query . GetQueryString ( ) ;
foreach ( var cat in MapTorznabCapsToTrackers ( query ) )
{
searchUrl + = "category%5B%5D=" + cat + "&" ;
}
2017-01-25 13:10:28 +00:00
if ( query . ImdbID ! = null )
{
queryCollection . Add ( "search" , query . ImdbID ) ;
}
else if ( ! string . IsNullOrWhiteSpace ( searchString ) )
2015-08-19 21:51:16 +00:00
{
queryCollection . Add ( "search" , searchString ) ;
}
2016-12-06 08:52:40 +00:00
queryCollection . Add ( "active" , "0" ) ;
2015-08-19 21:51:16 +00:00
queryCollection . Add ( "options" , "0" ) ;
2016-12-06 08:52:40 +00:00
searchUrl + = queryCollection . GetQueryString ( ) . Replace ( "(" , "%28" ) . Replace ( ")" , "%29" ) ; // maually url encode brackets to prevent "hacking" detection
2015-08-19 21:51:16 +00:00
2015-07-29 17:47:51 +00:00
var results = await RequestStringWithCookiesAndRetry ( searchUrl ) ;
2015-07-28 19:22:23 +00:00
try
2015-07-12 15:48:37 +00:00
{
2015-07-28 19:22:23 +00:00
CQ dom = results . Content ;
ReleaseInfo release ;
2015-07-12 15:48:37 +00:00
2018-10-20 18:45:19 +00:00
CQ userInfo = dom [ ".mainmenu > table > tbody > tr:has(td[title=\"Active-Torrents\"])" ] [ 0 ] . Cq ( ) ;
string rank = userInfo . Find ( "td:nth-child(2)" ) . Text ( ) . Substring ( 6 ) ;
HashSet < string > freeleechRanks = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
freeleechRanks . Add ( "VIP" ) ;
freeleechRanks . Add ( "Uploader" ) ;
freeleechRanks . Add ( "HD Internal" ) ;
freeleechRanks . Add ( "Moderator" ) ;
freeleechRanks . Add ( "Administrator" ) ;
freeleechRanks . Add ( "Owner" ) ;
bool hasFreeleech = freeleechRanks . Contains ( rank ) ;
2016-12-06 08:52:40 +00:00
var rows = dom [ ".mainblockcontenttt > tbody > tr:has(a[href^=\"details.php?id=\"])" ] ;
2015-07-28 19:22:23 +00:00
foreach ( var row in rows )
2015-07-12 15:48:37 +00:00
{
2015-07-28 19:22:23 +00:00
CQ qRow = row . Cq ( ) ;
2015-07-12 15:48:37 +00:00
2015-07-28 19:22:23 +00:00
release = new ReleaseInfo ( ) ;
2015-07-12 15:48:37 +00:00
2015-07-28 19:22:23 +00:00
release . Title = qRow . Find ( "td.mainblockcontent b a" ) . Text ( ) ;
2016-12-06 08:52:40 +00:00
release . Description = qRow . Find ( "td:nth-child(3) > span" ) . Text ( ) ;
2015-07-12 15:48:37 +00:00
2015-07-28 19:22:23 +00:00
if ( 0 ! = qRow . Find ( "td.mainblockcontent u" ) . Length )
{
var imdbStr = qRow . Find ( "td.mainblockcontent u" ) . Parent ( ) . First ( ) . Attr ( "href" ) . Replace ( "http://www.imdb.com/title/tt" , "" ) . Replace ( "/" , "" ) ;
long imdb ;
if ( ParseUtil . TryCoerceLong ( imdbStr , out imdb ) )
2015-07-12 19:50:24 +00:00
{
2015-07-28 19:22:23 +00:00
release . Imdb = imdb ;
2015-07-12 19:50:24 +00:00
}
2015-07-28 19:22:23 +00:00
}
2015-07-12 15:48:37 +00:00
2015-07-28 19:22:23 +00:00
release . MinimumRatio = 1 ;
release . MinimumSeedTime = 172800 ;
2018-10-13 05:10:46 +00:00
int tdIndex = 0 ;
if ( qRow . Find ( "td:nth-last-child(1)" ) . Text ( ) = = "Edit" ) tdIndex = 1 ;
2015-07-12 15:48:37 +00:00
2017-09-05 16:37:25 +00:00
// Sometimes the uploader column is missing
2015-07-28 19:22:23 +00:00
int seeders , peers ;
2018-10-13 05:10:46 +00:00
if ( ParseUtil . TryCoerceInt ( qRow . Find ( $"td:nth-last-child({tdIndex + 3})" ) . Text ( ) , out seeders ) )
2015-07-28 19:22:23 +00:00
{
release . Seeders = seeders ;
2018-10-13 05:10:46 +00:00
if ( ParseUtil . TryCoerceInt ( qRow . Find ( $"td:nth-last-child({tdIndex + 2})" ) . Text ( ) , out peers ) )
2015-07-12 19:50:24 +00:00
{
2015-07-28 19:22:23 +00:00
release . Peers = peers + release . Seeders ;
2015-07-12 19:50:24 +00:00
}
2015-07-28 19:22:23 +00:00
}
2015-07-12 15:48:37 +00:00
2018-10-13 05:10:46 +00:00
release . Grabs = ParseUtil . CoerceLong ( qRow . Find ( $"td:nth-last-child({tdIndex + 1})" ) . Text ( ) ) ;
2016-12-06 08:52:40 +00:00
2015-07-28 19:22:23 +00:00
string fullSize = qRow . Find ( "td.mainblockcontent" ) . Get ( 6 ) . InnerText ;
release . Size = ReleaseInfo . GetBytes ( fullSize ) ;
2015-07-12 15:48:37 +00:00
2015-08-19 21:51:16 +00:00
release . Guid = new Uri ( SiteLink + qRow . Find ( "td.mainblockcontent b a" ) . Attr ( "href" ) ) ;
release . Link = new Uri ( SiteLink + qRow . Find ( "td.mainblockcontent" ) . Get ( 3 ) . FirstChild . GetAttribute ( "href" ) ) ;
2016-12-06 08:52:40 +00:00
release . Comments = new Uri ( SiteLink + qRow . Find ( "td.mainblockcontent b a" ) . Attr ( "href" ) ) ;
2015-07-12 15:48:37 +00:00
2015-07-28 19:22:23 +00:00
string [ ] dateSplit = qRow . Find ( "td.mainblockcontent" ) . Get ( 5 ) . InnerHTML . Split ( ',' ) ;
2017-03-13 12:36:05 +00:00
string dateString = dateSplit [ 1 ] . Substring ( 0 , dateSplit [ 1 ] . IndexOf ( '>' ) ) . Trim ( ) ;
release . PublishDate = DateTime . ParseExact ( dateString , "dd MMM yyyy HH:mm:ss zz00" , CultureInfo . InvariantCulture ) . ToLocalTime ( ) ;
2015-07-18 20:35:02 +00:00
2015-08-19 21:51:16 +00:00
string category = qRow . Find ( "td:eq(0) a" ) . Attr ( "href" ) . Replace ( "torrents.php?category=" , "" ) ;
release . Category = MapTrackerCatToNewznab ( category ) ;
2016-12-14 07:55:05 +00:00
release . UploadVolumeFactor = 1 ;
2017-04-15 08:45:10 +00:00
if ( qRow . Find ( "img[alt=\"Free Torrent\"]" ) . Length > = 1 )
2017-10-29 06:21:18 +00:00
{
2017-04-15 08:45:10 +00:00
release . DownloadVolumeFactor = 0 ;
release . UploadVolumeFactor = 0 ;
2016-12-14 07:55:05 +00:00
}
2018-10-20 18:45:19 +00:00
else if ( hasFreeleech )
release . DownloadVolumeFactor = 0 ;
2017-04-15 08:45:10 +00:00
else if ( qRow . Find ( "img[alt=\"Silver Torrent\"]" ) . Length > = 1 )
release . DownloadVolumeFactor = 0.5 ;
else if ( qRow . Find ( "img[alt=\"Bronze Torrent\"]" ) . Length > = 1 )
release . DownloadVolumeFactor = 0.75 ;
else if ( qRow . Find ( "img[alt=\"Blue Torrent\"]" ) . Length > = 1 )
release . DownloadVolumeFactor = 0.25 ;
2016-12-06 08:52:40 +00:00
else
release . DownloadVolumeFactor = 1 ;
2015-07-28 19:22:23 +00:00
releases . Add ( release ) ;
2015-07-12 15:48:37 +00:00
}
}
2015-07-28 19:22:23 +00:00
catch ( Exception ex )
{
OnParseError ( results . Content , ex ) ;
}
2015-07-11 19:27:57 +00:00
2015-07-28 23:10:04 +00:00
return releases ;
2015-07-11 19:27:57 +00:00
}
}
}