using NadekoBot.Common.Configs; namespace NadekoBot.Services; public sealed class ImagesConfig : ConfigServiceBase { private const string PATH = "data/images.yml"; private static readonly TypedKey _changeKey = new("config.images.updated"); public override string Name => "images"; public ImagesConfig(IConfigSeria serializer, IPubSub pubSub) : base(PATH, serializer, pubSub, _changeKey) { } } public interface IImageCache { Task GetHeadsImageAsync(); Task GetTailsImageAsync(); Task GetCurrencyImageAsync(); Task GetXpBackgroundImageAsync(); Task GetRategirlBgAsync(); Task GetRategirlDotAsync(); Task GetDiceAsync(int num); Task GetSlotEmojiAsync(int number); Task GetSlotBgAsync(); Task GetRipBgAsync(); Task GetRipOverlayAsync(); } public sealed class ImageCache : IImageCache, INService { private readonly IBotCache _cache; private readonly ImagesConfig _ic; private readonly Random _rng; private readonly IHttpClientFactory _httpFactory; public ImageCache( IBotCache cache, ImagesConfig ic, IHttpClientFactory httpFactory) { _cache = cache; _ic = ic; _httpFactory = httpFactory; _rng = new NadekoRandom(); } private static TypedKey GetImageKey(Uri url) => new($"image:{url}"); private async Task GetImageDataAsync(Uri url) => await _cache.GetOrAddAsync( GetImageKey(url), async () => { using var http = _httpFactory.CreateClient(); var bytes = await http.GetByteArrayAsync(url); return bytes; }, expiry: 48.Hours()); private async Task GetRandomImageDataAsync(Uri[] urls) { if (urls.Length == 0) return null; var url = urls[_rng.Next(0, urls.Length)]; var data = await GetImageDataAsync(url); return data; } public Task GetHeadsImageAsync() => GetRandomImageDataAsync(_ic.Data.Coins.Heads); public Task GetTailsImageAsync() => GetRandomImageDataAsync(_ic.Data.Coins.Tails); public Task GetCurrencyImageAsync() => GetRandomImageDataAsync(_ic.Data.Currency); public Task GetXpBackgroundImageAsync() => GetImageDataAsync(_ic.Data.Xp.Bg); public Task GetRategirlBgAsync() => GetImageDataAsync(_ic.Data.Rategirl.Matrix); public Task GetRategirlDotAsync() => GetImageDataAsync(_ic.Data.Rategirl.Dot); public Task GetDiceAsync(int num) => GetImageDataAsync(_ic.Data.Dice[num]); public Task GetSlotEmojiAsync(int number) => GetImageDataAsync(_ic.Data.Slots.Emojis[number]); public Task GetSlotBgAsync() => GetImageDataAsync(_ic.Data.Slots.Bg); public Task GetRipBgAsync() => GetImageDataAsync(_ic.Data.Rip.Bg); public Task GetRipOverlayAsync() => GetImageDataAsync(_ic.Data.Rip.Overlay); }