aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server.Implementations/Item
diff options
context:
space:
mode:
authorJPVenson <github@jpb.email>2025-09-25 00:20:30 +0300
committerGitHub <noreply@github.com>2025-09-24 15:20:30 -0600
commit5a6d9180fed81a30cb91ef3fed30176cd4402116 (patch)
treec67bfa1cfe27ff1a7b7a09e3a7d201ef543652a0 /Jellyfin.Server.Implementations/Item
parent897975fc57f1669322f6db18753939dbf6be43e8 (diff)
Add People Dedup and multiple progress fixes (#14848)
Diffstat (limited to 'Jellyfin.Server.Implementations/Item')
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.cs20
-rw-r--r--Jellyfin.Server.Implementations/Item/PeopleRepository.cs34
2 files changed, 40 insertions, 14 deletions
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
index a34e95c4d..68260fbf0 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
@@ -99,11 +99,11 @@ public sealed class BaseItemRepository
}
/// <inheritdoc />
- public void DeleteItem(Guid id)
+ public void DeleteItem(params IReadOnlyList<Guid> ids)
{
- if (id.IsEmpty() || id.Equals(PlaceholderId))
+ if (ids is null || ids.Count == 0 || ids.Any(f => f.Equals(PlaceholderId)))
{
- throw new ArgumentException("Guid can't be empty or the placeholder id.", nameof(id));
+ throw new ArgumentException("Guid can't be empty or the placeholder id.", nameof(ids));
}
using var context = _dbProvider.CreateDbContext();
@@ -111,7 +111,7 @@ public sealed class BaseItemRepository
var date = (DateTime?)DateTime.UtcNow;
- var relatedItems = TraverseHirachyDown(id, context).ToArray();
+ var relatedItems = ids.SelectMany(f => TraverseHirachyDown(f, context)).ToArray();
// Remove any UserData entries for the placeholder item that would conflict with the UserData
// being detached from the item being deleted. This is necessary because, during an update,
@@ -2538,4 +2538,16 @@ public sealed class BaseItemRepository
return folderList;
}
+
+ /// <inheritdoc/>
+ public IReadOnlyDictionary<string, MusicArtist[]> FindArtists(IReadOnlyList<string> artistNames)
+ {
+ using var dbContext = _dbProvider.CreateDbContext();
+
+ var artists = dbContext.BaseItems.Where(e => e.Type == _itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist]!)
+ .Where(e => artistNames.Contains(e.Name))
+ .ToArray();
+
+ return artists.GroupBy(e => e.Name).ToDictionary(e => e.Key!, e => e.Select(f => DeserializeBaseItem(f)).Cast<MusicArtist>().ToArray());
+ }
}
diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
index 24afaea55..0f423cf5d 100644
--- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
@@ -74,20 +74,34 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I
/// <inheritdoc />
public void UpdatePeople(Guid itemId, IReadOnlyList<PersonInfo> people)
{
- // TODO: yes for __SOME__ reason there can be duplicates.
- people = people.DistinctBy(e => e.Id).ToArray();
- var personids = people.Select(f => f.Id);
+ // 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.Where(p => personids.Contains(p.Id)).Select(f => f.Id).ToArray();
- context.Peoples.AddRange(people.Where(e => !existingPersons.Contains(e.Id)).Select(Map));
+ 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 => !existingPersons.Any(f => f.Name == e.Name && f.PersonType == e.Type.ToString()))
+ .Select(Map);
+ context.Peoples.AddRange(toAdd);
context.SaveChanges();
- var maps = context.PeopleBaseItemMap.Where(e => e.ItemId == itemId).ToList();
+ var personsEntities = toAdd.Concat(existingPersons).ToArray();
+
+ var existingMaps = context.PeopleBaseItemMap.Include(e => e.People).Where(e => e.ItemId == itemId).ToList();
foreach (var person in people)
{
- var existingMap = maps.FirstOrDefault(e => e.PeopleId == person.Id);
+ 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.Role == person.Role);
if (existingMap is null)
{
var sortOrder = (person.SortOrder ?? context.PeopleBaseItemMap.Where(e => e.ItemId == itemId).Max(e => e.SortOrder) ?? 0) + 1;
@@ -96,7 +110,7 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I
Item = null!,
ItemId = itemId,
People = null!,
- PeopleId = person.Id,
+ PeopleId = entityPerson.Id,
ListOrder = sortOrder,
SortOrder = sortOrder,
Role = person.Role
@@ -105,11 +119,11 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I
else
{
// person mapping already exists so remove from list
- maps.Remove(existingMap);
+ existingMaps.Remove(existingMap);
}
}
- context.PeopleBaseItemMap.RemoveRange(maps);
+ context.PeopleBaseItemMap.RemoveRange(existingMaps);
context.SaveChanges();
transaction.Commit();