diff options
| author | Cody Robibero <cody@robibe.ro> | 2026-08-25 18:28:52 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-25 18:28:52 -0400 |
| commit | f682c22b08fd842e5642e4c19be6f0a9dd32f588 (patch) | |
| tree | 7336324e9d8fa4dbcc2385942e23944ff07533c1 /Jellyfin.Server.Implementations/Item/PeopleRepository.cs | |
| parent | a68793d08a83ddfa91bd3a22c3be0eb634579134 (diff) | |
| parent | 6978dfc29441eb1a37571be14fe165c622bff3c7 (diff) | |
Merge pull request #17715 from Shadowghost/fix-people-cleanup
Delete credits nothing maps to and bound item-by-name folder names
Diffstat (limited to 'Jellyfin.Server.Implementations/Item/PeopleRepository.cs')
| -rw-r--r-- | Jellyfin.Server.Implementations/Item/PeopleRepository.cs | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs index aaa363b046..da2ad033ec 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -194,13 +194,45 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I listOrder++; } + var droppedCredits = existingMaps.Select(e => e.PeopleId).Distinct().ToArray(); context.PeopleBaseItemMap.RemoveRange(existingMaps); context.SaveChanges(); + + // Nothing else ever deletes a credit row, so one left without a single mapping outlives the + // credit it stood for: it keeps a person of that name off the dead-person sweep, which only + // sees items no credit names, and keeps the name in every by-name list. That is how a credit + // a provider dropped, or one a broken provider result invented, becomes impossible to clean up. + DeleteCreditsWithoutMapping(context, droppedCredits); + + context.SaveChanges(); transaction.Commit(); } /// <inheritdoc/> + public int DeleteOrphanedCredits() + { + using var context = _dbProvider.CreateDbContext(); + + return DeleteCreditsWithoutMapping(context, null); + } + + // A null candidate list sweeps every credit, anything else only the ones just unmapped. + private int DeleteCreditsWithoutMapping(JellyfinDbContext context, IReadOnlyList<Guid>? candidates) + { + if (candidates is not null && candidates.Count == 0) + { + return 0; + } + + var credits = candidates is null + ? context.Peoples.AsQueryable() + : context.Peoples.WhereOneOrMany(candidates, e => e.Id); + + return credits.Where(e => !context.PeopleBaseItemMap.Any(f => f.PeopleId == e.Id)).ExecuteDelete(); + } + + /// <inheritdoc/> public IReadOnlyDictionary<Guid, IReadOnlyList<string>> GetPeopleNamesByItems(IReadOnlyList<Guid> itemIds, IReadOnlyList<string> personTypes) { using var context = _dbProvider.CreateDbContext(); |
