enable plex for movies (#72)

* re-enable plex, temp force secure connections

* add plex fanart

* synchronize genre from plex

* fix plex library sync

* improve stream error handling

* synchronize plex artwork

* use switch instead of button

* prioritize local connections for insecure plex sources

* sign out of plex

* better plex sign in/out

* code cleanup

* fix plex movie aspect ratio and scan type
This commit is contained in:
Jason Dove
2021-03-13 21:04:54 +00:00
committed by GitHub
parent a13f964200
commit aa938baec8
35 changed files with 602 additions and 132 deletions
+114 -13
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Plex;
@@ -38,19 +39,26 @@ namespace ErsatzTV.Core.Plex
await entries.Match(
async movieEntries =>
{
foreach (PlexMovie entry in movieEntries)
foreach (PlexMovie incoming in movieEntries)
{
// TODO: optimize dbcontext use here, do we need tracking? can we make partial updates with dapper?
// TODO: figure out how to rebuild playlists
Either<BaseError, PlexMovie> maybeMovie = await _movieRepository
.GetOrAdd(plexMediaSourceLibrary, entry)
.BindT(UpdateIfNeeded);
.GetOrAdd(plexMediaSourceLibrary, incoming)
.BindT(existing => UpdateStatistics(existing, incoming, connection, token))
.BindT(existing => UpdateMetadata(existing, incoming))
.BindT(existing => UpdateArtwork(existing, incoming));
maybeMovie.IfLeft(
error => _logger.LogWarning(
"Error processing plex movie at {Key}: {Error}",
entry.Key,
error.Value));
await maybeMovie.Match(
async movie => await _movieRepository.Update(movie),
error =>
{
_logger.LogWarning(
"Error processing plex movie at {Key}: {Error}",
incoming.Key,
error.Value);
return Task.CompletedTask;
});
}
},
error =>
@@ -68,10 +76,103 @@ namespace ErsatzTV.Core.Plex
return Unit.Default;
}
private Task<Either<BaseError, PlexMovie>> UpdateIfNeeded(PlexMovie plexMovie) =>
// .BindT(movie => UpdateStatistics(movie, ffprobePath).MapT(_ => movie))
// .BindT(UpdateMetadata)
// .BindT(UpdatePoster);
Right<BaseError, PlexMovie>(plexMovie).AsTask();
private async Task<Either<BaseError, PlexMovie>> UpdateStatistics(
PlexMovie existing,
PlexMovie incoming,
PlexConnection connection,
PlexServerAuthToken token)
{
MediaVersion existingVersion = existing.MediaVersions.Head();
MediaVersion incomingVersion = incoming.MediaVersions.Head();
if (incomingVersion.DateUpdated > existingVersion.DateUpdated ||
string.IsNullOrWhiteSpace(existingVersion.SampleAspectRatio))
{
Either<BaseError, MediaVersion> maybeStatistics =
await _plexServerApiClient.GetStatistics(incoming, connection, token);
maybeStatistics.IfRight(
mediaVersion =>
{
existingVersion.SampleAspectRatio = mediaVersion.SampleAspectRatio ?? "1:1";
existingVersion.VideoScanKind = mediaVersion.VideoScanKind;
existingVersion.DateUpdated = incomingVersion.DateUpdated;
});
}
return Right<BaseError, PlexMovie>(existing);
}
private Task<Either<BaseError, PlexMovie>> UpdateMetadata(PlexMovie existing, PlexMovie incoming)
{
MovieMetadata existingMetadata = existing.MovieMetadata.Head();
MovieMetadata incomingMetadata = incoming.MovieMetadata.Head();
if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated)
{
foreach (Genre genre in existingMetadata.Genres
.Filter(g => incomingMetadata.Genres.All(g2 => g2.Name != g.Name))
.ToList())
{
existingMetadata.Genres.Remove(genre);
}
foreach (Genre genre in incomingMetadata.Genres
.Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name))
.ToList())
{
existingMetadata.Genres.Add(genre);
}
}
return Right<BaseError, PlexMovie>(existing).AsTask();
}
private Task<Either<BaseError, PlexMovie>> UpdateArtwork(PlexMovie existing, PlexMovie incoming)
{
MovieMetadata existingMetadata = existing.MovieMetadata.Head();
MovieMetadata incomingMetadata = incoming.MovieMetadata.Head();
if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated)
{
UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.Poster);
UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.FanArt);
}
return Right<BaseError, PlexMovie>(existing).AsTask();
}
private void UpdateArtworkIfNeeded(
MovieMetadata existingMetadata,
MovieMetadata incomingMetadata,
ArtworkKind artworkKind)
{
Option<Artwork> maybeIncomingArtwork = Optional(incomingMetadata.Artwork).Flatten()
.Find(a => a.ArtworkKind == artworkKind);
maybeIncomingArtwork.Match(
incomingArtwork =>
{
Option<Artwork> maybeExistingArtwork = Optional(existingMetadata.Artwork).Flatten()
.Find(a => a.ArtworkKind == artworkKind);
maybeExistingArtwork.Match(
existingArtwork =>
{
existingArtwork.Path = incomingArtwork.Path;
existingArtwork.DateUpdated = incomingArtwork.DateUpdated;
},
() =>
{
existingMetadata.Artwork ??= new List<Artwork>();
existingMetadata.Artwork.Add(incomingArtwork);
});
},
() =>
{
existingMetadata.Artwork ??= new List<Artwork>();
existingMetadata.Artwork.RemoveAll(a => a.ArtworkKind == artworkKind);
});
}
}
}