mirror of https://github.com/Jackett/Jackett
This commit is contained in:
parent
51f7d6c306
commit
6dab689533
19
README.md
19
README.md
|
@ -586,25 +586,26 @@ To get all Jackett indexers including their capabilities you can use `t=indexers
|
|||
|
||||
### Filter indexers
|
||||
|
||||
Another special "filter" indexer is avaible at <code>/api/v2.0/indexers/<i><b>filter</b></i>/results/torznab</code>
|
||||
It will query the configured indexers that match the <i><b>filter</b></i> expression criterias and return the combined results as "all".
|
||||
Another special "filter" indexer is available at `/api/v2.0/indexers/<filter>/results/torznab`
|
||||
It will query the configured indexers that match the `<filter>` expression criterias and return the combined results as "all".
|
||||
|
||||
Supported filters
|
||||
Filter | Condition
|
||||
-|-
|
||||
<code>type:<i><b>type</b></i></code> | where the indexer type is equal to <i><b>type</b></i>
|
||||
<code>tag:<i><b>tag</b></i></code> | where the indexer tags contains <i><b>tag</b></i>
|
||||
<code>lang:<i><b>tag</b></i></code> | where the indexer language start with <i><b>lang</b></i>
|
||||
`type:<type>` | where the indexer type is equal to `<type>`
|
||||
`tag:<tag>` | where the indexer tags contains `<tag>`
|
||||
`lang:<tag>` | where the indexer language start with `<lang>`
|
||||
`test:{passed|failed}` | where the last indexer test performed `passed` or `failed`
|
||||
|
||||
Supported operators
|
||||
Operator | Condition
|
||||
-|-
|
||||
<code>!<i><b>filter</b></i></code> | where not <i><b>filter</b></i>
|
||||
<code><i><b>filter1</b></i>+<i><b>filter2</b></i>+...</code> | where <i><b>filter1</b></i> and <i><b>filter2</b> and ...</
|
||||
<code><i><b>filter1</b></i>,<i><b>filter2</b></i>,...</code> | where <i><b>filter1</b></i> or <i><b>filter2</b> or ...</
|
||||
`!<expr>` | where not `<expr>`
|
||||
`<expr1>+<expr2>[+<expr3>...]` | where `<expr1>` and `<expr2>` [and `<expr3>`...]
|
||||
`<expr1>,<expr2>[+<expr3>...]` | where `<expr1>` or `<expr2>` [or `<expr3>`...]
|
||||
|
||||
Example:
|
||||
The "filter" indexer at <code>/api/v2.0/indexers/<b>tag:group1,!type:private+lang:en</b>/results/torznab</code> will query all the configured indexers tagged with `group1` or all the indexers not private and with `en` language (`en-en`,`en-us`,...)
|
||||
The "filter" indexer at `/api/v2.0/indexers/tag:group1,!type:private+lang:en/results/torznab` will query all the configured indexers tagged with `group1` or all the indexers not private and with `en` language (`en-en`,`en-us`,...)
|
||||
|
||||
## Installation on Windows
|
||||
We recommend you install Jackett as a Windows service using the supplied installer. You may also download the zipped version if you would like to configure everything manually.
|
||||
|
|
|
@ -84,6 +84,10 @@ function tag_filter(indexer) {
|
|||
return indexer.tags.map(t => t.toLowerCase()).indexOf(this.value.toLowerCase()) > -1;
|
||||
}
|
||||
|
||||
function state_filter(indexer) {
|
||||
return indexer.state == this.value;
|
||||
}
|
||||
|
||||
function getJackettConfig(callback) {
|
||||
api.getServerConfig(callback).fail(function () {
|
||||
doNotify("Error loading Jackett settings, request to Jackett server failed, is server running ?", "danger", "glyphicon glyphicon-alert");
|
||||
|
@ -211,6 +215,9 @@ function configureFilters(indexers) {
|
|||
availableFilters.push(f);
|
||||
}
|
||||
|
||||
availableFilters.push({id: "test:passed", apply: state_filter, value: "success" });
|
||||
availableFilters.push({id: "test:failed", apply: state_filter, value: "error" });
|
||||
|
||||
["public", "private", "semi-private"]
|
||||
.map(t => { return { id: "type:" + t, apply: type_filter, value: t } })
|
||||
.forEach(add);
|
||||
|
@ -606,6 +613,10 @@ function updateTestState(id, state, message, parent) {
|
|||
}).rows().invalidate('dom');
|
||||
if (state != "inprogres")
|
||||
dt.draw();
|
||||
|
||||
var indexer = configuredIndexers.find(x => x.id == id);
|
||||
if (indexer)
|
||||
indexer.state = state;
|
||||
}
|
||||
|
||||
function testIndexer(id, notifyResult) {
|
||||
|
|
|
@ -16,10 +16,11 @@ namespace Jackett.Common.Utils
|
|||
});
|
||||
public static readonly FilterFuncComponent Language = Component("lang", args => indexer => indexer.Language.StartsWith(args, StringComparison.InvariantCultureIgnoreCase));
|
||||
public static readonly FilterFuncComponent Type = Component("type", args => indexer => string.Equals(indexer.Type, args, StringComparison.InvariantCultureIgnoreCase));
|
||||
public static readonly FilterFuncComponent Test = TestFilterFunc.Default;
|
||||
|
||||
static FilterFunc()
|
||||
{
|
||||
Expression = new FilterFuncExpression(Tag, Language, Type);
|
||||
Expression = new FilterFuncExpression(Tag, Language, Type, Test);
|
||||
}
|
||||
|
||||
public static bool TryParse(string source, out Func<IIndexer, bool> func)
|
||||
|
@ -49,10 +50,10 @@ namespace Jackett.Common.Utils
|
|||
public override Func<IIndexer, bool> ToFunc(string args)
|
||||
{
|
||||
var func = builder(args);
|
||||
return indexer => indexer != null
|
||||
? indexer.IsConfigured && func(indexer)
|
||||
: throw new ArgumentNullException(nameof(indexer));
|
||||
return indexer => IsValid(indexer) && func(indexer);
|
||||
}
|
||||
}
|
||||
|
||||
protected static bool IsValid(IIndexer indexer) => (indexer?.IsConfigured ?? throw new ArgumentNullException(nameof(indexer)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
|
||||
using Jackett.Common.Indexers;
|
||||
|
||||
namespace Jackett.Common.Utils.FilterFuncs
|
||||
{
|
||||
public class TestFilterFunc : FilterFuncComponent
|
||||
{
|
||||
public static readonly TestFilterFunc Default = new TestFilterFunc();
|
||||
public const string Passed = "passed";
|
||||
public const string Failed = "failed";
|
||||
|
||||
private TestFilterFunc() : base("test")
|
||||
{
|
||||
}
|
||||
|
||||
public override Func<IIndexer, bool> ToFunc(string args)
|
||||
{
|
||||
if (args == null)
|
||||
throw new ArgumentNullException(nameof(args));
|
||||
if (string.Equals(Passed, args, StringComparison.InvariantCultureIgnoreCase))
|
||||
return i => IsValid(i) && i.LastError == null;
|
||||
if (string.Equals(Failed, args, StringComparison.InvariantCultureIgnoreCase))
|
||||
return i => IsValid(i) && i.LastError != null;
|
||||
throw new ArgumentException($"Invalid filter. Status should be '{Passed}' or '{Failed}'", nameof(args));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace Jackett.Test.Common.Utils.FilterFuncs
|
||||
{
|
||||
public class IndexerStub : IIndexer
|
||||
public abstract class IndexerBaseStub : IIndexer
|
||||
{
|
||||
public virtual string SiteLink => throw TestExceptions.UnexpectedInvocation;
|
||||
|
|
@ -6,9 +6,9 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
[TestFixture]
|
||||
public class LanguageFuncTests
|
||||
{
|
||||
private class LanguageIndexerStub : IndexerStub
|
||||
private class IndexerStub : IndexerBaseStub
|
||||
{
|
||||
public LanguageIndexerStub(string language)
|
||||
public IndexerStub(string language)
|
||||
{
|
||||
Language = language;
|
||||
}
|
||||
|
@ -24,19 +24,19 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
var language = "en";
|
||||
var region = "US";
|
||||
|
||||
var lrLanguage = new LanguageIndexerStub($"{language.ToLower()}-{region.ToLower()}");
|
||||
var lrLanguage = new IndexerStub(language: $"{language.ToLower()}-{region.ToLower()}");
|
||||
var LRFilterFunc = Language.ToFunc($"{language.ToUpper()}-{region.ToUpper()}");
|
||||
Assert.IsTrue(LRFilterFunc(lrLanguage));
|
||||
|
||||
var lRLanguage = new LanguageIndexerStub($"{language.ToLower()}-{region.ToUpper()}");
|
||||
var lRLanguage = new IndexerStub(language: $"{language.ToLower()}-{region.ToUpper()}");
|
||||
var LrFilterFunc = Language.ToFunc($"{language.ToUpper()}-{region.ToLower()}");
|
||||
Assert.IsTrue(LrFilterFunc(lRLanguage));
|
||||
|
||||
var LrLanguage = new LanguageIndexerStub($"{language.ToUpper()}-{region.ToLower()}");
|
||||
var LrLanguage = new IndexerStub(language: $"{language.ToUpper()}-{region.ToLower()}");
|
||||
var lRFilterFunc = Language.ToFunc($"{language.ToLower()}-{region.ToUpper()}");
|
||||
Assert.IsTrue(lRFilterFunc(LrLanguage));
|
||||
|
||||
var LRLanguage = new LanguageIndexerStub($"{language.ToUpper()}-{region.ToUpper()}");
|
||||
var LRLanguage = new IndexerStub(language: $"{language.ToUpper()}-{region.ToUpper()}");
|
||||
var lrFilterFunc = Language.ToFunc($"{language.ToLower()}-{region.ToLower()}");
|
||||
Assert.IsTrue(lrFilterFunc(LRLanguage));
|
||||
}
|
||||
|
@ -47,9 +47,9 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
var language = "en";
|
||||
var funcFilter = Language.ToFunc(language);
|
||||
|
||||
Assert.IsTrue(funcFilter(new LanguageIndexerStub(language)));
|
||||
Assert.IsTrue(funcFilter(new LanguageIndexerStub($"{language}-region1")));
|
||||
Assert.IsFalse(funcFilter(new LanguageIndexerStub($"language2-{language}")));
|
||||
Assert.IsTrue(funcFilter(new IndexerStub(language: language)));
|
||||
Assert.IsTrue(funcFilter(new IndexerStub(language: $"{language}-region1")));
|
||||
Assert.IsFalse(funcFilter(new IndexerStub(language: $"language2-{language}")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
[TestFixture]
|
||||
public class TagFuncTests
|
||||
{
|
||||
private class TagsIndexerStub : IndexerStub
|
||||
private class IndexerStub : IndexerBaseStub
|
||||
{
|
||||
public TagsIndexerStub(params string[] tags)
|
||||
public IndexerStub(params string[] tags)
|
||||
{
|
||||
Tags = tags;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
{
|
||||
var tagId = "g1";
|
||||
|
||||
var tag = new TagsIndexerStub(tagId);
|
||||
var tag = new IndexerStub(tagId);
|
||||
|
||||
var upperTarget = Tag.ToFunc(tagId.ToUpper());
|
||||
Assert.IsTrue(upperTarget(tag));
|
||||
|
@ -38,10 +38,10 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
var tagId = "g1";
|
||||
var target = Tag.ToFunc(tagId);
|
||||
|
||||
Assert.IsTrue(target(new TagsIndexerStub(tagId)));
|
||||
Assert.IsTrue(target(new TagsIndexerStub(tagId, "g2")));
|
||||
Assert.IsTrue(target(new TagsIndexerStub("g2", tagId)));
|
||||
Assert.IsFalse(target(new TagsIndexerStub("g2")));
|
||||
Assert.IsTrue(target(new IndexerStub(tagId)));
|
||||
Assert.IsTrue(target(new IndexerStub(tagId, "g2")));
|
||||
Assert.IsTrue(target(new IndexerStub("g2", tagId)));
|
||||
Assert.IsFalse(target(new IndexerStub("g2")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using Jackett.Common.Utils;
|
||||
using Jackett.Common.Utils.FilterFuncs;
|
||||
using Jackett.Test.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Jackett.Test.Common.Utils.FilterFuncs
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestFuncTests
|
||||
{
|
||||
private static readonly IndexerStub HealthyIndexer = new IndexerStub(lastError: null);
|
||||
private static readonly IndexerStub ErrorIndexer = new IndexerStub(lastError: "error");
|
||||
|
||||
private class IndexerStub : IndexerBaseStub
|
||||
{
|
||||
private readonly string lastError;
|
||||
|
||||
public IndexerStub(string lastError)
|
||||
{
|
||||
this.lastError = lastError;
|
||||
}
|
||||
|
||||
public override bool IsConfigured => true;
|
||||
|
||||
public override string LastError
|
||||
{
|
||||
get => lastError;
|
||||
set => throw TestExceptions.UnexpectedInvocation;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NullStatus_ThrowsException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => FilterFunc.Test.ToFunc(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EmptyStatus_ThrowsException()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => FilterFunc.Test.ToFunc(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InvalidStatus_ThrowsException()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => FilterFunc.Test.ToFunc(TestFilterFunc.Passed + TestFilterFunc.Failed));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PassedFilter()
|
||||
{
|
||||
var passedFilterFunc = FilterFunc.Test.ToFunc(TestFilterFunc.Passed);
|
||||
Assert.IsTrue(passedFilterFunc(HealthyIndexer));
|
||||
Assert.IsFalse(passedFilterFunc(ErrorIndexer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailedFilter()
|
||||
{
|
||||
var failedFilterFunc = FilterFunc.Test.ToFunc(TestFilterFunc.Failed);
|
||||
Assert.IsFalse(failedFilterFunc(HealthyIndexer));
|
||||
Assert.IsTrue(failedFilterFunc(ErrorIndexer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PassedFilter_CaseInsensitiveSource()
|
||||
{
|
||||
var upperFilterFunc = FilterFunc.Test.ToFunc(TestFilterFunc.Passed.ToUpper());
|
||||
Assert.IsTrue(upperFilterFunc(HealthyIndexer));
|
||||
Assert.IsFalse(upperFilterFunc(ErrorIndexer));
|
||||
|
||||
var lowerFilterFunc = FilterFunc.Test.ToFunc(TestFilterFunc.Passed.ToLower());
|
||||
Assert.IsTrue(lowerFilterFunc(HealthyIndexer));
|
||||
Assert.IsFalse(lowerFilterFunc(ErrorIndexer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailedFilter_CaseInsensitiveSource()
|
||||
{
|
||||
var upperFilterFunc = FilterFunc.Test.ToFunc(TestFilterFunc.Failed.ToUpper());
|
||||
Assert.IsFalse(upperFilterFunc(HealthyIndexer));
|
||||
Assert.IsTrue(upperFilterFunc(ErrorIndexer));
|
||||
|
||||
var lowerFilterFunc = FilterFunc.Test.ToFunc(TestFilterFunc.Failed.ToLower());
|
||||
Assert.IsFalse(lowerFilterFunc(HealthyIndexer));
|
||||
Assert.IsTrue(lowerFilterFunc(ErrorIndexer));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using NUnit.Framework;
|
||||
|
||||
using static Jackett.Common.Utils.FilterFunc;
|
||||
|
||||
namespace Jackett.Test.Common.Utils.FilterFuncs
|
||||
|
@ -6,9 +7,9 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
[TestFixture]
|
||||
public class TypeFuncTests
|
||||
{
|
||||
private class TypeIndexerStub : IndexerStub
|
||||
private class IndexerStub : IndexerBaseStub
|
||||
{
|
||||
public TypeIndexerStub(string type)
|
||||
public IndexerStub(string type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
@ -23,8 +24,8 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
{
|
||||
var typeId = "type-id";
|
||||
|
||||
var lowerType = new TypeIndexerStub(typeId.ToLower());
|
||||
var upperType = new TypeIndexerStub(typeId.ToUpper());
|
||||
var lowerType = new IndexerStub(type: typeId.ToLower());
|
||||
var upperType = new IndexerStub(type: typeId.ToUpper());
|
||||
|
||||
var upperFilterFunc = Type.ToFunc(typeId.ToUpper());
|
||||
Assert.IsTrue(upperFilterFunc(lowerType));
|
||||
|
@ -42,11 +43,9 @@ namespace Jackett.Test.Common.Utils.FilterFuncs
|
|||
|
||||
var funcFilter = Type.ToFunc($"{typeId}");
|
||||
|
||||
Assert.IsFalse(funcFilter(new TypeIndexerStub($"{typeId}suffix")));
|
||||
Assert.IsFalse(funcFilter(new TypeIndexerStub($"prefix{typeId}")));
|
||||
Assert.IsFalse(funcFilter(new TypeIndexerStub($"prefix{typeId}suffix")));
|
||||
Assert.IsFalse(funcFilter(new IndexerStub(type: $"{typeId}suffix")));
|
||||
Assert.IsFalse(funcFilter(new IndexerStub(type: $"prefix{typeId}")));
|
||||
Assert.IsFalse(funcFilter(new IndexerStub(type: $"prefix{typeId}suffix")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue