This commit is contained in:
kaso17
2017-08-24 12:29:57 +02:00
9 changed files with 798 additions and 684 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,7 @@ using Jackett.Utils;
using Jackett.Utils.Clients;
using Newtonsoft.Json;
using NLog;
using Jackett.Models.DTO;
namespace Jackett.Controllers.V20
{
@@ -154,20 +155,67 @@ namespace Jackett.Controllers.V20
[HttpGet]
public async Task<Models.DTO.ManualSearchResult> Results([FromUri]Models.DTO.ApiSearch request)
{
var manualResult = new ManualSearchResult();
var trackers = IndexerService.GetAllIndexers().Where(t => t.IsConfigured);
if (CurrentIndexer.ID != "all")
trackers = trackers.Where(t => t.ID == CurrentIndexer.ID).ToList();
trackers = trackers.Where(t => t.IsConfigured && t.CanHandleQuery(CurrentQuery));
trackers = trackers.Where(t => t.CanHandleQuery(CurrentQuery));
var tasks = trackers.ToList().Select(t => t.ResultsForQuery(CurrentQuery)).ToList();
var aggregateTask = Task.WhenAll(tasks);
await aggregateTask;
var results = tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Where(t => t.Result.Count() > 0).SelectMany(t =>
try
{
var searchResults = t.Result;
var indexer = searchResults.First().Origin;
var aggregateTask = Task.WhenAll(tasks);
await aggregateTask;
}
catch (AggregateException aex)
{
foreach (var ex in aex.InnerExceptions)
{
logger.Error(ex);
}
}
catch (Exception ex)
{
logger.Error(ex);
}
manualResult.Indexers = tasks.Select(t =>
{
var resultIndexer = new ManualSearchResultIndexer();
IIndexer indexer = null;
if (t.Status == TaskStatus.RanToCompletion)
{
resultIndexer.Status = ManualSearchResultIndexerStatus.OK;
resultIndexer.Results = t.Result.Releases.Count();
resultIndexer.Error = null;
indexer = t.Result.Indexer;
}
else if (t.Exception.InnerException is IndexerException)
{
resultIndexer.Status = ManualSearchResultIndexerStatus.Error;
resultIndexer.Results = 0;
resultIndexer.Error = ((IndexerException)t.Exception.InnerException).ToString();
indexer = ((IndexerException)t.Exception.InnerException).Indexer;
}
else
{
resultIndexer.Status = ManualSearchResultIndexerStatus.Unknown;
resultIndexer.Results = 0;
resultIndexer.Error = null;
}
if (indexer != null)
{
resultIndexer.ID = indexer.ID;
resultIndexer.Name = indexer.DisplayName;
}
return resultIndexer;
}).ToList();
manualResult.Results = tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Where(t => t.Result.Releases.Count() > 0).SelectMany(t =>
{
var searchResults = t.Result.Releases;
var indexer = t.Result.Indexer;
cacheService.CacheRssResults(indexer, searchResults);
return searchResults.Select(result =>
@@ -181,17 +229,7 @@ namespace Jackett.Controllers.V20
});
}).OrderByDescending(d => d.PublishDate).ToList();
ConfigureCacheResults(results);
var manualResult = new Models.DTO.ManualSearchResult()
{
Results = results,
Indexers = trackers.Select(t => t.DisplayName).ToList()
};
if (manualResult.Indexers.Count() == 0)
manualResult.Indexers = new List<string>() { "None" };
ConfigureCacheResults(manualResult.Results);
logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", CurrentQuery.SanitizedSearchTerm, string.Join(", ", manualResult.Indexers), manualResult.Results.Count()));
return manualResult;
@@ -236,7 +274,7 @@ namespace Jackett.Controllers.V20
}
}
var releases = await CurrentIndexer.ResultsForQuery(CurrentQuery);
var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);
// Some trackers do not support multiple category filtering so filter the releases that match manually.
int? newItemCount = null;
@@ -244,19 +282,19 @@ namespace Jackett.Controllers.V20
// Cache non query results
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
{
newItemCount = cacheService.GetNewItemCount(CurrentIndexer, releases);
cacheService.CacheRssResults(CurrentIndexer, releases);
newItemCount = cacheService.GetNewItemCount(CurrentIndexer, result.Releases);
cacheService.CacheRssResults(CurrentIndexer, result.Releases);
}
// Log info
var logBuilder = new StringBuilder();
if (newItemCount != null)
{
logBuilder.AppendFormat("Found {0} ({1} new) releases from {2}", releases.Count(), newItemCount, CurrentIndexer.DisplayName);
logBuilder.AppendFormat("Found {0} ({1} new) releases from {2}", result.Releases.Count(), newItemCount, CurrentIndexer.DisplayName);
}
else
{
logBuilder.AppendFormat("Found {0} releases from {1}", releases.Count(), CurrentIndexer.DisplayName);
logBuilder.AppendFormat("Found {0} releases from {1}", result.Releases.Count(), CurrentIndexer.DisplayName);
}
if (!string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
@@ -278,7 +316,7 @@ namespace Jackett.Controllers.V20
ImageDescription = CurrentIndexer.DisplayName
});
var proxiedReleases = releases.Select(r => AutoMapper.Mapper.Map<ReleaseInfo>(r)).Select(r =>
var proxiedReleases = result.Releases.Select(r => AutoMapper.Mapper.Map<ReleaseInfo>(r)).Select(r =>
{
r.Link = serverService.ConvertToProxyLink(r.Link, serverUrl, r.Origin.ID, "dl", r.Title + ".torrent");
return r;
@@ -316,20 +354,20 @@ namespace Jackett.Controllers.V20
[JsonResponse]
public async Task<Models.DTO.TorrentPotatoResponse> Potato([FromUri]Models.DTO.TorrentPotatoRequest request)
{
var releases = await CurrentIndexer.ResultsForQuery(CurrentQuery);
var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);
// Cache non query results
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
cacheService.CacheRssResults(CurrentIndexer, releases);
cacheService.CacheRssResults(CurrentIndexer, result.Releases);
// Log info
if (string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
logger.Info($"Found {releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName}");
logger.Info($"Found {result.Releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName}");
else
logger.Info($"Found {releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName} for: {CurrentQuery.GetQueryString()}");
logger.Info($"Found {result.Releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName} for: {CurrentQuery.GetQueryString()}");
var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath());
var potatoReleases = releases.Where(r => r.Link != null || r.MagnetUri != null).Select(r =>
var potatoReleases = result.Releases.Where(r => r.Link != null || r.MagnetUri != null).Select(r =>
{
var release = AutoMapper.Mapper.Map<ReleaseInfo>(r);
release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, CurrentIndexer.ID, "dl", release.Title + ".torrent");

View File

@@ -0,0 +1,30 @@
using Jackett.Indexers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett
{
class IndexerException : Exception
{
public IIndexer Indexer { get; protected set; }
public IndexerException(IIndexer Indexer, string message, Exception innerException)
: base(message, innerException)
{
this.Indexer = Indexer;
}
public IndexerException(IIndexer Indexer, string message)
: this(Indexer, message, null)
{
}
public IndexerException(IIndexer Indexer, Exception innerException)
: this(Indexer, "Exception (" + Indexer.ID + "): " + innerException.Message, innerException)
{
}
}
}

View File

@@ -219,23 +219,30 @@ namespace Jackett.Indexers
public abstract Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson);
public virtual async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
public virtual async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
{
if (!CanHandleQuery(query))
return new ReleaseInfo[0];
var results = await PerformQuery(query);
results = FilterResults(query, results);
results = results.Select(r =>
try
{
r.Origin = this;
if (!CanHandleQuery(query))
return new IndexerResult(this, new ReleaseInfo[0]);
var results = await PerformQuery(query);
results = FilterResults(query, results);
results = results.Select(r =>
{
r.Origin = this;
// Some trackers do not keep their clocks up to date and can be ~20 minutes out!
if (r.PublishDate > DateTime.Now)
r.PublishDate = DateTime.Now;
return r;
});
// Some trackers do not keep their clocks up to date and can be ~20 minutes out!
if (r.PublishDate > DateTime.Now)
r.PublishDate = DateTime.Now;
return r;
});
return results;
return new IndexerResult(this, results);
}
catch (Exception ex)
{
throw new IndexerException(this, ex);
}
}
protected abstract Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query);
}
@@ -667,12 +674,12 @@ namespace Jackett.Indexers
return releases;
}
public override async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
public override async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
{
var results = await base.ResultsForQuery(query);
results = CleanLinks(results);
var result = await base.ResultsForQuery(query);
result.Releases = CleanLinks(result.Releases);
return results;
return result;
}
protected virtual Uri UncleanLink(Uri link)

View File

@@ -10,6 +10,18 @@ using System.Web.UI.WebControls;
namespace Jackett.Indexers
{
public class IndexerResult
{
public IIndexer Indexer { get; set; }
public IEnumerable<ReleaseInfo> Releases { get; set; }
public IndexerResult(IIndexer Indexer, IEnumerable<ReleaseInfo> Releases)
{
this.Indexer = Indexer;
this.Releases = Releases;
}
}
public interface IIndexer
{
string SiteLink { get; }
@@ -39,7 +51,7 @@ namespace Jackett.Indexers
void Unconfigure();
Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query);
Task<IndexerResult> ResultsForQuery(TorznabQuery query);
bool CanHandleQuery(TorznabQuery query);
}

View File

@@ -27,25 +27,32 @@ namespace Jackett.Indexers.Meta
return Task.FromResult(IndexerConfigurationStatus.Completed);
}
public override async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
public override async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
{
if (!CanHandleQuery(query))
return new ReleaseInfo[0];
var results = await PerformQuery(query);
var correctedResults = results.Select(r =>
try
{
if (r.PublishDate > DateTime.Now)
r.PublishDate = DateTime.Now;
return r;
});
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;
});
return correctedResults;
return new IndexerResult(this, correctedResults);
}
catch (Exception ex)
{
throw new IndexerException(this, ex);
}
}
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var indexers = validIndexers;
IEnumerable<Task<IEnumerable<ReleaseInfo>>> supportedTasks = indexers.Where(i => i.CanHandleQuery(query)).Select(i => i.ResultsForQuery(query)).ToList(); // explicit conversion to List to execute LINQ query
IEnumerable<Task<IndexerResult>> supportedTasks = indexers.Where(i => i.CanHandleQuery(query)).Select(i => i.ResultsForQuery(query)).ToList(); // explicit conversion to List to execute LINQ query
var fallbackStrategies = fallbackStrategyProvider.FallbackStrategiesForQuery(query);
var fallbackQueries = fallbackStrategies.Select(async f => await f.FallbackQueries()).SelectMany(t => t.Result);
@@ -72,7 +79,7 @@ namespace Jackett.Indexers.Meta
logger.Error(aggregateTask.Exception, "Error during request in metaindexer " + ID);
}
var unorderedResult = aggregateTask.Result.Flatten();
var unorderedResult = aggregateTask.Result.Select(r => r.Releases).Flatten();
var resultFilters = resultFilterProvider.FiltersForQuery(query);
var filteredResults = resultFilters.Select(async f => await f.FilterResults(unorderedResult)).SelectMany(t => t.Result);
var uniqueFilteredResults = filteredResults.Distinct();

View File

@@ -173,6 +173,7 @@
<ItemGroup>
<Compile Include="AuthenticationException.cs" />
<Compile Include="CacheControlAttribute.cs" />
<Compile Include="IndexerException.cs" />
<Compile Include="Controllers\BlackholeController.cs" />
<Compile Include="Controllers\DownloadController.cs" />
<Compile Include="Engine.cs" />

View File

@@ -7,9 +7,20 @@ using System.Threading.Tasks;
namespace Jackett.Models.DTO
{
public enum ManualSearchResultIndexerStatus { Unknown = 0, Error = 1, OK = 2 };
public class ManualSearchResultIndexer
{
public string ID { get; set; }
public string Name { get; set; }
public ManualSearchResultIndexerStatus Status { get; set; }
public int Results { get; set; }
public string Error { get; set; }
}
public class ManualSearchResult
{
public IEnumerable<TrackerCacheResult> Results { get; set; }
public IEnumerable<string> Indexers { get; set; }
public IList<ManualSearchResultIndexer> Indexers { get; set; }
}
}

View File

@@ -207,11 +207,11 @@ namespace Jackett.Services
browseQuery.QueryType = "search";
browseQuery.SearchTerm = "";
browseQuery.IsTest = true;
var results = await indexer.ResultsForQuery(browseQuery);
logger.Info(string.Format("Found {0} releases from {1}", results.Count(), indexer.DisplayName));
if (results.Count() == 0)
var result = await indexer.ResultsForQuery(browseQuery);
logger.Info(string.Format("Found {0} releases from {1}", result.Releases.Count(), indexer.DisplayName));
if (result.Releases.Count() == 0)
throw new Exception("Found no results while trying to browse this tracker");
cacheService.CacheRssResults(indexer, results);
cacheService.CacheRssResults(indexer, result.Releases);
}
public void DeleteIndexer(string name)