From f217ba185b74ab3628df08f9d48150b47613ee60 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:14:45 -0600 Subject: [PATCH] sync jf and emby library name and type changes (#2784) --- CHANGELOG.md | 4 +- .../Repositories/MediaSourceRepository.cs | 51 +++++++++++++++++-- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3903e962e..6a155a91a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix playback of AC3 audio when targeting stereo output and input layout changes mid-stream - Use other video artwork in XMLTV template - Properly update (add or remove) artwork for all local media libraries when files have changed -- Sync plex library name changes +- Sync Plex library name changes +- Sync Jellyfin and Emby library name and type changes + - Library type (movies, shows) can only be changed when synchronization is *disabled* for the library in ETV ## [26.1.1] - 2026-01-08 ### Fixed diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs index 27aa394f4..7541b221f 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs @@ -171,9 +171,10 @@ public class MediaSourceRepository(IDbContextFactory dbContextFactory foreach (PlexLibrary incoming in toUpdate) { Option maybeExisting = await dbContext.PlexLibraries - .Where(pl => pl.MediaSourceId == plexMediaSourceId) .Include(l => l.Paths) - .SingleOrDefaultAsync(l => l.Key == incoming.Key, cancellationToken); + .SingleOrDefaultAsync( + l => l.Key == incoming.Key && l.MediaSourceId == plexMediaSourceId, + cancellationToken); foreach (PlexLibrary existingLibrary in maybeExisting) { @@ -242,10 +243,29 @@ public class MediaSourceRepository(IDbContextFactory dbContextFactory { Option maybeExisting = await dbContext.JellyfinLibraries .Include(l => l.PathInfos) - .SelectOneAsync(l => l.ItemId, l => l.ItemId == incoming.ItemId, cancellationToken); + .SingleOrDefaultAsync( + l => l.ItemId == incoming.ItemId && l.MediaSourceId == jellyfinMediaSourceId, + cancellationToken); foreach (JellyfinLibrary existing in maybeExisting) { + // update library type, but only if not synchronized + if (incoming.MediaKind != existing.MediaKind) + { + if (existing.ShouldSyncItems) + { + logger.LogWarning( + "Jellyfin library \"{Name}\" should be type {NewType} (currently {OldType}) but cannot be updated while synchronization is enabled for this library.", + incoming.Name, + incoming.MediaKind, + existing.MediaKind); + } + else + { + existing.MediaKind = incoming.MediaKind; + } + } + // remove paths that are not on the incoming version existing.PathInfos.RemoveAll(pi => incoming.PathInfos.All(upi => upi.Path != pi.Path)); @@ -265,6 +285,8 @@ public class MediaSourceRepository(IDbContextFactory dbContextFactory { existing.PathInfos.Add(incomingPathInfo); } + + existing.Name = incoming.Name; } } @@ -303,10 +325,29 @@ public class MediaSourceRepository(IDbContextFactory dbContextFactory { Option maybeExisting = await dbContext.EmbyLibraries .Include(l => l.PathInfos) - .SelectOneAsync(l => l.ItemId, l => l.ItemId == incoming.ItemId, cancellationToken); + .SingleOrDefaultAsync( + l => l.ItemId == incoming.ItemId && l.MediaSourceId == embyMediaSourceId, + cancellationToken); foreach (EmbyLibrary existing in maybeExisting) { + // update library type, but only if not synchronized + if (incoming.MediaKind != existing.MediaKind) + { + if (existing.ShouldSyncItems) + { + logger.LogWarning( + "Emby library \"{Name}\" should be type {NewType} (currently {OldType}) but cannot be updated while synchronization is enabled for this library.", + incoming.Name, + incoming.MediaKind, + existing.MediaKind); + } + else + { + existing.MediaKind = incoming.MediaKind; + } + } + // remove paths that are not on the incoming version existing.PathInfos.RemoveAll(pi => incoming.PathInfos.All(upi => upi.Path != pi.Path)); @@ -326,6 +367,8 @@ public class MediaSourceRepository(IDbContextFactory dbContextFactory { existing.PathInfos.Add(incomingPathInfo); } + + existing.Name = incoming.Name; } }