diff --git a/Jellyfin.Plugin.ShareLinks/Services/ItemTagService.cs b/Jellyfin.Plugin.ShareLinks/Services/ItemTagService.cs index fdc1c86..faf7ef9 100644 --- a/Jellyfin.Plugin.ShareLinks/Services/ItemTagService.cs +++ b/Jellyfin.Plugin.ShareLinks/Services/ItemTagService.cs @@ -8,6 +8,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using Microsoft.Extensions.Logging; +using MediaBrowser.Controller.Entities.Movies; namespace Jellyfin.Plugin.ShareLinks.Services; @@ -147,15 +148,40 @@ public sealed class ItemTagService private static List BuildTagTreeTargets(BaseItem item) { var targets = new List { item }; - - if (item is Folder folder) - { - targets.AddRange(folder.GetRecursiveChildren()); - } - + CollectDescendants(item, targets, new HashSet { item.Id }); return targets; } + private static void CollectDescendants(BaseItem item, List targets, HashSet seen) + { + IEnumerable children = item switch + { + // A BoxSet's members are logical links, not real ParentId children - + // GetRecursiveChildren() does not follow LinkedChildren of a nested + // BoxSet, so each level has to be resolved and recursed into by hand. + BoxSet boxSet => boxSet.GetLinkedChildren(), + Folder folder => folder.GetRecursiveChildren(), + _ => Enumerable.Empty() + }; + + foreach (var child in children) + { + if (!seen.Add(child.Id)) + { + continue; + } + + targets.Add(child); + + // GetRecursiveChildren() already walks a physical folder tree fully, + // so only a BoxSet child (nested collection) needs an extra pass. + if (child is BoxSet) + { + CollectDescendants(child, targets, seen); + } + } + } + /// /// Removal deliberately reaches one level further than tagging does: up to a /// season's parent series. Builds before this fix put the share's tag on that