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
{
2020-05-11 19:59:28 +00:00
protected BaseMetaIndexer ( string name , string id , string description ,
IFallbackStrategyProvider fallbackStrategyProvider ,
2021-05-16 18:13:54 +00:00
IResultFilterProvider resultFilterProvider , IIndexerConfigurationService configService ,
2020-12-11 22:14:21 +00:00
WebClient client , Logger logger , ConfigurationData configData , IProtectionService ps ,
ICacheService cs , Func < IIndexer , bool > filter )
2020-05-11 19:59:28 +00:00
: base ( id : id ,
name : name ,
description : description ,
link : "http://127.0.0.1/" ,
2020-10-13 20:17:26 +00:00
caps : new TorznabCapabilities ( ) ,
2020-05-11 19:59:28 +00:00
configService : configService ,
client : client ,
logger : logger ,
2020-12-11 22:14:21 +00:00
p : ps ,
cacheService : cs ,
2020-05-11 19:59:28 +00:00
configData : configData )
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
2020-11-08 22:27:54 +00:00
public override async Task < IndexerResult > ResultsForQuery ( TorznabQuery query , bool isMetaIndexer )
2017-05-14 16:55:36 +00:00
{
2020-11-08 22:27:54 +00:00
if ( ! CanHandleQuery ( query ) | | ! CanHandleCategories ( query , true ) )
2020-12-11 22:14:21 +00:00
return new IndexerResult ( this , new ReleaseInfo [ 0 ] , false ) ;
2020-11-02 13:20:13 +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
var results = await PerformQuery ( query ) ;
2020-11-02 13:20:13 +00:00
// the results are already filtered and fixed by each indexer
2020-12-11 22:14:21 +00:00
// some results may come from cache, but we can't inform without refactor the code
return new IndexerResult ( this , results , false ) ;
2017-08-24 10:28:41 +00:00
}
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 )
{
2021-05-08 20:24:18 +00:00
var indexers = ValidIndexers ;
2020-11-08 22:27:54 +00:00
IEnumerable < Task < IndexerResult > > supportedTasks = indexers . Where ( i = > i . CanHandleQuery ( query ) ) . Select ( i = > i . ResultsForQuery ( query , true ) ) . 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 ) ;
2020-11-08 22:27:54 +00:00
var fallbackTasks = fallbackQueries . SelectMany ( q = > indexers . Where ( i = > ! i . CanHandleQuery ( query ) & & i . CanHandleQuery ( q ) ) . Select ( i = > i . ResultsForQuery ( q . Clone ( ) , true ) ) ) ;
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
{
2020-05-11 19:59:28 +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 ;
}
2021-05-08 20:24:18 +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
2021-05-08 20:24:18 +00:00
public override string [ ] Tags = > Array . Empty < string > ( ) ;
public 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
}
}