mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-17 17:34:09 +02:00
Merge branch 'master' of https://github.com/Jackett/Jackett
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
|
30
src/Jackett/IndexerException.cs
Normal file
30
src/Jackett/IndexerException.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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" />
|
||||
|
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user