aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server
diff options
context:
space:
mode:
authorShadowghost <Shadowghost@users.noreply.github.com>2026-09-15 11:13:45 -0400
committerCody Robibero <cody@robibe.ro>2026-09-15 11:13:45 -0400
commitfb055aa1fc44b06a7069327fa047cff933f75810 (patch)
tree371370b56e41a53f1752300d991423d9292b489f /Jellyfin.Server
parentb70e7f60ffe19847ef6259a13075c26fb6994363 (diff)
Backport pull request #17835 from jellyfin/release-12.z
Clean up invalid data before running migrations Original-merge: 75d7b2010ea2d75fdb7554c700c4e6981331b484 Merged-by: crobibero <cody@robibe.ro> Backported-by: Cody Robibero <cody@robibe.ro>
Diffstat (limited to 'Jellyfin.Server')
-rw-r--r--Jellyfin.Server/Migrations/Routines/20260825200000_ConsolidateLocalizedUserViews.cs28
1 files changed, 28 insertions, 0 deletions
diff --git a/Jellyfin.Server/Migrations/Routines/20260825200000_ConsolidateLocalizedUserViews.cs b/Jellyfin.Server/Migrations/Routines/20260825200000_ConsolidateLocalizedUserViews.cs
index 3fc2387e09..8eefbdb63a 100644
--- a/Jellyfin.Server/Migrations/Routines/20260825200000_ConsolidateLocalizedUserViews.cs
+++ b/Jellyfin.Server/Migrations/Routines/20260825200000_ConsolidateLocalizedUserViews.cs
@@ -156,6 +156,7 @@ internal class ConsolidateLocalizedUserViews : IAsyncMigrationRoutine
await MoveAncestorsAsync(dbContext, canonicalId, staleIds, cancellationToken).ConfigureAwait(false);
await MoveUserSettingsAsync(dbContext, canonicalId, sourceId, staleIds, cancellationToken).ConfigureAwait(false);
+ await MoveRemainingReferencesAsync(dbContext, newParentId, staleIds, cancellationToken).ConfigureAwait(false);
// Nothing points at them any more, and BaseItems cascades on ParentId, so this has to come last.
await dbContext.BaseItems
@@ -171,6 +172,31 @@ internal class ConsolidateLocalizedUserViews : IAsyncMigrationRoutine
canonicalId);
}
+ private static async Task MoveRemainingReferencesAsync(
+ JellyfinDbContext dbContext,
+ Guid? canonicalId,
+ IReadOnlyList<Guid> staleIds,
+ CancellationToken cancellationToken)
+ {
+ await dbContext.BaseItems
+ .Where(e => e.OwnerId.HasValue)
+ .WhereOneOrMany(staleIds, e => e.OwnerId!.Value)
+ .ExecuteUpdateAsync(e => e.SetProperty(f => f.OwnerId, canonicalId), cancellationToken)
+ .ConfigureAwait(false);
+
+ // Keyed by (ParentId, SortOrder), so these cannot be repointed onto the canonical view
+ // without risking a collision, and a view listing linked children is meaningless anyway.
+ await dbContext.LinkedChildren
+ .WhereOneOrMany(staleIds, e => e.ParentId)
+ .ExecuteDeleteAsync(cancellationToken)
+ .ConfigureAwait(false);
+
+ await dbContext.LinkedChildren
+ .WhereOneOrMany(staleIds, e => e.ChildId)
+ .ExecuteDeleteAsync(cancellationToken)
+ .ConfigureAwait(false);
+ }
+
private async Task<UserView> PickSourceAsync(
JellyfinDbContext dbContext,
IReadOnlyList<UserView> stale,
@@ -294,8 +320,10 @@ internal class ConsolidateLocalizedUserViews : IAsyncMigrationRoutine
IReadOnlyList<Guid> staleIds,
CancellationToken cancellationToken)
{
+ // Ancestry recorded against items that no longer exist is dead weight.
var items = await dbContext.AncestorIds
.WhereOneOrMany(staleIds, e => e.ParentItemId)
+ .Where(e => dbContext.BaseItems.Any(item => item.Id.Equals(e.ItemId)))
.Select(e => e.ItemId)
.Distinct()
.ToListAsync(cancellationToken)