Browse Source

use transcoded plex artwork

pull/34/head
Jason Dove 5 years ago
parent
commit
6202856a77
  1. 6
      ErsatzTV.Application/Plex/PlexConnectionParametersViewModel.cs
  2. 9
      ErsatzTV.Application/Plex/Queries/GetPlexConnectionParameters.cs
  3. 63
      ErsatzTV.Application/Plex/Queries/GetPlexConnectionParametersHandler.cs
  4. 9
      ErsatzTV.Application/Plex/Queries/GetPlexImage.cs
  5. 39
      ErsatzTV/Controllers/ArtworkController.cs

6
ErsatzTV.Application/Plex/PlexConnectionParametersViewModel.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
using System;
namespace ErsatzTV.Application.Plex
{
public record PlexConnectionParametersViewModel(Uri Uri, string AuthToken);
}

9
ErsatzTV.Application/Plex/Queries/GetPlexConnectionParameters.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Plex.Queries
{
public record GetPlexConnectionParameters
(int PlexMediaSourceId) : IRequest<Either<BaseError, PlexConnectionParametersViewModel>>;
}

63
ErsatzTV.Application/Plex/Queries/GetPlexImageHandler.cs → ErsatzTV.Application/Plex/Queries/GetPlexConnectionParametersHandler.cs

@ -1,9 +1,7 @@ @@ -1,9 +1,7 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Application.Images;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Plex;
@ -12,17 +10,17 @@ using ErsatzTV.Core.Plex; @@ -12,17 +10,17 @@ using ErsatzTV.Core.Plex;
using LanguageExt;
using MediatR;
using Microsoft.Extensions.Caching.Memory;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Plex.Queries
{
public class GetPlexImageHandler : IRequestHandler<GetPlexImage, Either<BaseError, ImageViewModel>>
public class GetPlexConnectionParametersHandler : IRequestHandler<GetPlexConnectionParameters,
Either<BaseError, PlexConnectionParametersViewModel>>
{
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMemoryCache _memoryCache;
private readonly IPlexSecretStore _plexSecretStore;
public GetPlexImageHandler(
public GetPlexConnectionParametersHandler(
IMemoryCache memoryCache,
IMediaSourceRepository mediaSourceRepository,
IPlexSecretStore plexSecretStore)
@ -32,50 +30,39 @@ namespace ErsatzTV.Application.Plex.Queries @@ -32,50 +30,39 @@ namespace ErsatzTV.Application.Plex.Queries
_plexSecretStore = plexSecretStore;
}
public async Task<Either<BaseError, ImageViewModel>>
Handle(GetPlexImage request, CancellationToken cancellationToken)
public async Task<Either<BaseError, PlexConnectionParametersViewModel>> Handle(
GetPlexConnectionParameters request,
CancellationToken cancellationToken)
{
if (!_memoryCache.TryGetValue(request, out ConnectionParameters parameters))
if (_memoryCache.TryGetValue(request, out PlexConnectionParametersViewModel parameters))
{
Either<BaseError, ConnectionParameters> maybeParameters =
await Validate(request).Map(v => v.ToEither<ConnectionParameters>());
return await maybeParameters.Match(
p =>
{
_memoryCache.Set(request, p, TimeSpan.FromHours(1));
return RequestImageFromPlex(request, p);
},
error => Left<BaseError, ImageViewModel>(error).AsTask());
return parameters;
}
return await RequestImageFromPlex(request, parameters);
}
private async Task<Either<BaseError, ImageViewModel>> RequestImageFromPlex(
GetPlexImage request,
ConnectionParameters connectionParameters)
{
var url = $"{connectionParameters.ActiveConnection.Uri}/{request.Path}";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Plex-Token", connectionParameters.PlexServerAuthToken.AuthToken);
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
return new ImageViewModel(
await response.Content.ReadAsByteArrayAsync(),
response.Content.Headers.ContentType?.MediaType ?? "image/jpeg");
}
Either<BaseError, PlexConnectionParametersViewModel> maybeParameters =
await Validate(request)
.MapT(
cp => new PlexConnectionParametersViewModel(
new Uri(cp.ActiveConnection.Uri),
cp.PlexServerAuthToken.AuthToken))
.Map(v => v.ToEither<PlexConnectionParametersViewModel>());
return BaseError.New($"Unsuccessful response from plex image request: {response.StatusCode}");
return maybeParameters.Match(
p =>
{
_memoryCache.Set(request, p, TimeSpan.FromHours(1));
return maybeParameters;
},
error => error);
}
private Task<Validation<BaseError, ConnectionParameters>> Validate(GetPlexImage request) =>
private Task<Validation<BaseError, ConnectionParameters>> Validate(GetPlexConnectionParameters request) =>
PlexMediaSourceMustExist(request)
.BindT(MediaSourceMustHaveActiveConnection)
.BindT(MediaSourceMustHaveToken);
private Task<Validation<BaseError, PlexMediaSource>> PlexMediaSourceMustExist(GetPlexImage request) =>
private Task<Validation<BaseError, PlexMediaSource>> PlexMediaSourceMustExist(
GetPlexConnectionParameters request) =>
_mediaSourceRepository.GetPlex(request.PlexMediaSourceId)
.Map(
v => v.ToValidation<BaseError>(

9
ErsatzTV.Application/Plex/Queries/GetPlexImage.cs

@ -1,9 +0,0 @@ @@ -1,9 +0,0 @@
using ErsatzTV.Application.Images;
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Plex.Queries
{
public record GetPlexImage(int PlexMediaSourceId, string Path) : IRequest<Either<BaseError, ImageViewModel>>;
}

39
ErsatzTV/Controllers/ArtworkController.cs

@ -1,6 +1,10 @@ @@ -1,6 +1,10 @@
using System.Threading.Tasks;
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using ErsatzTV.Application.Images;
using ErsatzTV.Application.Images.Queries;
using ErsatzTV.Application.Plex;
using ErsatzTV.Application.Plex.Queries;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -14,9 +18,14 @@ namespace ErsatzTV.Controllers @@ -14,9 +18,14 @@ namespace ErsatzTV.Controllers
[ApiExplorerSettings(IgnoreApi = true)]
public class PostersController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IMediator _mediator;
public PostersController(IMediator mediator) => _mediator = mediator;
public PostersController(IMediator mediator, IHttpClientFactory httpClientFactory)
{
_mediator = mediator;
_httpClientFactory = httpClientFactory;
}
[HttpGet("/artwork/posters/{fileName}")]
public async Task<IActionResult> GetPoster(string fileName)
@ -31,11 +40,27 @@ namespace ErsatzTV.Controllers @@ -31,11 +40,27 @@ namespace ErsatzTV.Controllers
[HttpGet("/artwork/posters/plex/{plexMediaSourceId}/{*path}")]
public async Task<IActionResult> GetPlexPoster(int plexMediaSourceId, string path)
{
Either<BaseError, ImageViewModel> imageContents =
await _mediator.Send(new GetPlexImage(plexMediaSourceId, path));
return imageContents.Match<IActionResult>(
Left: _ => new NotFoundResult(),
Right: r => new FileContentResult(r.Contents, r.MimeType));
Either<BaseError, PlexConnectionParametersViewModel> connectionParameters =
await _mediator.Send(new GetPlexConnectionParameters(plexMediaSourceId));
return await connectionParameters.Match<Task<IActionResult>>(
Left: _ => new NotFoundResult().AsTask<IActionResult>(),
Right: async r =>
{
HttpClient client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Add("X-Plex-Token", r.AuthToken);
var transcodePath = $"photo/:/transcode?url=/{path}&height=440&width=304&minSize=1&upscale=0";
var fullPath = new Uri(r.Uri, transcodePath);
HttpResponseMessage response = await client.GetAsync(
fullPath,
HttpCompletionOption.ResponseHeadersRead);
Stream stream = await response.Content.ReadAsStreamAsync();
return new FileStreamResult(
stream,
response.Content.Headers.ContentType?.MediaType ?? "image/jpeg");
});
}
[HttpGet("/artwork/thumbnails/{fileName}")]

Loading…
Cancel
Save