mirror of https://github.com/ErsatzTV/ErsatzTV.git
9 changed files with 116 additions and 94 deletions
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
namespace ErsatzTV.Application.Images |
||||
{ |
||||
public record CachedImagePathViewModel(string FileName, string MimeType); |
||||
} |
||||
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
namespace ErsatzTV.Application.Images |
||||
{ |
||||
// ReSharper disable once SuggestBaseTypeForParameter
|
||||
public record ImageViewModel(byte[] Contents, string MimeType); |
||||
} |
||||
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
using System; |
||||
using System.IO; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using ErsatzTV.Core; |
||||
using ErsatzTV.Core.Interfaces.Images; |
||||
using LanguageExt; |
||||
using MediatR; |
||||
using Winista.Mime; |
||||
using static LanguageExt.Prelude; |
||||
|
||||
namespace ErsatzTV.Application.Images.Queries |
||||
{ |
||||
public class |
||||
GetCachedImagePathHandler : IRequestHandler<GetCachedImagePath, Either<BaseError, CachedImagePathViewModel>> |
||||
{ |
||||
private static readonly MimeTypes MimeTypes = new(); |
||||
private readonly IImageCache _imageCache; |
||||
|
||||
public GetCachedImagePathHandler(IImageCache imageCache) => _imageCache = imageCache; |
||||
|
||||
public async Task<Either<BaseError, CachedImagePathViewModel>> Handle( |
||||
GetCachedImagePath request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
try |
||||
{ |
||||
MimeType mimeType; |
||||
|
||||
string cachePath = _imageCache.GetPathForImage( |
||||
request.FileName, |
||||
request.ArtworkKind, |
||||
Optional(request.MaxHeight)); |
||||
if (!File.Exists(cachePath)) |
||||
{ |
||||
if (request.MaxHeight.HasValue) |
||||
{ |
||||
string originalPath = _imageCache.GetPathForImage(request.FileName, request.ArtworkKind, None); |
||||
byte[] contents = await File.ReadAllBytesAsync(originalPath, cancellationToken); |
||||
Either<BaseError, byte[]> resizeResult = |
||||
await _imageCache.ResizeImage(contents, request.MaxHeight.Value); |
||||
resizeResult.IfRight(result => contents = result); |
||||
|
||||
string baseFolder = Path.GetDirectoryName(cachePath); |
||||
if (baseFolder != null && !Directory.Exists(baseFolder)) |
||||
{ |
||||
Directory.CreateDirectory(baseFolder); |
||||
} |
||||
|
||||
await File.WriteAllBytesAsync(cachePath, contents, cancellationToken); |
||||
|
||||
mimeType = new MimeType("image/jpeg"); |
||||
} |
||||
else |
||||
{ |
||||
return BaseError.New($"Artwork does not exist on disk at {cachePath}"); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
mimeType = MimeTypes.GetMimeTypeFromFile(cachePath); |
||||
} |
||||
|
||||
return new CachedImagePathViewModel(cachePath, mimeType.Name); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
return BaseError.New(ex.Message); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
using System; |
||||
using System.IO; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using ErsatzTV.Core; |
||||
using ErsatzTV.Core.Domain; |
||||
using ErsatzTV.Core.Interfaces.Images; |
||||
using LanguageExt; |
||||
using MediatR; |
||||
using Microsoft.Extensions.Caching.Memory; |
||||
using Winista.Mime; |
||||
|
||||
namespace ErsatzTV.Application.Images.Queries |
||||
{ |
||||
public class GetImageContentsHandler : IRequestHandler<GetImageContents, Either<BaseError, ImageViewModel>> |
||||
{ |
||||
private static readonly MimeTypes MimeTypes = new(); |
||||
private readonly IImageCache _imageCache; |
||||
private readonly IMemoryCache _memoryCache; |
||||
|
||||
public GetImageContentsHandler(IImageCache imageCache, IMemoryCache memoryCache) |
||||
{ |
||||
_imageCache = imageCache; |
||||
_memoryCache = memoryCache; |
||||
} |
||||
|
||||
public async Task<Either<BaseError, ImageViewModel>> Handle( |
||||
GetImageContents request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
try |
||||
{ |
||||
return await _memoryCache.GetOrCreateAsync( |
||||
request.FileName, |
||||
async entry => |
||||
{ |
||||
entry.SlidingExpiration = TimeSpan.FromHours(1); |
||||
|
||||
string subfolder = request.FileName.Substring(0, 2); |
||||
string baseFolder = request.ArtworkKind switch |
||||
{ |
||||
ArtworkKind.Poster => Path.Combine(FileSystemLayout.PosterCacheFolder, subfolder), |
||||
ArtworkKind.Thumbnail => Path.Combine(FileSystemLayout.ThumbnailCacheFolder, subfolder), |
||||
ArtworkKind.Logo => Path.Combine(FileSystemLayout.LogoCacheFolder, subfolder), |
||||
ArtworkKind.FanArt => Path.Combine(FileSystemLayout.FanArtCacheFolder, subfolder), |
||||
_ => FileSystemLayout.LegacyImageCacheFolder |
||||
}; |
||||
|
||||
string fileName = Path.Combine(baseFolder, request.FileName); |
||||
byte[] contents = await File.ReadAllBytesAsync(fileName, cancellationToken); |
||||
|
||||
if (request.MaxHeight.HasValue) |
||||
{ |
||||
Either<BaseError, byte[]> resizeResult = await _imageCache |
||||
.ResizeImage(contents, request.MaxHeight.Value); |
||||
resizeResult.IfRight(result => contents = result); |
||||
} |
||||
|
||||
MimeType mimeType = MimeTypes.GetMimeType(contents); |
||||
return new ImageViewModel(contents, mimeType.Name); |
||||
}); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
return BaseError.New(ex.Message); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue