Browse Source

fix plex other video library detection (#2679)

pull/2680/head
Jason Dove 8 months ago committed by GitHub
parent
commit
1f31beab5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 33
      ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs
  3. 34
      ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs

3
CHANGELOG.md

@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Fixed ### Fixed
- Fix startup on systems unsupported by NvEncSharp - Fix startup on systems unsupported by NvEncSharp
- Fix detection of Plex Other Video libraries using `Plex Personal Media` agent
- If the library is already detected as a Movies library in ETV, synchronization must be disabled for the library to change it to an Other Videos library
- A warning will be logged when this scenario is detected
## [25.9.0] - 2025-11-29 ## [25.9.0] - 2025-11-29
### Added ### Added

33
ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs

@ -6,10 +6,12 @@ using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Jellyfin; using ErsatzTV.Core.Jellyfin;
using ErsatzTV.Infrastructure.Extensions; using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.Infrastructure.Data.Repositories; namespace ErsatzTV.Infrastructure.Data.Repositories;
public class MediaSourceRepository(IDbContextFactory<TvContext> dbContextFactory) : IMediaSourceRepository public class MediaSourceRepository(IDbContextFactory<TvContext> dbContextFactory, ILogger<MediaSourceRepository> logger)
: IMediaSourceRepository
{ {
public async Task<PlexMediaSource> Add(PlexMediaSource plexMediaSource) public async Task<PlexMediaSource> Add(PlexMediaSource plexMediaSource)
{ {
@ -166,23 +168,42 @@ public class MediaSourceRepository(IDbContextFactory<TvContext> dbContextFactory
dbContext.PlexLibraries.Remove(delete); dbContext.PlexLibraries.Remove(delete);
} }
// update library path (for other video metadata)
foreach (PlexLibrary incoming in toUpdate) foreach (PlexLibrary incoming in toUpdate)
{ {
Option<PlexLibrary> maybeExisting = await dbContext.PlexLibraries Option<PlexLibrary> maybeExisting = await dbContext.PlexLibraries
.Include(l => l.Paths) .Include(l => l.Paths)
.SelectOneAsync(l => l.Key, l => l.Key == incoming.Key, cancellationToken); .SelectOneAsync(l => l.Key, l => l.Key == incoming.Key, cancellationToken);
foreach (LibraryPath existing in maybeExisting.Map(l => l.Paths.HeadOrNone())) foreach (PlexLibrary existingLibrary in maybeExisting)
{ {
foreach (LibraryPath path in incoming.Paths.HeadOrNone()) // update library type, but only if not synchronized
if (incoming.MediaKind != existingLibrary.MediaKind)
{ {
existing.Path = path.Path; if (existingLibrary.ShouldSyncItems)
{
logger.LogWarning(
"Plex library \"{Name}\" should be type {NewType} (currently {OldType}) but cannot be updated while synchronization is enabled for this library.",
incoming.Name,
incoming.MediaKind,
existingLibrary.MediaKind);
}
else
{
existingLibrary.MediaKind = incoming.MediaKind;
}
}
// update library path (for other video metadata)
foreach (LibraryPath existing in existingLibrary.Paths.HeadOrNone())
{
foreach (LibraryPath path in incoming.Paths.HeadOrNone())
{
existing.Path = path.Path;
}
} }
} }
} }
await dbContext.SaveChangesAsync(cancellationToken); await dbContext.SaveChangesAsync(cancellationToken);
return deletedMediaIds; return deletedMediaIds;

34
ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs

@ -14,16 +14,10 @@ using Refit;
namespace ErsatzTV.Infrastructure.Plex; namespace ErsatzTV.Infrastructure.Plex;
public class PlexServerApiClient : IPlexServerApiClient public class PlexServerApiClient(PlexEtag plexEtag, ILogger<PlexServerApiClient> logger) : IPlexServerApiClient
{ {
private readonly ILogger<PlexServerApiClient> _logger; private const string PersonalMediaAgent = "com.plexapp.agents.none";
private readonly PlexEtag _plexEtag; private const string PlexPersonalMediaAgent = "tv.plex.agents.none";
public PlexServerApiClient(PlexEtag plexEtag, ILogger<PlexServerApiClient> logger)
{
_plexEtag = plexEtag;
_logger = logger;
}
public async Task<bool> Ping( public async Task<bool> Ping(
PlexConnection connection, PlexConnection connection,
@ -537,7 +531,7 @@ public class PlexServerApiClient : IPlexServerApiClient
{ {
Key = response.Key, Key = response.Key,
Name = response.Title, Name = response.Title,
MediaKind = response.Agent == "com.plexapp.agents.none" && response.Language == "xn" MediaKind = response.Agent is PersonalMediaAgent or PlexPersonalMediaAgent
? LibraryMediaKind.OtherVideos ? LibraryMediaKind.OtherVideos
: LibraryMediaKind.Movies, : LibraryMediaKind.Movies,
ShouldSyncItems = false, ShouldSyncItems = false,
@ -565,13 +559,13 @@ public class PlexServerApiClient : IPlexServerApiClient
return new PlexCollection return new PlexCollection
{ {
Key = item.RatingKey, Key = item.RatingKey,
Etag = _plexEtag.ForCollection(item), Etag = plexEtag.ForCollection(item),
Name = item.Title Name = item.Title
}; };
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogWarning(ex, "Error projecting Plex collection"); logger.LogWarning(ex, "Error projecting Plex collection");
return None; return None;
} }
} }
@ -591,7 +585,7 @@ public class PlexServerApiClient : IPlexServerApiClient
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogWarning(ex, "Error projecting Plex collection media item"); logger.LogWarning(ex, "Error projecting Plex collection media item");
return None; return None;
} }
} }
@ -610,7 +604,7 @@ public class PlexServerApiClient : IPlexServerApiClient
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogWarning(ex, "Error projecting Plex tag"); logger.LogWarning(ex, "Error projecting Plex tag");
return None; return None;
} }
} }
@ -651,7 +645,7 @@ public class PlexServerApiClient : IPlexServerApiClient
var movie = new PlexMovie var movie = new PlexMovie
{ {
Etag = _plexEtag.ForMovie(response), Etag = plexEtag.ForMovie(response),
Key = response.Key, Key = response.Key,
MovieMetadata = [metadata], MovieMetadata = [metadata],
MediaVersions = [version], MediaVersions = [version],
@ -884,7 +878,7 @@ public class PlexServerApiClient : IPlexServerApiClient
var show = new PlexShow var show = new PlexShow
{ {
Key = response.Key, Key = response.Key,
Etag = _plexEtag.ForShow(response), Etag = plexEtag.ForShow(response),
ShowMetadata = new List<ShowMetadata> { metadata }, ShowMetadata = new List<ShowMetadata> { metadata },
TraktListItems = new List<TraktListItem>() TraktListItems = new List<TraktListItem>()
}; };
@ -1046,7 +1040,7 @@ public class PlexServerApiClient : IPlexServerApiClient
var season = new PlexSeason var season = new PlexSeason
{ {
Key = response.Key, Key = response.Key,
Etag = _plexEtag.ForSeason(response), Etag = plexEtag.ForSeason(response),
SeasonNumber = response.Index, SeasonNumber = response.Index,
SeasonMetadata = new List<SeasonMetadata> { metadata }, SeasonMetadata = new List<SeasonMetadata> { metadata },
TraktListItems = new List<TraktListItem>() TraktListItems = new List<TraktListItem>()
@ -1092,7 +1086,7 @@ public class PlexServerApiClient : IPlexServerApiClient
var episode = new PlexEpisode var episode = new PlexEpisode
{ {
Key = response.Key, Key = response.Key,
Etag = _plexEtag.ForEpisode(response), Etag = plexEtag.ForEpisode(response),
EpisodeMetadata = [metadata], EpisodeMetadata = [metadata],
MediaVersions = [version], MediaVersions = [version],
TraktListItems = [] TraktListItems = []
@ -1238,7 +1232,7 @@ public class PlexServerApiClient : IPlexServerApiClient
var otherVideo = new PlexOtherVideo var otherVideo = new PlexOtherVideo
{ {
Etag = _plexEtag.ForMovie(response), Etag = plexEtag.ForMovie(response),
Key = response.Key, Key = response.Key,
OtherVideoMetadata = [metadata], OtherVideoMetadata = [metadata],
MediaVersions = [version], MediaVersions = [version],
@ -1431,7 +1425,7 @@ public class PlexServerApiClient : IPlexServerApiClient
} }
else else
{ {
_logger.LogWarning("Unsupported guid format from Plex; ignoring: {Guid}", guid); logger.LogWarning("Unsupported guid format from Plex; ignoring: {Guid}", guid);
} }
return None; return None;

Loading…
Cancel
Save