2020-02-09 02:35:16 +00:00
using System ;
2015-07-19 02:19:09 +00:00
using System.Collections.Generic ;
2017-10-29 06:50:47 +00:00
using System.Collections.Specialized ;
2015-07-19 02:19:09 +00:00
using System.Globalization ;
2016-12-09 17:20:58 +00:00
using System.Text ;
2015-07-19 02:19:09 +00:00
using System.Threading.Tasks ;
2020-02-29 20:29:51 +00:00
using AngleSharp.Dom ;
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-19 02:19:09 +00:00
2018-03-10 08:05:56 +00:00
namespace Jackett.Common.Indexers
2015-07-19 02:19:09 +00:00
{
2017-07-10 20:58:44 +00:00
public class SpeedCD : BaseWebIndexer
2015-07-19 02:19:09 +00:00
{
2020-02-25 16:08:03 +00:00
private string LoginUrl = > SiteLink + "take_login.php" ;
private string SearchUrl = > SiteLink + "browse.php" ;
2015-08-03 21:38:45 +00:00
2017-10-29 06:50:47 +00:00
private new ConfigurationDataBasicLogin configData
2015-08-03 21:38:45 +00:00
{
2020-02-25 16:08:03 +00:00
get = > ( ConfigurationDataBasicLogin ) base . configData ;
set = > base . configData = value ;
2015-08-03 21:38:45 +00:00
}
2017-11-05 09:42:03 +00:00
public SpeedCD ( IIndexerConfigurationService configService , WebClient wc , Logger l , IProtectionService ps )
2015-07-19 23:05:30 +00:00
: base ( name : "Speed.cd" ,
description : "Your home now!" ,
2016-01-19 13:08:00 +00:00
link : "https://speed.cd/" ,
2015-12-09 08:45:44 +00:00
caps : new TorznabCapabilities ( ) ,
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 ,
2016-07-27 04:14:57 +00:00
configData : new ConfigurationDataBasicLogin ( @ "Speed.Cd have increased their security. If you are having problems please check the security tab in your Speed.Cd profile.
eg . Geo Locking , your seedbox may be in a different country to the one where you login via your web browser "))
2015-07-19 02:19:09 +00:00
{
2016-12-09 17:20:58 +00:00
Encoding = Encoding . UTF8 ;
Language = "en-us" ;
2017-01-27 15:57:32 +00:00
Type = "private" ;
2016-12-09 17:20:58 +00:00
2019-05-11 03:27:25 +00:00
TorznabCaps . SupportsImdbMovieSearch = true ;
2017-02-24 18:13:55 +00:00
2019-02-11 23:58:20 +00:00
AddCategoryMapping ( 1 , TorznabCatType . MoviesOther , "Movies/XviD" ) ;
AddCategoryMapping ( 42 , TorznabCatType . Movies , "Movies/Packs" ) ;
AddCategoryMapping ( 32 , TorznabCatType . Movies , "Movies/Kids" ) ;
AddCategoryMapping ( 43 , TorznabCatType . MoviesHD , "Movies/HD" ) ;
AddCategoryMapping ( 47 , TorznabCatType . Movies , "Movies/DiVERSiTY" ) ;
AddCategoryMapping ( 28 , TorznabCatType . MoviesBluRay , "Movies/B-Ray" ) ;
AddCategoryMapping ( 48 , TorznabCatType . Movies3D , "Movies/3D" ) ;
AddCategoryMapping ( 40 , TorznabCatType . MoviesDVD , "Movies/DVD-R" ) ;
AddCategoryMapping ( 56 , TorznabCatType . Movies , "Movies/Anime" ) ;
AddCategoryMapping ( 50 , TorznabCatType . TVSport , "TV/Sports" ) ;
AddCategoryMapping ( 52 , TorznabCatType . TVHD , "TV/B-Ray" ) ;
AddCategoryMapping ( 53 , TorznabCatType . TVSD , "TV/DVD-R" ) ;
AddCategoryMapping ( 41 , TorznabCatType . TV , "TV/Packs" ) ;
AddCategoryMapping ( 55 , TorznabCatType . TV , "TV/Kids" ) ;
AddCategoryMapping ( 57 , TorznabCatType . TV , "TV/DiVERSiTY" ) ;
AddCategoryMapping ( 49 , TorznabCatType . TVHD , "TV/HD" ) ;
AddCategoryMapping ( 2 , TorznabCatType . TVSD , "TV/Episodes" ) ;
AddCategoryMapping ( 30 , TorznabCatType . TVAnime , "TV/Anime" ) ;
AddCategoryMapping ( 25 , TorznabCatType . PCISO , "Games/PC ISO" ) ;
AddCategoryMapping ( 39 , TorznabCatType . ConsoleWii , "Games/Wii" ) ;
AddCategoryMapping ( 45 , TorznabCatType . ConsolePS3 , "Games/PS3" ) ;
AddCategoryMapping ( 35 , TorznabCatType . Console , "Games/Nintendo" ) ;
AddCategoryMapping ( 33 , TorznabCatType . ConsoleXbox360 , "Games/XboX360" ) ;
AddCategoryMapping ( 46 , TorznabCatType . PCPhoneOther , "Mobile" ) ;
AddCategoryMapping ( 24 , TorznabCatType . PC0day , "Apps/0DAY" ) ;
AddCategoryMapping ( 51 , TorznabCatType . PCMac , "Mac" ) ;
AddCategoryMapping ( 54 , TorznabCatType . Books , "Educational" ) ;
AddCategoryMapping ( 27 , TorznabCatType . Books , "Books-Mags" ) ;
AddCategoryMapping ( 26 , TorznabCatType . Audio , "Music/Audio" ) ;
AddCategoryMapping ( 44 , TorznabCatType . Audio , "Music/Pack" ) ;
AddCategoryMapping ( 29 , TorznabCatType . AudioVideo , "Music/Video" ) ;
2015-07-19 02:19:09 +00:00
}
2017-06-28 05:31:38 +00:00
public override async Task < IndexerConfigurationStatus > ApplyConfiguration ( JToken configJson )
2015-07-19 02:19:09 +00:00
{
2017-01-02 20:39:28 +00:00
LoadValuesFromJson ( configJson ) ;
2016-05-28 09:40:39 +00:00
await DoLogin ( ) ;
return IndexerConfigurationStatus . RequiresTesting ;
}
private async Task DoLogin ( )
{
2015-07-19 02:19:09 +00:00
var pairs = new Dictionary < string , string > {
2015-08-03 21:38:45 +00:00
{ "username" , configData . Username . Value } ,
{ "password" , configData . Password . Value } ,
} ;
2015-07-19 02:19:09 +00:00
2015-08-02 18:14:21 +00:00
var result = await RequestLoginAndFollowRedirect ( LoginUrl , pairs , null , true , null , SiteLink ) ;
2016-05-28 09:40:39 +00:00
2016-07-27 04:14:57 +00:00
await ConfigureIfOK ( result . Cookies , result . Content ! = null & & result . Content . Contains ( "/browse.php" ) , ( ) = >
2015-07-19 02:19:09 +00:00
{
2020-02-29 20:29:51 +00:00
var parser = new HtmlParser ( ) ;
var dom = parser . ParseDocument ( result . Content ) ;
2016-07-27 04:14:57 +00:00
var errorMessage = dom . Text ( ) ;
2019-01-16 11:26:43 +00:00
if ( errorMessage . Contains ( "Wrong Captcha!" ) )
errorMessage = "Captcha requiered due to a failed login attempt. Login via a browser to whitelist your IP and then reconfigure jackett." ;
2015-08-03 21:38:45 +00:00
throw new ExceptionWithConfigData ( errorMessage , configData ) ;
2015-07-27 00:03:51 +00:00
} ) ;
2015-07-19 02:19:09 +00:00
}
2017-07-03 05:15:47 +00:00
protected override async Task < IEnumerable < ReleaseInfo > > PerformQuery ( TorznabQuery query )
2015-07-19 02:19:09 +00:00
{
2015-07-27 00:03:51 +00:00
var releases = new List < ReleaseInfo > ( ) ;
2015-12-09 08:45:44 +00:00
2020-02-10 22:16:19 +00:00
var qParams = new NameValueCollection ( ) ;
2015-12-09 08:45:44 +00:00
2017-02-24 18:13:55 +00:00
if ( ! string . IsNullOrWhiteSpace ( query . ImdbID ) )
{
qParams . Add ( "search" , query . ImdbID ) ;
qParams . Add ( "d" , "on" ) ;
}
else if ( ! string . IsNullOrEmpty ( query . GetQueryString ( ) ) )
2015-12-09 08:45:44 +00:00
{
2016-01-20 08:45:39 +00:00
qParams . Add ( "search" , query . GetQueryString ( ) ) ;
2015-12-09 08:45:44 +00:00
}
2020-02-10 22:16:19 +00:00
var catList = MapTorznabCapsToTrackers ( query ) ;
foreach ( var cat in catList )
2015-12-09 08:45:44 +00:00
{
qParams . Add ( "c" + cat , "1" ) ;
}
2016-01-19 13:08:00 +00:00
2020-02-10 22:16:19 +00:00
var urlSearch = SearchUrl ;
2016-01-19 13:08:00 +00:00
if ( qParams . Count > 0 )
2015-07-19 02:19:09 +00:00
{
2016-01-19 13:08:00 +00:00
urlSearch + = $"?{qParams.GetQueryString()}" ;
}
2015-07-19 02:19:09 +00:00
2016-01-19 13:08:00 +00:00
var response = await RequestStringWithCookiesAndRetry ( urlSearch ) ;
2017-02-24 18:13:55 +00:00
if ( ! response . Content . Contains ( "/logout.php" ) )
{
//Cookie appears to expire after a period of time or logging in to the site via browser
await DoLogin ( ) ;
response = await RequestStringWithCookiesAndRetry ( urlSearch ) ;
}
2015-07-19 02:19:09 +00:00
2016-01-19 13:08:00 +00:00
try
{
2020-02-29 20:29:51 +00:00
var parser = new HtmlParser ( ) ;
var dom = parser . ParseDocument ( response . Content ) ;
var rows = dom . QuerySelectorAll ( "div[id='torrentTable'] > div[class^='box torrentBox'] > div[class='boxContent'] > table > tbody > tr" ) ;
2015-07-19 02:19:09 +00:00
2020-02-10 22:16:19 +00:00
foreach ( var row in rows )
2016-01-19 13:08:00 +00:00
{
2020-02-29 20:29:51 +00:00
var cells = row . QuerySelectorAll ( "td" ) ;
2020-02-10 22:16:19 +00:00
2020-02-29 20:29:51 +00:00
var title = row . QuerySelector ( "td[class='lft'] > div > a" ) . TextContent . Trim ( ) ;
var link = new Uri ( SiteLink + row . QuerySelector ( "img[title='Download']" ) . ParentElement . GetAttribute ( "href" ) . Trim ( ) ) ;
2020-02-10 22:16:19 +00:00
var guid = link ;
2020-02-29 20:29:51 +00:00
var comments = new Uri ( SiteLink + row . QuerySelector ( "td[class='lft'] > div > a" ) . GetAttribute ( "href" ) . Trim ( ) . Remove ( 0 , 1 ) ) ;
var size = ReleaseInfo . GetBytes ( cells [ 4 ] . TextContent ) ;
var grabs = ParseUtil . CoerceInt ( cells [ 5 ] . TextContent ) ;
var seeders = ParseUtil . CoerceInt ( cells [ 6 ] . TextContent ) ;
var leechers = ParseUtil . CoerceInt ( cells [ 7 ] . TextContent ) ;
2020-02-10 22:16:19 +00:00
2020-02-29 20:29:51 +00:00
var pubDateStr = row . QuerySelector ( "span[class^='elapsedDate']" ) . GetAttribute ( "title" ) . Trim ( ) . Replace ( " at" , "" ) ;
2020-02-10 22:16:19 +00:00
var publishDate = DateTime . ParseExact ( pubDateStr , "dddd, MMMM d, yyyy h:mmtt" , CultureInfo . InvariantCulture , DateTimeStyles . AssumeUniversal ) . ToLocalTime ( ) ;
2020-02-29 20:29:51 +00:00
var cat = row . QuerySelector ( "img[class^='Tcat']" ) . ParentElement . GetAttribute ( "href" ) . Trim ( ) . Remove ( 0 , 5 ) ;
2020-02-10 22:16:19 +00:00
long . TryParse ( cat , out var category ) ;
2015-12-09 08:45:44 +00:00
2020-02-25 16:08:03 +00:00
// This fixes the mixed initializer issue, so it's just inconsistent in the code base.
// https://github.com/Jackett/Jackett/pull/7166#discussion_r376817517
2016-01-19 13:08:00 +00:00
var release = new ReleaseInfo ( ) ;
release . Title = title ;
release . Guid = guid ;
release . Link = link ;
release . PublishDate = publishDate ;
release . Size = size ;
2018-08-29 10:26:48 +00:00
release . Grabs = grabs ;
2016-01-19 13:08:00 +00:00
release . Seeders = seeders ;
release . Peers = seeders + leechers ;
release . MinimumRatio = 1 ;
2020-01-11 18:07:19 +00:00
release . MinimumSeedTime = 172800 ; // 48 hours
2016-01-19 13:08:00 +00:00
release . Category = MapTrackerCatToNewznab ( category . ToString ( ) ) ;
2019-02-11 23:58:20 +00:00
release . Comments = comments ;
2015-07-19 02:19:09 +00:00
2020-02-29 20:29:51 +00:00
release . DownloadVolumeFactor = row . QuerySelector ( "span:contains(\"[Freeleech]\")" ) ! = null ? 0 : 1 ;
2017-02-24 18:16:57 +00:00
release . UploadVolumeFactor = 1 ;
2015-07-19 02:19:09 +00:00
releases . Add ( release ) ;
}
}
catch ( Exception ex )
{
2015-07-27 00:03:51 +00:00
OnParseError ( response . Content , ex ) ;
2015-07-19 02:19:09 +00:00
}
2015-07-28 23:10:04 +00:00
return releases ;
2015-07-19 02:19:09 +00:00
}
}
2016-01-20 08:45:39 +00:00
}