diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ed41bdb6ba..3f88557571 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -486,8 +486,8 @@ namespace MediaBrowser.Controller.Entities var itemsRemoved = currentChildren.Values.Except(validChildren).ToList(); var shouldRemove = !IsRoot || allowRemoveRoot; // If it's an AggregateFolder, don't remove - // Collect old primaries that need demotion to alternates of newly created primaries - var oldPrimariesToDemote = new List<(Video OldPrimary, Video NewPrimary)>(); + // Collect replaced primaries for deferred deletion (after CreateItems) + var replacedPrimaries = new List<(Video OldPrimary, Video NewPrimary)>(); if (shouldRemove && itemsRemoved.Count > 0) { @@ -518,6 +518,29 @@ namespace MediaBrowser.Controller.Entities } } + // Defer deletion if this primary video is being replaced by a new primary + // that takes over its alternates. Deleting now would trigger premature + // promotion inside DeleteItem and write stale paths to collection NFOs. + if (item is Video primaryVideo + && !primaryVideo.PrimaryVersionId.HasValue + && primaryVideo.OwnerId.IsEmpty() + && (primaryVideo.LocalAlternateVersions ?? []).Any(p => alternateVersionPaths.Contains(p))) + { + var newPrimary = newItems + .OfType