Fix Book collections scanning all items

Added static method GetBaseItemKindsForCollectionType in ItemsController (moved from ContentFolderImageProvider to be shared)

Added AudioBook to GetRepresentativeItemTypes for CollectionType.books for consistency

Added GetBooks to GetUserItems for CollectionType.books which gets BaseItemKind.Book and BaseItemKind.AudioBook

Move GetBaseItemKindsForCollectionType to DtoExtensions

Cleaned up the missing null checks and used new collection expressions.
Associate Person to Book and AudioBook for related items.
This commit is contained in:
Marc Brooks
2026-01-05 18:41:34 -06:00
parent b9db4566a7
commit 70b4589382
5 changed files with 53 additions and 38 deletions

View File

@@ -71,6 +71,8 @@ namespace Emby.Server.Implementations.Dto
{
BaseItemKind.Person, [
BaseItemKind.Audio,
BaseItemKind.AudioBook,
BaseItemKind.Book,
BaseItemKind.Episode,
BaseItemKind.Movie,
BaseItemKind.LiveTvProgram,

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using Jellyfin.Api.Extensions;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Common.Configuration;
@@ -14,7 +15,6 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Images
{
@@ -28,38 +28,7 @@ namespace Emby.Server.Implementations.Images
{
var view = (CollectionFolder)item;
var viewType = view.CollectionType;
BaseItemKind[] includeItemTypes;
switch (viewType)
{
case CollectionType.movies:
includeItemTypes = new[] { BaseItemKind.Movie };
break;
case CollectionType.tvshows:
includeItemTypes = new[] { BaseItemKind.Series };
break;
case CollectionType.music:
includeItemTypes = new[] { BaseItemKind.MusicArtist }; // Music albums usually don't have dedicated backdrops, so use artist instead
break;
case CollectionType.musicvideos:
includeItemTypes = new[] { BaseItemKind.MusicVideo };
break;
case CollectionType.books:
includeItemTypes = new[] { BaseItemKind.Book, BaseItemKind.AudioBook };
break;
case CollectionType.boxsets:
includeItemTypes = new[] { BaseItemKind.BoxSet };
break;
case CollectionType.homevideos:
case CollectionType.photos:
includeItemTypes = new[] { BaseItemKind.Video, BaseItemKind.Photo };
break;
default:
includeItemTypes = new[] { BaseItemKind.Video, BaseItemKind.Audio, BaseItemKind.Photo, BaseItemKind.Movie, BaseItemKind.Series };
break;
}
var includeItemTypes = DtoExtensions.GetBaseItemKindsForCollectionType(viewType);
var recursive = viewType != CollectionType.playlists;
return view.GetItemList(new InternalItemsQuery
@@ -67,12 +36,9 @@ namespace Emby.Server.Implementations.Images
CollapseBoxSetItems = false,
Recursive = recursive,
DtoOptions = new DtoOptions(false),
ImageTypes = new[] { ImageType.Primary },
ImageTypes = [ImageType.Primary],
Limit = 8,
OrderBy = new[]
{
(ItemSortBy.Random, SortOrder.Ascending)
},
OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)],
IncludeItemTypes = includeItemTypes
});
}

View File

@@ -287,6 +287,8 @@ public class ItemsController : BaseJellyfinApiController
QueryResult<BaseItem> result;
Guid[] linkedChildAncestorIds = [];
includeItemTypes ??= [];
if (includeItemTypes.Length == 1
&& (includeItemTypes[0] == BaseItemKind.BoxSet || includeItemTypes[0] == BaseItemKind.Playlist)
&& item is not BoxSet
@@ -314,6 +316,7 @@ public class ItemsController : BaseJellyfinApiController
if (folder is IHasCollectionType hasCollectionType)
{
collectionType = hasCollectionType.CollectionType;
includeItemTypes = [.. includeItemTypes.Union(DtoExtensions.GetBaseItemKindsForCollectionType(collectionType))];
}
if (collectionType == CollectionType.playlists)

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Entities;
@@ -9,6 +10,35 @@ namespace Jellyfin.Api.Extensions;
/// </summary>
public static class DtoExtensions
{
/// <summary>
/// Gets the BaseItemKind values associated with the specified CollectionType.
/// </summary>
/// <param name="collectionType">The collection type to map to BaseItemKind values.</param>
/// <returns>An array of BaseItemKind values that correspond to the collection type.</returns>
public static BaseItemKind[] GetBaseItemKindsForCollectionType(CollectionType? collectionType)
{
switch (collectionType)
{
case CollectionType.movies:
return [BaseItemKind.Movie];
case CollectionType.tvshows:
return [BaseItemKind.Series];
case CollectionType.music:
return [BaseItemKind.MusicAlbum, BaseItemKind.MusicArtist];
case CollectionType.musicvideos:
return [BaseItemKind.MusicVideo];
case CollectionType.books:
return [BaseItemKind.Book, BaseItemKind.AudioBook];
case CollectionType.boxsets:
return [BaseItemKind.BoxSet];
case CollectionType.homevideos:
case CollectionType.photos:
return [BaseItemKind.Video, BaseItemKind.Photo];
default:
return [BaseItemKind.Video, BaseItemKind.Audio, BaseItemKind.Photo, BaseItemKind.Movie, BaseItemKind.Series];
}
}
/// <summary>
/// Add additional DtoOptions.
/// </summary>

View File

@@ -61,6 +61,9 @@ namespace MediaBrowser.Controller.Entities
case CollectionType.folders:
return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), query);
case CollectionType.books:
return GetBooks(queryParent, user, query);
case CollectionType.tvshows:
return GetTvView(queryParent, user, query);
@@ -190,6 +193,17 @@ namespace MediaBrowser.Controller.Entities
return _libraryManager.GetItemsResult(query);
}
private QueryResult<BaseItem> GetBooks(Folder parent, User user, InternalItemsQuery query)
{
query.Recursive = true;
query.Parent = parent;
query.SetUser(user);
query.IncludeItemTypes = new[] { BaseItemKind.Book, BaseItemKind.AudioBook };
return _libraryManager.GetItemsResult(query);
}
private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query)
{
query.Recursive = true;