* starting database redesign * set season and episode numbers * use datetimes in db (utc); update movie metadata * get movie cards from new table * copy show/episode metadata * remove old movie metadata type * rename new movie metadata type * code cleanup * start to remove old television classes * remove old television tables from database * fix playout building * fix collection views * fix show/season views * clean up movie metadata table * fix scanner tests * add libraries ui * code cleanup * fix movie scanning/metadata * add library scan button to ui * delete library path from ui * temp disable movie scanning * remove orphan media items and prevent duplicate paths * attach artwork to metadata * fix split show/season display * fix television artwork * store year distinct from release date * fix collections ui * code cleanup * add library paths from ui * fix adding to collections from ui * fix schedule items loading * schedule editing works again * remove some todos * more cleanup * fix unit tests * fix episode sorting * fix deleting show library paths * remove unused class * fix playout list in ui * fix log viewer * start to use version/file instead of statistics * clean up old columns * fix playout display (time zone) * fix playback * fix channel guide time zone * cascade more deletes * fix compiler warnings * fix adding new seasons * use artwork for channel logo * clean cache folder on startup (move channel logos, delete everything else) * log database migration * update homepage docs for libraries * fix adding new channel with logo * fix episode numbers in epg
97 lines
3.7 KiB
C#
97 lines
3.7 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using ErsatzTV.Core;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Interfaces.Images;
|
|
using ErsatzTV.Core.Interfaces.Metadata;
|
|
using LanguageExt;
|
|
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.Formats.Jpeg;
|
|
using SixLabors.ImageSharp.Processing;
|
|
|
|
namespace ErsatzTV.Infrastructure.Images
|
|
{
|
|
public class ImageCache : IImageCache
|
|
{
|
|
private static readonly SHA1CryptoServiceProvider Crypto;
|
|
private readonly ILocalFileSystem _localFileSystem;
|
|
|
|
static ImageCache() => Crypto = new SHA1CryptoServiceProvider();
|
|
|
|
public ImageCache(ILocalFileSystem localFileSystem) => _localFileSystem = localFileSystem;
|
|
|
|
public async Task<Either<BaseError, byte[]>> ResizeImage(byte[] imageBuffer, int height)
|
|
{
|
|
await using var inStream = new MemoryStream(imageBuffer);
|
|
using var image = await Image.LoadAsync(inStream);
|
|
|
|
var size = new Size { Height = height };
|
|
|
|
image.Mutate(
|
|
i => i.Resize(
|
|
new ResizeOptions
|
|
{
|
|
Mode = ResizeMode.Max,
|
|
Size = size
|
|
}));
|
|
|
|
await using var outStream = new MemoryStream();
|
|
await image.SaveAsync(outStream, new JpegEncoder { Quality = 90 });
|
|
|
|
return outStream.ToArray();
|
|
}
|
|
|
|
public async Task<Either<BaseError, string>> SaveArtworkToCache(byte[] imageBuffer, ArtworkKind artworkKind)
|
|
{
|
|
try
|
|
{
|
|
byte[] hash = Crypto.ComputeHash(imageBuffer);
|
|
string hex = BitConverter.ToString(hash).Replace("-", string.Empty);
|
|
string subfolder = hex.Substring(0, 2);
|
|
string baseFolder = artworkKind switch
|
|
{
|
|
ArtworkKind.Poster => Path.Combine(FileSystemLayout.PosterCacheFolder, subfolder),
|
|
ArtworkKind.Thumbnail => Path.Combine(FileSystemLayout.ThumbnailCacheFolder, subfolder),
|
|
ArtworkKind.Logo => Path.Combine(FileSystemLayout.LogoCacheFolder, subfolder),
|
|
_ => FileSystemLayout.LegacyImageCacheFolder
|
|
};
|
|
string target = Path.Combine(baseFolder, hex);
|
|
|
|
if (!Directory.Exists(baseFolder))
|
|
{
|
|
Directory.CreateDirectory(baseFolder);
|
|
}
|
|
|
|
await File.WriteAllBytesAsync(target, imageBuffer);
|
|
return hex;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BaseError.New(ex.Message);
|
|
}
|
|
}
|
|
|
|
public string CopyArtworkToCache(string path, ArtworkKind artworkKind)
|
|
{
|
|
var filenameKey = $"{path}:{_localFileSystem.GetLastWriteTime(path).ToFileTimeUtc()}";
|
|
byte[] hash = Crypto.ComputeHash(Encoding.UTF8.GetBytes(filenameKey));
|
|
string hex = BitConverter.ToString(hash).Replace("-", string.Empty);
|
|
string subfolder = hex.Substring(0, 2);
|
|
string baseFolder = artworkKind switch
|
|
{
|
|
ArtworkKind.Poster => Path.Combine(FileSystemLayout.PosterCacheFolder, subfolder),
|
|
ArtworkKind.Thumbnail => Path.Combine(FileSystemLayout.ThumbnailCacheFolder, subfolder),
|
|
ArtworkKind.Logo => Path.Combine(FileSystemLayout.LogoCacheFolder, subfolder),
|
|
_ => FileSystemLayout.LegacyImageCacheFolder
|
|
};
|
|
string target = Path.Combine(baseFolder, hex);
|
|
_localFileSystem.CopyFile(path, target);
|
|
|
|
return hex;
|
|
}
|
|
}
|
|
}
|