aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-02-07 08:44:42 +0100
committerShadowghost <Ghost_of_Stone@web.de>2026-02-07 09:37:42 +0100
commit98d7c8d59fa3180e50ee311dfc53164325210896 (patch)
tree3a50217f9796d27c5a150cb84dd64e88c1969102
parent268d88a5fb8f0f71c96ba5abcef250d1f7e049ff (diff)
Make sure we deduplicate LinkedChildren
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.cs16
-rw-r--r--Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs11
-rw-r--r--MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs7
-rw-r--r--MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs7
4 files changed, 33 insertions, 8 deletions
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
index 20df42583d..3ba6750045 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
@@ -1553,7 +1553,13 @@ public sealed class BaseItemRepository
}
}
- var childIdsToCheck = resolvedChildren.Select(c => c.ChildId).Distinct().ToList();
+ // Deduplicate by ChildId, keeping the last occurrence (for playlist ordering)
+ resolvedChildren = resolvedChildren
+ .GroupBy(c => c.ChildId)
+ .Select(g => g.Last())
+ .ToList();
+
+ var childIdsToCheck = resolvedChildren.Select(c => c.ChildId).ToList();
var existingChildIds = childIdsToCheck.Count > 0
? context.BaseItems
.Where(e => childIdsToCheck.Contains(e.Id))
@@ -1646,8 +1652,14 @@ public sealed class BaseItemRepository
}
}
+ // Deduplicate by ChildId, keeping the last occurrence
+ newLinkedChildren = newLinkedChildren
+ .GroupBy(c => c.ChildId)
+ .Select(g => g.Last())
+ .ToList();
+
// Validate that all child items exist
- var childIdsToCheck = newLinkedChildren.Select(c => c.ChildId).Distinct().ToList();
+ var childIdsToCheck = newLinkedChildren.Select(c => c.ChildId).ToList();
var existingChildIds = childIdsToCheck.Count > 0
? context.BaseItems
.Where(e => childIdsToCheck.Contains(e.Id))
diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs b/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs
index 23f212424b..1545ebdc8e 100644
--- a/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs
+++ b/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs
@@ -45,10 +45,13 @@ internal class RemoveDuplicatePlaylistChildren : IMigrationRoutine
var linkedChildren = playlist.LinkedChildren;
if (linkedChildren.Length > 0)
{
- var nullItemChildren = linkedChildren.Where(c => c.ItemId is null);
- var deduplicatedChildren = linkedChildren.DistinctBy(c => c.ItemId);
- var newLinkedChildren = nullItemChildren.Concat(deduplicatedChildren);
- playlist.LinkedChildren = linkedChildren;
+ var newLinkedChildren = linkedChildren
+ .Where(c => c.ItemId is null || c.ItemId.Value.Equals(Guid.Empty))
+ .Concat(linkedChildren
+ .Where(c => c.ItemId.HasValue && !c.ItemId.Value.Equals(Guid.Empty))
+ .DistinctBy(c => c.ItemId))
+ .ToArray();
+ playlist.LinkedChildren = newLinkedChildren;
playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).GetAwaiter().GetResult();
_playlistManager.SavePlaylistFile(playlist);
}
diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
index bdc5b5df29..3a872f687c 100644
--- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
+++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Configuration;
@@ -70,7 +71,11 @@ public class BoxSetMetadataService : MetadataService<BoxSet, BoxSetInfo>
if (mergeMetadataSettings)
{
// TODO: Change to only replace when currently empty or requested. This is currently not done because the metadata service is not handling attaching collection items based on the provider responses
- targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren).DistinctBy(i => i.ItemId).ToArray();
+#pragma warning disable CS0618 // Type or member is obsolete - fallback for legacy path-based dedup
+ targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren)
+ .DistinctBy(i => i.ItemId.HasValue && !i.ItemId.Value.Equals(Guid.Empty) ? i.ItemId.Value.ToString() : i.Path ?? string.Empty)
+ .ToArray();
+#pragma warning restore CS0618
}
}
diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
index 45b61319b7..429830c70c 100644
--- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
+++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Configuration;
@@ -72,7 +73,11 @@ public class PlaylistMetadataService : MetadataService<Playlist, ItemLookupInfo>
}
else
{
- targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren).DistinctBy(i => i.ItemId).ToArray();
+#pragma warning disable CS0618 // Type or member is obsolete - fallback for legacy path-based dedup
+ targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren)
+ .DistinctBy(i => i.ItemId.HasValue && !i.ItemId.Value.Equals(Guid.Empty) ? i.ItemId.Value.ToString() : i.Path ?? string.Empty)
+ .ToArray();
+#pragma warning restore CS0618
}
if (replaceData || targetItem.Shares.Count == 0)