From 2e62c09f2e55b33c2ba8eeb97157495e2f8ab5a9 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 8 Mar 2021 02:16:35 +0100 Subject: [PATCH 1/2] Fix casing CollectionType --- .../Entities/JsonLowerCaseConverter.cs | 29 ++++++++ .../Entities/VirtualFolderInfo.cs | 2 + .../Entities/JsonLowerCaseConverterTests.cs | 70 +++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 MediaBrowser.Model/Entities/JsonLowerCaseConverter.cs create mode 100644 tests/Jellyfin.Model.Tests/Entities/JsonLowerCaseConverterTests.cs diff --git a/MediaBrowser.Model/Entities/JsonLowerCaseConverter.cs b/MediaBrowser.Model/Entities/JsonLowerCaseConverter.cs new file mode 100644 index 0000000000..7c627f0e39 --- /dev/null +++ b/MediaBrowser.Model/Entities/JsonLowerCaseConverter.cs @@ -0,0 +1,29 @@ +#nullable disable +// THIS IS A HACK +// TODO: @bond Move to separate project + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Model.Entities +{ + /// + /// Converts an object to a lowercase string. + /// + /// The object type. + public class JsonLowerCaseConverter : JsonConverter + { + /// + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return JsonSerializer.Deserialize(ref reader, options); + } + + /// + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + writer.WriteStringValue(value?.ToString().ToLowerInvariant()); + } + } +} diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index ea3df37265..8fed392b9d 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -2,6 +2,7 @@ #pragma warning disable CS1591 using System; +using System.Text.Json.Serialization; using MediaBrowser.Model.Configuration; namespace MediaBrowser.Model.Entities @@ -35,6 +36,7 @@ namespace MediaBrowser.Model.Entities /// Gets or sets the type of the collection. /// /// The type of the collection. + [JsonConverter(typeof(JsonLowerCaseConverter))] public CollectionTypeOptions? CollectionType { get; set; } public LibraryOptions LibraryOptions { get; set; } diff --git a/tests/Jellyfin.Model.Tests/Entities/JsonLowerCaseConverterTests.cs b/tests/Jellyfin.Model.Tests/Entities/JsonLowerCaseConverterTests.cs new file mode 100644 index 0000000000..955d296cc8 --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Entities/JsonLowerCaseConverterTests.cs @@ -0,0 +1,70 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using MediaBrowser.Model.Entities; +using Xunit; + +namespace Jellyfin.Model.Tests.Entities +{ + public class JsonLowerCaseConverterTests + { + private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions() + { + Converters = + { + new JsonStringEnumConverter() + } + }; + + [Theory] + [InlineData(null, "{\"CollectionType\":null}")] + [InlineData(CollectionTypeOptions.Movies, "{\"CollectionType\":\"movies\"}")] + [InlineData(CollectionTypeOptions.MusicVideos, "{\"CollectionType\":\"musicvideos\"}")] + public void Serialize_CollectionTypeOptions_Correct(CollectionTypeOptions? collectionType, string expected) + { + Assert.Equal(expected, JsonSerializer.Serialize(new TestContainer(collectionType), _jsonOptions)); + } + + [Theory] + [InlineData("{\"CollectionType\":null}", null)] + [InlineData("{\"CollectionType\":\"movies\"}", CollectionTypeOptions.Movies)] + [InlineData("{\"CollectionType\":\"musicvideos\"}", CollectionTypeOptions.MusicVideos)] + public void Deserialize_CollectionTypeOptions_Correct(string json, CollectionTypeOptions? result) + { + var res = JsonSerializer.Deserialize(json, _jsonOptions); + Assert.NotNull(res); + Assert.Equal(result, res!.CollectionType); + } + + [Theory] + [InlineData(null)] + [InlineData(CollectionTypeOptions.Movies)] + [InlineData(CollectionTypeOptions.MusicVideos)] + public void RoundTrip_CollectionTypeOptions_Correct(CollectionTypeOptions? value) + { + var res = JsonSerializer.Deserialize(JsonSerializer.Serialize(new TestContainer(value), _jsonOptions), _jsonOptions); + Assert.NotNull(res); + Assert.Equal(value, res!.CollectionType); + } + + [Theory] + [InlineData("{\"CollectionType\":null}")] + [InlineData("{\"CollectionType\":\"movies\"}")] + [InlineData("{\"CollectionType\":\"musicvideos\"}")] + public void RoundTrip_String_Correct(string json) + { + var res = JsonSerializer.Serialize(JsonSerializer.Deserialize(json, _jsonOptions), _jsonOptions); + Assert.Equal(json, res); + } + + private class TestContainer + { + public TestContainer(CollectionTypeOptions? collectionType) + { + CollectionType = collectionType; + } + + [JsonConverter(typeof(JsonLowerCaseConverter))] + public CollectionTypeOptions? CollectionType { get; set; } + } + } +} From 54f81c4da484e3bb3d62669f0216c2a3a239166d Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 8 Mar 2021 12:08:17 +0100 Subject: [PATCH 2/2] Call ToLower on CollectionTypeOptions.ToString --- Emby.Server.Implementations/Library/LibraryManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index d9ffe64b3b..6d92e12b3a 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1247,7 +1247,7 @@ namespace Emby.Server.Implementations.Library { // TODO: @bond use a ReadOnlySpan here when Enum.TryParse supports it // https://github.com/dotnet/runtime/issues/20008 - if (Enum.TryParse(Path.GetExtension(file), true, out var res)) + if (Enum.TryParse(Path.GetFileNameWithoutExtension(file), true, out var res)) { return res; } @@ -3001,7 +3001,7 @@ namespace Emby.Server.Implementations.Library if (collectionType != null) { - var path = Path.Combine(virtualFolderPath, collectionType.ToString() + ".collection"); + var path = Path.Combine(virtualFolderPath, collectionType.ToString().ToLowerInvariant() + ".collection"); File.WriteAllBytes(path, Array.Empty()); }