fix plex other video library detection (#2679)
This commit is contained in:
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
## [Unreleased]
|
||||
### Fixed
|
||||
- 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
|
||||
### Added
|
||||
|
||||
@@ -6,10 +6,12 @@ using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using ErsatzTV.Core.Jellyfin;
|
||||
using ErsatzTV.Infrastructure.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -166,23 +168,42 @@ public class MediaSourceRepository(IDbContextFactory<TvContext> dbContextFactory
|
||||
dbContext.PlexLibraries.Remove(delete);
|
||||
}
|
||||
|
||||
// update library path (for other video metadata)
|
||||
foreach (PlexLibrary incoming in toUpdate)
|
||||
{
|
||||
Option<PlexLibrary> maybeExisting = await dbContext.PlexLibraries
|
||||
.Include(l => l.Paths)
|
||||
.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);
|
||||
|
||||
return deletedMediaIds;
|
||||
|
||||
@@ -14,16 +14,10 @@ using Refit;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Plex;
|
||||
|
||||
public class PlexServerApiClient : IPlexServerApiClient
|
||||
public class PlexServerApiClient(PlexEtag plexEtag, ILogger<PlexServerApiClient> logger) : IPlexServerApiClient
|
||||
{
|
||||
private readonly ILogger<PlexServerApiClient> _logger;
|
||||
private readonly PlexEtag _plexEtag;
|
||||
|
||||
public PlexServerApiClient(PlexEtag plexEtag, ILogger<PlexServerApiClient> logger)
|
||||
{
|
||||
_plexEtag = plexEtag;
|
||||
_logger = logger;
|
||||
}
|
||||
private const string PersonalMediaAgent = "com.plexapp.agents.none";
|
||||
private const string PlexPersonalMediaAgent = "tv.plex.agents.none";
|
||||
|
||||
public async Task<bool> Ping(
|
||||
PlexConnection connection,
|
||||
@@ -537,7 +531,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
{
|
||||
Key = response.Key,
|
||||
Name = response.Title,
|
||||
MediaKind = response.Agent == "com.plexapp.agents.none" && response.Language == "xn"
|
||||
MediaKind = response.Agent is PersonalMediaAgent or PlexPersonalMediaAgent
|
||||
? LibraryMediaKind.OtherVideos
|
||||
: LibraryMediaKind.Movies,
|
||||
ShouldSyncItems = false,
|
||||
@@ -565,13 +559,13 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
return new PlexCollection
|
||||
{
|
||||
Key = item.RatingKey,
|
||||
Etag = _plexEtag.ForCollection(item),
|
||||
Etag = plexEtag.ForCollection(item),
|
||||
Name = item.Title
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Error projecting Plex collection");
|
||||
logger.LogWarning(ex, "Error projecting Plex collection");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -591,7 +585,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Error projecting Plex collection media item");
|
||||
logger.LogWarning(ex, "Error projecting Plex collection media item");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -610,7 +604,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Error projecting Plex tag");
|
||||
logger.LogWarning(ex, "Error projecting Plex tag");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -651,7 +645,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
|
||||
var movie = new PlexMovie
|
||||
{
|
||||
Etag = _plexEtag.ForMovie(response),
|
||||
Etag = plexEtag.ForMovie(response),
|
||||
Key = response.Key,
|
||||
MovieMetadata = [metadata],
|
||||
MediaVersions = [version],
|
||||
@@ -884,7 +878,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
var show = new PlexShow
|
||||
{
|
||||
Key = response.Key,
|
||||
Etag = _plexEtag.ForShow(response),
|
||||
Etag = plexEtag.ForShow(response),
|
||||
ShowMetadata = new List<ShowMetadata> { metadata },
|
||||
TraktListItems = new List<TraktListItem>()
|
||||
};
|
||||
@@ -1046,7 +1040,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
var season = new PlexSeason
|
||||
{
|
||||
Key = response.Key,
|
||||
Etag = _plexEtag.ForSeason(response),
|
||||
Etag = plexEtag.ForSeason(response),
|
||||
SeasonNumber = response.Index,
|
||||
SeasonMetadata = new List<SeasonMetadata> { metadata },
|
||||
TraktListItems = new List<TraktListItem>()
|
||||
@@ -1092,7 +1086,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
var episode = new PlexEpisode
|
||||
{
|
||||
Key = response.Key,
|
||||
Etag = _plexEtag.ForEpisode(response),
|
||||
Etag = plexEtag.ForEpisode(response),
|
||||
EpisodeMetadata = [metadata],
|
||||
MediaVersions = [version],
|
||||
TraktListItems = []
|
||||
@@ -1238,7 +1232,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
|
||||
var otherVideo = new PlexOtherVideo
|
||||
{
|
||||
Etag = _plexEtag.ForMovie(response),
|
||||
Etag = plexEtag.ForMovie(response),
|
||||
Key = response.Key,
|
||||
OtherVideoMetadata = [metadata],
|
||||
MediaVersions = [version],
|
||||
@@ -1431,7 +1425,7 @@ public class PlexServerApiClient : IPlexServerApiClient
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Unsupported guid format from Plex; ignoring: {Guid}", guid);
|
||||
logger.LogWarning("Unsupported guid format from Plex; ignoring: {Guid}", guid);
|
||||
}
|
||||
|
||||
return None;
|
||||
|
||||
Reference in New Issue
Block a user