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);
}
}
}