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

View File

@@ -440,7 +440,15 @@
<script id="jackett-search-results" type="text/x-handlebars-template"> <script id="jackett-search-results" type="text/x-handlebars-template">
<hr /> <hr />
<p>Your search was done using: {{#each Indexers}}{{this}}, {{/each}}</p> <p>Your search was done using:
{{#each Indexers}}{{Name}}
{{#if Error}}
(<span title="{{Error}}"><b>Error</b></span>)
{{else}}
({{Results}})
{{/if}}
, {{/each}}
</p>
<table id="jackett-search-results-datatable" class="dataTable compact cell-border hover stripe"> <table id="jackett-search-results-datatable" class="dataTable compact cell-border hover stripe">
<thead> <thead>
<tr> <tr>

View File

@@ -19,6 +19,7 @@ using Jackett.Utils;
using Jackett.Utils.Clients; using Jackett.Utils.Clients;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
using Jackett.Models.DTO;
namespace Jackett.Controllers.V20 namespace Jackett.Controllers.V20
{ {
@@ -154,20 +155,67 @@ namespace Jackett.Controllers.V20
[HttpGet] [HttpGet]
public async Task<Models.DTO.ManualSearchResult> Results([FromUri]Models.DTO.ApiSearch request) public async Task<Models.DTO.ManualSearchResult> Results([FromUri]Models.DTO.ApiSearch request)
{ {
var manualResult = new ManualSearchResult();
var trackers = IndexerService.GetAllIndexers().Where(t => t.IsConfigured); var trackers = IndexerService.GetAllIndexers().Where(t => t.IsConfigured);
if (CurrentIndexer.ID != "all") if (CurrentIndexer.ID != "all")
trackers = trackers.Where(t => t.ID == CurrentIndexer.ID).ToList(); 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 tasks = trackers.ToList().Select(t => t.ResultsForQuery(CurrentQuery)).ToList();
var aggregateTask = Task.WhenAll(tasks); try
await aggregateTask;
var results = tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Where(t => t.Result.Count() > 0).SelectMany(t =>
{ {
var searchResults = t.Result; var aggregateTask = Task.WhenAll(tasks);
var indexer = searchResults.First().Origin; 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); cacheService.CacheRssResults(indexer, searchResults);
return searchResults.Select(result => return searchResults.Select(result =>
@@ -181,17 +229,7 @@ namespace Jackett.Controllers.V20
}); });
}).OrderByDescending(d => d.PublishDate).ToList(); }).OrderByDescending(d => d.PublishDate).ToList();
ConfigureCacheResults(results); ConfigureCacheResults(manualResult.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" };
logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", CurrentQuery.SanitizedSearchTerm, string.Join(", ", manualResult.Indexers), manualResult.Results.Count())); logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", CurrentQuery.SanitizedSearchTerm, string.Join(", ", manualResult.Indexers), manualResult.Results.Count()));
return manualResult; 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. // Some trackers do not support multiple category filtering so filter the releases that match manually.
int? newItemCount = null; int? newItemCount = null;
@@ -244,19 +282,19 @@ namespace Jackett.Controllers.V20
// Cache non query results // Cache non query results
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm)) if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
{ {
newItemCount = cacheService.GetNewItemCount(CurrentIndexer, releases); newItemCount = cacheService.GetNewItemCount(CurrentIndexer, result.Releases);
cacheService.CacheRssResults(CurrentIndexer, releases); cacheService.CacheRssResults(CurrentIndexer, result.Releases);
} }
// Log info // Log info
var logBuilder = new StringBuilder(); var logBuilder = new StringBuilder();
if (newItemCount != null) 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 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)) if (!string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
@@ -278,7 +316,7 @@ namespace Jackett.Controllers.V20
ImageDescription = CurrentIndexer.DisplayName 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"); r.Link = serverService.ConvertToProxyLink(r.Link, serverUrl, r.Origin.ID, "dl", r.Title + ".torrent");
return r; return r;
@@ -316,20 +354,20 @@ namespace Jackett.Controllers.V20
[JsonResponse] [JsonResponse]
public async Task<Models.DTO.TorrentPotatoResponse> Potato([FromUri]Models.DTO.TorrentPotatoRequest request) 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 // Cache non query results
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm)) if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
cacheService.CacheRssResults(CurrentIndexer, releases); cacheService.CacheRssResults(CurrentIndexer, result.Releases);
// Log info // Log info
if (string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm)) 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 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 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); var release = AutoMapper.Mapper.Map<ReleaseInfo>(r);
release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, CurrentIndexer.ID, "dl", release.Title + ".torrent"); 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,10 +219,12 @@ namespace Jackett.Indexers
public abstract Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson); public abstract Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson);
public virtual async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query) public virtual async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
{
try
{ {
if (!CanHandleQuery(query)) if (!CanHandleQuery(query))
return new ReleaseInfo[0]; return new IndexerResult(this, new ReleaseInfo[0]);
var results = await PerformQuery(query); var results = await PerformQuery(query);
results = FilterResults(query, results); results = FilterResults(query, results);
results = results.Select(r => results = results.Select(r =>
@@ -235,7 +237,12 @@ namespace Jackett.Indexers
return r; 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); protected abstract Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query);
} }
@@ -667,12 +674,12 @@ namespace Jackett.Indexers
return releases; 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); var result = await base.ResultsForQuery(query);
results = CleanLinks(results); result.Releases = CleanLinks(result.Releases);
return results; return result;
} }
protected virtual Uri UncleanLink(Uri link) protected virtual Uri UncleanLink(Uri link)

View File

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

View File

@@ -27,10 +27,12 @@ namespace Jackett.Indexers.Meta
return Task.FromResult(IndexerConfigurationStatus.Completed); return Task.FromResult(IndexerConfigurationStatus.Completed);
} }
public override async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query) public override async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
{
try
{ {
if (!CanHandleQuery(query)) if (!CanHandleQuery(query))
return new ReleaseInfo[0]; return new IndexerResult(this, new ReleaseInfo[0]);
var results = await PerformQuery(query); var results = await PerformQuery(query);
var correctedResults = results.Select(r => var correctedResults = results.Select(r =>
{ {
@@ -39,13 +41,18 @@ namespace Jackett.Indexers.Meta
return r; 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) protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{ {
var indexers = validIndexers; 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 fallbackStrategies = fallbackStrategyProvider.FallbackStrategiesForQuery(query);
var fallbackQueries = fallbackStrategies.Select(async f => await f.FallbackQueries()).SelectMany(t => t.Result); 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); 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 resultFilters = resultFilterProvider.FiltersForQuery(query);
var filteredResults = resultFilters.Select(async f => await f.FilterResults(unorderedResult)).SelectMany(t => t.Result); var filteredResults = resultFilters.Select(async f => await f.FilterResults(unorderedResult)).SelectMany(t => t.Result);
var uniqueFilteredResults = filteredResults.Distinct(); var uniqueFilteredResults = filteredResults.Distinct();

View File

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

View File

@@ -7,9 +7,20 @@ using System.Threading.Tasks;
namespace Jackett.Models.DTO 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 class ManualSearchResult
{ {
public IEnumerable<TrackerCacheResult> Results { get; set; } 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.QueryType = "search";
browseQuery.SearchTerm = ""; browseQuery.SearchTerm = "";
browseQuery.IsTest = true; browseQuery.IsTest = true;
var results = await indexer.ResultsForQuery(browseQuery); var result = await indexer.ResultsForQuery(browseQuery);
logger.Info(string.Format("Found {0} releases from {1}", results.Count(), indexer.DisplayName)); logger.Info(string.Format("Found {0} releases from {1}", result.Releases.Count(), indexer.DisplayName));
if (results.Count() == 0) if (result.Releases.Count() == 0)
throw new Exception("Found no results while trying to browse this tracker"); 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) public void DeleteIndexer(string name)