Readded custom serialisation

This commit is contained in:
JPVenson 2024-10-10 18:01:14 +00:00
parent ea4c208fde
commit 439a997fca
15 changed files with 79 additions and 7 deletions

View File

@ -5,12 +5,14 @@ using System.Linq;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Common;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Playlists namespace Emby.Server.Implementations.Playlists
{ {
[RequiresSourceSerialisation]
public class PlaylistsFolder : BasePluginFolder public class PlaylistsFolder : BasePluginFolder
{ {
public PlaylistsFolder() public PlaylistsFolder()

View File

@ -3,14 +3,21 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection;
using System.Text; using System.Text;
using System.Text.Json;
using System.Threading; using System.Threading;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
@ -21,7 +28,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using SQLitePCL; using Microsoft.Extensions.Logging;
using BaseItemDto = MediaBrowser.Controller.Entities.BaseItem; using BaseItemDto = MediaBrowser.Controller.Entities.BaseItem;
using BaseItemEntity = Jellyfin.Data.Entities.BaseItemEntity; using BaseItemEntity = Jellyfin.Data.Entities.BaseItemEntity;
#pragma warning disable RS0030 // Do not use banned APIs #pragma warning disable RS0030 // Do not use banned APIs
@ -37,7 +44,14 @@ namespace Jellyfin.Server.Implementations.Item;
/// <param name="dbProvider">The db factory.</param> /// <param name="dbProvider">The db factory.</param>
/// <param name="appHost">The Application host.</param> /// <param name="appHost">The Application host.</param>
/// <param name="itemTypeLookup">The static type lookup.</param> /// <param name="itemTypeLookup">The static type lookup.</param>
public sealed class BaseItemRepository(IDbContextFactory<JellyfinDbContext> dbProvider, IServerApplicationHost appHost, IItemTypeLookup itemTypeLookup) /// <param name="serverConfigurationManager">The server Configuration manager.</param>
/// <param name="logger">System logger.</param>
public sealed class BaseItemRepository(
IDbContextFactory<JellyfinDbContext> dbProvider,
IServerApplicationHost appHost,
IItemTypeLookup itemTypeLookup,
IServerConfigurationManager serverConfigurationManager,
ILogger<BaseItemRepository> logger)
: IItemRepository, IDisposable : IItemRepository, IDisposable
{ {
/// <summary> /// <summary>
@ -244,7 +258,7 @@ public sealed class BaseItemRepository(IDbContextFactory<JellyfinDbContext> dbPr
} }
} }
result.Items = dbQuery.ToList().Select(DeserialiseBaseItem).ToImmutableArray(); result.Items = dbQuery.ToList().Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToImmutableArray();
result.StartIndex = filter.StartIndex ?? 0; result.StartIndex = filter.StartIndex ?? 0;
return result; return result;
} }
@ -272,7 +286,7 @@ public sealed class BaseItemRepository(IDbContextFactory<JellyfinDbContext> dbPr
} }
} }
return dbQuery.ToList().Select(DeserialiseBaseItem).ToImmutableArray(); return dbQuery.ToList().Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToImmutableArray();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -1675,10 +1689,42 @@ public sealed class BaseItemRepository(IDbContextFactory<JellyfinDbContext> dbPr
return query.Select(e => e.ItemValue.CleanValue).ToImmutableArray(); return query.Select(e => e.ItemValue.CleanValue).ToImmutableArray();
} }
private BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity) private bool TypeRequiresDeserialization(Type type)
{
if (serverConfigurationManager.Configuration.SkipDeserializationForBasicTypes)
{
if (type == typeof(Channel)
|| type == typeof(UserRootFolder))
{
return false;
}
}
return type.GetCustomAttribute<RequiresSourceSerialisationAttribute>() == null;
}
private BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, bool skipDeserialization = false)
{ {
var type = GetType(baseItemEntity.Type) ?? throw new InvalidOperationException("Cannot deserialise unkown type."); var type = GetType(baseItemEntity.Type) ?? throw new InvalidOperationException("Cannot deserialise unkown type.");
var dto = Activator.CreateInstance(type) as BaseItemDto ?? throw new InvalidOperationException("Cannot deserialise unkown type."); BaseItemDto? dto = null;
if (TypeRequiresDeserialization(type) && baseItemEntity.Data is not null && !skipDeserialization)
{
try
{
using var dataAsStream = new MemoryStream(Encoding.UTF8.GetBytes(baseItemEntity.Data!));
dto = JsonSerializer.Deserialize(dataAsStream, type, JsonDefaults.Options) as BaseItemDto;
}
catch (JsonException ex)
{
logger.LogError(ex, "Error deserializing item with JSON: {Data}", baseItemEntity.Data);
}
}
if (dto is null)
{
dto = Activator.CreateInstance(type) as BaseItemDto ?? throw new InvalidOperationException("Cannot deserialise unkown type.");
}
return Map(baseItemEntity, dto); return Map(baseItemEntity, dto);
} }
@ -1764,7 +1810,7 @@ public sealed class BaseItemRepository(IDbContextFactory<JellyfinDbContext> dbPr
result.StartIndex = filter.StartIndex ?? 0; result.StartIndex = filter.StartIndex ?? 0;
result.Items = resultQuery.ToImmutableArray().Select(e => result.Items = resultQuery.ToImmutableArray().Select(e =>
{ {
return (DeserialiseBaseItem(e.item), e.itemCount); return (DeserialiseBaseItem(e.item, filter.SkipDeserialization), e.itemCount);
}).ToImmutableArray(); }).ToImmutableArray();
return result; return result;

View File

@ -0,0 +1,11 @@
using System;
namespace MediaBrowser.Common;
/// <summary>
/// Marks a BaseItem as needing custom serialisation from the Data field of the db.
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public sealed class RequiresSourceSerialisationAttribute : System.Attribute
{
}

View File

@ -21,6 +21,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary> /// <summary>
/// Class MusicAlbum. /// Class MusicAlbum.
/// </summary> /// </summary>
[Common.RequiresSourceSerialisation]
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
{ {
public MusicAlbum() public MusicAlbum()

View File

@ -21,6 +21,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary> /// <summary>
/// Class MusicArtist. /// Class MusicArtist.
/// </summary> /// </summary>
[Common.RequiresSourceSerialisation]
public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo<ArtistInfo> public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo<ArtistInfo>
{ {
[JsonIgnore] [JsonIgnore]

View File

@ -14,6 +14,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary> /// <summary>
/// Class MusicGenre. /// Class MusicGenre.
/// </summary> /// </summary>
[Common.RequiresSourceSerialisation]
public class MusicGenre : BaseItem, IItemByName public class MusicGenre : BaseItem, IItemByName
{ {
[JsonIgnore] [JsonIgnore]

View File

@ -9,6 +9,7 @@ using MediaBrowser.Controller.Providers;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
[Common.RequiresSourceSerialisation]
public class AudioBook : Audio.Audio, IHasSeries, IHasLookupInfo<SongInfo> public class AudioBook : Audio.Audio, IHasSeries, IHasLookupInfo<SongInfo>
{ {
[JsonIgnore] [JsonIgnore]

View File

@ -10,6 +10,7 @@ using MediaBrowser.Controller.Providers;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
[Common.RequiresSourceSerialisation]
public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
{ {
public Book() public Book()

View File

@ -14,6 +14,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Class Genre. /// Class Genre.
/// </summary> /// </summary>
[Common.RequiresSourceSerialisation]
public class Genre : BaseItem, IItemByName public class Genre : BaseItem, IItemByName
{ {
/// <summary> /// <summary>

View File

@ -14,6 +14,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// This is the full Person object that can be retrieved with all of it's data. /// This is the full Person object that can be retrieved with all of it's data.
/// </summary> /// </summary>
[Common.RequiresSourceSerialisation]
public class Person : BaseItem, IItemByName, IHasLookupInfo<PersonLookupInfo> public class Person : BaseItem, IItemByName, IHasLookupInfo<PersonLookupInfo>
{ {
/// <summary> /// <summary>

View File

@ -4,6 +4,7 @@ using System.Text.Json.Serialization;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
[Common.RequiresSourceSerialisation]
public class PhotoAlbum : Folder public class PhotoAlbum : Folder
{ {
[JsonIgnore] [JsonIgnore]

View File

@ -13,6 +13,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Class Studio. /// Class Studio.
/// </summary> /// </summary>
[Common.RequiresSourceSerialisation]
public class Studio : BaseItem, IItemByName public class Studio : BaseItem, IItemByName
{ {
/// <summary> /// <summary>

View File

@ -10,6 +10,7 @@ using System.Text.Json.Serialization;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Common;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
@ -19,6 +20,7 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary> /// <summary>
/// Class Season. /// Class Season.
/// </summary> /// </summary>
[RequiresSourceSerialisation]
public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo> public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
{ {
[JsonIgnore] [JsonIgnore]

View File

@ -13,6 +13,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Class Year. /// Class Year.
/// </summary> /// </summary>
[Common.RequiresSourceSerialisation]
public class Year : BaseItem, IItemByName public class Year : BaseItem, IItemByName
{ {
[JsonIgnore] [JsonIgnore]

View File

@ -18,6 +18,7 @@ using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
[Common.RequiresSourceSerialisation]
public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes
{ {
private const string EmbyServiceName = "Emby"; private const string EmbyServiceName = "Emby";