diff --git a/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs b/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs index 0290dabfb..c0ac976f6 100644 --- a/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs +++ b/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.Serialization; using Newtonsoft.Json; namespace NzbDrone.Core.ImportLists.Simkl @@ -72,9 +73,17 @@ namespace NzbDrone.Core.ImportLists.Simkl public DateTime All { get; set; } } + [JsonConverter(typeof(TolerantEnumConverter))] public enum SimklAnimeType { + Unknown, Tv, - Movie + Movie, + Ova, + Ona, + Special, + + [EnumMember(Value = "music video")] + Music } } diff --git a/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs b/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs index 1419c6be7..a13b463d5 100644 --- a/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs +++ b/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.ImportLists.Simkl { var tentativeTvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0; - if (tentativeTvdbId > 0 && show.AnimeType == SimklAnimeType.Tv) + if (tentativeTvdbId > 0 && (show.AnimeType is SimklAnimeType.Tv or SimklAnimeType.Ona or SimklAnimeType.Ova or SimklAnimeType.Special)) { series.AddIfNotNull(new ImportListItemInfo() { @@ -55,7 +55,7 @@ namespace NzbDrone.Core.ImportLists.Simkl } else { - Logger.Warn("Skipping info grabbing for '{0}' because it is a movie or it is not the first season of the show", show.Show.Title); + Logger.Warn("Skipping info grabbing for '{0}' because it is an unsupported content type.", show.Show.Title); } } } diff --git a/src/NzbDrone.Core/ImportLists/TolerantEnumConverter.cs b/src/NzbDrone.Core/ImportLists/TolerantEnumConverter.cs new file mode 100644 index 000000000..9b402ae2b --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/TolerantEnumConverter.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace NzbDrone.Core.ImportLists +{ + /* This class was copied from gubenkoved TolerantEnumConverter.cs file, which is available from github + * https://gist.github.com/gubenkoved/999eb73e227b7063a67a50401578c3a7 + */ + public class TolerantEnumConverter : JsonConverter + { + [ThreadStatic] + private static Dictionary> _fromValueMap; // string representation to Enum value map + + [ThreadStatic] + private static Dictionary> _toValueMap; // Enum value to string map + + public string UnknownValue { get; set; } = "Unknown"; + + public override bool CanConvert(Type objectType) + { + var type = IsNullableType(objectType) ? Nullable.GetUnderlyingType(objectType) : objectType; + return type.IsEnum; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var isNullable = IsNullableType(objectType); + var enumType = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType; + + InitMap(enumType); + + if (reader.TokenType == JsonToken.String) + { + var enumText = reader.Value.ToString(); + + var val = FromValue(enumType, enumText); + + if (val != null) + { + return val; + } + } + else if (reader.TokenType == JsonToken.Integer) + { + var enumVal = Convert.ToInt32(reader.Value); + var values = (int[])Enum.GetValues(enumType); + if (values.Contains(enumVal)) + { + return Enum.Parse(enumType, enumVal.ToString()); + } + } + + if (!isNullable) + { + var names = Enum.GetNames(enumType); + + var unknownName = names + .Where(n => string.Equals(n, UnknownValue, StringComparison.OrdinalIgnoreCase)) + .FirstOrDefault(); + + if (unknownName == null) + { + throw new JsonSerializationException($"Unable to parse '{reader.Value}' to enum {enumType}. Consider adding Unknown as fail-back value."); + } + + return Enum.Parse(enumType, unknownName); + } + + return null; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var enumType = value.GetType(); + + InitMap(enumType); + + var val = ToValue(enumType, value); + + writer.WriteValue(val); + } + + private bool IsNullableType(Type t) + { + return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + private void InitMap(Type enumType) + { + if (_fromValueMap == null) + { + _fromValueMap = new Dictionary>(); + } + + if (_toValueMap == null) + { + _toValueMap = new Dictionary>(); + } + + if (_fromValueMap.ContainsKey(enumType)) + { + return; // already initialized + } + + var fromMap = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + var toMap = new Dictionary(); + + var fields = enumType.GetFields(BindingFlags.Static | BindingFlags.Public); + + foreach (var field in fields) + { + var name = field.Name; + var enumValue = Enum.Parse(enumType, name); + + // use EnumMember attribute if exists + var enumMemberAttrbiute = field.GetCustomAttribute(); + + if (enumMemberAttrbiute != null) + { + var enumMemberValue = enumMemberAttrbiute.Value; + + fromMap[enumMemberValue] = enumValue; + toMap[enumValue] = enumMemberValue; + } + else + { + toMap[enumValue] = name; + } + + fromMap[name] = enumValue; + } + + _fromValueMap[enumType] = fromMap; + _toValueMap[enumType] = toMap; + } + + private string ToValue(Type enumType, object obj) + { + var map = _toValueMap[enumType]; + + return map[obj]; + } + + private object FromValue(Type enumType, string value) + { + var map = _fromValueMap[enumType]; + + if (!map.ContainsKey(value)) + { + return null; + } + + return map[value]; + } + } +}