From a0346fe5b70a434860f973086be176ecc2018a52 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Thu, 5 Feb 2026 00:17:44 +0100 Subject: Fix multiple version handling --- .../Library/LibraryManager.cs | 74 +++++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 15705dee96..38aec6d491 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1986,6 +1986,12 @@ namespace Emby.Server.Implementations.Library return []; } + /// + public void UpsertLinkedChild(Guid parentId, Guid childId, MediaBrowser.Controller.Entities.LinkedChildType childType) + { + _itemRepository.UpsertLinkedChild(parentId, childId, childType); + } + /// public IEnumerable Sort(IEnumerable items, User? user, IEnumerable sortBy, SortOrder sortOrder) { @@ -2090,9 +2096,40 @@ namespace Emby.Server.Implementations.Library /// public void CreateItems(IReadOnlyList items, BaseItem? parent, CancellationToken cancellationToken) { - _itemRepository.SaveItems(items, cancellationToken); - + // Resolve and add any local alternate version items that don't exist yet + // This ensures they exist in the database when LinkedChildren are processed + var allItems = new List(items); foreach (var item in items) + { + if (item is Video video && video.LocalAlternateVersions.Length > 0) + { + var videoType = video.GetType(); + foreach (var path in video.LocalAlternateVersions) + { + if (string.IsNullOrEmpty(path)) + { + continue; + } + + // Use the primary video's type for ID calculation to ensure consistency + var altId = GetNewItemId(path, videoType); + if (GetItemById(altId) is null && !allItems.Any(i => i.Id.Equals(altId))) + { + // Alternate version doesn't exist, resolve and create it + var altVideo = ResolvePath(_fileSystem.GetFileSystemInfo(path)) as Video; + if (altVideo is not null) + { + altVideo.OwnerId = video.Id; + allItems.Add(altVideo); + } + } + } + } + } + + _itemRepository.SaveItems(allItems, cancellationToken); + + foreach (var item in allItems) { RegisterItem(item); } @@ -2258,7 +2295,38 @@ namespace Emby.Server.Implementations.Library item.DateLastSaved = DateTime.UtcNow; } - _itemRepository.SaveItems(items, cancellationToken); + // Resolve and add any local alternate version items that don't exist yet + // This ensures they exist in the database when LinkedChildren are processed + var allItems = new List(items); + foreach (var item in items) + { + if (item is Video video && video.LocalAlternateVersions.Length > 0) + { + var videoType = video.GetType(); + foreach (var path in video.LocalAlternateVersions) + { + if (string.IsNullOrEmpty(path)) + { + continue; + } + + // Use the primary video's type for ID calculation to ensure consistency + var altId = GetNewItemId(path, videoType); + if (GetItemById(altId) is null && !allItems.Any(i => i.Id.Equals(altId))) + { + // Alternate version doesn't exist, resolve and create it + var altVideo = ResolvePath(_fileSystem.GetFileSystemInfo(path)) as Video; + if (altVideo is not null) + { + altVideo.OwnerId = video.Id; + allItems.Add(altVideo); + } + } + } + } + } + + _itemRepository.SaveItems(allItems, cancellationToken); if (parent is Folder folder) { -- cgit v1.2.3