using Harmonia.Core.Caching; using Harmonia.Core.Imaging; using Harmonia.Core.Models; using Microsoft.Extensions.Caching.Memory; using Microsoft.UI.Xaml.Media.Imaging; using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Harmonia.WinUI.Caching; public class AudioBitmapImageCache(IAudioImageExtractor audioImageExtractor) : MemoryCache, IAudioBitmapImageCache { protected override MemoryCacheOptions Options => new() { SizeLimit = 200_000_000, CompactionPercentage = 0.2, }; protected override TimeSpan SlidingExpiration => TimeSpan.FromSeconds(600); protected override int MaxConcurrentRequests => 8; protected virtual int MaxImageWidthOrHeight => 1000; protected override object? GetKey(Song key) { if (string.IsNullOrWhiteSpace(key.ImageHash) == false) { return key.ImageHash; } else if (string.IsNullOrWhiteSpace(key.ImageName) == false) { return key.ImageName; } return "Default"; } protected override async ValueTask FetchAsync(Song key, CancellationToken cancellationToken) { SongPictureInfo? songPictureInfo = await audioImageExtractor.ExtractImageAsync(key.FileName, cancellationToken); if (songPictureInfo == null) return GetDefaultBitmapImage(); using MemoryStream stream = new(songPictureInfo.Data); BitmapImage bitmapImage = new(); await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream()); bitmapImage.DecodePixelWidth = GetDecodePixelWidth(bitmapImage); bitmapImage.DecodePixelHeight = GetDecodePixelHeight(bitmapImage); return bitmapImage; } private BitmapImage GetDefaultBitmapImage() { Uri uri = new("ms-appx:///Assets/Default.png", UriKind.Absolute); BitmapImage bitmapImage = new(); bitmapImage.DecodePixelWidth = GetDecodePixelWidth(bitmapImage); bitmapImage.DecodePixelHeight = GetDecodePixelHeight(bitmapImage); bitmapImage.UriSource = uri; return bitmapImage; } private int GetDecodePixelWidth(BitmapImage bitmapImage) { int originalImageWidth = bitmapImage.PixelWidth; int orignalImageHeight = bitmapImage.PixelHeight; if (originalImageWidth <= MaxImageWidthOrHeight && orignalImageHeight <= MaxImageWidthOrHeight) return 0; if (orignalImageHeight > originalImageWidth) return 0; return MaxImageWidthOrHeight; } private int GetDecodePixelHeight(BitmapImage bitmapImage) { int originalImageWidth = bitmapImage.PixelWidth; int orignalImageHeight = bitmapImage.PixelHeight; if (originalImageWidth <= MaxImageWidthOrHeight && orignalImageHeight <= MaxImageWidthOrHeight) return 0; if (originalImageWidth > orignalImageHeight) return 0; return MaxImageWidthOrHeight; } protected override long GetEntrySize(BitmapImage entry) { return entry.DecodePixelWidth * entry.DecodePixelHeight; } }