aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server.Implementations/Item/BaseItemRepository.QueryBuilding.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Server.Implementations/Item/BaseItemRepository.QueryBuilding.cs')
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.QueryBuilding.cs51
1 files changed, 30 insertions, 21 deletions
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.QueryBuilding.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.QueryBuilding.cs
index c0067d8392..1a4c9da41c 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.QueryBuilding.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.QueryBuilding.cs
@@ -271,7 +271,7 @@ public sealed partial class BaseItemRepository
if (filter.DtoOptions.EnableImages)
{
- dbQuery = dbQuery.Include(e => e.Images);
+ dbQuery = dbQuery.Include(e => e.Images!.OrderBy(i => i.Id));
}
// Include LinkedChildEntities for container types and videos that use them (BoxSet, Playlist,
@@ -291,7 +291,7 @@ public sealed partial class BaseItemRepository
};
if (filter.IncludeItemTypes.Length == 0 || filter.IncludeItemTypes.Any(linkedChildTypes.Contains))
{
- dbQuery = dbQuery.Include(e => e.LinkedChildEntities);
+ dbQuery = dbQuery.Include(e => e.LinkedChildEntities!.OrderBy(l => l.SortOrder));
}
if (filter.IncludeExtras)
@@ -465,16 +465,23 @@ public sealed partial class BaseItemRepository
baseQuery = ApplyParentalRestrictions(context, baseQuery, filter);
- // Exclude alternate versions (have PrimaryVersionId set) and owned non-extra items.
- // Extras (trailers, etc.) have OwnerId set but also have ExtraType set — keep those.
+ // Hide alternate versions behind the primary of their library, and exclude owned non-extra
+ // items. Extras (trailers, etc.) have OwnerId set but also have ExtraType set — keep those.
if (!filter.IncludeOwnedItems)
{
- baseQuery = baseQuery.Where(e => e.PrimaryVersionId == null && (e.OwnerId == null || e.ExtraType != null));
+ baseQuery = ApplyAlternateVersionFiltering(context, baseQuery)
+ .Where(e => e.OwnerId == null || e.ExtraType != null);
}
return baseQuery;
}
+ private static IQueryable<BaseItemEntity> ApplyAlternateVersionFiltering(
+ JellyfinDbContext context,
+ IQueryable<BaseItemEntity> baseQuery)
+ => baseQuery.Where(e => e.PrimaryVersionId == null
+ || !context.BaseItems.Any(p => p.Id == e.PrimaryVersionId && p.TopParentId == e.TopParentId));
+
/// <summary>
/// Restricts a query to the libraries the user may open, exempting requested by-name items.
/// </summary>
@@ -645,24 +652,26 @@ public sealed partial class BaseItemRepository
{
var maxScore = maxRating.Score;
var maxSubScore = maxRating.SubScore ?? 0;
- var linkedChildren = context.LinkedChildren;
+
+ // Only a manual link makes an item a container of other items.
+ var members = context.LinkedChildren
+ .Where(lc => lc.ChildType == Database.Implementations.Entities.LinkedChildType.Manual);
return e =>
- // Item has a rating: check against limit
- (e.InheritedParentalRatingValue != null
- && (e.InheritedParentalRatingValue < maxScore
- || (e.InheritedParentalRatingValue == maxScore && (e.InheritedParentalRatingSubValue ?? 0) <= maxSubScore)))
- // Item has no rating
- || (e.InheritedParentalRatingValue == null
- && (
- // No linked children (not a BoxSet/Playlist): pass as unrated
- !linkedChildren.Any(lc => lc.ParentId == e.Id)
- // Has linked children: at least one child must be within limits
- || linkedChildren.Any(lc => lc.ParentId == e.Id
- && (lc.Child!.InheritedParentalRatingValue == null
- || lc.Child.InheritedParentalRatingValue < maxScore
- || (lc.Child.InheritedParentalRatingValue == maxScore
- && (lc.Child.InheritedParentalRatingSubValue ?? 0) <= maxSubScore)))));
+ // The item's own rating, where it has one, has to be within the limit. An unrated item
+ // passes here; blocking those is what BlockUnratedItems does.
+ (e.InheritedParentalRatingValue == null
+ || e.InheritedParentalRatingValue < maxScore
+ || (e.InheritedParentalRatingValue == maxScore && (e.InheritedParentalRatingSubValue ?? 0) <= maxSubScore))
+ // A container is only as visible as its members: a BoxSet or Playlist with nothing left
+ // in it for this user is hidden whatever rating it carries itself. BoxSet.IsVisible
+ // applies the same rule in memory, and a count has to agree with the listing it counts.
+ && (!members.Any(lc => lc.ParentId == e.Id)
+ || members.Any(lc => lc.ParentId == e.Id
+ && (lc.Child!.InheritedParentalRatingValue == null
+ || lc.Child.InheritedParentalRatingValue < maxScore
+ || (lc.Child.InheritedParentalRatingValue == maxScore
+ && (lc.Child.InheritedParentalRatingSubValue ?? 0) <= maxSubScore))));
}
/// <inheritdoc />