diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index d12d9a042..5941c3666 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.IndexerVersions { /* Update Service will fall back if version # does not exist for an indexer per Ta */ - private const int DEFINITION_VERSION = 2; + private const int DEFINITION_VERSION = 3; private readonly List _defintionBlocklist = new List() { "aither", diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index fe4467ea3..d2b0b33cb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Indexers.Cardigann return element.QuerySelector(selector); } - protected string HandleSelector(SelectorBlock selector, IElement dom, Dictionary variables = null) + protected string HandleSelector(SelectorBlock selector, IElement dom, Dictionary variables = null, bool required = true) { if (selector.Text != null) { @@ -164,7 +164,12 @@ namespace NzbDrone.Core.Indexers.Cardigann if (selection == null) { - throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector.Selector, dom.ToHtmlPretty())); + if (required) + { + throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector.Selector, dom.ToHtmlPretty())); + } + + return null; } } @@ -189,7 +194,12 @@ namespace NzbDrone.Core.Indexers.Cardigann if (value == null) { - throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", selector.Case), selection.ToHtmlPretty())); + if (required) + { + throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", selector.Case), selection.ToHtmlPretty())); + } + + return null; } } else if (selector.Attribute != null) @@ -197,7 +207,12 @@ namespace NzbDrone.Core.Indexers.Cardigann value = selection.GetAttribute(selector.Attribute); if (value == null) { - throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", selector.Attribute, selection.ToHtmlPretty())); + if (required) + { + throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", selector.Attribute, selection.ToHtmlPretty())); + } + + return null; } } else @@ -208,6 +223,57 @@ namespace NzbDrone.Core.Indexers.Cardigann return ApplyFilters(ParseUtil.NormalizeSpace(value), selector.Filters, variables); } + protected string HandleJsonSelector(SelectorBlock selector, JToken parentObj, Dictionary variables = null, bool required = true) + { + if (selector.Text != null) + { + return ApplyFilters(ApplyGoTemplateText(selector.Text, variables), selector.Filters, variables); + } + + string value = null; + + if (selector.Selector != null) + { + var selector_Selector = ApplyGoTemplateText(selector.Selector.TrimStart('.'), variables); + var selection = parentObj.SelectToken(selector_Selector); + if (selection == null) + { + if (required) + { + throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector_Selector, parentObj.ToString())); + } + + return null; + } + + value = selection.Value(); + } + + if (selector.Case != null) + { + foreach (var jcase in selector.Case) + { + if (value.Equals(jcase.Key) || jcase.Key.Equals("*")) + { + value = jcase.Value; + break; + } + } + + if (value == null) + { + if (required) + { + throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", selector.Case), parentObj.ToString())); + } + + return null; + } + } + + return ApplyFilters(ParseUtil.NormalizeSpace(value), selector.Filters, variables); + } + protected Dictionary GetBaseTemplateVariables() { var indexerLogging = _configService.LogIndexerResponse; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index c666af501..4c7f0f32f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -150,13 +150,15 @@ namespace NzbDrone.Core.Indexers.Cardigann { public int After { get; set; } public SelectorBlock Dateheaders { get; set; } + public SelectorBlock Count { get; set; } } public class SearchPathBlock : RequestBlock { public List Categories { get; set; } public bool Inheritinputs { get; set; } = true; - public bool Followredirect { get; set; } = false; + public bool Followredirect { get; set; } + public ResponseBlock Response { get; set; } } public class RequestBlock @@ -194,4 +196,12 @@ namespace NzbDrone.Core.Indexers.Cardigann { public SelectorField Pathselector { get; set; } } + + public class ResponseBlock + { + public string Type { get; set; } + public string Attribute { get; set; } + public bool Multiple { get; set; } + public string NoResultsMessage { get; set; } + } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 525e67410..b59eb8f9e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -5,6 +5,7 @@ using System.Net; using System.Text.RegularExpressions; using AngleSharp.Dom; using AngleSharp.Html.Parser; +using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; @@ -55,59 +56,46 @@ namespace NzbDrone.Core.Indexers.Cardigann var searchUrlUri = new Uri(request.Url.FullUri); - try + if (request.SearchPath.Response != null && request.SearchPath.Response.Type.Equals("json")) { - var searchResultParser = new HtmlParser(); - var searchResultDocument = searchResultParser.ParseDocument(results); - - /* checkForError(response, Definition.Search.Error); */ - - if (search.Preprocessingfilters != null) + if (request.SearchPath.Response != null && request.SearchPath.Response.NoResultsMessage != null && (request.SearchPath.Response.NoResultsMessage.Equals(results) || (request.SearchPath.Response.NoResultsMessage == string.Empty && results == string.Empty))) { - results = ApplyFilters(results, search.Preprocessingfilters, variables); - searchResultDocument = searchResultParser.ParseDocument(results); - _logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results)); + return releases; } - var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables); - var rowsDom = searchResultDocument.QuerySelectorAll(rowsSelector); - var rows = new List(); - foreach (var rowDom in rowsDom) + var parsedJson = JToken.Parse(results); + if (parsedJson == null) { - rows.Add(rowDom); + throw new Exception("Error Parsing Json Response"); } - // merge following rows for After selector - var after = search.Rows.After; - if (after > 0) + if (search.Rows.Count != null) { - for (var i = 0; i < rows.Count; i += 1) + var countVal = HandleJsonSelector(search.Rows.Count, parsedJson, variables); + if (int.TryParse(countVal, out var count)) { - var currentRow = rows[i]; - for (var j = 0; j < after; j += 1) + if (count < 1) { - var mergeRowIndex = i + j + 1; - var mergeRow = rows[mergeRowIndex]; - var mergeNodes = new List(); - foreach (var node in mergeRow.ChildNodes) - { - mergeNodes.Add(node); - } - - currentRow.Append(mergeNodes.ToArray()); + return releases; } - - rows.RemoveRange(i + 1, after); } } - foreach (var row in rows) + var rowsObj = parsedJson.SelectToken(search.Rows.Selector); + if (rowsObj == null) { - try + throw new Exception("Error Parsing Rows Selector"); + } + + foreach (var row in rowsObj.Value()) + { + var selObj = request.SearchPath.Response.Attribute != null ? row.SelectToken(request.SearchPath.Response.Attribute).Value() : row; + var mulRows = request.SearchPath.Response.Multiple == true ? selObj.Values() : new List { selObj.Value() }; + + foreach (var mulRow in mulRows) { var release = new TorrentInfo(); - // Parse fields foreach (var field in search.Fields) { var fieldParts = field.Key.Split('|'); @@ -120,200 +108,23 @@ 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); - switch (fieldName) + var parentObj = mulRow; + if (field.Value.Selector != null && field.Value.Selector.StartsWith("..")) { - case "download": - if (string.IsNullOrEmpty(value)) - { - value = null; - release.DownloadUrl = null; - break; - } - - if (value.StartsWith("magnet:")) - { - release.MagnetUrl = value; - value = release.MagnetUrl; - } - else - { - release.DownloadUrl = ResolvePath(value, searchUrlUri).AbsoluteUri; - value = release.DownloadUrl; - } - - break; - case "magnet": - var magnetUri = value; - release.MagnetUrl = magnetUri; - value = magnetUri.ToString(); - break; - case "infohash": - release.InfoHash = value; - break; - case "details": - var url = ResolvePath(value, searchUrlUri)?.AbsoluteUri; - release.InfoUrl = url; - release.Guid = url; - value = url.ToString(); - break; - case "comments": - var commentsUrl = ResolvePath(value, searchUrlUri); - if (release.CommentUrl == null) - { - release.CommentUrl = commentsUrl.AbsoluteUri; - } - - value = commentsUrl.ToString(); - break; - case "title": - if (fieldModifiers.Contains("append")) - { - release.Title += value; - } - else - { - release.Title = value; - } - - value = release.Title; - break; - case "description": - if (fieldModifiers.Contains("append")) - { - release.Description += value; - } - else - { - release.Description = value; - } - - value = release.Description; - break; - case "category": - var cats = MapTrackerCatToNewznab(value); - if (cats.Any()) - { - if (release.Categories == null || fieldModifiers.Contains("noappend")) - { - release.Categories = cats; - } - else - { - release.Categories = release.Categories.Union(cats).ToList(); - } - } - - value = release.Categories.ToString(); - break; - case "size": - release.Size = ParseUtil.GetBytes(value); - value = release.Size.ToString(); - break; - case "leechers": - var leechers = ParseUtil.CoerceLong(value); - leechers = leechers < 5000000L ? leechers : 0; // to fix #6558 - if (release.Peers == null) - { - release.Peers = (int)leechers; - } - else - { - release.Peers += (int)leechers; - } - - value = leechers.ToString(); - break; - case "seeders": - release.Seeders = ParseUtil.CoerceInt(value); - release.Seeders = release.Seeders < 5000000L ? release.Seeders : 0; // to fix #6558 - if (release.Peers == null) - { - release.Peers = release.Seeders; - } - else - { - release.Peers += release.Seeders; - } - - value = release.Seeders.ToString(); - break; - case "date": - release.PublishDate = DateTimeUtil.FromUnknown(value); - value = release.PublishDate.ToString(DateTimeUtil.Rfc1123ZPattern); - break; - case "files": - release.Files = ParseUtil.CoerceInt(value); - value = release.Files.ToString(); - break; - case "grabs": - release.Grabs = ParseUtil.CoerceInt(value); - value = release.Grabs.ToString(); - break; - case "downloadvolumefactor": - release.DownloadVolumeFactor = ParseUtil.CoerceDouble(value); - value = release.DownloadVolumeFactor.ToString(); - break; - case "uploadvolumefactor": - release.UploadVolumeFactor = ParseUtil.CoerceDouble(value); - value = release.UploadVolumeFactor.ToString(); - break; - case "minimumratio": - release.MinimumRatio = ParseUtil.CoerceDouble(value); - value = release.MinimumRatio.ToString(); - break; - case "minimumseedtime": - release.MinimumSeedTime = ParseUtil.CoerceLong(value); - value = release.MinimumSeedTime.ToString(); - break; - case "imdb": - release.ImdbId = (int)ParseUtil.GetLongFromString(value); - value = release.ImdbId.ToString(); - break; - case "tmdbid": - var tmdbIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var tmdbIDMatch = tmdbIDRegEx.Match(value); - var tmdbID = tmdbIDMatch.Groups[1].Value; - release.TmdbId = (int)ParseUtil.CoerceLong(tmdbID); - value = release.TmdbId.ToString(); - break; - case "rageid": - var rageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var rageIDMatch = rageIDRegEx.Match(value); - var rageID = rageIDMatch.Groups[1].Value; - release.TvRageId = (int)ParseUtil.CoerceLong(rageID); - value = release.TvRageId.ToString(); - break; - case "tvdbid": - var tvdbIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var tvdbIdMatch = tvdbIdRegEx.Match(value); - var tvdbId = tvdbIdMatch.Groups[1].Value; - release.TvdbId = (int)ParseUtil.CoerceLong(tvdbId); - value = release.TvdbId.ToString(); - break; - case "poster": - if (!string.IsNullOrWhiteSpace(value)) - { - var poster = ResolvePath(value, searchUrlUri); - release.PosterUrl = poster.AbsoluteUri; - } - - value = release.PosterUrl; - break; - - //case "author": - // release.Author = value; - // break; - //case "booktitle": - // release.BookTitle = value; - // break; - default: - break; + parentObj = row.Value(); } - variables[variablesKey] = value; + value = HandleJsonSelector(field.Value, parentObj, variables, !isOptional); + if (isOptional && string.IsNullOrWhiteSpace(value)) + { + variables[variablesKey] = null; + continue; + } + + variables[variablesKey] = ParseFields(value, fieldName, release, fieldModifiers, searchUrlUri); } catch (Exception ex) { @@ -322,141 +133,202 @@ namespace NzbDrone.Core.Indexers.Cardigann 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); - } - } - } - - var filters = search.Rows.Filters; - var skipRelease = false; - if (filters != null) - { - foreach (var filter in filters) - { - switch (filter.Name) - { - case "andmatch": - var characterLimit = -1; - if (filter.Args != null) - { - characterLimit = int.Parse(filter.Args); - } - - /* - if (query.ImdbID != null && TorznabCaps.SupportsImdbMovieSearch) - { - break; // skip andmatch filter for imdb searches - } - - if (query.TmdbID != null && TorznabCaps.SupportsTmdbMovieSearch) - { - break; // skip andmatch filter for tmdb searches - } - - if (query.TvdbID != null && TorznabCaps.SupportsTvdbSearch) - { - break; // skip andmatch filter for tvdb searches - } - - var queryKeywords = variables[".Keywords"] as string; - - if (!query.MatchQueryStringAND(release.Title, characterLimit, queryKeywords)) - { - _logger.Debug(string.Format("CardigannIndexer ({0}): skipping {1} (andmatch filter)", _definition.Id, release.Title)); - skipRelease = true; - } - */ - - break; - case "strdump": - // for debugging - _logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToHtmlPretty())); - break; - default: - _logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", _definition.Id, filter.Name)); - break; - } - } - } - - if (skipRelease) - { - continue; - } - - // if DateHeaders is set go through the previous rows and look for the header selector - var dateHeaders = _definition.Search.Rows.Dateheaders; - if (release.PublishDate == DateTime.MinValue && dateHeaders != null) - { - var prevRow = row.PreviousElementSibling; - string value = null; - if (prevRow == null) - { - // continue with parent - var parent = row.ParentElement; - if (parent != null) - { - prevRow = parent.PreviousElementSibling; - } + throw new Exception(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "", ex.Message)); } - while (prevRow != null) - { - var curRow = prevRow; - _logger.Debug(prevRow.OuterHtml); - try - { - value = HandleSelector(dateHeaders, curRow); - break; - } - catch (Exception) - { - // do nothing - } + var filters = search.Rows.Filters; + var skipRelease = ParseRowFilters(filters, release, variables, row); - prevRow = curRow.PreviousElementSibling; - if (prevRow == null) - { - // continue with parent - var parent = curRow.ParentElement; - if (parent != null) - { - prevRow = parent.PreviousElementSibling; - } - } - } - - if (value == null && dateHeaders.Optional == false) + if (skipRelease) { - throw new Exception(string.Format("No date header row found for {0}", release.ToString())); - } - - if (value != null) - { - release.PublishDate = DateTimeUtil.FromUnknown(value); + continue; } } releases.Add(release); } - catch (Exception ex) - { - _logger.Error(ex, "CardigannIndexer ({0}): Error while parsing row '{1}':\n\n{2}", _definition.Id, row.ToHtmlPretty()); - } } } - catch (Exception) + else { - // OnParseError(results, ex); - throw; + try + { + var searchResultParser = new HtmlParser(); + var searchResultDocument = searchResultParser.ParseDocument(results); + + /* checkForError(response, Definition.Search.Error); */ + + if (search.Preprocessingfilters != null) + { + results = ApplyFilters(results, search.Preprocessingfilters, variables); + searchResultDocument = searchResultParser.ParseDocument(results); + _logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results)); + } + + var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables); + var rowsDom = searchResultDocument.QuerySelectorAll(rowsSelector); + var rows = new List(); + foreach (var rowDom in rowsDom) + { + rows.Add(rowDom); + } + + // merge following rows for After selector + var after = search.Rows.After; + if (after > 0) + { + for (var i = 0; i < rows.Count; i += 1) + { + var currentRow = rows[i]; + for (var j = 0; j < after; j += 1) + { + var mergeRowIndex = i + j + 1; + var mergeRow = rows[mergeRowIndex]; + var mergeNodes = new List(); + foreach (var node in mergeRow.ChildNodes) + { + mergeNodes.Add(node); + } + + currentRow.Append(mergeNodes.ToArray()); + } + + rows.RemoveRange(i + 1, after); + } + } + + foreach (var row in rows) + { + try + { + var release = new TorrentInfo(); + + // Parse fields + foreach (var field in search.Fields) + { + var fieldParts = field.Key.Split('|'); + var fieldName = fieldParts[0]; + var fieldModifiers = new List(); + for (var i = 1; i < fieldParts.Length; i++) + { + fieldModifiers.Add(fieldParts[i]); + } + + 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)) + { + variables[variablesKey] = null; + continue; + } + + variables[variablesKey] = ParseFields(value, fieldName, release, fieldModifiers, searchUrlUri); + } + catch (Exception ex) + { + if (!variables.ContainsKey(variablesKey)) + { + variables[variablesKey] = null; + } + + if (OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional) + { + 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); + } + } + } + + var filters = search.Rows.Filters; + var skipRelease = ParseRowFilters(filters, release, variables, row); + + if (skipRelease) + { + continue; + } + + // if DateHeaders is set go through the previous rows and look for the header selector + var dateHeaders = _definition.Search.Rows.Dateheaders; + if (release.PublishDate == DateTime.MinValue && dateHeaders != null) + { + var prevRow = row.PreviousElementSibling; + string value = null; + if (prevRow == null) + { + // continue with parent + var parent = row.ParentElement; + if (parent != null) + { + prevRow = parent.PreviousElementSibling; + } + } + + while (prevRow != null) + { + var curRow = prevRow; + _logger.Debug(prevRow.OuterHtml); + try + { + value = HandleSelector(dateHeaders, curRow); + break; + } + catch (Exception) + { + // do nothing + } + + prevRow = curRow.PreviousElementSibling; + if (prevRow == null) + { + // continue with parent + var parent = curRow.ParentElement; + if (parent != null) + { + prevRow = parent.PreviousElementSibling; + } + } + } + + if (value == null && dateHeaders.Optional == false) + { + throw new Exception(string.Format("No date header row found for {0}", release.ToString())); + } + + if (value != null) + { + release.PublishDate = DateTimeUtil.FromUnknown(value); + } + } + + releases.Add(release); + } + catch (Exception ex) + { + _logger.Error(ex, "CardigannIndexer ({0}): Error while parsing row '{1}':\n\n{2}", _definition.Id, row.ToHtmlPretty()); + } + } + } + catch (Exception) + { + // OnParseError(results, ex); + throw; + } } /* @@ -469,5 +341,234 @@ namespace NzbDrone.Core.Indexers.Cardigann return releases; } + + private string ParseFields(string value, string fieldName, TorrentInfo release, List fieldModifiers, Uri searchUrlUri) + { + switch (fieldName) + { + case "download": + if (string.IsNullOrEmpty(value)) + { + value = null; + release.DownloadUrl = null; + break; + } + + if (value.StartsWith("magnet:")) + { + release.MagnetUrl = value; + value = release.MagnetUrl; + } + else + { + release.DownloadUrl = ResolvePath(value, searchUrlUri).AbsoluteUri; + value = release.DownloadUrl; + } + + break; + case "magnet": + var magnetUri = value; + release.MagnetUrl = magnetUri; + value = magnetUri.ToString(); + break; + case "infohash": + release.InfoHash = value; + break; + case "details": + var url = ResolvePath(value, searchUrlUri)?.AbsoluteUri; + release.InfoUrl = url; + release.Guid = url; + value = url.ToString(); + break; + case "comments": + var commentsUrl = ResolvePath(value, searchUrlUri); + if (release.CommentUrl == null) + { + release.CommentUrl = commentsUrl.AbsoluteUri; + } + + value = commentsUrl.ToString(); + break; + case "title": + if (fieldModifiers.Contains("append")) + { + release.Title += value; + } + else + { + release.Title = value; + } + + value = release.Title; + break; + case "description": + if (fieldModifiers.Contains("append")) + { + release.Description += value; + } + else + { + release.Description = value; + } + + value = release.Description; + break; + case "category": + var cats = MapTrackerCatToNewznab(value); + if (cats.Any()) + { + if (release.Categories == null || fieldModifiers.Contains("noappend")) + { + release.Categories = cats; + } + else + { + release.Categories = release.Categories.Union(cats).ToList(); + } + } + + value = release.Categories.ToString(); + break; + case "size": + release.Size = ParseUtil.GetBytes(value); + value = release.Size.ToString(); + break; + case "leechers": + var leechers = ParseUtil.CoerceLong(value); + leechers = leechers < 5000000L ? leechers : 0; // to fix #6558 + if (release.Peers == null) + { + release.Peers = (int)leechers; + } + else + { + release.Peers += (int)leechers; + } + + value = leechers.ToString(); + break; + case "seeders": + release.Seeders = ParseUtil.CoerceInt(value); + release.Seeders = release.Seeders < 5000000L ? release.Seeders : 0; // to fix #6558 + if (release.Peers == null) + { + release.Peers = release.Seeders; + } + else + { + release.Peers += release.Seeders; + } + + value = release.Seeders.ToString(); + break; + case "date": + release.PublishDate = DateTimeUtil.FromUnknown(value); + value = release.PublishDate.ToString(DateTimeUtil.Rfc1123ZPattern); + break; + case "files": + release.Files = ParseUtil.CoerceInt(value); + value = release.Files.ToString(); + break; + case "grabs": + release.Grabs = ParseUtil.CoerceInt(value); + value = release.Grabs.ToString(); + break; + case "downloadvolumefactor": + release.DownloadVolumeFactor = ParseUtil.CoerceDouble(value); + value = release.DownloadVolumeFactor.ToString(); + break; + case "uploadvolumefactor": + release.UploadVolumeFactor = ParseUtil.CoerceDouble(value); + value = release.UploadVolumeFactor.ToString(); + break; + case "minimumratio": + release.MinimumRatio = ParseUtil.CoerceDouble(value); + value = release.MinimumRatio.ToString(); + break; + case "minimumseedtime": + release.MinimumSeedTime = ParseUtil.CoerceLong(value); + value = release.MinimumSeedTime.ToString(); + break; + case "imdb": + release.ImdbId = (int)ParseUtil.GetLongFromString(value); + value = release.ImdbId.ToString(); + break; + case "tmdbid": + var tmdbIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var tmdbIDMatch = tmdbIDRegEx.Match(value); + var tmdbID = tmdbIDMatch.Groups[1].Value; + release.TmdbId = (int)ParseUtil.CoerceLong(tmdbID); + value = release.TmdbId.ToString(); + break; + case "rageid": + var rageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var rageIDMatch = rageIDRegEx.Match(value); + var rageID = rageIDMatch.Groups[1].Value; + release.TvRageId = (int)ParseUtil.CoerceLong(rageID); + value = release.TvRageId.ToString(); + break; + case "tvdbid": + var tvdbIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var tvdbIdMatch = tvdbIdRegEx.Match(value); + var tvdbId = tvdbIdMatch.Groups[1].Value; + release.TvdbId = (int)ParseUtil.CoerceLong(tvdbId); + value = release.TvdbId.ToString(); + break; + case "poster": + if (!string.IsNullOrWhiteSpace(value)) + { + var poster = ResolvePath(value, searchUrlUri); + release.PosterUrl = poster.AbsoluteUri; + } + + value = release.PosterUrl; + break; + + //case "author": + // release.Author = value; + // break; + //case "booktitle": + // release.BookTitle = value; + // break; + default: + break; + } + + return value; + } + + private bool ParseRowFilters(List filters, ReleaseInfo release, Dictionary variables, object row) + { + var skipRelease = false; + + if (filters != null) + { + foreach (var filter in filters) + { + switch (filter.Name) + { + case "andmatch": + var characterLimit = -1; + if (filter.Args != null) + { + characterLimit = int.Parse(filter.Args); + } + + var queryKeywords = variables[".Keywords"] as string; + + break; + case "strdump": + // for debugging + _logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToString())); + break; + default: + _logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", _definition.Id, filter.Name)); + break; + } + } + } + + return skipRelease; + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs index e9115cdc1..37a5c2149 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs @@ -6,17 +6,20 @@ namespace NzbDrone.Core.Indexers.Cardigann public class CardigannRequest : IndexerRequest { public Dictionary Variables { get; private set; } + public SearchPathBlock SearchPath { get; private set; } - public CardigannRequest(string url, HttpAccept httpAccept, Dictionary variables) + public CardigannRequest(string url, HttpAccept httpAccept, Dictionary variables, SearchPathBlock searchPath) : base(url, httpAccept) { Variables = variables; + SearchPath = searchPath; } - public CardigannRequest(HttpRequest httpRequest, Dictionary variables) + public CardigannRequest(HttpRequest httpRequest, Dictionary variables, SearchPathBlock searchPath) : base(httpRequest) { Variables = variables; + SearchPath = searchPath; } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index b08755ca2..db85ca036 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1067,7 +1067,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - var request = new CardigannRequest(requestbuilder.Build(), variables); + var request = new CardigannRequest(requestbuilder.Build(), variables, searchPath); // send HTTP request if (search.Headers != null)