From e09d3ba9efa7505a14d57d344707fe7ce71119b2 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 13:06:29 +0100 Subject: [PATCH 01/24] Remove custom Json serializer from Providers --- .../Plugins/AudioDb/AlbumImageProvider.cs | 10 +++++---- .../Plugins/AudioDb/AlbumProvider.cs | 9 ++++---- .../Plugins/AudioDb/ArtistImageProvider.cs | 10 +++++---- .../Plugins/AudioDb/ArtistProvider.cs | 9 ++++---- .../Plugins/Omdb/OmdbEpisodeProvider.cs | 8 ++----- .../Plugins/Omdb/OmdbImageProvider.cs | 9 +++----- .../Plugins/Omdb/OmdbItemProvider.cs | 14 ++++++------- .../Plugins/Omdb/OmdbProvider.cs | 21 ++++++++++--------- 8 files changed, 44 insertions(+), 46 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs index 293087da7a..605b93788b 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs @@ -1,9 +1,12 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.IO; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -19,13 +22,11 @@ namespace MediaBrowser.Providers.Plugins.AudioDb { private readonly IServerConfigurationManager _config; private readonly IHttpClientFactory _httpClientFactory; - private readonly IJsonSerializer _json; - public AudioDbAlbumImageProvider(IServerConfigurationManager config, IHttpClientFactory httpClientFactory, IJsonSerializer json) + public AudioDbAlbumImageProvider(IServerConfigurationManager config, IHttpClientFactory httpClientFactory) { _config = config; _httpClientFactory = httpClientFactory; - _json = json; } /// @@ -56,7 +57,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbAlbumProvider.GetAlbumInfoPath(_config.ApplicationPaths, id); - var obj = _json.DeserializeFromFile(path); + var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); + var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); if (obj != null && obj.album != null && obj.album.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs index 97bba10baa..32ef135475 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs @@ -6,10 +6,12 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; @@ -27,16 +29,14 @@ namespace MediaBrowser.Providers.Plugins.AudioDb private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly IHttpClientFactory _httpClientFactory; - private readonly IJsonSerializer _json; public static AudioDbAlbumProvider Current; - public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpClientFactory, IJsonSerializer json) + public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpClientFactory) { _config = config; _fileSystem = fileSystem; _httpClientFactory = httpClientFactory; - _json = json; Current = this; } @@ -64,7 +64,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetAlbumInfoPath(_config.ApplicationPaths, id); - var obj = _json.DeserializeFromFile(path); + var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); + var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); if (obj != null && obj.album != null && obj.album.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs index d250acfa84..f0b8e00f3f 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs @@ -1,9 +1,12 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.IO; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -19,12 +22,10 @@ namespace MediaBrowser.Providers.Plugins.AudioDb { private readonly IServerConfigurationManager _config; private readonly IHttpClientFactory _httpClientFactory; - private readonly IJsonSerializer _json; - public AudioDbArtistImageProvider(IServerConfigurationManager config, IJsonSerializer json, IHttpClientFactory httpClientFactory) + public AudioDbArtistImageProvider(IServerConfigurationManager config, IHttpClientFactory httpClientFactory) { _config = config; - _json = json; _httpClientFactory = httpClientFactory; } @@ -58,7 +59,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbArtistProvider.GetArtistInfoPath(_config.ApplicationPaths, id); - var obj = _json.DeserializeFromFile(path); + var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); + var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); if (obj != null && obj.artists != null && obj.artists.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs index a2a03e1f9a..2476c86715 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs @@ -5,10 +5,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; @@ -29,14 +31,12 @@ namespace MediaBrowser.Providers.Plugins.AudioDb private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly IHttpClientFactory _httpClientFactory; - private readonly IJsonSerializer _json; - public AudioDbArtistProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpClientFactory, IJsonSerializer json) + public AudioDbArtistProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpClientFactory) { _config = config; _fileSystem = fileSystem; _httpClientFactory = httpClientFactory; - _json = json; Current = this; } @@ -65,7 +65,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetArtistInfoPath(_config.ApplicationPaths, id); - var obj = _json.DeserializeFromFile(path); + var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); + var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); if (obj != null && obj.artists != null && obj.artists.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs index bfc840ea59..24ef80a35d 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs @@ -12,13 +12,11 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; namespace MediaBrowser.Providers.Plugins.Omdb { public class OmdbEpisodeProvider : IRemoteMetadataProvider, IHasOrder { - private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClientFactory _httpClientFactory; private readonly OmdbItemProvider _itemProvider; private readonly IFileSystem _fileSystem; @@ -26,19 +24,17 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IApplicationHost _appHost; public OmdbEpisodeProvider( - IJsonSerializer jsonSerializer, IApplicationHost appHost, IHttpClientFactory httpClientFactory, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager configurationManager) { - _jsonSerializer = jsonSerializer; _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; _configurationManager = configurationManager; _appHost = appHost; - _itemProvider = new OmdbItemProvider(jsonSerializer, _appHost, httpClientFactory, libraryManager, fileSystem, configurationManager); + _itemProvider = new OmdbItemProvider(_appHost, httpClientFactory, libraryManager, fileSystem, configurationManager); } // After TheTvDb @@ -69,7 +65,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb { if (info.IndexNumber.HasValue && info.ParentIndexNumber.HasValue) { - result.HasMetadata = await new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager) + result.HasMetadata = await new OmdbProvider(_httpClientFactory, _fileSystem, _appHost, _configurationManager) .FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, info.GetProviderId(MetadataProvider.Imdb), seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs index 8f4240dc11..df67aff31c 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs @@ -1,8 +1,8 @@ #pragma warning disable CS1591 using System.Collections.Generic; -using System.Net.Http; using System.Globalization; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; @@ -15,21 +15,18 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; namespace MediaBrowser.Providers.Plugins.Omdb { public class OmdbImageProvider : IRemoteImageProvider, IHasOrder { private readonly IHttpClientFactory _httpClientFactory; - private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IApplicationHost _appHost; - public OmdbImageProvider(IJsonSerializer jsonSerializer, IApplicationHost appHost, IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IServerConfigurationManager configurationManager) + public OmdbImageProvider(IApplicationHost appHost, IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IServerConfigurationManager configurationManager) { - _jsonSerializer = jsonSerializer; _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; _configurationManager = configurationManager; @@ -56,7 +53,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var list = new List(); - var provider = new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager); + var provider = new OmdbProvider(_httpClientFactory, _fileSystem, _appHost, _configurationManager); if (!string.IsNullOrWhiteSpace(imdbId)) { diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 43d8af75f0..7e9ef974e2 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -6,9 +6,11 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -19,14 +21,12 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; namespace MediaBrowser.Providers.Plugins.Omdb { public class OmdbItemProvider : IRemoteMetadataProvider, IRemoteMetadataProvider, IRemoteMetadataProvider, IHasOrder { - private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryManager _libraryManager; private readonly IFileSystem _fileSystem; @@ -34,14 +34,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IApplicationHost _appHost; public OmdbItemProvider( - IJsonSerializer jsonSerializer, IApplicationHost appHost, IHttpClientFactory httpClientFactory, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager configurationManager) { - _jsonSerializer = jsonSerializer; _httpClientFactory = httpClientFactory; _libraryManager = libraryManager; _fileSystem = fileSystem; @@ -138,7 +136,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (isSearch) { - var searchResultList = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); + var searchResultList = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (searchResultList != null && searchResultList.Search != null) { resultList.AddRange(searchResultList.Search); @@ -146,7 +144,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } else { - var result = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); + var result = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase)) { resultList.Add(result); @@ -221,7 +219,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); result.HasMetadata = true; - await new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); + await new OmdbProvider(_httpClientFactory, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } return result; @@ -253,7 +251,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); result.HasMetadata = true; - await new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); + await new OmdbProvider(_httpClientFactory, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } return result; diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index e6c6050720..e73085460d 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -7,31 +7,30 @@ using System.IO; using System.Linq; using System.Net.Http; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Serialization; namespace MediaBrowser.Providers.Plugins.Omdb { public class OmdbProvider { - private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IHttpClientFactory _httpClientFactory; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IApplicationHost _appHost; - public OmdbProvider(IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IApplicationHost appHost, IServerConfigurationManager configurationManager) + public OmdbProvider(IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IApplicationHost appHost, IServerConfigurationManager configurationManager) { - _jsonSerializer = jsonSerializer; _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; _configurationManager = configurationManager; @@ -220,7 +219,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } - var result = _jsonSerializer.DeserializeFromString(resultString); + var result = JsonSerializer.Deserialize(resultString, JsonDefaults.GetOptions()); return result; } @@ -239,7 +238,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } - var result = _jsonSerializer.DeserializeFromString(resultString); + var result = JsonSerializer.Deserialize(resultString, JsonDefaults.GetOptions()); return result; } @@ -299,9 +298,10 @@ namespace MediaBrowser.Providers.Plugins.Omdb using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var rootObject = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); + var rootObject = await JsonSerializer.DeserializeAsync(stream, cancellationToken: cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); - _jsonSerializer.SerializeToFile(rootObject, path); + await using FileStream jsonFileStream = File.Create(path); + await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); return path; } @@ -337,9 +337,10 @@ namespace MediaBrowser.Providers.Plugins.Omdb using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var rootObject = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); + var rootObject = await JsonSerializer.DeserializeAsync(stream, cancellationToken: cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); - _jsonSerializer.SerializeToFile(rootObject, path); + await using FileStream jsonFileStream = File.Create(path); + await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); return path; } From bc0976ceac32b5f7e0ef234ec01a0b17477b9086 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 13:12:06 +0100 Subject: [PATCH 02/24] Remove custom Json serializer from Dlna --- Emby.Dlna/DlnaManager.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index fedd20b68a..df69dd5162 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -7,12 +7,14 @@ using System.IO; using System.Linq; using System.Reflection; using System.Text; +using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; using Emby.Dlna.Profiles; using Emby.Dlna.Server; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Controller; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; @@ -32,7 +34,6 @@ namespace Emby.Dlna private readonly IXmlSerializer _xmlSerializer; private readonly IFileSystem _fileSystem; private readonly ILogger _logger; - private readonly IJsonSerializer _jsonSerializer; private readonly IServerApplicationHost _appHost; private static readonly Assembly _assembly = typeof(DlnaManager).Assembly; @@ -43,14 +44,12 @@ namespace Emby.Dlna IFileSystem fileSystem, IApplicationPaths appPaths, ILoggerFactory loggerFactory, - IJsonSerializer jsonSerializer, IServerApplicationHost appHost) { _xmlSerializer = xmlSerializer; _fileSystem = fileSystem; _appPaths = appPaths; _logger = loggerFactory.CreateLogger(); - _jsonSerializer = jsonSerializer; _appHost = appHost; } @@ -495,9 +494,9 @@ namespace Emby.Dlna return profile; } - var json = _jsonSerializer.SerializeToString(profile); + var json = JsonSerializer.Serialize(profile, JsonDefaults.GetOptions()); - return _jsonSerializer.DeserializeFromString(json); + return JsonSerializer.Deserialize(json, options: JsonDefaults.GetOptions()); } public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress) From 196388d607a856050221d1b55192360dd3ea8be5 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 13:12:40 +0100 Subject: [PATCH 03/24] Remove custom Json serializer from Emby.Server.Implementations --- .../ApplicationHost.cs | 14 +++----- .../Channels/ChannelManager.cs | 32 +++++++++-------- .../Library/LiveStreamHelper.cs | 13 +++---- .../Library/MediaSourceManager.cs | 18 +++++----- .../LiveTv/EmbyTV/EmbyTV.cs | 12 +++---- .../LiveTv/EmbyTV/EncodedRecorder.cs | 8 ++--- .../LiveTv/EmbyTV/ItemDataProvider.cs | 12 +++---- .../LiveTv/EmbyTV/SeriesTimerManager.cs | 4 +-- .../LiveTv/EmbyTV/TimerManager.cs | 5 ++- .../LiveTv/Listings/SchedulesDirect.cs | 24 ++++++------- .../Localization/LocalizationManager.cs | 14 ++++---- .../ScheduledTasks/ScheduledTaskWorker.cs | 35 ++++++++++--------- .../ScheduledTasks/TaskManager.cs | 7 ++-- 13 files changed, 95 insertions(+), 103 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 50ef71a46d..fcc156e9c5 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -7,11 +7,9 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net; -using System.Net.Http; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Threading; using System.Threading.Tasks; using Emby.Dlna; @@ -50,6 +48,7 @@ using Jellyfin.Networking.Manager; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; @@ -101,6 +100,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Prometheus.DotNetRuntime; +using JsonSerializer = System.Text.Json.JsonSerializer; using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager; @@ -118,7 +118,6 @@ namespace Emby.Server.Implementations private readonly IFileSystem _fileSystemManager; private readonly IXmlSerializer _xmlSerializer; - private readonly IJsonSerializer _jsonSerializer; private readonly IStartupOptions _startupOptions; private IMediaEncoder _mediaEncoder; @@ -257,7 +256,6 @@ namespace Emby.Server.Implementations IServiceCollection serviceCollection) { _xmlSerializer = new MyXmlSerializer(); - _jsonSerializer = new JsonSerializer(); ServiceCollection = serviceCollection; @@ -528,8 +526,6 @@ namespace Emby.Server.Implementations ServiceCollection.AddSingleton(ApplicationPaths); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(_fileSystemManager); ServiceCollection.AddSingleton(); @@ -754,7 +750,6 @@ namespace Emby.Server.Implementations UserView.CollectionManager = Resolve(); BaseItem.MediaSourceManager = Resolve(); CollectionFolder.XmlSerializer = _xmlSerializer; - CollectionFolder.JsonSerializer = Resolve(); CollectionFolder.ApplicationHost = this; } @@ -967,7 +962,7 @@ namespace Emby.Server.Implementations { return true; } - + throw new FileNotFoundException( string.Format( CultureInfo.InvariantCulture, @@ -1051,7 +1046,8 @@ namespace Emby.Server.Implementations var metafile = Path.Combine(dir, "meta.json"); if (File.Exists(metafile)) { - var manifest = _jsonSerializer.DeserializeFromFile(metafile); + var jsonString = File.ReadAllText(metafile); + var manifest = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); if (!Version.TryParse(manifest.TargetAbi, out var targetAbi)) { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 57684a4298..0966c252ba 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -21,10 +22,10 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using JsonSerializer = System.Text.Json.JsonSerializer; using Movie = MediaBrowser.Controller.Entities.Movies.Movie; using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; using Season = MediaBrowser.Controller.Entities.TV.Season; @@ -44,7 +45,6 @@ namespace Emby.Server.Implementations.Channels private readonly ILogger _logger; private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; - private readonly IJsonSerializer _jsonSerializer; private readonly IProviderManager _providerManager; private readonly IMemoryCache _memoryCache; private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1); @@ -70,7 +70,6 @@ namespace Emby.Server.Implementations.Channels IServerConfigurationManager config, IFileSystem fileSystem, IUserDataManager userDataManager, - IJsonSerializer jsonSerializer, IProviderManager providerManager, IMemoryCache memoryCache) { @@ -81,7 +80,6 @@ namespace Emby.Server.Implementations.Channels _config = config; _fileSystem = fileSystem; _userDataManager = userDataManager; - _jsonSerializer = jsonSerializer; _providerManager = providerManager; _memoryCache = memoryCache; } @@ -343,7 +341,8 @@ namespace Emby.Server.Implementations.Channels try { - return _jsonSerializer.DeserializeFromFile>(path) ?? new List(); + var jsonString = File.ReadAllText(path); + return JsonSerializer.Deserialize>(jsonString, JsonDefaults.GetOptions()) ?? new List(); } catch { @@ -351,7 +350,7 @@ namespace Emby.Server.Implementations.Channels } } - private void SaveMediaSources(BaseItem item, List mediaSources) + private async Task SaveMediaSources(BaseItem item, List mediaSources) { var path = Path.Combine(item.GetInternalMetadataPath(), "channelmediasourceinfos.json"); @@ -369,8 +368,8 @@ namespace Emby.Server.Implementations.Channels } Directory.CreateDirectory(Path.GetDirectoryName(path)); - - _jsonSerializer.SerializeToFile(mediaSources, path); + await using FileStream createStream = File.Create(path); + await JsonSerializer.SerializeAsync(createStream, mediaSources, JsonDefaults.GetOptions()).ConfigureAwait(false); } /// @@ -812,7 +811,8 @@ namespace Emby.Server.Implementations.Channels { if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { - var cachedResult = _jsonSerializer.DeserializeFromFile(cachePath); + var jsonString = await File.ReadAllTextAsync(cachePath, cancellationToken); + var cachedResult = JsonSerializer.Deserialize(jsonString); if (cachedResult != null) { return null; @@ -834,7 +834,8 @@ namespace Emby.Server.Implementations.Channels { if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { - var cachedResult = _jsonSerializer.DeserializeFromFile(cachePath); + var jsonString = await File.ReadAllTextAsync(cachePath, cancellationToken); + var cachedResult = JsonSerializer.Deserialize(jsonString); if (cachedResult != null) { return null; @@ -865,7 +866,7 @@ namespace Emby.Server.Implementations.Channels throw new InvalidOperationException("Channel returned a null result from GetChannelItems"); } - CacheResponse(result, cachePath); + await CacheResponse(result, cachePath); return result; } @@ -875,13 +876,14 @@ namespace Emby.Server.Implementations.Channels } } - private void CacheResponse(object result, string path) + private async Task CacheResponse(object result, string path) { try { Directory.CreateDirectory(Path.GetDirectoryName(path)); - _jsonSerializer.SerializeToFile(result, path); + await using FileStream createStream = File.Create(path); + await JsonSerializer.SerializeAsync(createStream, result, JsonDefaults.GetOptions()).ConfigureAwait(false); } catch (Exception ex) { @@ -1176,11 +1178,11 @@ namespace Emby.Server.Implementations.Channels { if (enableMediaProbe && !info.IsLiveStream && item.HasPathProtocol) { - SaveMediaSources(item, new List()); + await SaveMediaSources(item, new List()); } else { - SaveMediaSources(item, info.MediaSources); + await SaveMediaSources(item, info.MediaSources); } } diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index 041619d1e5..ad7988fb15 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -5,16 +5,17 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library @@ -23,14 +24,12 @@ namespace Emby.Server.Implementations.Library { private readonly IMediaEncoder _mediaEncoder; private readonly ILogger _logger; - private readonly IJsonSerializer _json; private readonly IApplicationPaths _appPaths; - public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger, IJsonSerializer json, IApplicationPaths appPaths) + public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger, IApplicationPaths appPaths) { _mediaEncoder = mediaEncoder; _logger = logger; - _json = json; _appPaths = appPaths; } @@ -47,7 +46,8 @@ namespace Emby.Server.Implementations.Library { try { - mediaInfo = _json.DeserializeFromFile(cacheFilePath); + var jsonString = await File.ReadAllTextAsync(cacheFilePath, cancellationToken).ConfigureAwait(false); + JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); // _logger.LogDebug("Found cached media info"); } @@ -83,7 +83,8 @@ namespace Emby.Server.Implementations.Library if (cacheFilePath != null) { Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); - _json.SerializeToFile(mediaInfo, cacheFilePath); + await using FileStream createStream = File.Create(cacheFilePath); + await JsonSerializer.SerializeAsync(createStream, mediaInfo, cancellationToken: cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Saved media info to {0}", cacheFilePath); } diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 928f5f88e4..264390dd33 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -6,12 +6,14 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; @@ -23,7 +25,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library @@ -36,7 +37,6 @@ namespace Emby.Server.Implementations.Library private readonly IItemRepository _itemRepo; private readonly IUserManager _userManager; private readonly ILibraryManager _libraryManager; - private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly ILogger _logger; private readonly IUserDataManager _userDataManager; @@ -56,7 +56,6 @@ namespace Emby.Server.Implementations.Library IUserManager userManager, ILibraryManager libraryManager, ILogger logger, - IJsonSerializer jsonSerializer, IFileSystem fileSystem, IUserDataManager userDataManager, IMediaEncoder mediaEncoder) @@ -65,7 +64,6 @@ namespace Emby.Server.Implementations.Library _userManager = userManager; _libraryManager = libraryManager; _logger = logger; - _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; _userDataManager = userDataManager; _mediaEncoder = mediaEncoder; @@ -504,7 +502,7 @@ namespace Emby.Server.Implementations.Library // hack - these two values were taken from LiveTVMediaSourceProvider string cacheKey = request.OpenToken; - await new LiveStreamHelper(_mediaEncoder, _logger, _jsonSerializer, _appPaths) + await new LiveStreamHelper(_mediaEncoder, _logger, _appPaths) .AddMediaInfoWithProbe(mediaSource, isAudio, cacheKey, true, cancellationToken) .ConfigureAwait(false); } @@ -516,9 +514,9 @@ namespace Emby.Server.Implementations.Library } // TODO: @bond Fix - var json = _jsonSerializer.SerializeToString(mediaSource); + var json = JsonSerializer.Serialize(mediaSource, JsonDefaults.GetOptions()); _logger.LogInformation("Live stream opened: " + json); - var clone = _jsonSerializer.DeserializeFromString(json); + var clone = JsonSerializer.Deserialize(json, JsonDefaults.GetOptions()); if (!request.UserId.Equals(Guid.Empty)) { @@ -643,7 +641,8 @@ namespace Emby.Server.Implementations.Library { try { - mediaInfo = _jsonSerializer.DeserializeFromFile(cacheFilePath); + var json = await File.ReadAllTextAsync(cacheFilePath, cancellationToken).ConfigureAwait(false); + mediaInfo = JsonSerializer.Deserialize(json, JsonDefaults.GetOptions()); // _logger.LogDebug("Found cached media info"); } @@ -679,7 +678,8 @@ namespace Emby.Server.Implementations.Library if (cacheFilePath != null) { Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); - _jsonSerializer.SerializeToFile(mediaInfo, cacheFilePath); + await using FileStream createStream = File.Create(cacheFilePath); + await JsonSerializer.SerializeAsync(createStream, mediaInfo, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Saved media info to {0}", cacheFilePath); } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 0dc045ee6f..2c0de661df 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -36,7 +36,6 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.LiveTv.EmbyTV @@ -51,7 +50,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; private readonly IServerConfigurationManager _config; - private readonly IJsonSerializer _jsonSerializer; private readonly ItemDataProvider _seriesTimerProvider; private readonly TimerManager _timerProvider; @@ -81,7 +79,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV IStreamHelper streamHelper, IMediaSourceManager mediaSourceManager, ILogger logger, - IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory, IServerConfigurationManager config, ILiveTvManager liveTvManager, @@ -103,12 +100,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _providerManager = providerManager; _mediaEncoder = mediaEncoder; _liveTvManager = (LiveTvManager)liveTvManager; - _jsonSerializer = jsonSerializer; _mediaSourceManager = mediaSourceManager; _streamHelper = streamHelper; - _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers.json")); - _timerProvider = new TimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "timers.json")); + _seriesTimerProvider = new SeriesTimerManager(_logger, Path.Combine(DataPath, "seriestimers.json")); + _timerProvider = new TimerManager(_logger, Path.Combine(DataPath, "timers.json")); _timerProvider.TimerFired += OnTimerProviderTimerFired; _config.NamedConfigurationUpdated += OnNamedConfigurationUpdated; @@ -1052,7 +1048,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV IgnoreIndex = true }; - await new LiveStreamHelper(_mediaEncoder, _logger, _jsonSerializer, _config.CommonApplicationPaths) + await new LiveStreamHelper(_mediaEncoder, _logger, _config.CommonApplicationPaths) .AddMediaInfoWithProbe(stream, false, false, cancellationToken).ConfigureAwait(false); return new List @@ -1635,7 +1631,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { if (mediaSource.RequiresLooping || !(mediaSource.Container ?? string.Empty).EndsWith("ts", StringComparison.OrdinalIgnoreCase) || (mediaSource.Protocol != MediaProtocol.File && mediaSource.Protocol != MediaProtocol.Http)) { - return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, _config); + return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _config); } return new DirectRecorder(_logger, _httpClientFactory, _streamHelper); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index e6ee9819eb..9609f28816 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -6,16 +6,17 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Json; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.LiveTv.EmbyTV @@ -25,7 +26,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly ILogger _logger; private readonly IMediaEncoder _mediaEncoder; private readonly IServerApplicationPaths _appPaths; - private readonly IJsonSerializer _json; private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); private readonly IServerConfigurationManager _serverConfigurationManager; @@ -38,13 +38,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV ILogger logger, IMediaEncoder mediaEncoder, IServerApplicationPaths appPaths, - IJsonSerializer json, IServerConfigurationManager serverConfigurationManager) { _logger = logger; _mediaEncoder = mediaEncoder; _appPaths = appPaths; - _json = json; _serverConfigurationManager = serverConfigurationManager; } @@ -95,7 +93,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); - var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); + var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(mediaSource, JsonDefaults.GetOptions()) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); _logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length); _process = new Process diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index fc543dc551..5256a0ee72 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -4,7 +4,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Model.Serialization; +using System.Text.Json; +using MediaBrowser.Common.Json; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.LiveTv.EmbyTV @@ -12,18 +13,15 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public class ItemDataProvider where T : class { - private readonly IJsonSerializer _jsonSerializer; private readonly string _dataPath; private readonly object _fileDataLock = new object(); private T[] _items; public ItemDataProvider( - IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func equalityComparer) { - _jsonSerializer = jsonSerializer; Logger = logger; _dataPath = dataPath; EqualityComparer = equalityComparer; @@ -46,7 +44,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { - _items = _jsonSerializer.DeserializeFromFile(_dataPath); + var json = File.ReadAllText(_dataPath); + _items = JsonSerializer.Deserialize(json, JsonDefaults.GetOptions()); return; } catch (Exception ex) @@ -61,7 +60,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private void SaveList() { Directory.CreateDirectory(Path.GetDirectoryName(_dataPath)); - _jsonSerializer.SerializeToFile(_items, _dataPath); + using FileStream stream = File.OpenWrite(_dataPath); + JsonSerializer.SerializeAsync(stream, _items, JsonDefaults.GetOptions()); } public IReadOnlyList GetAll() diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs index 194e4606de..da707fec63 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs @@ -9,8 +9,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { public class SeriesTimerManager : ItemDataProvider { - public SeriesTimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath) - : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) + public SeriesTimerManager(ILogger logger, string dataPath) + : base(logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) { } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs index dd479b7d1b..1efa90e256 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -8,7 +8,6 @@ using System.Threading; using Jellyfin.Data.Events; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.LiveTv; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.LiveTv.EmbyTV @@ -17,8 +16,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { private readonly ConcurrentDictionary _timers = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - public TimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath) - : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) + public TimerManager(ILogger logger, string dataPath) + : base(logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) { } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 90e6cc9668..198d196c23 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -9,16 +9,17 @@ using System.Net; using System.Net.Http; using System.Net.Mime; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.LiveTv.Listings @@ -28,7 +29,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings private const string ApiUrl = "https://json.schedulesdirect.org/20141201"; private readonly ILogger _logger; - private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClientFactory _httpClientFactory; private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); private readonly IApplicationHost _appHost; @@ -39,13 +39,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings public SchedulesDirect( ILogger logger, - IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory, IApplicationHost appHost, ICryptoProvider cryptoProvider) { _logger = logger; - _jsonSerializer = jsonSerializer; _httpClientFactory = httpClientFactory; _appHost = appHost; _cryptoProvider = cryptoProvider; @@ -104,7 +102,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings } }; - var requestString = _jsonSerializer.SerializeToString(requestList); + var jsonOptions = JsonDefaults.GetOptions(); + + var requestString = JsonSerializer.Serialize(requestList, jsonOptions); _logger.LogDebug("Request string for schedules is: {RequestString}", requestString); using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules"); @@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Headers.TryAddWithoutValidation("token", token); using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync>(responseStream).ConfigureAwait(false); + var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, jsonOptions).ConfigureAwait(false); _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); @@ -123,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var programDetails = await _jsonSerializer.DeserializeFromStreamAsync>(innerResponseStream).ConfigureAwait(false); + var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, jsonOptions).ConfigureAwait(false); var programDict = programDetails.ToDictionary(p => p.programID, y => y); var programIdsWithImages = @@ -479,7 +479,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return await _jsonSerializer.DeserializeFromStreamAsync>(response).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync>(response, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -508,7 +508,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false); await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await _jsonSerializer.DeserializeFromStreamAsync>(response).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync>(response, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (root != null) { @@ -649,7 +649,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (string.Equals(root.message, "OK", StringComparison.Ordinal)) { _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token); @@ -705,7 +705,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpResponse.EnsureSuccessStatusCode(); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var response = httpResponse.Content; - var root = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions()).ConfigureAwait(false); return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); } @@ -777,7 +777,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions()).ConfigureAwait(false); _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count); _logger.LogInformation("Mapping Stations to Channel"); diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 30aaf3a058..11355872f3 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -5,7 +5,9 @@ using System.Globalization; using System.IO; using System.Linq; using System.Reflection; +using System.Text.Json; using System.Threading.Tasks; +using MediaBrowser.Common.Json; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; @@ -24,7 +26,6 @@ namespace Emby.Server.Implementations.Localization private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; private readonly IServerConfigurationManager _configurationManager; - private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; private readonly Dictionary> _allParentalRatings = @@ -43,11 +44,9 @@ namespace Emby.Server.Implementations.Localization /// The logger. public LocalizationManager( IServerConfigurationManager configurationManager, - IJsonSerializer jsonSerializer, ILogger logger) { _configurationManager = configurationManager; - _jsonSerializer = jsonSerializer; _logger = logger; } @@ -179,8 +178,11 @@ namespace Emby.Server.Implementations.Localization /// public IEnumerable GetCountries() - => _jsonSerializer.DeserializeFromStream>( - _assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json")); + { + StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json")); + + return JsonSerializer.Deserialize>(reader.ReadToEnd(), JsonDefaults.GetOptions()); + } /// public IEnumerable GetParentalRatings() @@ -344,7 +346,7 @@ namespace Emby.Server.Implementations.Localization // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain if (stream != null) { - var dict = await _jsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false); + var dict = await JsonSerializer.DeserializeAsync>(stream, JsonDefaults.GetOptions()).ConfigureAwait(false); foreach (var key in dict.Keys) { diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 3a9e284583..4ac4443cd6 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -4,13 +4,14 @@ using System; using System.Globalization; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Progress; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -21,11 +22,6 @@ namespace Emby.Server.Implementations.ScheduledTasks /// public class ScheduledTaskWorker : IScheduledTaskWorker { - /// - /// Gets or sets the json serializer. - /// - /// The json serializer. - private readonly IJsonSerializer _jsonSerializer; /// /// Gets or sets the application paths. @@ -88,7 +84,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// or /// logger. /// - public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger) + public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, ILogger logger) { if (scheduledTask == null) { @@ -105,11 +101,6 @@ namespace Emby.Server.Implementations.ScheduledTasks throw new ArgumentNullException(nameof(taskManager)); } - if (jsonSerializer == null) - { - throw new ArgumentNullException(nameof(jsonSerializer)); - } - if (logger == null) { throw new ArgumentNullException(nameof(logger)); @@ -118,7 +109,6 @@ namespace Emby.Server.Implementations.ScheduledTasks ScheduledTask = scheduledTask; _applicationPaths = applicationPaths; _taskManager = taskManager; - _jsonSerializer = jsonSerializer; _logger = logger; InitTriggerEvents(); @@ -150,7 +140,15 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - _lastExecutionResult = _jsonSerializer.DeserializeFromFile(path); + var jsonString = File.ReadAllText(path); + if (!string.IsNullOrWhiteSpace(jsonString)) + { + _lastExecutionResult = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + } + else + { + _logger.LogDebug("Scheduled Task history file {path} is empty. Skipping deserialization.", path); + } } catch (Exception ex) { @@ -174,7 +172,8 @@ namespace Emby.Server.Implementations.ScheduledTasks lock (_lastExecutionResultSyncLock) { - _jsonSerializer.SerializeToFile(value, path); + using FileStream createStream = File.OpenWrite(path); + JsonSerializer.SerializeAsync(createStream, value, JsonDefaults.GetOptions()); } } } @@ -537,7 +536,8 @@ namespace Emby.Server.Implementations.ScheduledTasks TaskTriggerInfo[] list = null; if (File.Exists(path)) { - list = _jsonSerializer.DeserializeFromFile(path); + var jsonString = File.ReadAllText(path); + list = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); } // Return defaults if file doesn't exist. @@ -573,7 +573,8 @@ namespace Emby.Server.Implementations.ScheduledTasks Directory.CreateDirectory(Path.GetDirectoryName(path)); - _jsonSerializer.SerializeToFile(triggers, path); + using FileStream stream = File.OpenWrite(path); + JsonSerializer.SerializeAsync(stream, triggers, JsonDefaults.GetOptions()); } /// diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index cfbf03ddc0..197a5ed5ef 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -19,6 +18,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public class TaskManager : ITaskManager { public event EventHandler> TaskExecuting; + public event EventHandler TaskCompleted; /// @@ -33,7 +33,6 @@ namespace Emby.Server.Implementations.ScheduledTasks private readonly ConcurrentQueue> _taskQueue = new ConcurrentQueue>(); - private readonly IJsonSerializer _jsonSerializer; private readonly IApplicationPaths _applicationPaths; private readonly ILogger _logger; @@ -45,11 +44,9 @@ namespace Emby.Server.Implementations.ScheduledTasks /// The logger. public TaskManager( IApplicationPaths applicationPaths, - IJsonSerializer jsonSerializer, ILogger logger) { _applicationPaths = applicationPaths; - _jsonSerializer = jsonSerializer; _logger = logger; ScheduledTasks = Array.Empty(); @@ -196,7 +193,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// The tasks. public void AddTasks(IEnumerable tasks) { - var list = tasks.Select(t => new ScheduledTaskWorker(t, _applicationPaths, this, _jsonSerializer, _logger)); + var list = tasks.Select(t => new ScheduledTaskWorker(t, _applicationPaths, this, _logger)); ScheduledTasks = ScheduledTasks.Concat(list).ToArray(); } From e9902e9d35978b0f0d56b35612fa092daf6145c8 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 13:13:28 +0100 Subject: [PATCH 04/24] Remove custom Json serializer --- .../Serialization/JsonSerializer.cs | 281 ------------------ .../Serialization/IJsonSerializer.cs | 102 ------- 2 files changed, 383 deletions(-) delete mode 100644 Emby.Server.Implementations/Serialization/JsonSerializer.cs delete mode 100644 MediaBrowser.Model/Serialization/IJsonSerializer.cs diff --git a/Emby.Server.Implementations/Serialization/JsonSerializer.cs b/Emby.Server.Implementations/Serialization/JsonSerializer.cs deleted file mode 100644 index 5ec3a735a6..0000000000 --- a/Emby.Server.Implementations/Serialization/JsonSerializer.cs +++ /dev/null @@ -1,281 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Globalization; -using System.IO; -using System.Threading.Tasks; -using MediaBrowser.Model.Serialization; - -namespace Emby.Server.Implementations.Serialization -{ - /// - /// Provides a wrapper around third party json serialization. - /// - public class JsonSerializer : IJsonSerializer - { - /// - /// Initializes a new instance of the class. - /// - public JsonSerializer() - { - ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.DateHandler.ISO8601; - ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; - ServiceStack.Text.JsConfig.IncludeNullValues = false; - ServiceStack.Text.JsConfig.AlwaysUseUtc = true; - ServiceStack.Text.JsConfig.AssumeUtc = true; - - ServiceStack.Text.JsConfig.SerializeFn = SerializeGuid; - } - - /// - /// Serializes to stream. - /// - /// The obj. - /// The stream. - /// obj - public void SerializeToStream(object obj, Stream stream) - { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream); - } - - /// - /// Serializes to stream. - /// - /// The obj. - /// The stream. - /// obj - public void SerializeToStream(T obj, Stream stream) - { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - ServiceStack.Text.JsonSerializer.SerializeToStream(obj, stream); - } - - /// - /// Serializes to file. - /// - /// The obj. - /// The file. - /// obj - public void SerializeToFile(object obj, string file) - { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (string.IsNullOrEmpty(file)) - { - throw new ArgumentNullException(nameof(file)); - } - - using (var stream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read)) - { - SerializeToStream(obj, stream); - } - } - - private static Stream OpenFile(string path) - { - return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 131072); - } - - /// - /// Deserializes from file. - /// - /// The type. - /// The file. - /// System.Object. - /// type - public object DeserializeFromFile(Type type, string file) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (string.IsNullOrEmpty(file)) - { - throw new ArgumentNullException(nameof(file)); - } - - using (var stream = OpenFile(file)) - { - return DeserializeFromStream(stream, type); - } - } - - /// - /// Deserializes from file. - /// - /// - /// The file. - /// ``0. - /// file - public T DeserializeFromFile(string file) - where T : class - { - if (string.IsNullOrEmpty(file)) - { - throw new ArgumentNullException(nameof(file)); - } - - using (var stream = OpenFile(file)) - { - return DeserializeFromStream(stream); - } - } - - /// - /// Deserializes from stream. - /// - /// - /// The stream. - /// ``0. - /// stream - public T DeserializeFromStream(Stream stream) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromStream(stream); - } - - public Task DeserializeFromStreamAsync(Stream stream) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromStreamAsync(stream); - } - - /// - /// Deserializes from string. - /// - /// - /// The text. - /// ``0. - /// text - public T DeserializeFromString(string text) - { - if (string.IsNullOrEmpty(text)) - { - throw new ArgumentNullException(nameof(text)); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromString(text); - } - - /// - /// Deserializes from stream. - /// - /// The stream. - /// The type. - /// System.Object. - /// stream - public object DeserializeFromStream(Stream stream, Type type) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); - } - - public async Task DeserializeFromStreamAsync(Stream stream, Type type) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - using (var reader = new StreamReader(stream)) - { - var json = await reader.ReadToEndAsync().ConfigureAwait(false); - - return ServiceStack.Text.JsonSerializer.DeserializeFromString(json, type); - } - } - - private static string SerializeGuid(Guid guid) - { - if (guid.Equals(Guid.Empty)) - { - return null; - } - - return guid.ToString("N", CultureInfo.InvariantCulture); - } - - /// - /// Deserializes from string. - /// - /// The json. - /// The type. - /// System.Object. - /// json - public object DeserializeFromString(string json, Type type) - { - if (string.IsNullOrEmpty(json)) - { - throw new ArgumentNullException(nameof(json)); - } - - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromString(json, type); - } - - /// - /// Serializes to string. - /// - /// The obj. - /// System.String. - /// obj - public string SerializeToString(object obj) - { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return ServiceStack.Text.JsonSerializer.SerializeToString(obj, obj.GetType()); - } - } -} diff --git a/MediaBrowser.Model/Serialization/IJsonSerializer.cs b/MediaBrowser.Model/Serialization/IJsonSerializer.cs deleted file mode 100644 index 09b6ff9b5a..0000000000 --- a/MediaBrowser.Model/Serialization/IJsonSerializer.cs +++ /dev/null @@ -1,102 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; -using System.IO; -using System.Threading.Tasks; - -namespace MediaBrowser.Model.Serialization -{ - public interface IJsonSerializer - { - /// - /// Serializes to stream. - /// - /// The obj. - /// The stream. - /// obj - void SerializeToStream(object obj, Stream stream); - - /// - /// Serializes to stream. - /// - /// The obj. - /// The stream. - /// obj - void SerializeToStream(T obj, Stream stream); - - /// - /// Serializes to file. - /// - /// The obj. - /// The file. - /// obj - void SerializeToFile(object obj, string file); - - /// - /// Deserializes from file. - /// - /// The type. - /// The file. - /// System.Object. - /// type - object DeserializeFromFile(Type type, string file); - - /// - /// Deserializes from file. - /// - /// - /// The file. - /// ``0. - /// file - T DeserializeFromFile(string file) - where T : class; - - /// - /// Deserializes from stream. - /// - /// - /// The stream. - /// ``0. - /// stream - T DeserializeFromStream(Stream stream); - - /// - /// Deserializes from string. - /// - /// - /// The text. - /// ``0. - /// text - T DeserializeFromString(string text); - - /// - /// Deserializes from stream. - /// - /// The stream. - /// The type. - /// System.Object. - /// stream - object DeserializeFromStream(Stream stream, Type type); - - /// - /// Deserializes from string. - /// - /// The json. - /// The type. - /// System.Object. - /// json - object DeserializeFromString(string json, Type type); - - /// - /// Serializes to string. - /// - /// The obj. - /// System.String. - /// obj - string SerializeToString(object obj); - - Task DeserializeFromStreamAsync(Stream stream, Type type); - Task DeserializeFromStreamAsync(Stream stream); - } -} From b9dbdc7e542af6e84de75e5548f4185646383d6d Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 13:24:14 +0100 Subject: [PATCH 05/24] Remove custom Json serializer from MediaBrowser.Controller --- MediaBrowser.Controller/Entities/CollectionFolder.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index d25545a2fc..b960278b85 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -4,9 +4,11 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Json; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; @@ -26,8 +28,6 @@ namespace MediaBrowser.Controller.Entities { public static IXmlSerializer XmlSerializer { get; set; } - public static IJsonSerializer JsonSerializer { get; set; } - public static IServerApplicationHost ApplicationHost { get; set; } public CollectionFolder() @@ -122,7 +122,8 @@ namespace MediaBrowser.Controller.Entities { LibraryOptions[path] = options; - var clone = JsonSerializer.DeserializeFromString(JsonSerializer.SerializeToString(options)); + var jsonOptions = JsonDefaults.GetOptions(); + var clone = JsonSerializer.Deserialize(JsonSerializer.Serialize(options, jsonOptions), jsonOptions); foreach (var mediaPath in clone.PathInfos) { if (!string.IsNullOrEmpty(mediaPath.Path)) From 62fcc84bf4ba3affeb7ab853cfb6880417fd1a9e Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 13:35:49 +0100 Subject: [PATCH 06/24] Remove nuget reference --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 9e9452f32c..1416ffa261 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -37,7 +37,6 @@ - From 276b219fbdaaf14e16bc9e3435d1d9c571ed1cf8 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 13:43:42 +0100 Subject: [PATCH 07/24] Add missing options --- MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index e73085460d..374b154e1e 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -298,10 +298,11 @@ namespace MediaBrowser.Providers.Plugins.Omdb using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var rootObject = await JsonSerializer.DeserializeAsync(stream, cancellationToken: cancellationToken).ConfigureAwait(false); + var jsonOptions = JsonDefaults.GetOptions(); + var rootObject = await JsonSerializer.DeserializeAsync(stream, jsonOptions, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream jsonFileStream = File.Create(path); - await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); return path; } @@ -337,10 +338,11 @@ namespace MediaBrowser.Providers.Plugins.Omdb using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var rootObject = await JsonSerializer.DeserializeAsync(stream, cancellationToken: cancellationToken).ConfigureAwait(false); + var jsonOptions = JsonDefaults.GetOptions(); + var rootObject = await JsonSerializer.DeserializeAsync(stream, jsonOptions, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream jsonFileStream = File.Create(path); - await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); return path; } From e2d338412fea5489aadb0e75af96cb36e4f13317 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 14:45:05 +0100 Subject: [PATCH 08/24] Fix OMDb "N/A" --- .../Plugins/Omdb/OmdbProvider.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 374b154e1e..bbedffbc7d 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -296,10 +296,8 @@ namespace MediaBrowser.Providers.Plugins.Omdb "i={0}&plot=short&tomatoes=true&r=json", imdbParam)); - using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var jsonOptions = JsonDefaults.GetOptions(); - var rootObject = await JsonSerializer.DeserializeAsync(stream, jsonOptions, cancellationToken).ConfigureAwait(false); + var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, jsonOptions, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream jsonFileStream = File.Create(path); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); @@ -336,10 +334,8 @@ namespace MediaBrowser.Providers.Plugins.Omdb imdbParam, seasonId)); - using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var jsonOptions = JsonDefaults.GetOptions(); - var rootObject = await JsonSerializer.DeserializeAsync(stream, jsonOptions, cancellationToken).ConfigureAwait(false); + var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, jsonOptions, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream jsonFileStream = File.Create(path); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); @@ -347,6 +343,16 @@ namespace MediaBrowser.Providers.Plugins.Omdb return path; } + public static async Task GetDeserializedOmdbResponse(HttpClient httpClient, string url, JsonSerializerOptions jsonOptions, CancellationToken cancellationToken) + { + using var response = await GetOmdbResponse(httpClient, url, cancellationToken).ConfigureAwait(false); + var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); + + // OMDb is sending "N/A" for no empty number fields + content = content.Replace("\"N/A\"", "\"0\"", StringComparison.InvariantCulture); + return JsonSerializer.Deserialize(content, jsonOptions); + } + public static Task GetOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) { return httpClient.GetAsync(url, cancellationToken); From f38970cbd32c845d1740828450aac8de16fec788 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 15:03:14 +0100 Subject: [PATCH 09/24] Remove xml docs --- Emby.Server.Implementations/Channels/ChannelManager.cs | 1 - Emby.Server.Implementations/Localization/LocalizationManager.cs | 1 - .../ScheduledTasks/ScheduledTaskWorker.cs | 1 - Emby.Server.Implementations/ScheduledTasks/TaskManager.cs | 1 - 4 files changed, 4 deletions(-) diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 0966c252ba..4e4fbf82c6 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -59,7 +59,6 @@ namespace Emby.Server.Implementations.Channels /// The server configuration manager. /// The filesystem. /// The user data manager. - /// The JSON serializer. /// The provider manager. /// The memory cache. public ChannelManager( diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 11355872f3..2d6fb252d2 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -40,7 +40,6 @@ namespace Emby.Server.Implementations.Localization /// Initializes a new instance of the class. /// /// The configuration manager. - /// The json serializer. /// The logger. public LocalizationManager( IServerConfigurationManager configurationManager, diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 4ac4443cd6..eee7aeea30 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -71,7 +71,6 @@ namespace Emby.Server.Implementations.ScheduledTasks /// The scheduled task. /// The application paths. /// The task manager. - /// The json serializer. /// The logger. /// /// scheduledTask diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 197a5ed5ef..af316e1083 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -40,7 +40,6 @@ namespace Emby.Server.Implementations.ScheduledTasks /// Initializes a new instance of the class. /// /// The application paths. - /// The json serializer. /// The logger. public TaskManager( IApplicationPaths applicationPaths, From 2a574914eaca486f6216db400d9fdf88ad88636e Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 19:24:58 +0100 Subject: [PATCH 10/24] Use streams instead of strings --- Emby.Server.Implementations/ApplicationHost.cs | 5 +++-- .../Channels/ChannelManager.cs | 4 ++-- .../Library/LiveStreamHelper.cs | 4 ++-- .../Library/MediaSourceManager.cs | 4 ++-- .../LiveTv/EmbyTV/ItemDataProvider.cs | 4 ++-- .../ScheduledTasks/ScheduledTaskWorker.cs | 11 ++--------- .../Plugins/AudioDb/AlbumImageProvider.cs | 4 ++-- .../Plugins/AudioDb/AlbumProvider.cs | 4 ++-- .../Plugins/AudioDb/ArtistImageProvider.cs | 4 ++-- .../Plugins/AudioDb/ArtistProvider.cs | 4 ++-- MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs | 6 +++--- 11 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index fcc156e9c5..99cd3b6cc1 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1038,6 +1038,7 @@ namespace Emby.Server.Implementations } var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly); + var jsonOptions = JsonDefaults.GetOptions(); foreach (var dir in directories) { @@ -1046,8 +1047,8 @@ namespace Emby.Server.Implementations var metafile = Path.Combine(dir, "meta.json"); if (File.Exists(metafile)) { - var jsonString = File.ReadAllText(metafile); - var manifest = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + using FileStream jsonStream = File.OpenRead(metafile); + var manifest = JsonSerializer.DeserializeAsync(jsonStream, jsonOptions).GetAwaiter().GetResult(); if (!Version.TryParse(manifest.TargetAbi, out var targetAbi)) { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 4e4fbf82c6..b462d7bdcd 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -340,8 +340,8 @@ namespace Emby.Server.Implementations.Channels try { - var jsonString = File.ReadAllText(path); - return JsonSerializer.Deserialize>(jsonString, JsonDefaults.GetOptions()) ?? new List(); + using FileStream jsonStream = File.OpenRead(path); + return JsonSerializer.DeserializeAsync>(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult(); } catch { diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index ad7988fb15..3ceba0fe94 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -46,8 +46,8 @@ namespace Emby.Server.Implementations.Library { try { - var jsonString = await File.ReadAllTextAsync(cacheFilePath, cancellationToken).ConfigureAwait(false); - JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + await using FileStream jsonStream = File.OpenRead(cacheFilePath); + await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Found cached media info"); } diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 264390dd33..b3900e4aa1 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -641,8 +641,8 @@ namespace Emby.Server.Implementations.Library { try { - var json = await File.ReadAllTextAsync(cacheFilePath, cancellationToken).ConfigureAwait(false); - mediaInfo = JsonSerializer.Deserialize(json, JsonDefaults.GetOptions()); + await using FileStream jsonStream = File.OpenRead(cacheFilePath); + mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Found cached media info"); } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 5256a0ee72..1b9abaa78e 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -44,8 +44,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { - var json = File.ReadAllText(_dataPath); - _items = JsonSerializer.Deserialize(json, JsonDefaults.GetOptions()); + using FileStream jsonStream = File.OpenRead(_dataPath); + _items = JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult(); return; } catch (Exception ex) diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index eee7aeea30..a9f4599864 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -139,15 +139,8 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - var jsonString = File.ReadAllText(path); - if (!string.IsNullOrWhiteSpace(jsonString)) - { - _lastExecutionResult = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); - } - else - { - _logger.LogDebug("Scheduled Task history file {path} is empty. Skipping deserialization.", path); - } + using FileStream jsonStream = File.OpenRead(path); + _lastExecutionResult = JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult(); } catch (Exception ex) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs index 605b93788b..a5aeba7d2d 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs @@ -57,8 +57,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbAlbumProvider.GetAlbumInfoPath(_config.ApplicationPaths, id); - var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); - var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + await using FileStream jsonStream = File.OpenRead(path); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (obj != null && obj.album != null && obj.album.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs index 32ef135475..9a61abc1ac 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs @@ -64,8 +64,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetAlbumInfoPath(_config.ApplicationPaths, id); - var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); - var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + await using FileStream jsonStream = File.OpenRead(path); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (obj != null && obj.album != null && obj.album.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs index f0b8e00f3f..639bbe8595 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs @@ -59,8 +59,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbArtistProvider.GetArtistInfoPath(_config.ApplicationPaths, id); - var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); - var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + await using FileStream jsonStream = File.OpenRead(path); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (obj != null && obj.artists != null && obj.artists.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs index 2476c86715..71efd194e3 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs @@ -65,8 +65,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetArtistInfoPath(_config.ApplicationPaths, id); - var jsonString = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); - var obj = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + await using FileStream jsonStream = File.OpenRead(path); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (obj != null && obj.artists != null && obj.artists.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index bbedffbc7d..fa75e4ec49 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -299,7 +299,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var jsonOptions = JsonDefaults.GetOptions(); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, jsonOptions, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); - await using FileStream jsonFileStream = File.Create(path); + await using FileStream jsonFileStream = File.OpenWrite(path); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); return path; @@ -337,7 +337,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var jsonOptions = JsonDefaults.GetOptions(); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, jsonOptions, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); - await using FileStream jsonFileStream = File.Create(path); + await using FileStream jsonFileStream = File.OpenWrite(path); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); return path; @@ -349,7 +349,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); // OMDb is sending "N/A" for no empty number fields - content = content.Replace("\"N/A\"", "\"0\"", StringComparison.InvariantCulture); + content = content.Replace("\"N/A\"", "\"\"", StringComparison.InvariantCulture); return JsonSerializer.Deserialize(content, jsonOptions); } From a714008b596b108a44020f61ca384b30263df984 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 23 Dec 2020 21:00:50 +0100 Subject: [PATCH 11/24] Add missing FileStreams --- .../Channels/ChannelManager.cs | 11 ++++++----- .../Library/LiveStreamHelper.cs | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index b462d7bdcd..3663e5094b 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -341,7 +341,8 @@ namespace Emby.Server.Implementations.Channels try { using FileStream jsonStream = File.OpenRead(path); - return JsonSerializer.DeserializeAsync>(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult(); + return JsonSerializer.DeserializeAsync>(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult() + ?? new List(); } catch { @@ -810,8 +811,8 @@ namespace Emby.Server.Implementations.Channels { if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { - var jsonString = await File.ReadAllTextAsync(cachePath, cancellationToken); - var cachedResult = JsonSerializer.Deserialize(jsonString); + await using FileStream jsonStream = File.OpenRead(cachePath); + var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (cachedResult != null) { return null; @@ -833,8 +834,8 @@ namespace Emby.Server.Implementations.Channels { if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { - var jsonString = await File.ReadAllTextAsync(cachePath, cancellationToken); - var cachedResult = JsonSerializer.Deserialize(jsonString); + await using FileStream jsonStream = File.OpenRead(cachePath); + var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); if (cachedResult != null) { return null; diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index 3ceba0fe94..80729a280c 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.Library try { await using FileStream jsonStream = File.OpenRead(cacheFilePath); - await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Found cached media info"); } @@ -83,8 +83,8 @@ namespace Emby.Server.Implementations.Library if (cacheFilePath != null) { Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); - await using FileStream createStream = File.Create(cacheFilePath); - await JsonSerializer.SerializeAsync(createStream, mediaInfo, cancellationToken: cancellationToken).ConfigureAwait(false); + await using FileStream createStream = File.OpenWrite(cacheFilePath); + await JsonSerializer.SerializeAsync(createStream, mediaInfo, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Saved media info to {0}", cacheFilePath); } From e835dfb27d4a25e2057047692fd58af439b15acc Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 Dec 2020 10:31:51 +0100 Subject: [PATCH 12/24] Use sync string instead of file --- Emby.Server.Implementations/ApplicationHost.cs | 6 +++--- .../Channels/ChannelManager.cs | 5 +++-- .../LiveTv/EmbyTV/ItemDataProvider.cs | 4 ++-- .../ScheduledTasks/ScheduledTaskWorker.cs | 11 +++++++++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 99cd3b6cc1..6e360ed852 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -10,6 +10,7 @@ using System.Net; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Emby.Dlna; @@ -100,7 +101,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Prometheus.DotNetRuntime; -using JsonSerializer = System.Text.Json.JsonSerializer; using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager; @@ -1047,8 +1047,8 @@ namespace Emby.Server.Implementations var metafile = Path.Combine(dir, "meta.json"); if (File.Exists(metafile)) { - using FileStream jsonStream = File.OpenRead(metafile); - var manifest = JsonSerializer.DeserializeAsync(jsonStream, jsonOptions).GetAwaiter().GetResult(); + var jsonString = File.ReadAllText(metafile); + var manifest = JsonSerializer.Deserialize(jsonString, jsonOptions); if (!Version.TryParse(manifest.TargetAbi, out var targetAbi)) { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 3663e5094b..f06ad4436b 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -340,8 +340,8 @@ namespace Emby.Server.Implementations.Channels try { - using FileStream jsonStream = File.OpenRead(path); - return JsonSerializer.DeserializeAsync>(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult() + var jsonString = File.ReadAllText(path); + return JsonSerializer.Deserialize>(jsonString, JsonDefaults.GetOptions()) ?? new List(); } catch @@ -368,6 +368,7 @@ namespace Emby.Server.Implementations.Channels } Directory.CreateDirectory(Path.GetDirectoryName(path)); + await using FileStream createStream = File.Create(path); await JsonSerializer.SerializeAsync(createStream, mediaSources, JsonDefaults.GetOptions()).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 1b9abaa78e..bbe9b50dd5 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -44,8 +44,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { - using FileStream jsonStream = File.OpenRead(_dataPath); - _items = JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult(); + var jsonString = File.ReadAllText(_dataPath); + _items = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); return; } catch (Exception ex) diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index a9f4599864..eee7aeea30 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -139,8 +139,15 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - using FileStream jsonStream = File.OpenRead(path); - _lastExecutionResult = JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions()).GetAwaiter().GetResult(); + var jsonString = File.ReadAllText(path); + if (!string.IsNullOrWhiteSpace(jsonString)) + { + _lastExecutionResult = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + } + else + { + _logger.LogDebug("Scheduled Task history file {path} is empty. Skipping deserialization.", path); + } } catch (Exception ex) { From 043d04544850bb82972bb7817510984c2ddea75a Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 Dec 2020 11:15:12 +0100 Subject: [PATCH 13/24] Put json serializer options in private field --- Emby.Dlna/DlnaManager.cs | 5 +++-- .../ApplicationHost.cs | 4 ++-- .../Channels/ChannelManager.cs | 13 +++++++------ .../Library/LiveStreamHelper.cs | 5 +++-- .../Library/MediaSourceManager.cs | 9 +++++---- .../LiveTv/EmbyTV/EncodedRecorder.cs | 4 ++-- .../LiveTv/EmbyTV/ItemDataProvider.cs | 5 +++-- .../LiveTv/Listings/SchedulesDirect.cs | 19 +++++++++---------- .../Localization/LocalizationManager.cs | 6 ++++-- .../ScheduledTasks/ScheduledTaskWorker.cs | 13 +++++++++---- .../Entities/CollectionFolder.cs | 4 ++-- .../Plugins/AudioDb/AlbumImageProvider.cs | 3 ++- .../Plugins/AudioDb/AlbumProvider.cs | 3 ++- .../Plugins/AudioDb/ArtistImageProvider.cs | 3 ++- .../Plugins/AudioDb/ArtistProvider.cs | 3 ++- .../Plugins/Omdb/OmdbItemProvider.cs | 5 +++-- .../Plugins/Omdb/OmdbProvider.cs | 19 +++++++++---------- 17 files changed, 69 insertions(+), 54 deletions(-) diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index df69dd5162..21ba1c7552 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -36,6 +36,7 @@ namespace Emby.Dlna private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; private static readonly Assembly _assembly = typeof(DlnaManager).Assembly; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); private readonly Dictionary> _profiles = new Dictionary>(StringComparer.Ordinal); @@ -494,9 +495,9 @@ namespace Emby.Dlna return profile; } - var json = JsonSerializer.Serialize(profile, JsonDefaults.GetOptions()); + var json = JsonSerializer.Serialize(profile, _jsonOptions); - return JsonSerializer.Deserialize(json, options: JsonDefaults.GetOptions()); + return JsonSerializer.Deserialize(json, _jsonOptions); } public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 6e360ed852..115d94b316 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -123,6 +123,7 @@ namespace Emby.Server.Implementations private IMediaEncoder _mediaEncoder; private ISessionManager _sessionManager; private string[] _urlPrefixes; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); /// /// Gets a value indicating whether this instance can self restart. @@ -1038,7 +1039,6 @@ namespace Emby.Server.Implementations } var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly); - var jsonOptions = JsonDefaults.GetOptions(); foreach (var dir in directories) { @@ -1048,7 +1048,7 @@ namespace Emby.Server.Implementations if (File.Exists(metafile)) { var jsonString = File.ReadAllText(metafile); - var manifest = JsonSerializer.Deserialize(jsonString, jsonOptions); + var manifest = JsonSerializer.Deserialize(jsonString, _jsonOptions); if (!Version.TryParse(manifest.TargetAbi, out var targetAbi)) { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index f06ad4436b..cf6a87ecfd 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -25,7 +26,6 @@ using MediaBrowser.Model.Querying; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Episode = MediaBrowser.Controller.Entities.TV.Episode; -using JsonSerializer = System.Text.Json.JsonSerializer; using Movie = MediaBrowser.Controller.Entities.Movies.Movie; using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; using Season = MediaBrowser.Controller.Entities.TV.Season; @@ -48,6 +48,7 @@ namespace Emby.Server.Implementations.Channels private readonly IProviderManager _providerManager; private readonly IMemoryCache _memoryCache; private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1); + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); /// /// Initializes a new instance of the class. @@ -341,7 +342,7 @@ namespace Emby.Server.Implementations.Channels try { var jsonString = File.ReadAllText(path); - return JsonSerializer.Deserialize>(jsonString, JsonDefaults.GetOptions()) + return JsonSerializer.Deserialize>(jsonString, _jsonOptions) ?? new List(); } catch @@ -370,7 +371,7 @@ namespace Emby.Server.Implementations.Channels Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream createStream = File.Create(path); - await JsonSerializer.SerializeAsync(createStream, mediaSources, JsonDefaults.GetOptions()).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(createStream, mediaSources, _jsonOptions).ConfigureAwait(false); } /// @@ -813,7 +814,7 @@ namespace Emby.Server.Implementations.Channels if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { await using FileStream jsonStream = File.OpenRead(cachePath); - var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (cachedResult != null) { return null; @@ -836,7 +837,7 @@ namespace Emby.Server.Implementations.Channels if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { await using FileStream jsonStream = File.OpenRead(cachePath); - var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (cachedResult != null) { return null; @@ -884,7 +885,7 @@ namespace Emby.Server.Implementations.Channels Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream createStream = File.Create(path); - await JsonSerializer.SerializeAsync(createStream, result, JsonDefaults.GetOptions()).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(createStream, result, _jsonOptions).ConfigureAwait(false); } catch (Exception ex) { diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index 80729a280c..2070df31e4 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -25,6 +25,7 @@ namespace Emby.Server.Implementations.Library private readonly IMediaEncoder _mediaEncoder; private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger, IApplicationPaths appPaths) { @@ -47,7 +48,7 @@ namespace Emby.Server.Implementations.Library try { await using FileStream jsonStream = File.OpenRead(cacheFilePath); - mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Found cached media info"); } @@ -84,7 +85,7 @@ namespace Emby.Server.Implementations.Library { Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); await using FileStream createStream = File.OpenWrite(cacheFilePath); - await JsonSerializer.SerializeAsync(createStream, mediaInfo, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Saved media info to {0}", cacheFilePath); } diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index b3900e4aa1..660ec106bd 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -46,6 +46,7 @@ namespace Emby.Server.Implementations.Library private readonly ConcurrentDictionary _openStreams = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); private IMediaSourceProvider[] _providers; @@ -514,9 +515,9 @@ namespace Emby.Server.Implementations.Library } // TODO: @bond Fix - var json = JsonSerializer.Serialize(mediaSource, JsonDefaults.GetOptions()); + var json = JsonSerializer.Serialize(mediaSource, _jsonOptions); _logger.LogInformation("Live stream opened: " + json); - var clone = JsonSerializer.Deserialize(json, JsonDefaults.GetOptions()); + var clone = JsonSerializer.Deserialize(json, _jsonOptions); if (!request.UserId.Equals(Guid.Empty)) { @@ -642,7 +643,7 @@ namespace Emby.Server.Implementations.Library try { await using FileStream jsonStream = File.OpenRead(cacheFilePath); - mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Found cached media info"); } @@ -679,7 +680,7 @@ namespace Emby.Server.Implementations.Library { Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); await using FileStream createStream = File.Create(cacheFilePath); - await JsonSerializer.SerializeAsync(createStream, mediaInfo, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Saved media info to {0}", cacheFilePath); } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 9609f28816..a70a72b74f 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly IServerApplicationPaths _appPaths; private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); private readonly IServerConfigurationManager _serverConfigurationManager; - + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); private bool _hasExited; private Stream _logFileStream; private string _targetPath; @@ -93,7 +93,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); - var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(mediaSource, JsonDefaults.GetOptions()) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); + var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(mediaSource, _jsonOptions) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); _logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length); _process = new Process diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index bbe9b50dd5..f16d96a592 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -15,6 +15,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { private readonly string _dataPath; private readonly object _fileDataLock = new object(); + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); private T[] _items; public ItemDataProvider( @@ -45,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { var jsonString = File.ReadAllText(_dataPath); - _items = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + _items = JsonSerializer.Deserialize(jsonString, _jsonOptions); return; } catch (Exception ex) @@ -61,7 +62,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { Directory.CreateDirectory(Path.GetDirectoryName(_dataPath)); using FileStream stream = File.OpenWrite(_dataPath); - JsonSerializer.SerializeAsync(stream, _items, JsonDefaults.GetOptions()); + JsonSerializer.SerializeAsync(stream, _items, _jsonOptions); } public IReadOnlyList GetAll() diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 198d196c23..2b8ccfb628 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -36,6 +36,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); private DateTime _lastErrorResponse; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public SchedulesDirect( ILogger logger, @@ -102,9 +103,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings } }; - var jsonOptions = JsonDefaults.GetOptions(); - - var requestString = JsonSerializer.Serialize(requestList, jsonOptions); + var requestString = JsonSerializer.Serialize(requestList, _jsonOptions); _logger.LogDebug("Request string for schedules is: {RequestString}", requestString); using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules"); @@ -112,7 +111,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Headers.TryAddWithoutValidation("token", token); using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, jsonOptions).ConfigureAwait(false); + var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions).ConfigureAwait(false); _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); @@ -123,7 +122,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, jsonOptions).ConfigureAwait(false); + var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions).ConfigureAwait(false); var programDict = programDetails.ToDictionary(p => p.programID, y => y); var programIdsWithImages = @@ -479,7 +478,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return await JsonSerializer.DeserializeAsync>(response, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -508,7 +507,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false); await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync>(response, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); if (root != null) { @@ -649,7 +648,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (string.Equals(root.message, "OK", StringComparison.Ordinal)) { _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token); @@ -705,7 +704,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpResponse.EnsureSuccessStatusCode(); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var response = httpResponse.Content; - var root = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions()).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions).ConfigureAwait(false); return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); } @@ -777,7 +776,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions()).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions).ConfigureAwait(false); _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count); _logger.LogInformation("Mapping Stations to Channel"); diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 2d6fb252d2..3f9e221066 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -36,6 +36,8 @@ namespace Emby.Server.Implementations.Localization private List _cultures; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); + /// /// Initializes a new instance of the class. /// @@ -180,7 +182,7 @@ namespace Emby.Server.Implementations.Localization { StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json")); - return JsonSerializer.Deserialize>(reader.ReadToEnd(), JsonDefaults.GetOptions()); + return JsonSerializer.Deserialize>(reader.ReadToEnd(), _jsonOptions); } /// @@ -345,7 +347,7 @@ namespace Emby.Server.Implementations.Localization // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain if (stream != null) { - var dict = await JsonSerializer.DeserializeAsync>(stream, JsonDefaults.GetOptions()).ConfigureAwait(false); + var dict = await JsonSerializer.DeserializeAsync>(stream, _jsonOptions).ConfigureAwait(false); foreach (var key in dict.Keys) { diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index eee7aeea30..3dca05bf98 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -65,6 +65,11 @@ namespace Emby.Server.Implementations.ScheduledTasks /// private string _id; + /// + /// The options for the json Serializer. + /// + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); + /// /// Initializes a new instance of the class. /// @@ -142,7 +147,7 @@ namespace Emby.Server.Implementations.ScheduledTasks var jsonString = File.ReadAllText(path); if (!string.IsNullOrWhiteSpace(jsonString)) { - _lastExecutionResult = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + _lastExecutionResult = JsonSerializer.Deserialize(jsonString, _jsonOptions); } else { @@ -172,7 +177,7 @@ namespace Emby.Server.Implementations.ScheduledTasks lock (_lastExecutionResultSyncLock) { using FileStream createStream = File.OpenWrite(path); - JsonSerializer.SerializeAsync(createStream, value, JsonDefaults.GetOptions()); + JsonSerializer.SerializeAsync(createStream, value, _jsonOptions); } } } @@ -536,7 +541,7 @@ namespace Emby.Server.Implementations.ScheduledTasks if (File.Exists(path)) { var jsonString = File.ReadAllText(path); - list = JsonSerializer.Deserialize(jsonString, JsonDefaults.GetOptions()); + list = JsonSerializer.Deserialize(jsonString, _jsonOptions); } // Return defaults if file doesn't exist. @@ -573,7 +578,7 @@ namespace Emby.Server.Implementations.ScheduledTasks Directory.CreateDirectory(Path.GetDirectoryName(path)); using FileStream stream = File.OpenWrite(path); - JsonSerializer.SerializeAsync(stream, triggers, JsonDefaults.GetOptions()); + JsonSerializer.SerializeAsync(stream, triggers, _jsonOptions); } /// diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index b960278b85..c3b6af76ea 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Controller.Entities /// public class CollectionFolder : Folder, ICollectionFolder { + private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public static IXmlSerializer XmlSerializer { get; set; } public static IServerApplicationHost ApplicationHost { get; set; } @@ -122,8 +123,7 @@ namespace MediaBrowser.Controller.Entities { LibraryOptions[path] = options; - var jsonOptions = JsonDefaults.GetOptions(); - var clone = JsonSerializer.Deserialize(JsonSerializer.Serialize(options, jsonOptions), jsonOptions); + var clone = JsonSerializer.Deserialize(JsonSerializer.Serialize(options, _jsonOptions), _jsonOptions); foreach (var mediaPath in clone.PathInfos) { if (!string.IsNullOrEmpty(mediaPath.Path)) diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs index a5aeba7d2d..cd9e477432 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs @@ -22,6 +22,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb { private readonly IServerConfigurationManager _config; private readonly IHttpClientFactory _httpClientFactory; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public AudioDbAlbumImageProvider(IServerConfigurationManager config, IHttpClientFactory httpClientFactory) { @@ -58,7 +59,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbAlbumProvider.GetAlbumInfoPath(_config.ApplicationPaths, id); await using FileStream jsonStream = File.OpenRead(path); - var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.album != null && obj.album.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs index 9a61abc1ac..f463a3566b 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs @@ -29,6 +29,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly IHttpClientFactory _httpClientFactory; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public static AudioDbAlbumProvider Current; @@ -65,7 +66,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetAlbumInfoPath(_config.ApplicationPaths, id); await using FileStream jsonStream = File.OpenRead(path); - var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.album != null && obj.album.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs index 639bbe8595..36700d1917 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs @@ -22,6 +22,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb { private readonly IServerConfigurationManager _config; private readonly IHttpClientFactory _httpClientFactory; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public AudioDbArtistImageProvider(IServerConfigurationManager config, IHttpClientFactory httpClientFactory) { @@ -60,7 +61,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbArtistProvider.GetArtistInfoPath(_config.ApplicationPaths, id); await using FileStream jsonStream = File.OpenRead(path); - var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.artists != null && obj.artists.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs index 71efd194e3..7a15adb8e8 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs @@ -31,6 +31,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly IHttpClientFactory _httpClientFactory; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public AudioDbArtistProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpClientFactory) { @@ -66,7 +67,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetArtistInfoPath(_config.ApplicationPaths, id); await using FileStream jsonStream = File.OpenRead(path); - var obj = await JsonSerializer.DeserializeAsync(jsonStream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.artists != null && obj.artists.Count > 0) { diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 7e9ef974e2..3ef404b535 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -32,6 +32,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IApplicationHost _appHost; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public OmdbItemProvider( IApplicationHost appHost, @@ -136,7 +137,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (isSearch) { - var searchResultList = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var searchResultList = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (searchResultList != null && searchResultList.Search != null) { resultList.AddRange(searchResultList.Search); @@ -144,7 +145,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } else { - var result = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); + var result = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase)) { resultList.Add(result); diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index fa75e4ec49..3c21629990 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -28,6 +28,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IHttpClientFactory _httpClientFactory; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IApplicationHost _appHost; + private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); public OmdbProvider(IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IApplicationHost appHost, IServerConfigurationManager configurationManager) { @@ -219,7 +220,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } - var result = JsonSerializer.Deserialize(resultString, JsonDefaults.GetOptions()); + var result = JsonSerializer.Deserialize(resultString, _jsonOptions); return result; } @@ -238,7 +239,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } - var result = JsonSerializer.Deserialize(resultString, JsonDefaults.GetOptions()); + var result = JsonSerializer.Deserialize(resultString, _jsonOptions); return result; } @@ -296,11 +297,10 @@ namespace MediaBrowser.Providers.Plugins.Omdb "i={0}&plot=short&tomatoes=true&r=json", imdbParam)); - var jsonOptions = JsonDefaults.GetOptions(); - var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, jsonOptions, cancellationToken).ConfigureAwait(false); + var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream jsonFileStream = File.OpenWrite(path); - await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; } @@ -334,23 +334,22 @@ namespace MediaBrowser.Providers.Plugins.Omdb imdbParam, seasonId)); - var jsonOptions = JsonDefaults.GetOptions(); - var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, jsonOptions, cancellationToken).ConfigureAwait(false); + var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); await using FileStream jsonFileStream = File.OpenWrite(path); - await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, jsonOptions, cancellationToken).ConfigureAwait(false); + await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; } - public static async Task GetDeserializedOmdbResponse(HttpClient httpClient, string url, JsonSerializerOptions jsonOptions, CancellationToken cancellationToken) + public static async Task GetDeserializedOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) { using var response = await GetOmdbResponse(httpClient, url, cancellationToken).ConfigureAwait(false); var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); // OMDb is sending "N/A" for no empty number fields content = content.Replace("\"N/A\"", "\"\"", StringComparison.InvariantCulture); - return JsonSerializer.Deserialize(content, jsonOptions); + return JsonSerializer.Deserialize(content, _jsonOptions); } public static Task GetOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) From 6ddbe8420f6bc61b2561c20def326fa1b4291c5e Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 24 Dec 2020 08:10:30 -0700 Subject: [PATCH 14/24] Add tests for special Omdb json --- .../JsonOmdbNotAvailableConverterFactory.cs | 36 +++++++++++++++++ .../JsonOmdbNotAvailableStringConverter.cs | 33 +++++++++++++++ .../JsonOmdbNotAvailableStructConverter.cs | 35 ++++++++++++++++ .../Plugins/Omdb/OmdbProvider.cs | 40 +++++++++++++++++-- .../Jellyfin.Common.Tests.csproj | 1 + .../Json/JsonOmdbConverterTests.cs | 21 ++++++++++ 6 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs create mode 100644 MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs create mode 100644 MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs create mode 100644 tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs new file mode 100644 index 0000000000..5994ce9226 --- /dev/null +++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs @@ -0,0 +1,36 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Common.Json.Converters +{ + /// + /// Json Omdb converter factory. + /// + /// + /// Remove when Omdb is moved to plugin. + /// + public class JsonOmdbNotAvailableConverterFactory : JsonConverterFactory + { + /// + public override bool CanConvert(Type typeToConvert) + { + return (typeToConvert.IsGenericType + && typeToConvert.GetGenericTypeDefinition() == typeof(Nullable<>) + && typeToConvert.GenericTypeArguments[0].IsValueType) + || typeToConvert == typeof(string); + } + + /// + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + if (typeToConvert == typeof(string)) + { + return (JsonConverter)Activator.CreateInstance(typeof(JsonOmdbNotAvailableStringConverter)); + } + + var structType = typeToConvert.GenericTypeArguments[0]; + return (JsonConverter)Activator.CreateInstance(typeof(JsonOmdbNotAvailableStructConverter<>).MakeGenericType(structType)); + } + } +} diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs new file mode 100644 index 0000000000..2b343a5059 --- /dev/null +++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Common.Json.Converters +{ + /// + /// Converts a string N/A to string.Empty. + /// + public class JsonOmdbNotAvailableStringConverter : JsonConverter + { + /// + public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var str = reader.GetString(); + if (str != null && str.Equals("N/A", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + } + + return JsonSerializer.Deserialize(ref reader, options); + } + + /// + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(value, options); + } + } +} diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs new file mode 100644 index 0000000000..b9e67ce2de --- /dev/null +++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStructConverter.cs @@ -0,0 +1,35 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Common.Json.Converters +{ + /// + /// Converts a string N/A to string.Empty. + /// + /// The resulting type. + public class JsonOmdbNotAvailableStructConverter : JsonConverter + where T : struct + { + /// + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var str = reader.GetString(); + if (str != null && str.Equals("N/A", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + } + + return JsonSerializer.Deserialize(ref reader, options); + } + + /// + public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(value, options); + } + } +} diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 3c21629990..1ebd1b13a3 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -8,10 +8,12 @@ using System.Linq; using System.Net.Http; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; using MediaBrowser.Common.Json; +using MediaBrowser.Common.Json.Converters; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -467,74 +469,104 @@ namespace MediaBrowser.Providers.Plugins.Omdb return string.Equals(lang, "en", StringComparison.OrdinalIgnoreCase); } - internal class SeasonRootObject + public class SeasonRootObject { + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Title { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string seriesID { get; set; } - public int Season { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + public int? Season { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public int? totalSeasons { get; set; } public RootObject[] Episodes { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Response { get; set; } } - internal class RootObject + public class RootObject { + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Title { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Year { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Rated { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Released { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Runtime { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Genre { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Director { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Writer { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Actors { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Plot { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Language { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Country { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Awards { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Poster { get; set; } public List Ratings { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Metascore { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string imdbRating { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string imdbVotes { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string imdbID { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Type { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string DVD { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string BoxOffice { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Production { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Website { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] public string Response { get; set; } - public int Episode { get; set; } + [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + public int? Episode { get; set; } public float? GetRottenTomatoScore() { diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index af4684f562..91b34546f3 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -29,6 +29,7 @@ + diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs new file mode 100644 index 0000000000..90537dc1ff --- /dev/null +++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs @@ -0,0 +1,21 @@ +using System.Text.Json; +using MediaBrowser.Common.Json; +using MediaBrowser.Providers.Plugins.Omdb; +using Xunit; + +namespace Jellyfin.Common.Tests.Json +{ + public static class JsonOmdbConverterTests + { + [Fact] + public static void Deserialize_Omdb_Response_Not_Available_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 seasonRootObject = JsonSerializer.Deserialize(Input, JsonDefaults.GetOptions()); + Assert.NotNull(seasonRootObject); + Assert.Null(seasonRootObject?.Awards); + Assert.Null(seasonRootObject?.Episode); + Assert.Null(seasonRootObject?.Metascore); + } + } +} From fc212e5e5f698482abbf19912787cd2691bae981 Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 24 Dec 2020 08:16:50 -0700 Subject: [PATCH 15/24] Remove JsonOmdbNotAvailableConverterFactory --- .../JsonOmdbNotAvailableConverterFactory.cs | 36 ----------- .../Plugins/Omdb/OmdbProvider.cs | 60 +++++++++---------- 2 files changed, 30 insertions(+), 66 deletions(-) delete mode 100644 MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs deleted file mode 100644 index 5994ce9226..0000000000 --- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableConverterFactory.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace MediaBrowser.Common.Json.Converters -{ - /// - /// Json Omdb converter factory. - /// - /// - /// Remove when Omdb is moved to plugin. - /// - public class JsonOmdbNotAvailableConverterFactory : JsonConverterFactory - { - /// - public override bool CanConvert(Type typeToConvert) - { - return (typeToConvert.IsGenericType - && typeToConvert.GetGenericTypeDefinition() == typeof(Nullable<>) - && typeToConvert.GenericTypeArguments[0].IsValueType) - || typeToConvert == typeof(string); - } - - /// - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) - { - if (typeToConvert == typeof(string)) - { - return (JsonConverter)Activator.CreateInstance(typeof(JsonOmdbNotAvailableStringConverter)); - } - - var structType = typeToConvert.GenericTypeArguments[0]; - return (JsonConverter)Activator.CreateInstance(typeof(JsonOmdbNotAvailableStructConverter<>).MakeGenericType(structType)); - } - } -} diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 1ebd1b13a3..e700e6969b 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -471,101 +471,101 @@ namespace MediaBrowser.Providers.Plugins.Omdb public class SeasonRootObject { - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Title { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string seriesID { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStructConverter))] public int? Season { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStructConverter))] public int? totalSeasons { get; set; } public RootObject[] Episodes { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Response { get; set; } } public class RootObject { - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Title { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Year { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Rated { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Released { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Runtime { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Genre { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Director { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Writer { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Actors { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Plot { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Language { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Country { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Awards { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Poster { get; set; } public List Ratings { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Metascore { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string imdbRating { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string imdbVotes { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string imdbID { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Type { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string DVD { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string BoxOffice { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Production { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Website { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Response { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableConverterFactory))] + [JsonConverter(typeof(JsonOmdbNotAvailableStructConverter))] public int? Episode { get; set; } public float? GetRottenTomatoScore() From e09dd5aa87a61c38e3995d351efd8419555939f6 Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 24 Dec 2020 08:26:26 -0700 Subject: [PATCH 16/24] Add targeted tests --- .../Json/JsonOmdbConverterTests.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs index 90537dc1ff..aae95e7314 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs @@ -1,5 +1,7 @@ using System.Text.Json; +using System.Text.Json.Serialization; using MediaBrowser.Common.Json; +using MediaBrowser.Common.Json.Converters; using MediaBrowser.Providers.Plugins.Omdb; using Xunit; @@ -17,5 +19,39 @@ namespace Jellyfin.Common.Tests.Json Assert.Null(seasonRootObject?.Episode); Assert.Null(seasonRootObject?.Metascore); } + + [Fact] + public static void Deserialize_Not_Available_Int_Success() + { + const string Input = "\"N/A\""; + var options = new JsonSerializerOptions + { + NumberHandling = JsonNumberHandling.AllowReadingFromString, + Converters = + { + new JsonOmdbNotAvailableStructConverter() + } + }; + + var result = JsonSerializer.Deserialize(Input, options); + Assert.Null(result); + } + + [Fact] + public static void Deserialize_Not_Available_String_Success() + { + const string Input = "\"N/A\""; + var options = new JsonSerializerOptions + { + Converters = + { + new JsonOmdbNotAvailableStringConverter() + } + }; + + options.Converters.Add(new JsonOmdbNotAvailableStringConverter()); + var result = JsonSerializer.Deserialize(Input, options); + Assert.Null(result); + } } } From af62ab490c1afc4702db88e5f004aa2fb5930b33 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Dec 2020 15:21:57 +0100 Subject: [PATCH 17/24] Update tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj Co-authored-by: Bond-009 --- tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 91b34546f3..19c5612c06 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -29,7 +29,7 @@ - + From aacda01ca5a1197a1b6e637488639dae6455d6d8 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Dec 2020 19:21:58 +0100 Subject: [PATCH 18/24] Add more tests --- .../JsonOmdbNotAvailableStringConverter.cs | 2 + .../Json/JsonOmdbConverterTests.cs | 90 ++++++++++++++----- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs index 2b343a5059..4fec2ea3fd 100644 --- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs +++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs @@ -19,6 +19,8 @@ namespace MediaBrowser.Common.Json.Converters { return null; } + + return str; } return JsonSerializer.Deserialize(ref reader, options); diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs index aae95e7314..e1436a648e 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs @@ -7,10 +7,20 @@ using Xunit; namespace Jellyfin.Common.Tests.Json { - public static class JsonOmdbConverterTests + public class JsonOmdbConverterTests { + private readonly JsonSerializerOptions _options; + + public JsonOmdbConverterTests() + { + _options = new JsonSerializerOptions(); + _options.Converters.Add(new JsonOmdbNotAvailableStringConverter()); + _options.Converters.Add(new JsonOmdbNotAvailableStructConverter()); + _options.NumberHandling = JsonNumberHandling.AllowReadingFromString; + } + [Fact] - public static void Deserialize_Omdb_Response_Not_Available_Success() + public void Deserialize_Omdb_Response_Not_Available_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 seasonRootObject = JsonSerializer.Deserialize(Input, JsonDefaults.GetOptions()); @@ -21,36 +31,68 @@ namespace Jellyfin.Common.Tests.Json } [Fact] - public static void Deserialize_Not_Available_Int_Success() + public void Deserialize_Not_Available_Int_Success() { const string Input = "\"N/A\""; - var options = new JsonSerializerOptions - { - NumberHandling = JsonNumberHandling.AllowReadingFromString, - Converters = - { - new JsonOmdbNotAvailableStructConverter() - } - }; - - var result = JsonSerializer.Deserialize(Input, options); + + var result = JsonSerializer.Deserialize(Input, _options); + Assert.Null(result); + } + + [Fact] + public void Deserialize_Not_Available_String_Success() + { + const string Input = "\"N/A\""; + + var result = JsonSerializer.Deserialize(Input, _options); + Assert.Null(result); + } + + [Fact] + public void Deserialize_Normal_String_Success() + { + const string Expected = "Jellyfin"; + const string Input = "\"Jellyfin\""; + + var result = JsonSerializer.Deserialize(Input, _options); + Assert.Equal(Expected, result); + } + + [Fact] + public void Deserialize_Null_Success() + { + const string Input = "null"; + + var result = JsonSerializer.Deserialize(Input, _options); Assert.Null(result); } [Fact] - public static void Deserialize_Not_Available_String_Success() + public void Deserialize_Number_Success() + { + const int Number = 8; + const string Input = "8"; + + var result = JsonSerializer.Deserialize(Input, _options); + Assert.Equal(Number, result); + } + + [Fact] + public void Deserialize_Quoted_Number_Success() + { + const int Number = 8; + const string Input = "\"8\""; + + var result = JsonSerializer.Deserialize(Input, _options); + Assert.Equal(Number, result); + } + + [Fact] + public void Deserialize_NA_Number_Success() { const string Input = "\"N/A\""; - var options = new JsonSerializerOptions - { - Converters = - { - new JsonOmdbNotAvailableStringConverter() - } - }; - - options.Converters.Add(new JsonOmdbNotAvailableStringConverter()); - var result = JsonSerializer.Deserialize(Input, options); + + var result = JsonSerializer.Deserialize(Input, _options); Assert.Null(result); } } From e0499f87690bca88c878b2115ba9e2dbb00f0ad4 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Dec 2020 19:37:38 +0100 Subject: [PATCH 19/24] Remove attributes --- .../Plugins/Omdb/OmdbItemProvider.cs | 7 +++- .../Plugins/Omdb/OmdbProvider.cs | 38 +++---------------- .../Json/JsonOmdbConverterTests.cs | 2 +- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 3ef404b535..71d5510632 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; using MediaBrowser.Common.Json; +using MediaBrowser.Common.Json.Converters; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -32,7 +33,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IApplicationHost _appHost; - private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); + private readonly JsonSerializerOptions _jsonOptions; public OmdbItemProvider( IApplicationHost appHost, @@ -46,6 +47,10 @@ namespace MediaBrowser.Providers.Plugins.Omdb _fileSystem = fileSystem; _configurationManager = configurationManager; _appHost = appHost; + + _jsonOptions = new JsonSerializerOptions(JsonDefaults.GetOptions()); + _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter()); + _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStructConverter()); } public string Name => "The Open Movie Database"; diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index e700e6969b..a177ae30a9 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IHttpClientFactory _httpClientFactory; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IApplicationHost _appHost; - private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions(); + private readonly JsonSerializerOptions _jsonOptions; public OmdbProvider(IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IApplicationHost appHost, IServerConfigurationManager configurationManager) { @@ -38,6 +38,10 @@ namespace MediaBrowser.Providers.Plugins.Omdb _fileSystem = fileSystem; _configurationManager = configurationManager; _appHost = appHost; + + _jsonOptions = new JsonSerializerOptions(JsonDefaults.GetOptions()); + _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter()); + _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStructConverter()); } public async Task Fetch(MetadataResult itemResult, string imdbId, string language, string country, CancellationToken cancellationToken) @@ -344,7 +348,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb return path; } - public static async Task GetDeserializedOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) + public async Task GetDeserializedOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) { using var response = await GetOmdbResponse(httpClient, url, cancellationToken).ConfigureAwait(false); var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); @@ -471,101 +475,71 @@ namespace MediaBrowser.Providers.Plugins.Omdb public class SeasonRootObject { - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Title { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string seriesID { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStructConverter))] public int? Season { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStructConverter))] public int? totalSeasons { get; set; } public RootObject[] Episodes { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Response { get; set; } } public class RootObject { - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Title { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Year { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Rated { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Released { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Runtime { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Genre { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Director { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Writer { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Actors { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Plot { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Language { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Country { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Awards { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Poster { get; set; } public List Ratings { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Metascore { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string imdbRating { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string imdbVotes { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string imdbID { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Type { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string DVD { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string BoxOffice { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Production { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Website { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStringConverter))] public string Response { get; set; } - [JsonConverter(typeof(JsonOmdbNotAvailableStructConverter))] public int? Episode { get; set; } public float? GetRottenTomatoScore() diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs index e1436a648e..06a4855bfd 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Common.Tests.Json public void Deserialize_Omdb_Response_Not_Available_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 seasonRootObject = JsonSerializer.Deserialize(Input, JsonDefaults.GetOptions()); + var seasonRootObject = JsonSerializer.Deserialize(Input, _options); Assert.NotNull(seasonRootObject); Assert.Null(seasonRootObject?.Awards); Assert.Null(seasonRootObject?.Episode); From f73bb92ce3a86a024cd72a59bbc461707687a4c7 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 26 Dec 2020 20:00:54 +0100 Subject: [PATCH 20/24] Remove manual N/A removal and write directly to stream --- .../LiveTv/EmbyTV/EncodedRecorder.cs | 8 +++----- MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index a70a72b74f..2545ffdd2e 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -64,7 +64,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logger.LogInformation("Recording completed to file {0}", targetFile); } - private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) + private async Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) { _targetPath = targetFile; Directory.CreateDirectory(Path.GetDirectoryName(targetFile)); @@ -93,8 +93,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); - var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(mediaSource, _jsonOptions) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); - _logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length); + await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); + await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken); _process = new Process { @@ -113,8 +113,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _ = StartStreamingLog(_process.StandardError.BaseStream, _logFileStream); _logger.LogInformation("ffmpeg recording process started for {0}", _targetPath); - - return _taskCompletionSource.Task; } private string GetCommandLineArgs(MediaSourceInfo mediaSource, string inputTempFile, string targetFile, TimeSpan duration) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index a177ae30a9..9f3fdd60b1 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -353,8 +353,6 @@ namespace MediaBrowser.Providers.Plugins.Omdb using var response = await GetOmdbResponse(httpClient, url, cancellationToken).ConfigureAwait(false); var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); - // OMDb is sending "N/A" for no empty number fields - content = content.Replace("\"N/A\"", "\"\"", StringComparison.InvariantCulture); return JsonSerializer.Deserialize(content, _jsonOptions); } From 21fd124bcaabcc1c01d58757ed54b5fe09273c36 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 27 Dec 2020 11:15:46 +0100 Subject: [PATCH 21/24] Code revie --- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 6 +++--- MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 2545ffdd2e..78a82118ed 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); - await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken); + await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); _process = new Process { diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 3dca05bf98..0bb627192f 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -151,7 +151,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } else { - _logger.LogDebug("Scheduled Task history file {path} is empty. Skipping deserialization.", path); + _logger.LogDebug("Scheduled Task history file {Path} is empty. Skipping deserialization.", path); } } catch (Exception ex) @@ -577,8 +577,8 @@ namespace Emby.Server.Implementations.ScheduledTasks Directory.CreateDirectory(Path.GetDirectoryName(path)); - using FileStream stream = File.OpenWrite(path); - JsonSerializer.SerializeAsync(stream, triggers, _jsonOptions); + var json = JsonSerializer.Serialize(triggers, _jsonOptions); + File.WriteAllText(path, json); } /// diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 9f3fdd60b1..25371e27ea 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -351,9 +351,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb public async Task GetDeserializedOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) { using var response = await GetOmdbResponse(httpClient, url, cancellationToken).ConfigureAwait(false); - var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); + await using Stream content = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return JsonSerializer.Deserialize(content, _jsonOptions); + return await JsonSerializer.DeserializeAsync(content, _jsonOptions, cancellationToken).ConfigureAwait(false); } public static Task GetOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) From 9e0f4257838ca79b0babe7bbb62ae2a79797fc26 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 Dec 2020 23:41:46 +0100 Subject: [PATCH 22/24] Make RootObject and SeasonRootObject internal again --- MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs | 4 ++-- MediaBrowser.Providers/Properties/AssemblyInfo.cs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 25371e27ea..2372e31834 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -471,7 +471,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb return string.Equals(lang, "en", StringComparison.OrdinalIgnoreCase); } - public class SeasonRootObject + internal class SeasonRootObject { public string Title { get; set; } @@ -486,7 +486,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb public string Response { get; set; } } - public class RootObject + internal class RootObject { public string Title { get; set; } diff --git a/MediaBrowser.Providers/Properties/AssemblyInfo.cs b/MediaBrowser.Providers/Properties/AssemblyInfo.cs index f1c46899ce..fe4749c799 100644 --- a/MediaBrowser.Providers/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Providers/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Resources; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -14,6 +15,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] +[assembly: InternalsVisibleTo("Jellyfin.Common.Tests")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from From 8ac1ed16ca6d539cf9061b3c9de139dcf148f401 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 29 Dec 2020 00:15:36 +0100 Subject: [PATCH 23/24] Use Theory instead of Fact for unit tests --- .../Json/JsonOmdbConverterTests.cs | 71 ++++++------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs index 06a4855bfd..6f85fe0929 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs @@ -1,6 +1,5 @@ using System.Text.Json; using System.Text.Json.Serialization; -using MediaBrowser.Common.Json; using MediaBrowser.Common.Json.Converters; using MediaBrowser.Providers.Plugins.Omdb; using Xunit; @@ -30,70 +29,40 @@ namespace Jellyfin.Common.Tests.Json Assert.Null(seasonRootObject?.Metascore); } - [Fact] - public void Deserialize_Not_Available_Int_Success() + [Theory] + [InlineData("\"N/A\"")] + [InlineData("null")] + public void Deserialization_To_Nullable_Int_Shoud_Be_Null(string input) { - const string Input = "\"N/A\""; - - var result = JsonSerializer.Deserialize(Input, _options); + var result = JsonSerializer.Deserialize(input, _options); Assert.Null(result); } - [Fact] - public void Deserialize_Not_Available_String_Success() + [Theory] + [InlineData("\"N/A\"")] + [InlineData("null")] + public void Deserialization_To_Nullable_String_Shoud_Be_Null(string input) { - const string Input = "\"N/A\""; - - var result = JsonSerializer.Deserialize(Input, _options); + var result = JsonSerializer.Deserialize(input, _options); Assert.Null(result); } - [Fact] - public void Deserialize_Normal_String_Success() + [Theory] + [InlineData("\"8\"", 8)] + [InlineData("8", 8)] + public void Deserialize_Int_Success(string input, int expected) { - const string Expected = "Jellyfin"; - const string Input = "\"Jellyfin\""; - - var result = JsonSerializer.Deserialize(Input, _options); - Assert.Equal(Expected, result); + var result = JsonSerializer.Deserialize(input, _options); + Assert.Equal(result, expected); } [Fact] - public void Deserialize_Null_Success() + public void Deserialize_Normal_String_Success() { - const string Input = "null"; - + const string Input = "\"Jellyfin\""; + const string Expected = "Jellyfin"; var result = JsonSerializer.Deserialize(Input, _options); - Assert.Null(result); - } - - [Fact] - public void Deserialize_Number_Success() - { - const int Number = 8; - const string Input = "8"; - - var result = JsonSerializer.Deserialize(Input, _options); - Assert.Equal(Number, result); - } - - [Fact] - public void Deserialize_Quoted_Number_Success() - { - const int Number = 8; - const string Input = "\"8\""; - - var result = JsonSerializer.Deserialize(Input, _options); - Assert.Equal(Number, result); - } - - [Fact] - public void Deserialize_NA_Number_Success() - { - const string Input = "\"N/A\""; - - var result = JsonSerializer.Deserialize(Input, _options); - Assert.Null(result); + Assert.Equal(Expected, result); } } } From 3dec1fd6b23fa4f7f9bc3f66edca8ec0f285ae0f Mon Sep 17 00:00:00 2001 From: David Date: Tue, 29 Dec 2020 00:35:59 +0100 Subject: [PATCH 24/24] Use UTF8 encoding and async correctly --- Emby.Server.Implementations/ApplicationHost.cs | 3 ++- Emby.Server.Implementations/Channels/ChannelManager.cs | 7 ++++--- .../LiveTv/EmbyTV/ItemDataProvider.cs | 8 +++++--- .../ScheduledTasks/ScheduledTaskWorker.cs | 7 ++++--- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 115d94b316..8fa712914a 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -10,6 +10,7 @@ using System.Net; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; +using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -1047,7 +1048,7 @@ namespace Emby.Server.Implementations var metafile = Path.Combine(dir, "meta.json"); if (File.Exists(metafile)) { - var jsonString = File.ReadAllText(metafile); + var jsonString = File.ReadAllText(metafile, Encoding.UTF8); var manifest = JsonSerializer.Deserialize(jsonString, _jsonOptions); if (!Version.TryParse(manifest.TargetAbi, out var targetAbi)) diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index cf6a87ecfd..2d5b19fa69 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -341,7 +342,7 @@ namespace Emby.Server.Implementations.Channels try { - var jsonString = File.ReadAllText(path); + var jsonString = File.ReadAllText(path, Encoding.UTF8); return JsonSerializer.Deserialize>(jsonString, _jsonOptions) ?? new List(); } @@ -1180,11 +1181,11 @@ namespace Emby.Server.Implementations.Channels { if (enableMediaProbe && !info.IsLiveStream && item.HasPathProtocol) { - await SaveMediaSources(item, new List()); + await SaveMediaSources(item, new List()).ConfigureAwait(false); } else { - await SaveMediaSources(item, info.MediaSources); + await SaveMediaSources(item, info.MediaSources).ConfigureAwait(false); } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index f16d96a592..c80ecd6b3c 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Text.Json; +using System.Threading.Tasks; using MediaBrowser.Common.Json; using Microsoft.Extensions.Logging; @@ -45,7 +47,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { - var jsonString = File.ReadAllText(_dataPath); + var jsonString = File.ReadAllText(_dataPath, Encoding.UTF8); _items = JsonSerializer.Deserialize(jsonString, _jsonOptions); return; } @@ -61,8 +63,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private void SaveList() { Directory.CreateDirectory(Path.GetDirectoryName(_dataPath)); - using FileStream stream = File.OpenWrite(_dataPath); - JsonSerializer.SerializeAsync(stream, _items, _jsonOptions); + var jsonString = JsonSerializer.Serialize(_items, _jsonOptions); + File.WriteAllText(_dataPath, jsonString); } public IReadOnlyList GetAll() diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 0bb627192f..29440b64a0 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -4,6 +4,7 @@ using System; using System.Globalization; using System.IO; using System.Linq; +using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -144,7 +145,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - var jsonString = File.ReadAllText(path); + var jsonString = File.ReadAllText(path, Encoding.UTF8); if (!string.IsNullOrWhiteSpace(jsonString)) { _lastExecutionResult = JsonSerializer.Deserialize(jsonString, _jsonOptions); @@ -540,7 +541,7 @@ namespace Emby.Server.Implementations.ScheduledTasks TaskTriggerInfo[] list = null; if (File.Exists(path)) { - var jsonString = File.ReadAllText(path); + var jsonString = File.ReadAllText(path, Encoding.UTF8); list = JsonSerializer.Deserialize(jsonString, _jsonOptions); } @@ -578,7 +579,7 @@ namespace Emby.Server.Implementations.ScheduledTasks Directory.CreateDirectory(Path.GetDirectoryName(path)); var json = JsonSerializer.Serialize(triggers, _jsonOptions); - File.WriteAllText(path, json); + File.WriteAllText(path, json, Encoding.UTF8); } ///