aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server.Implementations/Item
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-05-04 02:20:48 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-05-04 02:20:48 +0200
commitea7000a4d6bec1cd289eb947b1ad8b7a756d41b7 (patch)
treec3db26d27dc6523903e476bedd8da52fb19b3162 /Jellyfin.Server.Implementations/Item
parent07a802d8fa93460c9f2a7f42da7a1f14a893a322 (diff)
Fix Sonar complaints
Diffstat (limited to 'Jellyfin.Server.Implementations/Item')
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs187
1 files changed, 97 insertions, 90 deletions
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs
index f557e3732a..7c64d9854d 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.ByName.cs
@@ -167,43 +167,7 @@ public sealed partial class BaseItemRepository
// Build the master query and collapse rows that share a PresentationUniqueKey
// (e.g. alternate versions) by picking the lowest Id per group.
var masterQuery = TranslateQuery(innerQuery, context, outerQueryFilter);
-
- IQueryable<Guid> orderedMasterQuery;
- if (!string.IsNullOrEmpty(filter.SearchTerm))
- {
- var cleanSearchTerm = filter.SearchTerm.GetCleanValue();
- var cleanSearchPrefix = cleanSearchTerm + " ";
-
- orderedMasterQuery = masterQuery
- .Select(e => new
- {
- e.Id,
- e.PresentationUniqueKey,
- e.SortName,
- Score = (e.CleanName == cleanSearchTerm) ? 0
- : e.CleanName!.StartsWith(cleanSearchTerm) ? 1
- : e.CleanName!.Contains(cleanSearchPrefix) ? 2
- : 3
- })
- .GroupBy(x => x.PresentationUniqueKey)
- .Select(g => new
- {
- Id = g.Min(x => x.Id),
- Score = g.Min(x => x.Score),
- SortName = g.Min(x => x.SortName)
- })
- .OrderBy(x => x.Score)
- .ThenBy(x => x.SortName)
- .Select(x => x.Id);
- }
- else
- {
- orderedMasterQuery = masterQuery
- .GroupBy(e => e.PresentationUniqueKey)
- .Select(g => new { Id = g.Min(e => e.Id), SortName = g.Min(e => e.SortName) })
- .OrderBy(x => x.SortName)
- .Select(x => x.Id);
- }
+ var orderedMasterQuery = BuildOrderedMasterQuery(masterQuery, filter.SearchTerm);
var result = new QueryResult<(BaseItemDto, ItemCounts?)>();
if (filter.EnableTotalRecordCount)
@@ -229,60 +193,10 @@ public sealed partial class BaseItemRepository
query = ApplyOrder(query, filter, context);
+ result.StartIndex = filter.StartIndex ?? 0;
if (filter.IncludeItemTypes.Length > 0)
{
- var typeSubQuery = new InternalItemsQuery(filter.User)
- {
- ExcludeItemTypes = filter.ExcludeItemTypes,
- IncludeItemTypes = filter.IncludeItemTypes,
- MediaTypes = filter.MediaTypes,
- AncestorIds = filter.AncestorIds,
- ExcludeItemIds = filter.ExcludeItemIds,
- ItemIds = filter.ItemIds,
- TopParentIds = filter.TopParentIds,
- ParentId = filter.ParentId,
- IsPlayed = filter.IsPlayed
- };
-
- var itemCountQuery = TranslateQuery(context.BaseItems.AsNoTracking().Where(e => e.Id != EF.Constant(PlaceholderId)), context, typeSubQuery)
- .Where(e => e.ItemValues!.Any(f => itemValueTypes!.Contains(f.ItemValue.Type)));
-
- var seriesTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Series];
- var movieTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Movie];
- var episodeTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Episode];
- var musicAlbumTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicAlbum];
- var musicArtistTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist];
- var audioTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Audio];
- var trailerTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Trailer];
- var itemIds = itemCountQuery.Select(e => e.Id);
-
- // Rewrite query to avoid SelectMany on navigation properties (which requires SQL APPLY, not supported on SQLite)
- // Instead, start from ItemValueMaps and join with BaseItems
- var countsByCleanName = context.ItemValuesMap
- .Where(ivm => itemValueTypes.Contains(ivm.ItemValue.Type))
- .Where(ivm => itemIds.Contains(ivm.ItemId))
- .Join(
- context.BaseItems,
- ivm => ivm.ItemId,
- e => e.Id,
- (ivm, e) => new { CleanName = ivm.ItemValue.CleanValue, e.Type })
- .GroupBy(x => new { x.CleanName, x.Type })
- .Select(g => new { g.Key.CleanName, g.Key.Type, Count = g.Count() })
- .GroupBy(x => x.CleanName)
- .ToDictionary(
- g => g.Key,
- g => new ItemCounts
- {
- SeriesCount = g.Where(x => x.Type == seriesTypeName).Sum(x => x.Count),
- EpisodeCount = g.Where(x => x.Type == episodeTypeName).Sum(x => x.Count),
- MovieCount = g.Where(x => x.Type == movieTypeName).Sum(x => x.Count),
- AlbumCount = g.Where(x => x.Type == musicAlbumTypeName).Sum(x => x.Count),
- ArtistCount = g.Where(x => x.Type == musicArtistTypeName).Sum(x => x.Count),
- SongCount = g.Where(x => x.Type == audioTypeName).Sum(x => x.Count),
- TrailerCount = g.Where(x => x.Type == trailerTypeName).Sum(x => x.Count),
- });
-
- result.StartIndex = filter.StartIndex ?? 0;
+ var countsByCleanName = BuildItemCountsByCleanName(context, filter, itemValueTypes);
result.Items =
[
.. query
@@ -300,7 +214,6 @@ public sealed partial class BaseItemRepository
}
else
{
- result.StartIndex = filter.StartIndex ?? 0;
result.Items =
[
.. query
@@ -314,4 +227,98 @@ public sealed partial class BaseItemRepository
return result;
}
+
+ private static IQueryable<Guid> BuildOrderedMasterQuery(IQueryable<BaseItemEntity> masterQuery, string? searchTerm)
+ {
+ if (string.IsNullOrEmpty(searchTerm))
+ {
+ return masterQuery
+ .GroupBy(e => e.PresentationUniqueKey)
+ .Select(g => new { Id = g.Min(e => e.Id), SortName = g.Min(e => e.SortName) })
+ .OrderBy(x => x.SortName)
+ .Select(x => x.Id);
+ }
+
+ var cleanSearchTerm = searchTerm.GetCleanValue();
+ var cleanSearchPrefix = cleanSearchTerm + " ";
+
+ return masterQuery
+ .Select(e => new
+ {
+ e.Id,
+ e.PresentationUniqueKey,
+ e.SortName,
+ Score = (e.CleanName == cleanSearchTerm) ? 0
+ : e.CleanName!.StartsWith(cleanSearchTerm) ? 1
+ : e.CleanName!.Contains(cleanSearchPrefix) ? 2
+ : 3
+ })
+ .GroupBy(x => x.PresentationUniqueKey)
+ .Select(g => new
+ {
+ Id = g.Min(x => x.Id),
+ Score = g.Min(x => x.Score),
+ SortName = g.Min(x => x.SortName)
+ })
+ .OrderBy(x => x.Score)
+ .ThenBy(x => x.SortName)
+ .Select(x => x.Id);
+ }
+
+ private Dictionary<string, ItemCounts> BuildItemCountsByCleanName(
+ Database.Implementations.JellyfinDbContext context,
+ InternalItemsQuery filter,
+ IReadOnlyList<ItemValueType> itemValueTypes)
+ {
+ var typeSubQuery = new InternalItemsQuery(filter.User)
+ {
+ ExcludeItemTypes = filter.ExcludeItemTypes,
+ IncludeItemTypes = filter.IncludeItemTypes,
+ MediaTypes = filter.MediaTypes,
+ AncestorIds = filter.AncestorIds,
+ ExcludeItemIds = filter.ExcludeItemIds,
+ ItemIds = filter.ItemIds,
+ TopParentIds = filter.TopParentIds,
+ ParentId = filter.ParentId,
+ IsPlayed = filter.IsPlayed
+ };
+
+ var itemCountQuery = TranslateQuery(context.BaseItems.AsNoTracking().Where(e => e.Id != EF.Constant(PlaceholderId)), context, typeSubQuery)
+ .Where(e => e.ItemValues!.Any(f => itemValueTypes!.Contains(f.ItemValue.Type)));
+
+ var seriesTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Series];
+ var movieTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Movie];
+ var episodeTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Episode];
+ var musicAlbumTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicAlbum];
+ var musicArtistTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist];
+ var audioTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Audio];
+ var trailerTypeName = _itemTypeLookup.BaseItemKindNames[BaseItemKind.Trailer];
+ var itemIds = itemCountQuery.Select(e => e.Id);
+
+ // Rewrite query to avoid SelectMany on navigation properties (which requires SQL APPLY, not supported on SQLite)
+ // Instead, start from ItemValueMaps and join with BaseItems
+ return context.ItemValuesMap
+ .Where(ivm => itemValueTypes.Contains(ivm.ItemValue.Type))
+ .Where(ivm => itemIds.Contains(ivm.ItemId))
+ .Join(
+ context.BaseItems,
+ ivm => ivm.ItemId,
+ e => e.Id,
+ (ivm, e) => new { CleanName = ivm.ItemValue.CleanValue, e.Type })
+ .GroupBy(x => new { x.CleanName, x.Type })
+ .Select(g => new { g.Key.CleanName, g.Key.Type, Count = g.Count() })
+ .GroupBy(x => x.CleanName)
+ .ToDictionary(
+ g => g.Key,
+ g => new ItemCounts
+ {
+ SeriesCount = g.Where(x => x.Type == seriesTypeName).Sum(x => x.Count),
+ EpisodeCount = g.Where(x => x.Type == episodeTypeName).Sum(x => x.Count),
+ MovieCount = g.Where(x => x.Type == movieTypeName).Sum(x => x.Count),
+ AlbumCount = g.Where(x => x.Type == musicAlbumTypeName).Sum(x => x.Count),
+ ArtistCount = g.Where(x => x.Type == musicArtistTypeName).Sum(x => x.Count),
+ SongCount = g.Where(x => x.Type == audioTypeName).Sum(x => x.Count),
+ TrailerCount = g.Where(x => x.Type == trailerTypeName).Sum(x => x.Count),
+ });
+ }
}