diff options
Diffstat (limited to 'Jellyfin.Server.Implementations/Item/PeopleRepository.cs')
| -rw-r--r-- | Jellyfin.Server.Implementations/Item/PeopleRepository.cs | 109 |
1 files changed, 81 insertions, 28 deletions
diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs index 77877835e..355ed6479 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -5,6 +5,7 @@ using System.Linq; using Jellyfin.Data.Enums; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Database.Implementations.Entities.Libraries; using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; @@ -34,16 +35,22 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I using var context = _dbProvider.CreateDbContext(); var dbQuery = TranslateQuery(context.Peoples.AsNoTracking(), context, filter); - // dbQuery = dbQuery.OrderBy(e => e.ListOrder); - if (filter.Limit > 0) + // Include PeopleBaseItemMap + if (!filter.ItemId.IsEmpty()) { - dbQuery = dbQuery.Take(filter.Limit); + dbQuery = dbQuery.Include(p => p.BaseItems!.Where(m => m.ItemId == filter.ItemId)) + .OrderBy(e => e.BaseItems!.First(e => e.ItemId == filter.ItemId).ListOrder) + .ThenBy(e => e.PersonType) + .ThenBy(e => e.Name); + } + else + { + dbQuery = dbQuery.OrderBy(e => e.Name); } - // Include PeopleBaseItemMap - if (!filter.ItemId.IsEmpty()) + if (filter.Limit > 0) { - dbQuery = dbQuery.Include(p => p.BaseItems!.Where(m => m.ItemId == filter.ItemId)); + dbQuery = dbQuery.Take(filter.Limit); } return dbQuery.AsEnumerable().Select(Map).ToArray(); @@ -53,7 +60,7 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I public IReadOnlyList<string> GetPeopleNames(InternalPeopleQuery filter) { using var context = _dbProvider.CreateDbContext(); - var dbQuery = TranslateQuery(context.Peoples.AsNoTracking(), context, filter); + var dbQuery = TranslateQuery(context.Peoples.AsNoTracking(), context, filter).Select(e => e.Name).Distinct(); // dbQuery = dbQuery.OrderBy(e => e.ListOrder); if (filter.Limit > 0) @@ -61,39 +68,81 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I dbQuery = dbQuery.Take(filter.Limit); } - return dbQuery.Select(e => e.Name).ToArray(); + return dbQuery.ToArray(); } /// <inheritdoc /> public void UpdatePeople(Guid itemId, IReadOnlyList<PersonInfo> people) { + foreach (var item in people.Where(e => e.Role is null)) + { + item.Role = string.Empty; + } + + // multiple metadata providers can provide the _same_ person + people = people.DistinctBy(e => e.Name + "-" + e.Type).ToArray(); + var personKeys = people.Select(e => e.Name + "-" + e.Type).ToArray(); + using var context = _dbProvider.CreateDbContext(); using var transaction = context.Database.BeginTransaction(); + var existingPersons = context.Peoples.Select(e => new + { + item = e, + SelectionKey = e.Name + "-" + e.PersonType + }) + .Where(p => personKeys.Contains(p.SelectionKey)) + .Select(f => f.item) + .ToArray(); + + var toAdd = people + .Where(e => e.Type is not PersonKind.Artist && e.Type is not PersonKind.AlbumArtist) + .Where(e => !existingPersons.Any(f => f.Name == e.Name && f.PersonType == e.Type.ToString())) + .Select(Map); + context.Peoples.AddRange(toAdd); + context.SaveChanges(); + + var personsEntities = toAdd.Concat(existingPersons).ToArray(); + + var existingMaps = context.PeopleBaseItemMap.Include(e => e.People).Where(e => e.ItemId == itemId).ToList(); + + var listOrder = 0; - context.PeopleBaseItemMap.Where(e => e.ItemId == itemId).ExecuteDelete(); - // TODO: yes for __SOME__ reason there can be duplicates. - foreach (var item in people.DistinctBy(e => e.Id)) + foreach (var person in people) { - var personEntity = Map(item); - var existingEntity = context.Peoples.FirstOrDefault(e => e.Id == personEntity.Id); - if (existingEntity is null) + if (person.Type == PersonKind.Artist || person.Type == PersonKind.AlbumArtist) { - context.Peoples.Add(personEntity); - existingEntity = personEntity; + continue; } - context.PeopleBaseItemMap.Add(new PeopleBaseItemMap() + var entityPerson = personsEntities.First(e => e.Name == person.Name && e.PersonType == person.Type.ToString()); + var existingMap = existingMaps.FirstOrDefault(e => e.People.Name == person.Name && e.People.PersonType == person.Type.ToString() && e.Role == person.Role); + if (existingMap is null) { - Item = null!, - ItemId = itemId, - People = existingEntity, - PeopleId = existingEntity.Id, - ListOrder = item.SortOrder, - SortOrder = item.SortOrder, - Role = item.Role - }); + context.PeopleBaseItemMap.Add(new PeopleBaseItemMap() + { + Item = null!, + ItemId = itemId, + People = null!, + PeopleId = entityPerson.Id, + ListOrder = listOrder, + SortOrder = person.SortOrder, + Role = person.Role + }); + } + else + { + // Update the order for existing mappings + existingMap.ListOrder = listOrder; + existingMap.SortOrder = person.SortOrder; + // person mapping already exists so remove from list + existingMaps.Remove(existingMap); + } + + listOrder++; } + context.PeopleBaseItemMap.RemoveRange(existingMaps); + context.SaveChanges(); transaction.Commit(); } @@ -133,9 +182,13 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I if (filter.User is not null && filter.IsFavorite.HasValue) { var personType = itemTypeLookup.BaseItemKindNames[BaseItemKind.Person]; - query = query.Where(e => e.PersonType == personType) - .Where(e => context.BaseItems.Where(d => d.UserData!.Any(w => w.IsFavorite == filter.IsFavorite && w.UserId.Equals(filter.User.Id))) - .Select(f => f.Name).Contains(e.Name)); + var oldQuery = query; + + query = context.UserData + .Where(u => u.Item!.Type == personType && u.IsFavorite == filter.IsFavorite && u.UserId.Equals(filter.User.Id)) + .Join(oldQuery, e => e.Item!.Name, e => e.Name, (item, person) => person) + .Distinct() + .AsNoTracking(); } if (!filter.ItemId.IsEmpty()) |
