2017-10-29 06:50:47 +00:00
using System ;
using System.Collections.Generic ;
2018-06-07 16:33:44 +00:00
using System.Collections.Specialized ;
2017-10-29 06:50:47 +00:00
using System.Linq ;
using System.Text ;
using System.Text.RegularExpressions ;
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-12 21:43:00 +00:00
using Newtonsoft.Json.Linq ;
2015-07-19 00:27:41 +00:00
using NLog ;
2015-07-12 21:43:00 +00:00
2018-03-10 08:05:56 +00:00
namespace Jackett.Common.Indexers
2015-07-12 21:43:00 +00:00
{
2017-07-10 20:58:44 +00:00
public class SceneTime : BaseWebIndexer
2015-07-12 21:43:00 +00:00
{
2016-09-29 19:09:20 +00:00
private string StartPageUrl { get { return SiteLink + "login.php" ; } }
2015-07-27 00:03:51 +00:00
private string LoginUrl { get { return SiteLink + "takelogin.php" ; } }
2018-06-05 11:09:07 +00:00
private string SearchUrl { get { return SiteLink + "browse.php" ; } }
2015-07-27 00:03:51 +00:00
private string DownloadUrl { get { return SiteLink + "download.php/{0}/download.torrent" ; } }
2015-07-12 21:43:00 +00:00
2017-10-29 06:50:47 +00:00
private new ConfigurationDataRecaptchaLogin configData
2015-08-03 21:38:45 +00:00
{
2016-09-29 19:09:20 +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 SceneTime ( IIndexerConfigurationService configService , WebClient w , Logger l , IProtectionService ps )
2015-07-19 23:05:30 +00:00
: base ( name : "SceneTime" ,
description : "Always on time" ,
2015-07-27 00:03:51 +00:00
link : "https://www.scenetime.com/" ,
2016-02-13 05:55:23 +00:00
caps : new TorznabCapabilities ( ) ,
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-04-15 08:45:10 +00:00
configData : new ConfigurationDataRecaptchaLogin ( "For best results, change the 'Torrents per page' setting to the maximum in your profile on the SceneTime webpage." ) )
2015-07-12 21:43:00 +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" ;
2016-12-06 13:56:47 +00:00
2017-10-19 14:45:07 +00:00
//Movies
AddCategoryMapping ( 1 , TorznabCatType . MoviesSD , "Movies/XviD" ) ;
AddCategoryMapping ( 3 , TorznabCatType . MoviesDVD , "Movies/DVD-R" ) ;
AddCategoryMapping ( 10 , TorznabCatType . XXX , "Movies/XxX" ) ;
AddCategoryMapping ( 47 , TorznabCatType . Movies , "Movie/Packs" ) ;
AddCategoryMapping ( 56 , TorznabCatType . Movies , "Movies/Anime" ) ;
AddCategoryMapping ( 57 , TorznabCatType . MoviesSD , "Movies/SD" ) ;
AddCategoryMapping ( 59 , TorznabCatType . MoviesHD , "Movies/HD" ) ;
AddCategoryMapping ( 61 , TorznabCatType . Movies , "Movies/Classic" ) ;
AddCategoryMapping ( 64 , TorznabCatType . Movies3D , "Movies/3D" ) ;
AddCategoryMapping ( 80 , TorznabCatType . MoviesForeign , "Movies/Non-English" ) ;
AddCategoryMapping ( 81 , TorznabCatType . MoviesBluRay , "Movies/BluRay" ) ;
AddCategoryMapping ( 82 , TorznabCatType . MoviesOther , "Movies/CAM-TS" ) ;
AddCategoryMapping ( 102 , TorznabCatType . MoviesOther , "Movies/Remux" ) ;
AddCategoryMapping ( 103 , TorznabCatType . MoviesWEBDL , "Movies/Web-Rip" ) ;
AddCategoryMapping ( 105 , TorznabCatType . Movies , "Movies/Kids" ) ;
2018-06-05 11:09:07 +00:00
AddCategoryMapping ( 16 , TorznabCatType . MoviesUHD , "Movies/4K" ) ;
AddCategoryMapping ( 17 , TorznabCatType . MoviesBluRay , "Movies/4K bluray" ) ;
2017-10-29 06:50:47 +00:00
2017-10-19 14:45:07 +00:00
//TV
AddCategoryMapping ( 2 , TorznabCatType . TVSD , "TV/XviD" ) ;
AddCategoryMapping ( 43 , TorznabCatType . TV , "TV/Packs" ) ;
AddCategoryMapping ( 9 , TorznabCatType . TVHD , "TV-HD" ) ;
AddCategoryMapping ( 63 , TorznabCatType . TV , "TV/Classic" ) ;
AddCategoryMapping ( 77 , TorznabCatType . TVSD , "TV/SD" ) ;
AddCategoryMapping ( 79 , TorznabCatType . TVSport , "Sports" ) ;
AddCategoryMapping ( 100 , TorznabCatType . TVFOREIGN , "TV/Non-English" ) ;
AddCategoryMapping ( 83 , TorznabCatType . TVWEBDL , "TV/Web-Rip" ) ;
AddCategoryMapping ( 8 , TorznabCatType . TVOTHER , "TV-Mobile" ) ;
2018-06-05 11:09:07 +00:00
AddCategoryMapping ( 18 , TorznabCatType . TVAnime , "TV/Anime" ) ;
AddCategoryMapping ( 19 , TorznabCatType . TVHD , "TV-x265" ) ;
2017-10-19 14:45:07 +00:00
// Games
AddCategoryMapping ( 6 , TorznabCatType . PCGames , "Games/PC ISO" ) ;
AddCategoryMapping ( 48 , TorznabCatType . ConsoleXbox , "Games/XBOX" ) ;
AddCategoryMapping ( 49 , TorznabCatType . ConsolePSP , "Games/PSP" ) ;
AddCategoryMapping ( 50 , TorznabCatType . ConsolePS3 , "Games/PS3" ) ;
AddCategoryMapping ( 51 , TorznabCatType . ConsoleWii , "Games/Wii" ) ;
AddCategoryMapping ( 55 , TorznabCatType . ConsoleNDS , "Games/Nintendo DS" ) ;
AddCategoryMapping ( 12 , TorznabCatType . ConsolePS4 , "Games/Ps4" ) ;
AddCategoryMapping ( 13 , TorznabCatType . ConsoleOther , "Games/PS1" ) ;
AddCategoryMapping ( 14 , TorznabCatType . ConsoleOther , "Games/PS2" ) ;
AddCategoryMapping ( 15 , TorznabCatType . ConsoleOther , "Games/Dreamcast" ) ;
// Miscellaneous
AddCategoryMapping ( 5 , TorznabCatType . PC0day , "Apps/0DAY" ) ;
AddCategoryMapping ( 7 , TorznabCatType . Books , "Books-Mags" ) ;
AddCategoryMapping ( 52 , TorznabCatType . PCMac , "Mac" ) ;
AddCategoryMapping ( 65 , TorznabCatType . BooksComics , "Books/Comic" ) ;
AddCategoryMapping ( 53 , TorznabCatType . PC , "Appz" ) ;
// Music
AddCategoryMapping ( 4 , TorznabCatType . Audio , "Music/Audio" ) ;
AddCategoryMapping ( 11 , TorznabCatType . AudioVideo , "Music/Videos" ) ;
2015-07-12 21:43:00 +00:00
}
2016-09-29 19:09:20 +00:00
public override async Task < ConfigurationData > GetConfigurationForSetup ( )
{
var loginPage = await RequestStringWithCookies ( StartPageUrl , string . Empty ) ;
CQ cq = loginPage . Content ;
2016-10-27 07:26:11 +00:00
var result = this . configData ;
result . Captcha . Version = "2" ;
2016-09-29 19:09:20 +00:00
CQ recaptcha = cq . Find ( ".g-recaptcha" ) . Attr ( "data-sitekey" ) ;
if ( recaptcha . Length ! = 0 )
{
result . CookieHeader . Value = loginPage . Cookies ;
result . Captcha . SiteKey = cq . Find ( ".g-recaptcha" ) . Attr ( "data-sitekey" ) ;
return result ;
2017-04-15 08:45:10 +00:00
}
2016-09-29 19:09:20 +00:00
else
{
var stdResult = new ConfigurationDataBasicLogin ( ) ;
2017-01-02 20:39:28 +00:00
stdResult . SiteLink . Value = configData . SiteLink . Value ;
2016-10-27 07:26:11 +00:00
stdResult . Username . Value = configData . Username . Value ;
stdResult . Password . Value = configData . Password . Value ;
2016-09-29 19:09:20 +00:00
stdResult . CookieHeader . Value = loginPage . Cookies ;
return stdResult ;
2017-04-15 08:45:10 +00:00
}
2016-09-29 19:09:20 +00:00
}
2017-06-28 05:31:38 +00:00
public override async Task < IndexerConfigurationStatus > ApplyConfiguration ( JToken configJson )
2015-07-12 21:43:00 +00:00
{
2017-01-02 20:39:28 +00:00
LoadValuesFromJson ( configJson ) ;
2015-07-12 21:43:00 +00:00
var pairs = new Dictionary < string , string > {
2015-08-03 21:38:45 +00:00
{ "username" , configData . Username . Value } ,
2016-09-29 19:09:20 +00:00
{ "password" , configData . Password . Value } ,
{ "g-recaptcha-response" , configData . Captcha . Value }
2015-08-03 21:38:45 +00:00
} ;
2015-07-12 21:43:00 +00:00
2016-09-29 19:09:20 +00:00
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 ;
2017-05-06 17:39:02 +00:00
SaveConfig ( ) ;
2016-09-29 19:09:20 +00:00
return IndexerConfigurationStatus . Completed ;
}
catch ( Exception e )
{
IsConfigured = false ;
throw new Exception ( "Your cookie did not work: " + e . Message ) ;
}
}
2015-07-27 00:03:51 +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 ( "logout.php" ) , ( ) = >
2015-07-12 21:43:00 +00:00
{
2015-07-27 00:03:51 +00:00
CQ dom = result . Content ;
2015-07-12 21:43:00 +00:00
var errorMessage = dom [ "td.text" ] . Text ( ) . Trim ( ) ;
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-12 21:43:00 +00:00
}
2017-07-03 05:15:47 +00:00
protected override async Task < IEnumerable < ReleaseInfo > > PerformQuery ( TorznabQuery query )
2015-07-12 21:43:00 +00:00
{
2018-06-07 16:33:44 +00:00
var qParams = new NameValueCollection ( ) ;
2016-02-13 05:55:23 +00:00
qParams . Add ( "cata" , "yes" ) ;
qParams . Add ( "sec" , "jax" ) ;
2017-10-29 06:50:47 +00:00
2016-02-13 05:55:23 +00:00
List < string > catList = MapTorznabCapsToTrackers ( query ) ;
foreach ( string cat in catList )
{
qParams . Add ( "c" + cat , "1" ) ;
}
if ( ! string . IsNullOrEmpty ( query . SanitizedSearchTerm ) )
{
qParams . Add ( "search" , query . GetQueryString ( ) ) ;
}
2018-06-07 16:33:44 +00:00
var searchUrl = SearchUrl + "?" + qParams . GetQueryString ( ) ;
var results = await RequestStringWithCookies ( searchUrl ) ;
2016-10-25 06:46:06 +00:00
List < ReleaseInfo > releases = ParseResponse ( query , results . Content ) ;
2017-10-29 06:50:47 +00:00
2016-02-13 05:55:23 +00:00
return releases ;
2015-07-12 21:43:00 +00:00
}
2016-10-25 06:46:06 +00:00
public List < ReleaseInfo > ParseResponse ( TorznabQuery query , string htmlResponse )
2015-07-12 21:43:00 +00:00
{
2016-02-13 05:55:23 +00:00
List < ReleaseInfo > releases = new List < ReleaseInfo > ( ) ;
2015-07-12 21:43:00 +00:00
2015-07-18 20:35:02 +00:00
try
{
2016-02-13 05:55:23 +00:00
CQ dom = htmlResponse ;
List < string > headerColumns = dom [ "table[class*='movehere']" ] . First ( ) . Find ( "tbody > tr > td[class='cat_Head']" ) . Select ( x = > x . Cq ( ) . Text ( ) ) . ToList ( ) ;
int categoryIndex = headerColumns . FindIndex ( x = > x . Equals ( "Type" ) ) ;
int nameIndex = headerColumns . FindIndex ( x = > x . Equals ( "Name" ) ) ;
int sizeIndex = headerColumns . FindIndex ( x = > x . Equals ( "Size" ) ) ;
int seedersIndex = headerColumns . FindIndex ( x = > x . Equals ( "Seeders" ) ) ;
int leechersIndex = headerColumns . FindIndex ( x = > x . Equals ( "Leechers" ) ) ;
2015-07-18 20:35:02 +00:00
var rows = dom [ "tr.browse" ] ;
foreach ( var row in rows )
2015-07-12 21:43:00 +00:00
{
2015-07-18 20:35:02 +00:00
var release = new ReleaseInfo ( ) ;
release . MinimumRatio = 1 ;
release . MinimumSeedTime = 172800 ;
2016-02-13 05:55:23 +00:00
var categoryCol = row . ChildElements . ElementAt ( categoryIndex ) ;
string catLink = categoryCol . Cq ( ) . Find ( "a" ) . Attr ( "href" ) ;
2017-10-29 06:50:47 +00:00
if ( catLink ! = null )
{
2017-09-01 15:46:24 +00:00
string catId = new Regex ( @"\?cat=(\d*)" ) . Match ( catLink ) . Groups [ 1 ] . ToString ( ) . Trim ( ) ;
release . Category = MapTrackerCatToNewznab ( catId ) ;
}
2016-02-13 05:55:23 +00:00
var descCol = row . ChildElements . ElementAt ( nameIndex ) ;
2015-07-18 20:35:02 +00:00
var qDescCol = descCol . Cq ( ) ;
var qLink = qDescCol . Find ( "a" ) ;
release . Title = qLink . Text ( ) ;
2017-04-15 08:45:10 +00:00
if ( ! query . MatchQueryStringAND ( release . Title ) )
2016-10-25 06:46:06 +00:00
continue ;
2015-07-19 17:18:54 +00:00
release . Comments = new Uri ( SiteLink + "/" + qLink . Attr ( "href" ) ) ;
2015-07-18 20:35:02 +00:00
release . Guid = release . Comments ;
var torrentId = qLink . Attr ( "href" ) . Split ( '=' ) [ 1 ] ;
release . Link = new Uri ( string . Format ( DownloadUrl , torrentId ) ) ;
2015-08-10 20:46:58 +00:00
release . PublishDate = DateTimeUtil . FromTimeAgo ( descCol . ChildNodes . Last ( ) . InnerText ) ;
2015-07-18 20:35:02 +00:00
2016-02-13 05:55:23 +00:00
var sizeStr = row . ChildElements . ElementAt ( sizeIndex ) . Cq ( ) . Text ( ) ;
2015-07-26 03:53:53 +00:00
release . Size = ReleaseInfo . GetBytes ( sizeStr ) ;
2015-07-18 20:35:02 +00:00
2016-02-13 05:55:23 +00:00
release . Seeders = ParseUtil . CoerceInt ( row . ChildElements . ElementAt ( seedersIndex ) . Cq ( ) . Text ( ) . Trim ( ) ) ;
release . Peers = ParseUtil . CoerceInt ( row . ChildElements . ElementAt ( leechersIndex ) . Cq ( ) . Text ( ) . Trim ( ) ) + release . Seeders ;
2015-07-18 20:35:02 +00:00
2017-04-15 08:45:10 +00:00
if ( row . Cq ( ) . Find ( "font > b:contains(Freeleech)" ) . Length > = 1 )
release . DownloadVolumeFactor = 0 ;
2016-10-27 07:35:31 +00:00
else
2017-04-15 08:45:10 +00:00
release . DownloadVolumeFactor = 1 ;
2016-10-27 07:35:31 +00:00
release . UploadVolumeFactor = 1 ;
2015-07-18 20:35:02 +00:00
releases . Add ( release ) ;
2015-07-12 21:43:00 +00:00
}
}
2015-07-18 20:35:02 +00:00
catch ( Exception ex )
{
2016-02-13 05:55:23 +00:00
OnParseError ( htmlResponse , ex ) ;
2015-07-18 20:35:02 +00:00
}
2016-02-13 05:55:23 +00:00
2015-07-28 23:10:04 +00:00
return releases ;
2015-07-12 21:43:00 +00:00
}
}
}