mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-03 23:36:38 +01:00
Reroute on version removal
This commit is contained in:
@@ -428,6 +428,9 @@ namespace Emby.Server.Implementations.Library
|
||||
newPrimary.SetPrimaryVersionId(null);
|
||||
newPrimary.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
// Re-route playlist/collection references from deleted primary to new primary
|
||||
_itemRepository.RerouteLinkedChildren(video.Id, newPrimary.Id);
|
||||
|
||||
// Update remaining alternates to point to new primary
|
||||
foreach (var alternate in alternateVersions.Skip(1))
|
||||
{
|
||||
@@ -436,6 +439,12 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item is Video alternateVideo && !string.IsNullOrEmpty(alternateVideo.PrimaryVersionId)
|
||||
&& Guid.TryParse(alternateVideo.PrimaryVersionId, out var primaryId))
|
||||
{
|
||||
// If deleting an alternate version, re-route references to its primary
|
||||
_itemRepository.RerouteLinkedChildren(alternateVideo.Id, primaryId);
|
||||
}
|
||||
|
||||
var children = item.IsFolder
|
||||
? ((Folder)item).GetRecursiveChildren(false)
|
||||
@@ -3480,5 +3489,11 @@ namespace Emby.Server.Implementations.Library
|
||||
_fileSystem.CreateShortcut(lnk, _appHost.ReverseVirtualPath(path));
|
||||
RemoveContentTypeOverrides(path);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int RerouteLinkedChildReferences(Guid fromChildId, Guid toChildId)
|
||||
{
|
||||
return _itemRepository.RerouteLinkedChildren(fromChildId, toChildId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,9 @@ public class VideosController : BaseJellyfinApiController
|
||||
|
||||
await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
// Re-route any playlist/collection references from this item to the primary
|
||||
_libraryManager.RerouteLinkedChildReferences(item.Id, primaryVersion.Id);
|
||||
|
||||
if (!alternateVersionsOfPrimary.Any(i => i.ItemId.HasValue && i.ItemId.Value.Equals(item.Id)))
|
||||
{
|
||||
alternateVersionsOfPrimary.Add(new LinkedChild
|
||||
|
||||
@@ -3843,4 +3843,43 @@ public sealed class BaseItemRepository
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyList<Guid> GetManualLinkedParentIds(Guid childId)
|
||||
{
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
return context.LinkedChildren
|
||||
.Where(lc => lc.ChildId == childId && lc.ChildType == DbLinkedChildType.Manual)
|
||||
.Select(lc => lc.ParentId)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int RerouteLinkedChildren(Guid fromChildId, Guid toChildId)
|
||||
{
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
|
||||
// Get parents that already reference toChildId (to avoid duplicates)
|
||||
var parentsWithTarget = context.LinkedChildren
|
||||
.Where(lc => lc.ChildId == toChildId && lc.ChildType == DbLinkedChildType.Manual)
|
||||
.Select(lc => lc.ParentId)
|
||||
.ToHashSet();
|
||||
|
||||
// Update references that won't create duplicates
|
||||
var updated = context.LinkedChildren
|
||||
.Where(lc => lc.ChildId == fromChildId
|
||||
&& lc.ChildType == DbLinkedChildType.Manual
|
||||
&& !parentsWithTarget.Contains(lc.ParentId))
|
||||
.ExecuteUpdate(s => s.SetProperty(e => e.ChildId, toChildId));
|
||||
|
||||
// Remove references that would be duplicates
|
||||
context.LinkedChildren
|
||||
.Where(lc => lc.ChildId == fromChildId
|
||||
&& lc.ChildType == DbLinkedChildType.Manual
|
||||
&& parentsWithTarget.Contains(lc.ParentId))
|
||||
.ExecuteDelete();
|
||||
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,5 +714,14 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="virtualFolderPath">The path to the virtualfolder.</param>
|
||||
/// <param name="pathInfo">The new virtualfolder.</param>
|
||||
public void CreateShortcut(string virtualFolderPath, MediaPathInfo pathInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Re-routes LinkedChildren references from one child to another.
|
||||
/// Used when video versions change to maintain playlist/BoxSet integrity.
|
||||
/// </summary>
|
||||
/// <param name="fromChildId">The child ID to re-route from.</param>
|
||||
/// <param name="toChildId">The child ID to re-route to.</param>
|
||||
/// <returns>Number of references updated.</returns>
|
||||
int RerouteLinkedChildReferences(Guid fromChildId, Guid toChildId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,4 +210,21 @@ public interface IItemRepository
|
||||
/// <param name="userId">The user ID for access filtering.</param>
|
||||
/// <returns>Dictionary mapping parent ID to child count.</returns>
|
||||
Dictionary<Guid, int> GetChildCountBatch(IReadOnlyList<Guid> parentIds, Guid? userId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets parent IDs (Playlists/BoxSets) that reference the specified child with LinkedChildType.Manual.
|
||||
/// </summary>
|
||||
/// <param name="childId">The child item ID.</param>
|
||||
/// <returns>List of parent IDs that reference the child.</returns>
|
||||
IReadOnlyList<Guid> GetManualLinkedParentIds(Guid childId);
|
||||
|
||||
/// <summary>
|
||||
/// Updates LinkedChildren references from one child to another, preserving SortOrder.
|
||||
/// Handles duplicates: if parent already references toChildId, removes the old reference instead.
|
||||
/// Used when video versions change to maintain collection integrity.
|
||||
/// </summary>
|
||||
/// <param name="fromChildId">The child ID to re-route from.</param>
|
||||
/// <param name="toChildId">The child ID to re-route to.</param>
|
||||
/// <returns>Number of references updated.</returns>
|
||||
int RerouteLinkedChildren(Guid fromChildId, Guid toChildId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user