From 46e9f5ad2e1f61cefe719d03f5a8986434fbb7b6 Mon Sep 17 00:00:00 2001 From: Egor Bakanov <33174871+EgorBakanov@users.noreply.github.com> Date: Sun, 8 Jan 2023 01:48:14 +0700 Subject: [PATCH] Fix recursive children lookup of folders (#8678) Fixes https://github.com/jellyfin/jellyfin/issues/6193 Fixes https://github.com/jellyfin/jellyfin/issues/7226 --- CONTRIBUTORS.md | 1 + MediaBrowser.Controller/Entities/Folder.cs | 54 +++++++++++----------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 8daaae4d94..42242c51a0 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -37,6 +37,7 @@ - [DMouse10462](https://github.com/DMouse10462) - [DrPandemic](https://github.com/DrPandemic) - [eglia](https://github.com/eglia) + - [EgorBakanov](https://github.com/EgorBakanov) - [EraYaN](https://github.com/EraYaN) - [escabe](https://github.com/escabe) - [excelite](https://github.com/excelite) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index e586205c32..bccb4107ff 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1300,8 +1300,15 @@ namespace MediaBrowser.Controller.Entities /// /// Adds the children to list. /// - private void AddChildren(User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query) + private void AddChildren(User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query, HashSet visitedFolders = null) { + // Prevent infinite recursion of nested folders + visitedFolders ??= new HashSet(); + if (!visitedFolders.Add(this)) + { + return; + } + // If Query.AlbumFolders is set, then enforce the format as per the db in that it permits sub-folders in music albums. IEnumerable children = null; if ((query?.DisplayAlbumFolders ?? false) && (this is MusicAlbum)) @@ -1316,42 +1323,33 @@ namespace MediaBrowser.Controller.Entities children = GetEligibleChildrenForRecursiveChildren(user); } - foreach (var child in children) + AddChildrenFromCollection(children, user, includeLinkedChildren, result, recursive, query, visitedFolders); + + if (includeLinkedChildren) { - bool? isVisibleToUser = null; + AddChildrenFromCollection(GetLinkedChildren(user), user, includeLinkedChildren, result, recursive, query, visitedFolders); + } + } - if (query is null || UserViewBuilder.FilterItem(child, query)) + private void AddChildrenFromCollection(IEnumerable children, User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query, HashSet visitedFolders) + { + foreach (var child in children) + { + if (!child.IsVisible(user)) { - isVisibleToUser = child.IsVisible(user); - - if (isVisibleToUser.Value) - { - result[child.Id] = child; - } + continue; } - if (isVisibleToUser ?? child.IsVisible(user)) + if (query is null || UserViewBuilder.FilterItem(child, query)) { - if (recursive && child.IsFolder) - { - var folder = (Folder)child; - - folder.AddChildren(user, includeLinkedChildren, result, true, query); - } + result[child.Id] = child; } - } - if (includeLinkedChildren) - { - foreach (var child in GetLinkedChildren(user)) + if (recursive && child.IsFolder) { - if (query is null || UserViewBuilder.FilterItem(child, query)) - { - if (child.IsVisible(user)) - { - result[child.Id] = child; - } - } + var folder = (Folder)child; + + folder.AddChildren(user, includeLinkedChildren, result, true, query, visitedFolders); } } }