Merge pull request #3984 from crobibero/json-prerelease
Use Prerelease System.Text.Json
This commit is contained in:
commit
4f6c98b325
|
@ -90,9 +90,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
_typeMapper = new TypeMapper();
|
_typeMapper = new TypeMapper();
|
||||||
_jsonOptions = JsonDefaults.GetOptions();
|
_jsonOptions = JsonDefaults.GetOptions();
|
||||||
|
|
||||||
// GetItem throws NotSupportedException with this enabled, so hardcode false.
|
|
||||||
_jsonOptions.IgnoreNullValues = false;
|
|
||||||
|
|
||||||
DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
|
DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketMessage<object> stub;
|
WebSocketMessage<object>? stub;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -209,6 +209,12 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stub == null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error processing web socket message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Tell the PipeReader how much of the buffer we have consumed
|
// Tell the PipeReader how much of the buffer we have consumed
|
||||||
reader.AdvanceTo(buffer.End);
|
reader.AdvanceTo(buffer.End);
|
||||||
|
|
||||||
|
|
|
@ -120,10 +120,14 @@ namespace Jellyfin.Api.Controllers
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var configuration = (BasePluginConfiguration)await JsonSerializer.DeserializeAsync(Request.Body, plugin.ConfigurationType, _serializerOptions)
|
var configuration = (BasePluginConfiguration?)await JsonSerializer.DeserializeAsync(Request.Body, plugin.ConfigurationType, _serializerOptions)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
plugin.UpdateConfiguration(configuration);
|
if (configuration != null)
|
||||||
|
{
|
||||||
|
plugin.UpdateConfiguration(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,11 @@ namespace Jellyfin.Api.Helpers
|
||||||
{
|
{
|
||||||
// Since we're going to be setting properties on MediaSourceInfos that come out of _mediaSourceManager, we should clone it
|
// Since we're going to be setting properties on MediaSourceInfos that come out of _mediaSourceManager, we should clone it
|
||||||
// Should we move this directly into MediaSourceManager?
|
// Should we move this directly into MediaSourceManager?
|
||||||
result.MediaSources = JsonSerializer.Deserialize<MediaSourceInfo[]>(JsonSerializer.SerializeToUtf8Bytes(mediaSources));
|
var mediaSourcesClone = JsonSerializer.Deserialize<MediaSourceInfo[]>(JsonSerializer.SerializeToUtf8Bytes(mediaSources));
|
||||||
|
if (mediaSourcesClone != null)
|
||||||
|
{
|
||||||
|
result.MediaSources = mediaSourcesClone;
|
||||||
|
}
|
||||||
|
|
||||||
result.PlaySessionId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
result.PlaySessionId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,8 @@ namespace Jellyfin.Server.Extensions
|
||||||
// From JsonDefaults
|
// From JsonDefaults
|
||||||
options.JsonSerializerOptions.ReadCommentHandling = jsonOptions.ReadCommentHandling;
|
options.JsonSerializerOptions.ReadCommentHandling = jsonOptions.ReadCommentHandling;
|
||||||
options.JsonSerializerOptions.WriteIndented = jsonOptions.WriteIndented;
|
options.JsonSerializerOptions.WriteIndented = jsonOptions.WriteIndented;
|
||||||
options.JsonSerializerOptions.IgnoreNullValues = jsonOptions.IgnoreNullValues;
|
options.JsonSerializerOptions.DefaultIgnoreCondition = jsonOptions.DefaultIgnoreCondition;
|
||||||
|
options.JsonSerializerOptions.NumberHandling = jsonOptions.NumberHandling;
|
||||||
|
|
||||||
options.JsonSerializerOptions.Converters.Clear();
|
options.JsonSerializerOptions.Converters.Clear();
|
||||||
foreach (var converter in jsonOptions.Converters)
|
foreach (var converter in jsonOptions.Converters)
|
||||||
|
|
|
@ -81,6 +81,11 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||||
foreach (var result in results)
|
foreach (var result in results)
|
||||||
{
|
{
|
||||||
var dto = JsonSerializer.Deserialize<DisplayPreferencesDto>(result[3].ToString(), _jsonOptions);
|
var dto = JsonSerializer.Deserialize<DisplayPreferencesDto>(result[3].ToString(), _jsonOptions);
|
||||||
|
if (dto == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var chromecastVersion = dto.CustomPrefs.TryGetValue("chromecastVersion", out var version)
|
var chromecastVersion = dto.CustomPrefs.TryGetValue("chromecastVersion", out var version)
|
||||||
? chromecastDict[version]
|
? chromecastDict[version]
|
||||||
: ChromecastVersion.Stable;
|
: ChromecastVersion.Stable;
|
||||||
|
|
|
@ -74,7 +74,12 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||||
|
|
||||||
foreach (var entry in queryResult)
|
foreach (var entry in queryResult)
|
||||||
{
|
{
|
||||||
UserMockup mockup = JsonSerializer.Deserialize<UserMockup>(entry[2].ToBlob(), JsonDefaults.GetOptions());
|
UserMockup? mockup = JsonSerializer.Deserialize<UserMockup>(entry[2].ToBlob(), JsonDefaults.GetOptions());
|
||||||
|
if (mockup == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var userDataDir = Path.Combine(_paths.UserConfigurationDirectoryPath, mockup.Name);
|
var userDataDir = Path.Combine(_paths.UserConfigurationDirectoryPath, mockup.Name);
|
||||||
|
|
||||||
var config = File.Exists(Path.Combine(userDataDir, "config.xml"))
|
var config = File.Exists(Path.Combine(userDataDir, "config.xml"))
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Buffers.Text;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Json.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Double to String JSON converter.
|
|
||||||
/// Web client send quoted doubles.
|
|
||||||
/// </summary>
|
|
||||||
public class JsonDoubleConverter : JsonConverter<double>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Read JSON string as double.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reader"><see cref="Utf8JsonReader"/>.</param>
|
|
||||||
/// <param name="typeToConvert">Type.</param>
|
|
||||||
/// <param name="options">Options.</param>
|
|
||||||
/// <returns>Parsed value.</returns>
|
|
||||||
public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.String)
|
|
||||||
{
|
|
||||||
// try to parse number directly from bytes
|
|
||||||
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
|
|
||||||
if (Utf8Parser.TryParse(span, out double number, out var bytesConsumed) && span.Length == bytesConsumed)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
|
|
||||||
if (double.TryParse(reader.GetString(), out number))
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to default handling
|
|
||||||
return reader.GetDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write double to JSON string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="writer"><see cref="Utf8JsonWriter"/>.</param>
|
|
||||||
/// <param name="value">Value to write.</param>
|
|
||||||
/// <param name="options">Options.</param>
|
|
||||||
public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
writer.WriteNumberValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Buffers.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Json.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a int32 object or value to/from JSON.
|
|
||||||
/// </summary>
|
|
||||||
public class JsonInt32Converter : JsonConverter<int>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.String)
|
|
||||||
{
|
|
||||||
ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
|
|
||||||
if (Utf8Parser.TryParse(span, out int number, out int bytesConsumed) && span.Length == bytesConsumed)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int.TryParse(reader.GetString(), out number))
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.GetInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
writer.WriteNumberValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Buffers.Text;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Json.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Parse JSON string as long.
|
|
||||||
/// Javascript does not support 64-bit integers.
|
|
||||||
/// </summary>
|
|
||||||
public class JsonInt64Converter : JsonConverter<long>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Read JSON string as int64.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reader"><see cref="Utf8JsonReader"/>.</param>
|
|
||||||
/// <param name="type">Type.</param>
|
|
||||||
/// <param name="options">Options.</param>
|
|
||||||
/// <returns>Parsed value.</returns>
|
|
||||||
public override long Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.String)
|
|
||||||
{
|
|
||||||
// try to parse number directly from bytes
|
|
||||||
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
|
|
||||||
if (Utf8Parser.TryParse(span, out long number, out var bytesConsumed) && span.Length == bytesConsumed)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
|
|
||||||
if (long.TryParse(reader.GetString(), out number))
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to default handling
|
|
||||||
return reader.GetInt64();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write long to JSON long.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="writer"><see cref="Utf8JsonWriter"/>.</param>
|
|
||||||
/// <param name="value">Value to write.</param>
|
|
||||||
/// <param name="options">Options.</param>
|
|
||||||
public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
writer.WriteNumberValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Json.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converter for Dictionaries without string key.
|
|
||||||
/// TODO This can be removed when System.Text.Json supports Dictionaries with non-string keys.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">Type of key.</typeparam>
|
|
||||||
/// <typeparam name="TValue">Type of value.</typeparam>
|
|
||||||
internal sealed class JsonNonStringKeyDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Read JSON.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reader">The Utf8JsonReader.</param>
|
|
||||||
/// <param name="typeToConvert">The type to convert.</param>
|
|
||||||
/// <param name="options">The json serializer options.</param>
|
|
||||||
/// <returns>Typed dictionary.</returns>
|
|
||||||
/// <exception cref="NotSupportedException">Dictionary key type not supported.</exception>
|
|
||||||
public override IDictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
var convertedType = typeof(Dictionary<,>).MakeGenericType(typeof(string), typeToConvert.GenericTypeArguments[1]);
|
|
||||||
var value = JsonSerializer.Deserialize(ref reader, convertedType, options);
|
|
||||||
var instance = (Dictionary<TKey, TValue>)Activator.CreateInstance(
|
|
||||||
typeToConvert,
|
|
||||||
BindingFlags.Instance | BindingFlags.Public,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
CultureInfo.CurrentCulture);
|
|
||||||
var enumerator = (IEnumerator)convertedType.GetMethod("GetEnumerator")!.Invoke(value, null);
|
|
||||||
var parse = typeof(TKey).GetMethod(
|
|
||||||
"Parse",
|
|
||||||
0,
|
|
||||||
BindingFlags.Public | BindingFlags.Static,
|
|
||||||
null,
|
|
||||||
CallingConventions.Any,
|
|
||||||
new[] { typeof(string) },
|
|
||||||
null);
|
|
||||||
if (parse == null)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException($"{typeof(TKey)} as TKey in IDictionary<TKey, TValue> is not supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
var element = (KeyValuePair<string?, TValue>)enumerator.Current;
|
|
||||||
instance.Add((TKey)parse.Invoke(null, new[] { (object?)element.Key }), element.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write dictionary as Json.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="writer">The Utf8JsonWriter.</param>
|
|
||||||
/// <param name="value">The dictionary value.</param>
|
|
||||||
/// <param name="options">The Json serializer options.</param>
|
|
||||||
public override void Write(Utf8JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
var convertedDictionary = new Dictionary<string?, TValue>(value.Count);
|
|
||||||
foreach (var (k, v) in value)
|
|
||||||
{
|
|
||||||
if (k != null)
|
|
||||||
{
|
|
||||||
convertedDictionary[k.ToString()] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonSerializer.Serialize(writer, convertedDictionary, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Json.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// https://github.com/dotnet/runtime/issues/30524#issuecomment-524619972.
|
|
||||||
/// TODO This can be removed when System.Text.Json supports Dictionaries with non-string keys.
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class JsonNonStringKeyDictionaryConverterFactory : JsonConverterFactory
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Only convert objects that implement IDictionary and do not have string keys.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="typeToConvert">Type convert.</param>
|
|
||||||
/// <returns>Conversion ability.</returns>
|
|
||||||
public override bool CanConvert(Type typeToConvert)
|
|
||||||
{
|
|
||||||
if (!typeToConvert.IsGenericType)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let built in converter handle string keys
|
|
||||||
if (typeToConvert.GenericTypeArguments[0] == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only support objects that implement IDictionary
|
|
||||||
return typeToConvert.GetInterface(nameof(IDictionary)) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create converter for generic dictionary type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="typeToConvert">Type to convert.</param>
|
|
||||||
/// <param name="options">Json serializer options.</param>
|
|
||||||
/// <returns>JsonConverter for given type.</returns>
|
|
||||||
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
var converterType = typeof(JsonNonStringKeyDictionaryConverter<,>)
|
|
||||||
.MakeGenericType(typeToConvert.GenericTypeArguments[0], typeToConvert.GenericTypeArguments[1]);
|
|
||||||
var converter = (JsonConverter)Activator.CreateInstance(
|
|
||||||
converterType,
|
|
||||||
BindingFlags.Instance | BindingFlags.Public,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
CultureInfo.CurrentCulture);
|
|
||||||
return converter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Buffers.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Json.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a nullable int32 object or value to/from JSON.
|
|
||||||
/// </summary>
|
|
||||||
public class JsonNullableInt32Converter : JsonConverter<int?>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.String)
|
|
||||||
{
|
|
||||||
ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
|
|
||||||
if (Utf8Parser.TryParse(span, out int number, out int bytesConsumed) && span.Length == bytesConsumed)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
var stringValue = reader.GetString().AsSpan();
|
|
||||||
|
|
||||||
// value is null or empty, just return null.
|
|
||||||
if (stringValue.IsEmpty)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int.TryParse(stringValue, out number))
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.GetInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
writer.WriteNullValue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writer.WriteNumberValue(value.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Buffers.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Json.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Parse JSON string as nullable long.
|
|
||||||
/// Javascript does not support 64-bit integers.
|
|
||||||
/// </summary>
|
|
||||||
public class JsonNullableInt64Converter : JsonConverter<long?>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Read JSON string as int64.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reader"><see cref="Utf8JsonReader"/>.</param>
|
|
||||||
/// <param name="type">Type.</param>
|
|
||||||
/// <param name="options">Options.</param>
|
|
||||||
/// <returns>Parsed value.</returns>
|
|
||||||
public override long? Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.String)
|
|
||||||
{
|
|
||||||
// try to parse number directly from bytes
|
|
||||||
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
|
|
||||||
if (Utf8Parser.TryParse(span, out long number, out var bytesConsumed) && span.Length == bytesConsumed)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
var stringValue = reader.GetString().AsSpan();
|
|
||||||
|
|
||||||
// value is null or empty, just return null.
|
|
||||||
if (stringValue.IsEmpty)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
|
|
||||||
if (long.TryParse(stringValue, out number))
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to default handling
|
|
||||||
return reader.GetInt64();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write long to JSON long.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="writer"><see cref="Utf8JsonWriter"/>.</param>
|
|
||||||
/// <param name="value">Value to write.</param>
|
|
||||||
/// <param name="options">Options.</param>
|
|
||||||
public override void Write(Utf8JsonWriter writer, long? value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
writer.WriteNullValue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writer.WriteNumberValue(value.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,17 +25,12 @@ namespace MediaBrowser.Common.Json
|
||||||
{
|
{
|
||||||
ReadCommentHandling = JsonCommentHandling.Disallow,
|
ReadCommentHandling = JsonCommentHandling.Disallow,
|
||||||
WriteIndented = false,
|
WriteIndented = false,
|
||||||
IgnoreNullValues = true
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
NumberHandling = JsonNumberHandling.AllowReadingFromString
|
||||||
};
|
};
|
||||||
|
|
||||||
options.Converters.Add(new JsonGuidConverter());
|
options.Converters.Add(new JsonGuidConverter());
|
||||||
options.Converters.Add(new JsonInt32Converter());
|
|
||||||
options.Converters.Add(new JsonNullableInt32Converter());
|
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
options.Converters.Add(new JsonStringEnumConverter());
|
||||||
options.Converters.Add(new JsonNonStringKeyDictionaryConverterFactory());
|
|
||||||
options.Converters.Add(new JsonInt64Converter());
|
|
||||||
options.Converters.Add(new JsonNullableInt64Converter());
|
|
||||||
options.Converters.Add(new JsonDoubleConverter());
|
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Common.Json;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.MediaEncoding.Probing;
|
using MediaBrowser.MediaEncoding.Probing;
|
||||||
|
@ -54,6 +55,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
private readonly object _runningProcessesLock = new object();
|
private readonly object _runningProcessesLock = new object();
|
||||||
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
||||||
|
|
||||||
|
// MediaEncoder is registered as a Singleton
|
||||||
|
private readonly JsonSerializerOptions _jsonSerializerOptions;
|
||||||
|
|
||||||
private List<string> _encoders = new List<string>();
|
private List<string> _encoders = new List<string>();
|
||||||
private List<string> _decoders = new List<string>();
|
private List<string> _decoders = new List<string>();
|
||||||
private List<string> _hwaccels = new List<string>();
|
private List<string> _hwaccels = new List<string>();
|
||||||
|
@ -75,6 +79,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_encodingHelperFactory = encodingHelperFactory;
|
_encodingHelperFactory = encodingHelperFactory;
|
||||||
_startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty;
|
_startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty;
|
||||||
|
_jsonSerializerOptions = JsonDefaults.GetOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
private EncodingHelper EncodingHelper => _encodingHelperFactory.Value;
|
private EncodingHelper EncodingHelper => _encodingHelperFactory.Value;
|
||||||
|
@ -414,6 +419,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
result = await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(
|
result = await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(
|
||||||
process.StandardOutput.BaseStream,
|
process.StandardOutput.BaseStream,
|
||||||
|
_jsonSerializerOptions,
|
||||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
|
@ -133,7 +133,6 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The bits_per_raw_sample.</value>
|
/// <value>The bits_per_raw_sample.</value>
|
||||||
[JsonPropertyName("bits_per_raw_sample")]
|
[JsonPropertyName("bits_per_raw_sample")]
|
||||||
[JsonConverter(typeof(JsonInt32Converter))]
|
|
||||||
public int BitsPerRawSample { get; set; }
|
public int BitsPerRawSample { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.6" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.6" />
|
||||||
<PackageReference Include="System.Globalization" Version="4.3.0" />
|
<PackageReference Include="System.Globalization" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Text.Json" Version="4.7.2" />
|
<PackageReference Include="System.Text.Json" Version="5.0.0-preview.8.20407.11" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common.Json;
|
||||||
using MediaBrowser.MediaEncoding.Probing;
|
using MediaBrowser.MediaEncoding.Probing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ namespace Jellyfin.MediaEncoding.Tests
|
||||||
var path = Path.Join("Test Data", fileName);
|
var path = Path.Join("Test Data", fileName);
|
||||||
using (var stream = File.OpenRead(path))
|
using (var stream = File.OpenRead(path))
|
||||||
{
|
{
|
||||||
await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream).ConfigureAwait(false);
|
await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream, JsonDefaults.GetOptions()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user