New: (Cardigann) Allow JSON filters

Fixes #844
pull/868/head
Qstick 3 years ago
parent c29fba3a2b
commit 76afb70b01

@ -28,7 +28,7 @@ namespace NzbDrone.Core.IndexerVersions
/* Update Service will fall back if version # does not exist for an indexer per Ta */
private const string DEFINITION_BRANCH = "master";
private const int DEFINITION_VERSION = 4;
private const int DEFINITION_VERSION = 5;
//Used when moving yml to C#
private readonly List<string> _defintionBlocklist = new List<string>()

@ -48,6 +48,9 @@ namespace NzbDrone.Core.Indexers.Cardigann
protected static readonly Regex _LogicFunctionRegex = new Regex(
$@"\b({string.Join("|", _SupportedLogicFunctions.Select(Regex.Escape))})(?:\s+(\(?\.[^\)\s]+\)?|""[^""]+"")){{2,}}");
// Matches CSS selectors for the JSON parser
protected static readonly Regex _jsonSelectorRegex = new Regex(@"\:(?<filter>.+?)\((?<key>.+?)\)(?=:|\z)", RegexOptions.Compiled);
public CardigannSettings Settings { get; set; }
public CardigannBase(IConfigService configService,
@ -234,13 +237,20 @@ namespace NzbDrone.Core.Indexers.Cardigann
if (selector.Selector != null)
{
var selector_Selector = ApplyGoTemplateText(selector.Selector.TrimStart('.'), variables);
var selection = parentObj.SelectToken(selector_Selector);
var selectorSelector = ApplyGoTemplateText(selector.Selector.TrimStart('.'), variables);
selectorSelector = JsonParseFieldSelector(parentObj, selectorSelector);
JToken selection = null;
if (selectorSelector != null)
{
selection = parentObj.SelectToken(selectorSelector);
}
if (selection == null)
{
if (required)
{
throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector_Selector, parentObj.ToString()));
throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selectorSelector, parentObj.ToString()));
}
return null;
@ -851,5 +861,89 @@ namespace NzbDrone.Core.Indexers.Cardigann
return settingsBaseUrl;
}
protected JArray JsonParseRowsSelector(JToken parsedJson, string rowSelector)
{
var selector = rowSelector.Split(':')[0];
var rowsObj = parsedJson.SelectToken(selector).Value<JArray>();
return new JArray(rowsObj.Where(t =>
JsonParseFieldSelector(t.Value<JObject>(), rowSelector.Remove(0, selector.Length)) != null));
}
private string JsonParseFieldSelector(JToken parsedJson, string rowSelector)
{
var selector = rowSelector.Split(':')[0];
JToken parsedObject;
if (string.IsNullOrWhiteSpace(selector))
{
parsedObject = parsedJson;
}
else if (parsedJson.SelectToken(selector) != null)
{
parsedObject = parsedJson.SelectToken(selector);
}
else
{
return null;
}
foreach (Match match in _jsonSelectorRegex.Matches(rowSelector))
{
var filter = match.Result("${filter}");
var key = match.Result("${key}");
Match innerMatch;
switch (filter)
{
case "has":
innerMatch = _jsonSelectorRegex.Match(key);
if (innerMatch.Success)
{
if (JsonParseFieldSelector(parsedObject, key) == null)
{
return null;
}
}
else
{
if (parsedObject.SelectToken(key) == null)
{
return null;
}
}
break;
case "not":
innerMatch = _jsonSelectorRegex.Match(key);
if (innerMatch.Success)
{
if (JsonParseFieldSelector(parsedObject, key) != null)
{
return null;
}
}
else
{
if (parsedObject.SelectToken(key) != null)
{
return null;
}
}
break;
case "contains":
if (!parsedObject.ToString().Contains(key))
{
return null;
}
break;
default:
_logger.Error(string.Format("CardigannIndexer ({0}): Unsupported selector: {1}", _definition.Id, rowSelector));
continue;
}
}
return selector;
}
}
}

@ -151,6 +151,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
public int After { get; set; }
public SelectorBlock Dateheaders { get; set; }
public SelectorBlock Count { get; set; }
public bool Multiple { get; set; } = false;
}
public class SearchPathBlock : RequestBlock
@ -200,8 +201,6 @@ namespace NzbDrone.Core.Indexers.Cardigann
public class ResponseBlock
{
public string Type { get; set; }
public string Attribute { get; set; }
public bool Multiple { get; set; }
public string NoResultsMessage { get; set; }
}
}

@ -83,16 +83,16 @@ namespace NzbDrone.Core.Indexers.Cardigann
}
}
var rowsObj = parsedJson.SelectToken(search.Rows.Selector);
if (rowsObj == null)
var rowsArray = JsonParseRowsSelector(parsedJson, search.Rows.Selector);
if (rowsArray == null)
{
throw new IndexerException(indexerResponse, "Error Parsing Rows Selector");
}
foreach (var row in rowsObj.Value<JArray>())
foreach (var row in rowsArray)
{
var selObj = request.SearchPath.Response.Attribute != null ? row.SelectToken(request.SearchPath.Response.Attribute).Value<JToken>() : row;
var mulRows = request.SearchPath.Response.Multiple == true ? selObj.Values<JObject>() : new List<JObject> { selObj.Value<JObject>() };
var selObj = search.Rows.Attribute != null ? row.SelectToken(search.Rows.Attribute).Value<JToken>() : row;
var mulRows = search.Rows.Multiple ? selObj.Values<JObject>() : new List<JObject> { selObj.Value<JObject>() };
foreach (var mulRow in mulRows)
{

@ -8,13 +8,6 @@ namespace NzbDrone.Core.Indexers.Cardigann
public Dictionary<string, object> Variables { get; private set; }
public SearchPathBlock SearchPath { get; private set; }
public CardigannRequest(string url, HttpAccept httpAccept, Dictionary<string, object> variables, SearchPathBlock searchPath)
: base(url, httpAccept)
{
Variables = variables;
SearchPath = searchPath;
}
public CardigannRequest(HttpRequest httpRequest, Dictionary<string, object> variables, SearchPathBlock searchPath)
: base(httpRequest)
{

Loading…
Cancel
Save