aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-08-01 21:41:16 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-08-01 21:41:16 +0200
commit705368ee495cfb8967d3f1651318fbdb85ad89e6 (patch)
treed0c99252541c73ddeaddb036079a00808ab9a955 /MediaBrowser.Controller
parentcbc2c7c32345f670d928f7840e5fd7422241845d (diff)
parente16c8a07bd8e21973a88231eeed83c9699fd58b2 (diff)
Merge remote-tracking branch 'upstream/master' into fix-byname-queries
# Conflicts: # src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/Migrations/JellyfinDbModelSnapshot.cs
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs28
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs7
-rw-r--r--MediaBrowser.Controller/Persistence/IItemQueryHelpers.cs26
3 files changed, 44 insertions, 17 deletions
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index b1f7f29bad..f475379cc3 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -43,11 +43,7 @@ namespace MediaBrowser.Controller.Entities
public class Folder : BaseItem
{
private IEnumerable<BaseItem> _children;
-
- public Folder()
- {
- LinkedChildren = Array.Empty<LinkedChild>();
- }
+ private LinkedChild[] _linkedChildren = [];
public static IUserViewManager UserViewManager { get; set; }
@@ -63,7 +59,27 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the linked children.
/// </summary>
[JsonIgnore]
- public LinkedChild[] LinkedChildren { get; set; }
+ public LinkedChild[] LinkedChildren
+ {
+ get => _linkedChildren;
+ set
+ {
+ _linkedChildren = value;
+
+ // Assigning the collection means the caller knows the complete set of links.
+ LinkedChildrenLoaded = true;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether <see cref="LinkedChildren"/> holds the stored set of links.
+ /// </summary>
+ /// <remarks>
+ /// An unloaded instance carries an empty array that means "unknown", not "no children" —
+ /// persisting it would delete every link the item has.
+ /// </remarks>
+ [JsonIgnore]
+ public bool LinkedChildrenLoaded { get; private set; }
[JsonIgnore]
public DateTime? DateLastMediaAdded { get; set; }
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 9ba103cc8b..aed11e5cc3 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -461,11 +461,12 @@ namespace MediaBrowser.Controller.Entities
var counts = libraryManager.GetPlayedAndTotalCountBatch(folderIds, user);
var isPlayedValue = query.IsPlayed.Value;
- return itemList.Where(i =>
+ return itemList.Where(item =>
{
- if (i.IsFolder && counts.TryGetValue(i.Id, out var c))
+ if (item is Folder)
{
- return (c.Total > 0 && c.Played == c.Total) == isPlayedValue;
+ var itemCount = counts.GetValueOrDefault(item.Id);
+ return (itemCount.Played >= itemCount.Total) == isPlayedValue;
}
return true;
diff --git a/MediaBrowser.Controller/Persistence/IItemQueryHelpers.cs b/MediaBrowser.Controller/Persistence/IItemQueryHelpers.cs
index 2e29cbdbba..f9a050d591 100644
--- a/MediaBrowser.Controller/Persistence/IItemQueryHelpers.cs
+++ b/MediaBrowser.Controller/Persistence/IItemQueryHelpers.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using System.Linq.Expressions;
using Jellyfin.Database.Implementations;
using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Controller.Entities;
@@ -79,17 +80,26 @@ public interface IItemQueryHelpers
Guid ancestorId);
/// <summary>
- /// Builds an <see cref="IQueryable{Guid}"/> of folder IDs whose descendants are all played
- /// for the given user. Composable into outer queries to avoid an extra DB roundtrip.
+ /// Builds a query for the playable leaf items a user can access.
/// </summary>
/// <param name="context">The database context the resulting query is bound to.</param>
- /// <param name="folderIds">A query yielding candidate folder IDs.</param>
- /// <param name="user">The user for access filtering and played status.</param>
- /// <returns>An <see cref="IQueryable{Guid}"/> of fully-played folder IDs.</returns>
- IQueryable<Guid> GetFullyPlayedFolderIdsQuery(
+ /// <param name="user">The user to filter accessible items for.</param>
+ /// <param name="includeOwnedItems">Whether to include alternate versions and owned items.</param>
+ /// <returns>The access-filtered leaf item queryable.</returns>
+ IQueryable<BaseItemEntity> GetAccessFilteredLeafItemsQuery(
JellyfinDbContext context,
- IQueryable<Guid> folderIds,
- User user);
+ User user,
+ bool includeOwnedItems = false);
+
+ /// <summary>
+ /// Builds a filter matching items that have at least one of <paramref name="descendants"/> below them.
+ /// </summary>
+ /// <param name="context">The database context the resulting filter is bound to.</param>
+ /// <param name="descendants">A query yielding the descendants to look for.</param>
+ /// <returns>A filter expression matching items with a matching descendant.</returns>
+ Expression<Func<BaseItemEntity, bool>> BuildHasDescendantFilter(
+ JellyfinDbContext context,
+ IQueryable<BaseItemEntity> descendants);
/// <summary>
/// Deserializes a <see cref="BaseItemEntity"/> into a <see cref="BaseItem"/>.