diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-05-24 18:26:21 +0200 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-05-24 18:26:21 +0200 |
| commit | cb9d6e9884d3b952321736392801743198b0ccd9 (patch) | |
| tree | 20d5c3e533f1447ceb0d1c6413d831f075702828 | |
| parent | 11758461200c7b369dd23db5ac7c9f232a87cf21 (diff) | |
Add batch method for people names
4 files changed, 82 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 30ff1bd333..662e28ec1d 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -3394,6 +3394,12 @@ namespace Emby.Server.Implementations.Library return _peopleRepository.GetPeopleNames(query); } + /// <inheritdoc/> + public IReadOnlyDictionary<Guid, IReadOnlyList<string>> GetPeopleNamesByItem(IReadOnlyList<Guid> itemIds, IReadOnlyList<string> personTypes) + { + return _peopleRepository.GetPeopleNamesByItem(itemIds, personTypes); + } + public void UpdatePeople(BaseItem item, List<PersonInfo> people) { UpdatePeopleAsync(item, people, CancellationToken.None).GetAwaiter().GetResult(); diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs index b612112d49..d84a59850d 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -165,6 +165,64 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I transaction.Commit(); } + /// <inheritdoc/> + public IReadOnlyDictionary<Guid, IReadOnlyList<string>> GetPeopleNamesByItem(IReadOnlyList<Guid> itemIds, IReadOnlyList<string> personTypes) + { + if (itemIds.Count == 0) + { + return new Dictionary<Guid, IReadOnlyList<string>>(); + } + + using var context = _dbProvider.CreateDbContext(); + var query = context.PeopleBaseItemMap + .AsNoTracking() + .Where(m => itemIds.Contains(m.ItemId)); + + if (personTypes.Count > 0) + { + query = query.Where(m => personTypes.Contains(m.People.PersonType)); + } + + // One round-trip: pull (ItemId, ListOrder, Name) sorted by ItemId+ListOrder, group in memory. + var rows = query + .OrderBy(m => m.ItemId) + .ThenBy(m => m.ListOrder) + .Select(m => new { m.ItemId, m.People.Name }) + .ToArray(); + + var result = new Dictionary<Guid, IReadOnlyList<string>>(); + List<string>? current = null; + var currentId = Guid.Empty; + var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase); + + foreach (var row in rows) + { + if (row.ItemId != currentId) + { + if (current is { Count: > 0 }) + { + result[currentId] = current; + } + + currentId = row.ItemId; + current = new List<string>(); + seen.Clear(); + } + + if (!string.IsNullOrWhiteSpace(row.Name) && seen.Add(row.Name)) + { + current!.Add(row.Name); + } + } + + if (current is { Count: > 0 }) + { + result[currentId] = current; + } + + return result; + } + private PersonInfo Map(People people) { var mapping = people.BaseItems?.FirstOrDefault(); diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index f4c2196400..d794205f00 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -598,6 +598,14 @@ namespace MediaBrowser.Controller.Library IReadOnlyList<string> GetPeopleNames(InternalPeopleQuery query); /// <summary> + /// Gets the people names per item for a batch of item IDs in a single DB round-trip. + /// </summary> + /// <param name="itemIds">The item IDs to look up.</param> + /// <param name="personTypes">Optional person types to include. Empty for all.</param> + /// <returns>Dictionary keyed by item id; values are the per-item people names. Items with no people are absent.</returns> + IReadOnlyDictionary<Guid, IReadOnlyList<string>> GetPeopleNamesByItem(IReadOnlyList<Guid> itemIds, IReadOnlyList<string> personTypes); + + /// <summary> /// Queries the items. /// </summary> /// <param name="query">The query.</param> diff --git a/MediaBrowser.Controller/Persistence/IPeopleRepository.cs b/MediaBrowser.Controller/Persistence/IPeopleRepository.cs index a89f3ef9ee..3a3b2bfb1f 100644 --- a/MediaBrowser.Controller/Persistence/IPeopleRepository.cs +++ b/MediaBrowser.Controller/Persistence/IPeopleRepository.cs @@ -32,4 +32,14 @@ public interface IPeopleRepository /// <param name="filter">The query.</param> /// <returns>The list of people names matching the filter.</returns> IReadOnlyList<string> GetPeopleNames(InternalPeopleQuery filter); + + /// <summary> + /// Gets the people names per item for a batch of item IDs, preserving per-item list order. + /// One database round-trip for the whole batch; grouped by item id in memory. + /// Items with no people are omitted from the returned dictionary. + /// </summary> + /// <param name="itemIds">The item IDs to get people for.</param> + /// <param name="personTypes">Optional person types to include (e.g. "Actor", "Director"). Empty for all.</param> + /// <returns>Dictionary keyed by item id; values are the per-item people names.</returns> + IReadOnlyDictionary<Guid, IReadOnlyList<string>> GetPeopleNamesByItem(IReadOnlyList<Guid> itemIds, IReadOnlyList<string> personTypes); } |
