From bceebc34c134db8140a307e25312cb15e0ff5d63 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Thu, 30 Mar 2023 14:57:04 +0300 Subject: [PATCH] New: (Cardigann) Bump to v9 (#1551) * New: (Cardigann) Add MissingAttributeEqualsNoResults support (cherry picked from commit 4e8bb37a5c984b074e7a0103ad3fd403f5410038) * New: (Cardigann) Add AllowEmptyInputs * New: (Cardigann) Bump to v9 * New: (Cardigann) Add default value for fields --- .../IndexerDefinitionUpdateService.cs | 2 +- .../Definitions/Cardigann/CardigannBase.cs | 16 +++++-- .../Cardigann/CardigannDefinition.cs | 3 ++ .../Definitions/Cardigann/CardigannParser.cs | 47 ++++++++++++++----- .../Cardigann/CardigannRequestGenerator.cs | 8 +++- 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 8c8c83224..d0edcec25 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -29,7 +29,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 = 8; + private const int DEFINITION_VERSION = 9; // Used when moving yml to C# private readonly List _definitionBlocklist = new () diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index dcfeb4024..afee4d523 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -825,9 +825,19 @@ namespace NzbDrone.Core.Indexers.Cardigann protected JArray JsonParseRowsSelector(JToken parsedJson, string rowSelector) { var selector = rowSelector.Split(':')[0]; - var rowsObj = parsedJson.SelectToken(selector).Value(); - return new JArray(rowsObj.Where(t => - JsonParseFieldSelector(t.Value(), rowSelector.Remove(0, selector.Length)) != null)); + + try + { + var rowsObj = parsedJson.SelectToken(selector).Value(); + + return new JArray(rowsObj.Where(t => JsonParseFieldSelector(t.Value(), rowSelector.Remove(0, selector.Length)) != null)); + } + catch (Exception ex) + { + _logger.Trace(ex, "Failed to parse JSON rows for selector \"{0}\"", rowSelector); + + return null; + } } private string JsonParseFieldSelector(JToken parsedJson, string rowSelector) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index d3f6019da..1e64df388 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -116,6 +116,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { public string Selector { get; set; } public bool Optional { get; set; } + public string Default { get; set; } public string Text { get; set; } public string Attribute { get; set; } public string Remove { get; set; } @@ -146,6 +147,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public List Paths { get; set; } public Dictionary> Headers { get; set; } public List Keywordsfilters { get; set; } + public bool AllowEmptyInputs { get; set; } public Dictionary Inputs { get; set; } public List Error { get; set; } public List Preprocessingfilters { get; set; } @@ -159,6 +161,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public SelectorBlock Dateheaders { get; set; } public SelectorBlock Count { get; set; } public bool Multiple { get; set; } + public bool MissingAttributeEqualsNoResults { get; set; } } public class SearchPathBlock : RequestBlock diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index de392978e..ec646848c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -90,8 +90,14 @@ namespace NzbDrone.Core.Indexers.Cardigann } var rowsArray = JsonParseRowsSelector(parsedJson, search.Rows.Selector); + if (rowsArray == null) { + if (search.Rows.MissingAttributeEqualsNoResults) + { + return releases; + } + throw new IndexerException(indexerResponse, "Error Parsing Rows Selector"); } @@ -117,6 +123,7 @@ namespace NzbDrone.Core.Indexers.Cardigann string value = null; var variablesKey = ".Result." + fieldName; var isOptional = OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional; + try { var parentObj = mulRow; @@ -126,28 +133,35 @@ namespace NzbDrone.Core.Indexers.Cardigann } value = HandleJsonSelector(field.Value, parentObj, variables, !isOptional); - if (isOptional && string.IsNullOrWhiteSpace(value)) + + if (isOptional && value.IsNullOrWhiteSpace()) { - variables[variablesKey] = null; - continue; + var defaultValue = ApplyGoTemplateText(field.Value.Default, variables); + + if (defaultValue.IsNullOrWhiteSpace()) + { + variables[variablesKey] = null; + continue; + } + + value = defaultValue; } variables[variablesKey] = ParseFields(value, fieldName, release, fieldModifiers, searchUrlUri); } catch (Exception ex) { - if (!variables.ContainsKey(variablesKey)) + if (!variables.ContainsKey(variablesKey) || isOptional) { variables[variablesKey] = null; } if (isOptional) { - variables[variablesKey] = null; continue; } - throw new CardigannException(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "", ex.Message)); + throw new CardigannException($"Error while parsing field={field.Key}, selector={field.Value.Selector}, value={value ?? ""}: {ex.Message}", ex); } } @@ -248,34 +262,41 @@ namespace NzbDrone.Core.Indexers.Cardigann string value = null; var variablesKey = ".Result." + fieldName; var isOptional = OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional; + try { value = HandleSelector(field.Value, row, variables, !isOptional); - if (isOptional && string.IsNullOrWhiteSpace(value)) + if (isOptional && value.IsNullOrWhiteSpace()) { - variables[variablesKey] = null; - continue; + var defaultValue = ApplyGoTemplateText(field.Value.Default, variables); + + if (defaultValue.IsNullOrWhiteSpace()) + { + variables[variablesKey] = null; + continue; + } + + value = defaultValue; } variables[variablesKey] = ParseFields(value, fieldName, release, fieldModifiers, searchUrlUri); } catch (Exception ex) { - if (!variables.ContainsKey(variablesKey)) + if (!variables.ContainsKey(variablesKey) || isOptional) { variables[variablesKey] = null; } - if (OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional) + if (isOptional) { - variables[variablesKey] = null; continue; } if (indexerLogging) { - _logger.Trace("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value == null ? "" : value, ex.Message); + _logger.Trace(ex, "Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "", ex.Message); } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 97f588648..006745755 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -9,6 +9,7 @@ using AngleSharp.Html.Dom; using AngleSharp.Html.Parser; using Newtonsoft.Json.Linq; using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Definitions.Cardigann; @@ -1119,7 +1120,12 @@ namespace NzbDrone.Core.Indexers.Cardigann } else { - queryCollection.Add(input.Key, ApplyGoTemplateText(input.Value, variables)); + var inputValue = ApplyGoTemplateText(input.Value, variables); + + if (inputValue.IsNotNullOrWhiteSpace() || search.AllowEmptyInputs) + { + queryCollection.Add(input.Key, inputValue); + } } } }