aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-07-28 12:42:34 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-07-28 12:43:12 +0200
commiteed664b7d351ae9a22b0722b18d65dcff3fc185d (patch)
treec7a74f40096024617667ab266a65dc5a10d3ec9b /Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
parent5b550517b2ca64fee0d060f537901a2bc6604a64 (diff)
Fix played/unplayed filter for empty Series and BoxSets
Diffstat (limited to 'Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs')
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs29
1 files changed, 13 insertions, 16 deletions
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
index 47f8a40b9c..6006bfb2bf 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
@@ -476,19 +476,14 @@ public sealed partial class BaseItemRepository
var seriesTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Series];
var boxSetTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.BoxSet];
- // Series: played = at least one episode AND all episodes played; unplayed = otherwise.
- IQueryable<Guid> playedSeriesIds = hasSeries
- ? context.BaseItems
- .AsNoTracking()
- .Where(e => !e.IsFolder && !e.IsVirtualItem && e.SeriesId.HasValue)
- .GroupBy(e => e.SeriesId!.Value)
- .Where(g => !g.Any(e => !e.UserData!.Any(ud => ud.UserId == userId && ud.Played)))
- .Select(g => g.Key)
- : Enumerable.Empty<Guid>().AsQueryable();
+ // Series and BoxSets are matched by absence of an unplayed descendant rather than by
+ // "all descendants played".
+ var seriesEpisodes = context.BaseItems
+ .AsNoTracking()
+ .Where(e => !e.IsFolder && !e.IsVirtualItem);
- // BoxSet: played = all children played.
- IQueryable<Guid> playedBoxSetIds = hasBoxSet
- ? GetFullyPlayedFolderIdsQuery(
+ IQueryable<Guid> unplayedBoxSetIds = hasBoxSet
+ ? GetFoldersWithUnplayedItemsQuery(
context,
baseQuery.Where(e => e.Type == boxSetTypeName).Select(e => e.Id),
filter.User!)
@@ -502,15 +497,17 @@ public sealed partial class BaseItemRepository
if (isPlayed)
{
baseQuery = baseQuery.Where(e =>
- (e.Type == seriesTypeName && playedSeriesIds.Contains(e.Id))
- || (e.Type == boxSetTypeName && playedBoxSetIds.Contains(e.Id))
+ (e.Type == seriesTypeName && !seriesEpisodes.Any(ep => ep.SeriesId == e.Id
+ && !ep.UserData!.Any(ud => ud.UserId == userId && ud.Played)))
+ || (e.Type == boxSetTypeName && !unplayedBoxSetIds.Contains(e.Id))
|| (e.Type != seriesTypeName && e.Type != boxSetTypeName && playedItemIds.Contains(e.Id)));
}
else
{
baseQuery = baseQuery.Where(e =>
- (e.Type == seriesTypeName && !playedSeriesIds.Contains(e.Id))
- || (e.Type == boxSetTypeName && !playedBoxSetIds.Contains(e.Id))
+ (e.Type == seriesTypeName && seriesEpisodes.Any(ep => ep.SeriesId == e.Id
+ && !ep.UserData!.Any(ud => ud.UserId == userId && ud.Played)))
+ || (e.Type == boxSetTypeName && unplayedBoxSetIds.Contains(e.Id))
|| (e.Type != seriesTypeName && e.Type != boxSetTypeName && !playedItemIds.Contains(e.Id)));
}
}