Explorar o código

Readded custom serialisation

JPVenson hai 7 meses
pai
achega
439a997fca

+ 2 - 0
Emby.Server.Implementations/Playlists/PlaylistsFolder.cs

@@ -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()

+ 53 - 7
Jellyfin.Server.Implementations/Item/BaseItemRepository.cs

@@ -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;

+ 11 - 0
MediaBrowser.Common/RequiresSourceSerialisationAttribute.cs

@@ -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
+{
+}

+ 1 - 0
MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs

@@ -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()

+ 1 - 0
MediaBrowser.Controller/Entities/Audio/MusicArtist.cs

@@ -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]

+ 1 - 0
MediaBrowser.Controller/Entities/Audio/MusicGenre.cs

@@ -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]

+ 1 - 0
MediaBrowser.Controller/Entities/AudioBook.cs

@@ -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]

+ 1 - 0
MediaBrowser.Controller/Entities/Book.cs

@@ -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()

+ 1 - 0
MediaBrowser.Controller/Entities/Genre.cs

@@ -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>

+ 1 - 0
MediaBrowser.Controller/Entities/Person.cs

@@ -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>

+ 1 - 0
MediaBrowser.Controller/Entities/PhotoAlbum.cs

@@ -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]

+ 1 - 0
MediaBrowser.Controller/Entities/Studio.cs

@@ -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>

+ 2 - 0
MediaBrowser.Controller/Entities/TV/Season.cs

@@ -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]

+ 1 - 0
MediaBrowser.Controller/Entities/Year.cs

@@ -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]

+ 1 - 0
MediaBrowser.Controller/LiveTv/LiveTvProgram.cs

@@ -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";