Browse Source

fix artwork uploads (#516)

pull/517/head
Jason Dove 4 years ago committed by GitHub
parent
commit
475dc7660b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 5
      ErsatzTV.Application/Images/Commands/SaveArtworkToDisk.cs
  3. 2
      ErsatzTV.Application/Images/Commands/SaveArtworkToDiskHandler.cs
  4. 3
      ErsatzTV.Core/FFmpeg/TempFileCategory.cs
  5. 5
      ErsatzTV.Core/Interfaces/Images/IImageCache.cs
  6. 28
      ErsatzTV.Infrastructure/Images/ImageCache.cs
  7. 9
      ErsatzTV/Pages/ChannelEditor.razor
  8. 4
      ErsatzTV/Pages/WatermarkEditor.razor

1
CHANGELOG.md

@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Use subtitles to display errors, which fixes many edge cases of unescaped characters
- Properly split song genre tags
- Properly display all songs that have an identical album and title
- Fix channel logo and watermark uploads
### Added
- Add song genres to search index

5
ErsatzTV.Application/Images/Commands/SaveArtworkToDisk.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core;
using System.IO;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using LanguageExt;
using MediatR;
@ -6,5 +7,5 @@ using MediatR; @@ -6,5 +7,5 @@ using MediatR;
namespace ErsatzTV.Application.Images.Commands
{
// ReSharper disable once SuggestBaseTypeForParameter
public record SaveArtworkToDisk(byte[] Buffer, ArtworkKind ArtworkKind) : IRequest<Either<BaseError, string>>;
public record SaveArtworkToDisk(Stream Stream, ArtworkKind ArtworkKind) : IRequest<Either<BaseError, string>>;
}

2
ErsatzTV.Application/Images/Commands/SaveArtworkToDiskHandler.cs

@ -14,6 +14,6 @@ namespace ErsatzTV.Application.Images.Commands @@ -14,6 +14,6 @@ namespace ErsatzTV.Application.Images.Commands
public SaveArtworkToDiskHandler(IImageCache imageCache) => _imageCache = imageCache;
public Task<Either<BaseError, string>> Handle(SaveArtworkToDisk request, CancellationToken cancellationToken) =>
_imageCache.SaveArtworkToCache(request.Buffer, request.ArtworkKind);
_imageCache.SaveArtworkToCache(request.Stream, request.ArtworkKind);
}
}

3
ErsatzTV.Core/FFmpeg/TempFileCategory.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
{
Subtitle = 0,
SongBackground = 1,
CoverArt = 2
CoverArt = 2,
CachedArtwork = 3
}
}

5
ErsatzTV.Core/Interfaces/Images/IImageCache.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.IO;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using LanguageExt;
@ -7,7 +8,7 @@ namespace ErsatzTV.Core.Interfaces.Images @@ -7,7 +8,7 @@ namespace ErsatzTV.Core.Interfaces.Images
public interface IImageCache
{
Task<Either<BaseError, byte[]>> ResizeImage(byte[] imageBuffer, int height);
Task<Either<BaseError, string>> SaveArtworkToCache(byte[] imageBuffer, ArtworkKind artworkKind);
Task<Either<BaseError, string>> SaveArtworkToCache(Stream stream, ArtworkKind artworkKind);
Task<Either<BaseError, string>> CopyArtworkToCache(string path, ArtworkKind artworkKind);
string GetPathForImage(string fileName, ArtworkKind artworkKind, Option<int> maybeMaxHeight);
Task<bool> IsAnimated(string fileName);

28
ErsatzTV.Infrastructure/Images/ImageCache.cs

@ -5,6 +5,8 @@ using System.Text; @@ -5,6 +5,8 @@ using System.Text;
using System.Threading.Tasks;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Interfaces.Metadata;
using LanguageExt;
@ -22,13 +24,19 @@ namespace ErsatzTV.Infrastructure.Images @@ -22,13 +24,19 @@ namespace ErsatzTV.Infrastructure.Images
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<ImageCache> _logger;
private readonly IMemoryCache _memoryCache;
private readonly ITempFilePool _tempFilePool;
static ImageCache() => Crypto = SHA1.Create();
public ImageCache(ILocalFileSystem localFileSystem, IMemoryCache memoryCache, ILogger<ImageCache> logger)
public ImageCache(
ILocalFileSystem localFileSystem,
IMemoryCache memoryCache,
ITempFilePool tempFilePool,
ILogger<ImageCache> logger)
{
_localFileSystem = localFileSystem;
_memoryCache = memoryCache;
_tempFilePool = tempFilePool;
_logger = logger;
}
@ -53,11 +61,14 @@ namespace ErsatzTV.Infrastructure.Images @@ -53,11 +61,14 @@ namespace ErsatzTV.Infrastructure.Images
return outStream.ToArray();
}
public async Task<Either<BaseError, string>> SaveArtworkToCache(byte[] imageBuffer, ArtworkKind artworkKind)
public async Task<Either<BaseError, string>> SaveArtworkToCache(Stream stream, ArtworkKind artworkKind)
{
try
{
byte[] hash = Crypto.ComputeHash(imageBuffer);
string tempFileName = _tempFilePool.GetNextTempFile(TempFileCategory.CachedArtwork);
await using var fs = new FileStream(tempFileName, FileMode.OpenOrCreate);
await stream.CopyToAsync(fs);
byte[] hash = await ComputeFileHash(tempFileName);
string hex = BitConverter.ToString(hash).Replace("-", string.Empty);
string subfolder = hex[..2];
string baseFolder = artworkKind switch
@ -76,7 +87,8 @@ namespace ErsatzTV.Infrastructure.Images @@ -76,7 +87,8 @@ namespace ErsatzTV.Infrastructure.Images
Directory.CreateDirectory(baseFolder);
}
await File.WriteAllBytesAsync(target, imageBuffer);
await _localFileSystem.CopyFile(tempFileName, target);
return hex;
}
catch (Exception ex)
@ -85,6 +97,14 @@ namespace ErsatzTV.Infrastructure.Images @@ -85,6 +97,14 @@ namespace ErsatzTV.Infrastructure.Images
}
}
private static async Task<byte[]> ComputeFileHash(string fileName)
{
using var md5 = MD5.Create();
await using var fs = new FileStream(fileName, FileMode.Open);
fs.Position = 0;
return await md5.ComputeHashAsync(fs);
}
public async Task<Either<BaseError, string>> CopyArtworkToCache(string path, ArtworkKind artworkKind)
{
try

9
ErsatzTV/Pages/ChannelEditor.razor

@ -199,9 +199,8 @@ @@ -199,9 +199,8 @@
{
try
{
var buffer = new byte[e.File.Size];
await e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024).ReadAsync(buffer);
Either<BaseError, string> maybeCacheFileName = await _mediator.Send(new SaveArtworkToDisk(buffer, ArtworkKind.Logo));
Either<BaseError, string> maybeCacheFileName =
await _mediator.Send(new SaveArtworkToDisk(e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024), ArtworkKind.Logo));
maybeCacheFileName.Match(
relativeFileName =>
{
@ -210,12 +209,14 @@ @@ -210,12 +209,14 @@
},
error =>
{
Console.WriteLine($"error saving {error}");
_snackbar.Add($"Unexpected error saving channel logo: {error.Value}", Severity.Error);
_logger.LogError("Unexpected error saving channel logo: {Error}", error.Value);
});
}
catch (IOException)
catch (IOException ex)
{
Console.WriteLine(ex);
_snackbar.Add("Channel logo exceeds maximum allowed file size of 10 MB", Severity.Error);
_logger.LogError("Channel logo exceeds maximum allowed file size of 10 MB");
}

4
ErsatzTV/Pages/WatermarkEditor.razor

@ -209,10 +209,8 @@ @@ -209,10 +209,8 @@
{
try
{
var buffer = new byte[e.File.Size];
await e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024).ReadAsync(buffer);
Either<BaseError, string> maybeCacheFileName = await _mediator
.Send(new SaveArtworkToDisk(buffer, ArtworkKind.Watermark));
.Send(new SaveArtworkToDisk(e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024), ArtworkKind.Watermark));
maybeCacheFileName.Match(
relativeFileName =>
{

Loading…
Cancel
Save