From a3a31952f4739a98d12de12ebe25d5535cf4a805 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 3 Jan 2021 09:35:22 -0700 Subject: [PATCH 1/3] Fix OMDb converter --- .../JsonOmdbNotAvailableStructConverter.cs | 4 +++ .../Plugins/Omdb/OmdbProvider.cs | 32 +++---------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs index b9e67ce2de..062c497373 100644 --- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs +++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Text.Json; using System.Text.Json.Serialization; @@ -21,6 +22,9 @@ namespace MediaBrowser.Common.Json.Converters { return null; } + + var converter = TypeDescriptor.GetConverter(typeToConvert); + return (T?)converter.ConvertFromString(str); } return JsonSerializer.Deserialize(ref reader, options); diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 2372e31834..a759f5408c 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -214,39 +214,15 @@ namespace MediaBrowser.Providers.Plugins.Omdb internal async Task GetRootObject(string imdbId, CancellationToken cancellationToken) { var path = await EnsureItemInfo(imdbId, cancellationToken).ConfigureAwait(false); - - string resultString; - - using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (var reader = new StreamReader(stream, new UTF8Encoding(false))) - { - resultString = reader.ReadToEnd(); - resultString = resultString.Replace("\"N/A\"", "\"\""); - } - } - - var result = JsonSerializer.Deserialize(resultString, _jsonOptions); - return result; + await using var stream = File.OpenRead(path); + return await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken); } internal async Task GetSeasonRootObject(string imdbId, int seasonId, CancellationToken cancellationToken) { var path = await EnsureSeasonInfo(imdbId, seasonId, cancellationToken).ConfigureAwait(false); - - string resultString; - - using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (var reader = new StreamReader(stream, new UTF8Encoding(false))) - { - resultString = reader.ReadToEnd(); - resultString = resultString.Replace("\"N/A\"", "\"\""); - } - } - - var result = JsonSerializer.Deserialize(resultString, _jsonOptions); - return result; + await using var stream = File.OpenRead(path); + return await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken); } internal static bool IsValidSeries(Dictionary seriesProviderIds) From c1d1b6e9f411c0b2d6d4d2d16e48c8a265111871 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 4 Jan 2021 07:52:44 -0700 Subject: [PATCH 2/3] Fix serialization loop --- ... => JsonOmdbNotAvailableInt32Converter.cs} | 21 ++++++++++++------- .../JsonOmdbNotAvailableStringConverter.cs | 2 +- .../Plugins/Omdb/OmdbItemProvider.cs | 2 +- .../Plugins/Omdb/OmdbProvider.cs | 2 +- .../Json/JsonOmdbConverterTests.cs | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) rename MediaBrowser.Common/Json/Converters/{JsonOmdbNotAvailableStructConverter.cs => JsonOmdbNotAvailableInt32Converter.cs} (54%) diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableInt32Converter.cs similarity index 54% rename from MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs rename to MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableInt32Converter.cs index 062c497373..cb3d83f584 100644 --- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs +++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableInt32Converter.cs @@ -8,12 +8,10 @@ namespace MediaBrowser.Common.Json.Converters /// /// Converts a string N/A to string.Empty. /// - /// The resulting type. - public class JsonOmdbNotAvailableStructConverter : JsonConverter - where T : struct + public class JsonOmdbNotAvailableInt32Converter : JsonConverter { /// - public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { @@ -24,16 +22,23 @@ namespace MediaBrowser.Common.Json.Converters } var converter = TypeDescriptor.GetConverter(typeToConvert); - return (T?)converter.ConvertFromString(str); + return (int?)converter.ConvertFromString(str); } - return JsonSerializer.Deserialize(ref reader, options); + return JsonSerializer.Deserialize(ref reader, options); } /// - public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options) { - JsonSerializer.Serialize(value, options); + if (value.HasValue) + { + writer.WriteNumberValue(value.Value); + } + else + { + writer.WriteNullValue(); + } } } } diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs index 4fec2ea3fd..6a8790374b 100644 --- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs +++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Common.Json.Converters /// public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) { - JsonSerializer.Serialize(value, options); + writer.WriteStringValue(value); } } } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 71d5510632..97fcbfb6fe 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb _jsonOptions = new JsonSerializerOptions(JsonDefaults.GetOptions()); _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter()); - _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStructConverter()); + _jsonOptions.Converters.Add(new JsonOmdbNotAvailableInt32Converter()); } public string Name => "The Open Movie Database"; diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index a759f5408c..3da999ad06 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb _jsonOptions = new JsonSerializerOptions(JsonDefaults.GetOptions()); _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter()); - _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStructConverter()); + _jsonOptions.Converters.Add(new JsonOmdbNotAvailableInt32Converter()); } public async Task Fetch(MetadataResult itemResult, string imdbId, string language, string country, CancellationToken cancellationToken) diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs index 6f85fe0929..03226cf31b 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs @@ -14,7 +14,7 @@ namespace Jellyfin.Common.Tests.Json { _options = new JsonSerializerOptions(); _options.Converters.Add(new JsonOmdbNotAvailableStringConverter()); - _options.Converters.Add(new JsonOmdbNotAvailableStructConverter()); + _options.Converters.Add(new JsonOmdbNotAvailableInt32Converter()); _options.NumberHandling = JsonNumberHandling.AllowReadingFromString; } From 75ed532fca9e5b3e8f83ca72cf54ecbafa3e1d1d Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 6 Jan 2021 07:07:38 -0700 Subject: [PATCH 3/3] Add serialize test --- .../Json/JsonOmdbConverterTests.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs index 03226cf31b..faed086a12 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs @@ -64,5 +64,25 @@ namespace Jellyfin.Common.Tests.Json var result = JsonSerializer.Deserialize(Input, _options); Assert.Equal(Expected, result); } + + [Fact] + public void Roundtrip_Valid_Success() + { + const string Input = "{\"Title\":\"Chapter 1\",\"Year\":\"2013\",\"Rated\":\"TV-MA\",\"Released\":\"01 Feb 2013\",\"Season\":\"N/A\",\"Episode\":\"N/A\",\"Runtime\":\"55 min\",\"Genre\":\"Drama\",\"Director\":\"David Fincher\",\"Writer\":\"Michael Dobbs (based on the novels by), Andrew Davies (based on the mini-series by), Beau Willimon (created for television by), Beau Willimon, Sam Forman (staff writer)\",\"Actors\":\"Kevin Spacey, Robin Wright, Kate Mara, Corey Stoll\",\"Plot\":\"Congressman Francis Underwood has been declined the chair for Secretary of State. He's now gathering his own team to plot his revenge. Zoe Barnes, a reporter for the Washington Herald, will do anything to get her big break.\",\"Language\":\"English\",\"Country\":\"USA\",\"Awards\":\"N/A\",\"Poster\":\"https://m.media-amazon.com/images/M/MV5BMTY5MTU4NDQzNV5BMl5BanBnXkFtZTgwMzk2ODcxMzE@._V1_SX300.jpg\",\"Ratings\":[{\"Source\":\"Internet Movie Database\",\"Value\":\"8.7/10\"}],\"Metascore\":\"N/A\",\"imdbRating\":\"8.7\",\"imdbVotes\":\"6736\",\"imdbID\":\"tt2161930\",\"seriesID\":\"N/A\",\"Type\":\"episode\",\"Response\":\"True\"}"; + var trip1 = JsonSerializer.Deserialize(Input, _options); + Assert.NotNull(trip1); + Assert.NotNull(trip1?.Title); + Assert.Null(trip1?.Awards); + Assert.Null(trip1?.Episode); + Assert.Null(trip1?.Metascore); + + var serializedTrip1 = JsonSerializer.Serialize(trip1!, _options); + var trip2 = JsonSerializer.Deserialize(serializedTrip1, _options); + Assert.NotNull(trip2); + Assert.NotNull(trip2?.Title); + Assert.Null(trip2?.Awards); + Assert.Null(trip2?.Episode); + Assert.Null(trip2?.Metascore); + } } }