Cleanup logging and user data import skip on missing user

This commit is contained in:
Shadowghost 2025-06-18 21:33:32 +02:00
parent 7cf6389ab5
commit ccb917b8df
2 changed files with 43 additions and 42 deletions

View File

@ -256,7 +256,7 @@ public sealed class BaseItemRepository
dbQuery = ApplyGroupingFilter(dbQuery, filter); dbQuery = ApplyGroupingFilter(dbQuery, filter);
dbQuery = ApplyQueryPaging(dbQuery, filter); dbQuery = ApplyQueryPaging(dbQuery, filter);
result.Items = dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray(); result.Items = dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserializeBaseItem(w, filter.SkipDeserialization)).ToArray();
result.StartIndex = filter.StartIndex ?? 0; result.StartIndex = filter.StartIndex ?? 0;
return result; return result;
} }
@ -275,7 +275,7 @@ public sealed class BaseItemRepository
dbQuery = ApplyGroupingFilter(dbQuery, filter); dbQuery = ApplyGroupingFilter(dbQuery, filter);
dbQuery = ApplyQueryPaging(dbQuery, filter); dbQuery = ApplyQueryPaging(dbQuery, filter);
return dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray(); return dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserializeBaseItem(w, filter.SkipDeserialization)).ToArray();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -317,7 +317,7 @@ public sealed class BaseItemRepository
mainquery = ApplyGroupingFilter(mainquery, filter); mainquery = ApplyGroupingFilter(mainquery, filter);
mainquery = ApplyQueryPaging(mainquery, filter); mainquery = ApplyQueryPaging(mainquery, filter);
return mainquery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray(); return mainquery.AsEnumerable().Where(e => e is not null).Select(w => DeserializeBaseItem(w, filter.SkipDeserialization)).ToArray();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -655,7 +655,7 @@ public sealed class BaseItemRepository
return null; return null;
} }
return DeserialiseBaseItem(item); return DeserializeBaseItem(item);
} }
/// <summary> /// <summary>
@ -1017,7 +1017,7 @@ public sealed class BaseItemRepository
return type.GetCustomAttribute<RequiresSourceSerialisationAttribute>() == null; return type.GetCustomAttribute<RequiresSourceSerialisationAttribute>() == null;
} }
private BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, bool skipDeserialization = false) private BaseItemDto DeserializeBaseItem(BaseItemEntity baseItemEntity, bool skipDeserialization = false)
{ {
ArgumentNullException.ThrowIfNull(baseItemEntity, nameof(baseItemEntity)); ArgumentNullException.ThrowIfNull(baseItemEntity, nameof(baseItemEntity));
if (_serverConfigurationManager?.Configuration is null) if (_serverConfigurationManager?.Configuration is null)
@ -1026,7 +1026,7 @@ public sealed class BaseItemRepository
} }
var typeToSerialise = GetType(baseItemEntity.Type); var typeToSerialise = GetType(baseItemEntity.Type);
return BaseItemRepository.DeserialiseBaseItem( return BaseItemRepository.DeserializeBaseItem(
baseItemEntity, baseItemEntity,
_logger, _logger,
_appHost, _appHost,
@ -1034,7 +1034,7 @@ public sealed class BaseItemRepository
} }
/// <summary> /// <summary>
/// Deserialises a BaseItemEntity and sets all properties. /// Deserializes a BaseItemEntity and sets all properties.
/// </summary> /// </summary>
/// <param name="baseItemEntity">The DB entity.</param> /// <param name="baseItemEntity">The DB entity.</param>
/// <param name="logger">Logger.</param> /// <param name="logger">Logger.</param>
@ -1042,9 +1042,9 @@ public sealed class BaseItemRepository
/// <param name="skipDeserialization">If only mapping should be processed.</param> /// <param name="skipDeserialization">If only mapping should be processed.</param>
/// <returns>A mapped BaseItem.</returns> /// <returns>A mapped BaseItem.</returns>
/// <exception cref="InvalidOperationException">Will be thrown if an invalid serialisation is requested.</exception> /// <exception cref="InvalidOperationException">Will be thrown if an invalid serialisation is requested.</exception>
public static BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, ILogger logger, IServerApplicationHost? appHost, bool skipDeserialization = false) public static BaseItemDto DeserializeBaseItem(BaseItemEntity baseItemEntity, ILogger logger, IServerApplicationHost? appHost, bool skipDeserialization = false)
{ {
var type = GetType(baseItemEntity.Type) ?? throw new InvalidOperationException("Cannot deserialise unknown type."); var type = GetType(baseItemEntity.Type) ?? throw new InvalidOperationException("Cannot Deserialize unknown type.");
BaseItemDto? dto = null; BaseItemDto? dto = null;
if (TypeRequiresDeserialization(type) && baseItemEntity.Data is not null && !skipDeserialization) if (TypeRequiresDeserialization(type) && baseItemEntity.Data is not null && !skipDeserialization)
{ {
@ -1060,7 +1060,7 @@ public sealed class BaseItemRepository
if (dto is null) if (dto is null)
{ {
dto = Activator.CreateInstance(type) as BaseItemDto ?? throw new InvalidOperationException("Cannot deserialise unknown type."); dto = Activator.CreateInstance(type) as BaseItemDto ?? throw new InvalidOperationException("Cannot Deserialize unknown type.");
} }
return Map(baseItemEntity, dto, appHost); return Map(baseItemEntity, dto, appHost);
@ -1206,7 +1206,7 @@ public sealed class BaseItemRepository
.Where(e => e is not null) .Where(e => e is not null)
.Select(e => .Select(e =>
{ {
return (DeserialiseBaseItem(e.item, filter.SkipDeserialization), e.itemCount); return (DeserializeBaseItem(e.item, filter.SkipDeserialization), e.itemCount);
}) })
]; ];
} }
@ -1221,7 +1221,7 @@ public sealed class BaseItemRepository
.Where(e => e is not null) .Where(e => e is not null)
.Select<BaseItemEntity, (BaseItemDto, ItemCounts?)>(e => .Select<BaseItemEntity, (BaseItemDto, ItemCounts?)>(e =>
{ {
return (DeserialiseBaseItem(e, filter.SkipDeserialization), null); return (DeserializeBaseItem(e, filter.SkipDeserialization), null);
}) })
]; ];
} }

View File

@ -94,7 +94,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
connection.Open(); connection.Open();
var baseItemIds = new HashSet<Guid>(); var baseItemIds = new HashSet<Guid>();
using (var operation = GetPreparedDbContext("moving TypedBaseItem")) using (var operation = GetPreparedDbContext("Moving TypedBaseItem"))
{ {
const string typedBaseItemsQuery = const string typedBaseItemsQuery =
""" """
@ -121,13 +121,13 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
} }
} }
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.BaseItems.Local.Count} BaseItem entries", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.BaseItems.Local.Count} BaseItem entries", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
} }
using (var operation = GetPreparedDbContext("moving ItemValues")) using (var operation = GetPreparedDbContext("Moving ItemValues"))
{ {
// do not migrate inherited types as they are now properly mapped in search and lookup. // do not migrate inherited types as they are now properly mapped in search and lookup.
const string itemValueQuery = const string itemValueQuery =
@ -138,7 +138,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
// EFCores local lookup sucks. We cannot use context.ItemValues.Local here because its just super slow. // EFCores local lookup sucks. We cannot use context.ItemValues.Local here because its just super slow.
var localItems = new Dictionary<(int Type, string Value), (Database.Implementations.Entities.ItemValue ItemValue, List<Guid> ItemIds)>(); var localItems = new Dictionary<(int Type, string Value), (Database.Implementations.Entities.ItemValue ItemValue, List<Guid> ItemIds)>();
using (new TrackedMigrationStep("loading ItemValues", _logger)) using (new TrackedMigrationStep("Loading ItemValues", _logger))
{ {
foreach (SqliteDataReader dto in connection.Query(itemValueQuery)) foreach (SqliteDataReader dto in connection.Query(itemValueQuery))
{ {
@ -166,13 +166,13 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
} }
} }
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.ItemValues.Local.Count} ItemValues entries", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.ItemValues.Local.Count} ItemValues entries", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
} }
using (var operation = GetPreparedDbContext("moving UserData")) using (var operation = GetPreparedDbContext("Moving UserData"))
{ {
var queryResult = connection.Query( var queryResult = connection.Query(
""" """
@ -181,7 +181,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.UserDataKey = UserDatas.key) WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.UserDataKey = UserDatas.key)
"""); """);
using (new TrackedMigrationStep("loading UserData", _logger)) using (new TrackedMigrationStep("Loading UserData", _logger))
{ {
var users = operation.JellyfinDbContext.Users.AsNoTracking().ToImmutableArray(); var users = operation.JellyfinDbContext.Users.AsNoTracking().ToImmutableArray();
var userIdBlacklist = new HashSet<int>(); var userIdBlacklist = new HashSet<int>();
@ -218,7 +218,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
legacyBaseItemWithUserKeys.Clear(); legacyBaseItemWithUserKeys.Clear();
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.UserData.Local.Count} UserData entries", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.UserData.Local.Count} UserData entries", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
@ -237,7 +237,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = MediaStreams.ItemId) WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = MediaStreams.ItemId)
"""; """;
using (new TrackedMigrationStep("loading MediaStreamInfos", _logger)) using (new TrackedMigrationStep("Loading MediaStreamInfos", _logger))
{ {
foreach (SqliteDataReader dto in connection.Query(mediaStreamQuery)) foreach (SqliteDataReader dto in connection.Query(mediaStreamQuery))
{ {
@ -245,13 +245,13 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
} }
} }
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.MediaStreamInfos.Local.Count} MediaStreamInfos entries", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.MediaStreamInfos.Local.Count} MediaStreamInfos entries", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
} }
using (var operation = GetPreparedDbContext("moving AttachmentStreamInfos")) using (var operation = GetPreparedDbContext("Moving AttachmentStreamInfos"))
{ {
const string mediaAttachmentQuery = const string mediaAttachmentQuery =
""" """
@ -260,7 +260,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = mediaattachments.ItemId) WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = mediaattachments.ItemId)
"""; """;
using (new TrackedMigrationStep("loading AttachmentStreamInfos", _logger)) using (new TrackedMigrationStep("Loading AttachmentStreamInfos", _logger))
{ {
foreach (SqliteDataReader dto in connection.Query(mediaAttachmentQuery)) foreach (SqliteDataReader dto in connection.Query(mediaAttachmentQuery))
{ {
@ -268,13 +268,13 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
} }
} }
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.AttachmentStreamInfos.Local.Count} AttachmentStreamInfos entries", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.AttachmentStreamInfos.Local.Count} AttachmentStreamInfos entries", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
} }
using (var operation = GetPreparedDbContext("moving People")) using (var operation = GetPreparedDbContext("Moving People"))
{ {
const string personsQuery = const string personsQuery =
""" """
@ -284,14 +284,14 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
var peopleCache = new Dictionary<string, (People Person, List<PeopleBaseItemMap> Items)>(); var peopleCache = new Dictionary<string, (People Person, List<PeopleBaseItemMap> Items)>();
using (new TrackedMigrationStep("loading People", _logger)) using (new TrackedMigrationStep("Loading People", _logger))
{ {
foreach (SqliteDataReader reader in connection.Query(personsQuery)) foreach (SqliteDataReader reader in connection.Query(personsQuery))
{ {
var itemId = reader.GetGuid(0); var itemId = reader.GetGuid(0);
if (!baseItemIds.Contains(itemId)) if (!baseItemIds.Contains(itemId))
{ {
_logger.LogError("Dont save person {0} because its not in use by any BaseItem", reader.GetString(1)); _logger.LogError("Not saving person {0} because it's not in use by any BaseItem", reader.GetString(1));
continue; continue;
} }
@ -330,13 +330,13 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
peopleCache.Clear(); peopleCache.Clear();
} }
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.Peoples.Local.Count} People entries and {operation.JellyfinDbContext.PeopleBaseItemMap.Local.Count} maps", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.Peoples.Local.Count} People entries and {operation.JellyfinDbContext.PeopleBaseItemMap.Local.Count} maps", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
} }
using (var operation = GetPreparedDbContext("moving Chapters")) using (var operation = GetPreparedDbContext("Moving Chapters"))
{ {
const string chapterQuery = const string chapterQuery =
""" """
@ -344,7 +344,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = Chapters2.ItemId) WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = Chapters2.ItemId)
"""; """;
using (new TrackedMigrationStep("loading Chapters", _logger)) using (new TrackedMigrationStep("Loading Chapters", _logger))
{ {
foreach (SqliteDataReader dto in connection.Query(chapterQuery)) foreach (SqliteDataReader dto in connection.Query(chapterQuery))
{ {
@ -353,13 +353,13 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
} }
} }
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.Chapters.Local.Count} Chapters entries", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.Chapters.Local.Count} Chapters entries", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
} }
using (var operation = GetPreparedDbContext("moving AncestorIds")) using (var operation = GetPreparedDbContext("Moving AncestorIds"))
{ {
const string ancestorIdsQuery = const string ancestorIdsQuery =
""" """
@ -370,7 +370,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = AncestorIds.AncestorId) EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = AncestorIds.AncestorId)
"""; """;
using (new TrackedMigrationStep("loading AncestorIds", _logger)) using (new TrackedMigrationStep("Loading AncestorIds", _logger))
{ {
foreach (SqliteDataReader dto in connection.Query(ancestorIdsQuery)) foreach (SqliteDataReader dto in connection.Query(ancestorIdsQuery))
{ {
@ -379,7 +379,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
} }
} }
using (new TrackedMigrationStep($"saving {operation.JellyfinDbContext.AncestorIds.Local.Count} AncestorId entries", _logger)) using (new TrackedMigrationStep($"Saving {operation.JellyfinDbContext.AncestorIds.Local.Count} AncestorId entries", _logger))
{ {
operation.JellyfinDbContext.SaveChanges(); operation.JellyfinDbContext.SaveChanges();
} }
@ -407,16 +407,17 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
private UserData? GetUserData(ImmutableArray<User> users, SqliteDataReader dto, HashSet<int> userIdBlacklist) private UserData? GetUserData(ImmutableArray<User> users, SqliteDataReader dto, HashSet<int> userIdBlacklist)
{ {
var internalUserId = dto.GetInt32(1); var internalUserId = dto.GetInt32(1);
var user = users.FirstOrDefault(e => e.InternalId == internalUserId);
if (user is null)
{
if (userIdBlacklist.Contains(internalUserId)) if (userIdBlacklist.Contains(internalUserId))
{ {
return null; return null;
} }
_logger.LogError("Tried to find user with index '{Idx}' but there are only '{MaxIdx}' users.", internalUserId, users.Length); var user = users.FirstOrDefault(e => e.InternalId == internalUserId);
if (user is null)
{
_logger.LogError("Tried to find user with index '{Idx}' but was not found, skipping user data import.", internalUserId);
userIdBlacklist.Add(internalUserId);
return null; return null;
} }
@ -1168,7 +1169,7 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
entity.UnratedType = unratedType; entity.UnratedType = unratedType;
} }
var baseItem = BaseItemRepository.DeserialiseBaseItem(entity, _logger, null, false); var baseItem = BaseItemRepository.DeserializeBaseItem(entity, _logger, null, false);
var dataKeys = baseItem.GetUserDataKeys(); var dataKeys = baseItem.GetUserDataKeys();
userDataKeys.AddRange(dataKeys); userDataKeys.AddRange(dataKeys);