118 lines
4.9 KiB
C#
118 lines
4.9 KiB
C#
using ErsatzTV.Core;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Interfaces.Plex;
|
|
using ErsatzTV.Core.Interfaces.Repositories;
|
|
using ErsatzTV.Core.Interfaces.Search;
|
|
using ErsatzTV.Core.Plex;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace ErsatzTV.Application.Plex;
|
|
|
|
public class
|
|
SynchronizePlexLibrariesHandler : IRequestHandler<SynchronizePlexLibraries, Either<BaseError, Unit>>
|
|
{
|
|
private readonly ILogger<SynchronizePlexLibrariesHandler> _logger;
|
|
private readonly IMediaSourceRepository _mediaSourceRepository;
|
|
private readonly IPlexSecretStore _plexSecretStore;
|
|
private readonly IPlexServerApiClient _plexServerApiClient;
|
|
private readonly ISearchIndex _searchIndex;
|
|
|
|
public SynchronizePlexLibrariesHandler(
|
|
IMediaSourceRepository mediaSourceRepository,
|
|
IPlexSecretStore plexSecretStore,
|
|
IPlexServerApiClient plexServerApiClient,
|
|
ILogger<SynchronizePlexLibrariesHandler> logger,
|
|
ISearchIndex searchIndex)
|
|
{
|
|
_mediaSourceRepository = mediaSourceRepository;
|
|
_plexSecretStore = plexSecretStore;
|
|
_plexServerApiClient = plexServerApiClient;
|
|
_logger = logger;
|
|
_searchIndex = searchIndex;
|
|
}
|
|
|
|
public Task<Either<BaseError, Unit>> Handle(
|
|
SynchronizePlexLibraries request,
|
|
CancellationToken cancellationToken) =>
|
|
Validate(request, cancellationToken)
|
|
.MapT(p => SynchronizeLibraries(p, cancellationToken))
|
|
.Bind(v => v.ToEitherAsync());
|
|
|
|
private Task<Validation<BaseError, ConnectionParameters>> Validate(
|
|
SynchronizePlexLibraries request,
|
|
CancellationToken cancellationToken) =>
|
|
MediaSourceMustExist(request, cancellationToken)
|
|
.BindT(MediaSourceMustHaveActiveConnection)
|
|
.BindT(MediaSourceMustHaveToken);
|
|
|
|
private Task<Validation<BaseError, PlexMediaSource>> MediaSourceMustExist(
|
|
SynchronizePlexLibraries request,
|
|
CancellationToken cancellationToken) =>
|
|
_mediaSourceRepository.GetPlex(request.PlexMediaSourceId, cancellationToken)
|
|
.Map(o => o.ToValidation<BaseError>("Plex media source does not exist."));
|
|
|
|
private Validation<BaseError, ConnectionParameters> MediaSourceMustHaveActiveConnection(
|
|
PlexMediaSource plexMediaSource)
|
|
{
|
|
Option<PlexConnection> maybeConnection =
|
|
plexMediaSource.Connections.SingleOrDefault(c => c.IsActive);
|
|
return maybeConnection.Map(connection => new ConnectionParameters(plexMediaSource, connection))
|
|
.ToValidation<BaseError>("Plex media source requires an active connection");
|
|
}
|
|
|
|
private async Task<Validation<BaseError, ConnectionParameters>> MediaSourceMustHaveToken(
|
|
ConnectionParameters connectionParameters)
|
|
{
|
|
Option<PlexServerAuthToken> maybeToken = await
|
|
_plexSecretStore.GetServerAuthToken(connectionParameters.PlexMediaSource.ClientIdentifier);
|
|
return maybeToken.Map(token => connectionParameters with { PlexServerAuthToken = token })
|
|
.ToValidation<BaseError>("Plex media source requires a token");
|
|
}
|
|
|
|
private async Task<Unit> SynchronizeLibraries(
|
|
ConnectionParameters connectionParameters,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
Either<BaseError, List<PlexLibrary>> maybeLibraries = await _plexServerApiClient.GetLibraries(
|
|
connectionParameters.ActiveConnection,
|
|
connectionParameters.PlexServerAuthToken);
|
|
|
|
foreach (BaseError error in maybeLibraries.LeftToSeq())
|
|
{
|
|
_logger.LogWarning(
|
|
"Unable to synchronize libraries from plex server {PlexServer}: {Error}",
|
|
connectionParameters.PlexMediaSource.ServerName,
|
|
error.Value);
|
|
}
|
|
|
|
foreach (List<PlexLibrary> libraries in maybeLibraries.RightToSeq())
|
|
{
|
|
var existing = connectionParameters.PlexMediaSource.Libraries.OfType<PlexLibrary>().ToList();
|
|
var toAdd = libraries.Filter(library => existing.All(l => l.Key != library.Key)).ToList();
|
|
var toRemove = existing.Filter(library => libraries.All(l => l.Key != library.Key)).ToList();
|
|
var toUpdate = libraries
|
|
.Filter(l => toAdd.All(a => a.Key != l.Key) && toRemove.All(r => r.Key != l.Key)).ToList();
|
|
List<int> ids = await _mediaSourceRepository.UpdateLibraries(
|
|
connectionParameters.PlexMediaSource.Id,
|
|
toAdd,
|
|
toRemove,
|
|
toUpdate,
|
|
cancellationToken);
|
|
if (ids.Count != 0)
|
|
{
|
|
await _searchIndex.RemoveItems(ids);
|
|
_searchIndex.Commit();
|
|
}
|
|
}
|
|
|
|
return Unit.Default;
|
|
}
|
|
|
|
private sealed record ConnectionParameters(
|
|
PlexMediaSource PlexMediaSource,
|
|
PlexConnection ActiveConnection)
|
|
{
|
|
public PlexServerAuthToken PlexServerAuthToken { get; set; }
|
|
}
|
|
}
|