2020-02-09 02:35:16 +00:00
using System ;
2017-05-14 16:55:36 +00:00
using System.Collections.Generic ;
using System.Linq ;
using System.Threading.Tasks ;
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-05-14 16:55:36 +00:00
using Newtonsoft.Json.Linq ;
using NLog ;
2018-03-10 08:05:56 +00:00
namespace Jackett.Common.Indexers.Meta
2017-05-14 16:55:36 +00:00
{
2017-07-10 20:58:44 +00:00
public abstract class BaseMetaIndexer : BaseWebIndexer
2017-05-14 16:55:36 +00:00
{
2017-11-05 09:42:03 +00:00
protected BaseMetaIndexer ( string name , string description , IFallbackStrategyProvider fallbackStrategyProvider , IResultFilterProvider resultFilterProvider , IIndexerConfigurationService configService , WebClient webClient , Logger logger , ConfigurationData configData , IProtectionService p , Func < IIndexer , bool > filter )
2017-07-10 20:58:44 +00:00
: base ( name , "http://127.0.0.1/" , description , configService , webClient , logger , configData , p , null , null )
2017-05-14 16:55:36 +00:00
{
filterFunc = filter ;
2017-06-28 05:31:38 +00:00
this . fallbackStrategyProvider = fallbackStrategyProvider ;
this . resultFilterProvider = resultFilterProvider ;
2017-05-14 16:55:36 +00:00
}
2018-04-06 15:43:18 +00:00
public override bool CanHandleQuery ( TorznabQuery query )
{
if ( query = = null )
return false ;
if ( query . QueryType = = "indexers" )
return true ;
return base . CanHandleQuery ( query ) ;
}
2020-02-25 16:08:03 +00:00
public override Task < IndexerConfigurationStatus > ApplyConfiguration ( JToken configJson ) = > Task . FromResult ( IndexerConfigurationStatus . Completed ) ;
2017-05-14 16:55:36 +00:00
2017-08-24 10:28:41 +00:00
public override async Task < IndexerResult > ResultsForQuery ( TorznabQuery query )
2017-05-14 16:55:36 +00:00
{
2017-08-24 10:28:41 +00:00
try
2017-08-12 09:12:02 +00:00
{
2017-08-24 10:28:41 +00:00
if ( ! CanHandleQuery ( query ) )
return new IndexerResult ( this , new ReleaseInfo [ 0 ] ) ;
var results = await PerformQuery ( query ) ;
var correctedResults = results . Select ( r = >
{
if ( r . PublishDate > DateTime . Now )
r . PublishDate = DateTime . Now ;
return r ;
} ) ;
2017-08-12 09:12:02 +00:00
2017-08-24 10:28:41 +00:00
return new IndexerResult ( this , correctedResults ) ;
}
catch ( Exception ex )
{
throw new IndexerException ( this , ex ) ;
}
2017-07-03 05:15:47 +00:00
}
protected override async Task < IEnumerable < ReleaseInfo > > PerformQuery ( TorznabQuery query )
{
2017-07-10 20:58:44 +00:00
var indexers = validIndexers ;
2017-08-24 10:28:41 +00:00
IEnumerable < Task < IndexerResult > > supportedTasks = indexers . Where ( i = > i . CanHandleQuery ( query ) ) . Select ( i = > i . ResultsForQuery ( query ) ) . ToList ( ) ; // explicit conversion to List to execute LINQ query
2017-06-03 13:04:51 +00:00
2017-06-28 05:31:38 +00:00
var fallbackStrategies = fallbackStrategyProvider . FallbackStrategiesForQuery ( query ) ;
var fallbackQueries = fallbackStrategies . Select ( async f = > await f . FallbackQueries ( ) ) . SelectMany ( t = > t . Result ) ;
2017-07-10 20:58:44 +00:00
var fallbackTasks = fallbackQueries . SelectMany ( q = > indexers . Where ( i = > ! i . CanHandleQuery ( query ) & & i . CanHandleQuery ( q ) ) . Select ( i = > i . ResultsForQuery ( q . Clone ( ) ) ) ) ;
2017-06-28 05:31:38 +00:00
var tasks = supportedTasks . Concat ( fallbackTasks . ToList ( ) ) ; // explicit conversion to List to execute LINQ query
2017-08-07 20:33:23 +00:00
// When there are many indexers used by a metaindexer querying each and every one of them can take very very
// long. This may result in a problem especially with Sonarr, which does consecutive searches when searching
// for a season. Also, there might be indexers that do not support fast consecutive searches.
// Therefore doing a season search in Sonarr might take for more than 90 seconds (approx. timeout in Sonarr)
// which will mark Jackett as unresponsive (and therefore deactivated).
// Although that 40 second is just an arbitrary number, doing a 40 second timeout is acceptable since an API
// not responding for 40 second.. well, no one should really use that.
// I hope in the future these queries will speed up (using caching or some other magic), however until then
// just stick with a timeout.
var aggregateTask = tasks . Until ( TimeSpan . FromSeconds ( 40 ) ) ;
2017-06-03 13:04:51 +00:00
2017-07-03 05:15:47 +00:00
try
{
2017-06-03 13:04:51 +00:00
await aggregateTask ;
2017-07-03 05:15:47 +00:00
}
catch
{
2017-05-14 16:55:36 +00:00
logger . Error ( aggregateTask . Exception , "Error during request in metaindexer " + ID ) ;
2017-06-03 13:04:51 +00:00
}
2020-03-27 03:13:38 +00:00
var unorderedResult = aggregateTask . Result . SelectMany ( r = > r . Releases ) ;
2017-06-28 05:31:38 +00:00
var resultFilters = resultFilterProvider . FiltersForQuery ( query ) ;
var filteredResults = resultFilters . Select ( async f = > await f . FilterResults ( unorderedResult ) ) . SelectMany ( t = > t . Result ) ;
var uniqueFilteredResults = filteredResults . Distinct ( ) ;
var orderedResults = uniqueFilteredResults . OrderByDescending ( r = > r . Gain ) ;
2017-05-14 16:55:36 +00:00
// Limiting the response size might be interesting for use-cases where there are
// tons of trackers configured in Jackett. For now just use the limit param if
// someone wants to do that.
2017-06-28 05:31:38 +00:00
IEnumerable < ReleaseInfo > result = orderedResults ;
2017-05-14 16:55:36 +00:00
if ( query . Limit > 0 )
result = result . Take ( query . Limit ) ;
return result ;
}
2020-02-25 16:08:03 +00:00
public override TorznabCapabilities TorznabCaps = > validIndexers . Select ( i = > i . TorznabCaps ) . Aggregate ( new TorznabCapabilities ( ) , TorznabCapabilities . Concat ) ;
2017-05-14 16:55:36 +00:00
2020-02-25 16:08:03 +00:00
public override bool IsConfigured = > Indexers ! = null ;
2017-05-14 16:55:36 +00:00
2020-02-25 16:08:03 +00:00
private IEnumerable < IIndexer > validIndexers = > Indexers ? . Where ( i = > i . IsConfigured & & filterFunc ( i ) ) ;
2017-06-28 05:31:38 +00:00
2017-07-10 20:58:44 +00:00
public IEnumerable < IIndexer > Indexers ;
2020-02-10 22:16:19 +00:00
private readonly Func < IIndexer , bool > filterFunc ;
private readonly IFallbackStrategyProvider fallbackStrategyProvider ;
private readonly IResultFilterProvider resultFilterProvider ;
2017-05-14 16:55:36 +00:00
}
}