summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2026-03-11 00:58:13 +0100
committerRory& <root@rory.gay>2026-03-11 00:58:13 +0100
commitb40b5234f4cb3681bd9531d76c38111057f71733 (patch)
treeae238a01834f25871631b84d19141019c56c8f1b
parentfix: fall back to undefined in message create (diff)
downloadserver-ts-dev/emma/gateway-batch-presence-lookup.tar.xz
-rw-r--r--extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs4
-rw-r--r--extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs67
-rw-r--r--extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs41
-rw-r--r--extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs2
-rw-r--r--extra/admin-api/Spacebar.Cdn/Helpers/DefaultAvatarRenderer.cs24
-rw-r--r--extra/admin-api/Spacebar.Cdn/Mimes.cs15
-rw-r--r--extra/admin-api/Spacebar.Cdn/Properties/launchSettings.json3
-rw-r--r--extra/admin-api/Spacebar.Cdn/Services/CdnStorageRebuildService.cs5
-rw-r--r--extra/admin-api/Spacebar.Cdn/Services/DiscordImageResizeService.cs4
-rw-r--r--extra/admin-api/Spacebar.Cdn/Spacebar.Cdn.csproj2
10 files changed, 123 insertions, 44 deletions
diff --git a/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs b/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs

index 3bdee113..a3f0a7d8 100644 --- a/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs +++ b/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs
@@ -3,10 +3,6 @@ using ArcaneLibs; namespace Spacebar.Interop.Cdn.Abstractions; public class FilesystemFileSource(string baseUrl) : IFileSource { - private readonly StreamingHttpClient _httpClient = new() { - BaseAddress = new Uri(baseUrl) - }; - public string BaseUrl => baseUrl; public async Task Init(CancellationToken? cancellationToken = null) { diff --git a/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs b/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs
index 404e6e29..f595fba9 100644 --- a/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs +++ b/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs
@@ -1,3 +1,4 @@ +using ArcaneLibs; using ArcaneLibs.Collections; using ImageMagick; using Microsoft.AspNetCore.Mvc; @@ -6,7 +7,7 @@ using Spacebar.Cdn.Extensions; using Spacebar.Interop.Cdn.Abstractions; namespace Spacebar.Cdn.Controllers.Internal; -/* + [ApiController] public class IsPixelArtController(LruFileCache lfc, IFileSource fs, PixelArtDetectionService pads, DiscordImageResizeService dirs) : ControllerBase { private static readonly LruCache<bool> _isPixelArtCache = new(100_000); @@ -20,7 +21,7 @@ public class IsPixelArtController(LruFileCache lfc, IFileSource fs, PixelArtDete return pads.IsPixelArt(img); }); } - + [HttpGet("/isCartoonArt/{*_:required}")] public async Task<bool> IsCartoonArt() { return await _isPixelArtCache.GetOrAddAsync(Request.Path.ToString(), async () => { @@ -34,18 +35,19 @@ public class IsPixelArtController(LruFileCache lfc, IFileSource fs, PixelArtDete public async Task<FileContentResult> GetEdges([FromQuery] string applyMode = "pre") { return await _edgeCache.GetOrAdd(Request.Path.ToString() + Request.QueryString, async () => { var original = await fs.GetFile(Request.Path.ToString().Replace("/edges", "")); - + DiscordImageResizeParams resizeParams = new() { Size = Request.Query.ContainsKey("size") && uint.TryParse(Request.Query["size"], out uint size) ? size : null, - Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality) ? quality : DiscordImageResizeQuality.High, + Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality) + ? quality + : DiscordImageResizeQuality.High, KeepAspectRatio = !Request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(Request.Query["keepAspectRatio"], out bool kar) || kar, Passthrough = Request.Query.ContainsKey("passthrough") && bool.TryParse(Request.Query["passthrough"], out bool pt) && pt, Animated = Request.Query.ContainsKey("animated") && bool.TryParse(Request.Query["animated"], out bool an) && an, SpacebarAllowUpscale = Request.Query.ContainsKey("allowUpscale") && bool.TryParse(Request.Query["allowUpscale"], out bool au) && au, SpacebarOptimiseGif = Request.Query.ContainsKey("optimiseGif") && bool.TryParse(Request.Query["optimiseGif"], out bool og) && og }; - - + double radius = 1; if (Request.Query.ContainsKey("radius")) double.TryParse(Request.Query["radius"], out radius); @@ -65,27 +67,27 @@ public class IsPixelArtController(LruFileCache lfc, IFileSource fs, PixelArtDete }; }).ContinueWith(t => File(t.Result.Data, t.Result.MimeType)); } - - [HttpGet("/posterize/{*_:required}")] + + [HttpGet("/posterize/{*_:required}")] public async Task<FileContentResult> Posterize() { return await _edgeCache.GetOrAdd(Request.Path.ToString() + Request.QueryString, async () => { var original = await fs.GetFile(Request.Path.ToString().Replace("/posterize", "")); DiscordImageResizeParams resizeParams = new() { Size = Request.Query.ContainsKey("size") && uint.TryParse(Request.Query["size"], out uint size) ? size : null, - Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality) ? quality : DiscordImageResizeQuality.High, + Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality) + ? quality + : DiscordImageResizeQuality.High, KeepAspectRatio = !Request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(Request.Query["keepAspectRatio"], out bool kar) || kar, Passthrough = Request.Query.ContainsKey("passthrough") && bool.TryParse(Request.Query["passthrough"], out bool pt) && pt, Animated = Request.Query.ContainsKey("animated") && bool.TryParse(Request.Query["animated"], out bool an) && an, SpacebarAllowUpscale = Request.Query.ContainsKey("allowUpscale") && bool.TryParse(Request.Query["allowUpscale"], out bool au) && au }; - - + double radius = 1; if (Request.Query.ContainsKey("radius")) double.TryParse(Request.Query["radius"], out radius); var img = await original.ToMagickImageCollectionAsync(); - int inFrames = img.Count; // using var edged = pads.RenderEdges(img, radius); foreach (var frame in img) { @@ -94,9 +96,9 @@ public class IsPixelArtController(LruFileCache lfc, IFileSource fs, PixelArtDete frame.Posterize(16, DitherMethod.No); frame.ColorFuzz = new Percentage(0); } - - if(resizeParams.Size.HasValue) - img = dirs.Apply(img,resizeParams); + + if (resizeParams.Size.HasValue) + img = dirs.Apply(img, resizeParams); Console.WriteLine($"Generated edges for {Request.Path}, radius={radius}, inFrames={inFrames}, outFrames={img.Count}"); return new LruFileCache.Entry { @@ -106,36 +108,38 @@ public class IsPixelArtController(LruFileCache lfc, IFileSource fs, PixelArtDete }; }).ContinueWith(t => File(t.Result.Data, t.Result.MimeType)); } - + [HttpGet("/colorFuzz/{*_:required}")] public async Task<FileContentResult> ColorFuzz() { return await _edgeCache.GetOrAdd(Request.Path.ToString() + Request.QueryString, async () => { var original = await fs.GetFile(Request.Path.ToString().Replace("/colorFuzz", "")); DiscordImageResizeParams resizeParams = new() { - Size = Request.Query.ContainsKey("size") && uint.TryParse(Request.Query["size"], out uint size) ? size : null, - Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality) ? quality : DiscordImageResizeQuality.High, + Size = Request.Query.ContainsKey("size") && uint.TryParse(Request.Query["size"], out uint size) + ? size + : null, + Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality) + ? quality + : DiscordImageResizeQuality.High, KeepAspectRatio = !Request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(Request.Query["keepAspectRatio"], out bool kar) || kar, Passthrough = Request.Query.ContainsKey("passthrough") && bool.TryParse(Request.Query["passthrough"], out bool pt) && pt, Animated = Request.Query.ContainsKey("animated") && bool.TryParse(Request.Query["animated"], out bool an) && an, - SpacebarAllowUpscale = Request.Query.ContainsKey("allowUpscale") && bool.TryParse(Request.Query["allowUpscale"], out bool au) && au + SpacebarAllowUpscale = Request.Query.ContainsKey("allowUpscale") && bool.TryParse(Request.Query["allowUpscale"], out bool au) && au, }; - - + double colorFuzz = 1; if (Request.Query.ContainsKey("colorFuzz")) double.TryParse(Request.Query["colorFuzz"], out colorFuzz); var img = await original.ToMagickImageCollectionAsync(); - int inFrames = img.Count; // using var edged = pads.RenderEdges(img, radius); foreach (var frame in img) { // get major color count frame.ColorFuzz = new Percentage(colorFuzz); } - - if(resizeParams.Size.HasValue) - img = dirs.Apply(img,resizeParams); + + if (resizeParams.Size.HasValue) + img = dirs.Apply(img, resizeParams); Console.WriteLine($"Generated colorFuzz for {Request.Path}, fuzz={colorFuzz}, inFrames={inFrames}, outFrames={img.Count}"); return new LruFileCache.Entry { @@ -145,5 +149,14 @@ public class IsPixelArtController(LruFileCache lfc, IFileSource fs, PixelArtDete }; }).ContinueWith(t => File(t.Result.Data, t.Result.MimeType)); } -} -*/ \ No newline at end of file + + [HttpGet("/defaultAvatar")] + public async Task<FileContentResult> DefaultAvatar() { + var re = new RainbowEnumerator(); + var img = new MagickImageCollection(); + + var ms = new MemoryStream(); + + return new FileContentResult(ms.ToArray(), "image/gif"); + } +} \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs b/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs
index e2ad1377..5d9d0d78 100644 --- a/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs +++ b/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs
@@ -1,6 +1,6 @@ -using System.Collections.Immutable; using ArcaneLibs.Extensions.Streams; using Microsoft.AspNetCore.Mvc; +using Microsoft.OpenApi; using Spacebar.AdminApi.TestClient.Services.Services; using Spacebar.Cdn.Extensions; using Spacebar.Interop.Cdn.Abstractions; @@ -28,8 +28,39 @@ public class StaticAssetController(LruFileCache lfc, IFileSource fs, DiscordImag { "6", "1276374a404452756f3c9cc2601508a5" }, { "7", "904bf9f1b61f53ef4a3b7a893afeabe3" }, }; - // [HttpGet("/embed/avatars/{userIndex}")] - // public async Task<IActionResult> GetDefaultUserAvatar(string userIndex) { - // - // } + + // png only + [HttpGet("/embed/avatars/{userIndex}.{ext}")] + public async Task<IActionResult> GetDefaultUserAvatar(string userIndex, string ext) { + + var cacheKey = Request.Path + Request.QueryString; + + DiscordImageResizeParams resizeParams = GetResizeParams(); + + var entry = await lfc.GetOrAdd(cacheKey, async () => { + var original = await fs.GetFile(Request.Path); + + if (Request.Query.Any()) { + using var img = await original.ToMagickImageCollectionAsync(); + dirs.Apply(img, resizeParams); + + var outStream = new MemoryStream(); + await img.WriteAsync(outStream, img.First().Format); + outStream.Position = 0; + + return new LruFileCache.Entry() { + Data = outStream.ReadToEnd().ToArray(), + MimeType = original.MimeType + }; + } + + return new LruFileCache.Entry() { + Data = original.Stream.ReadToEnd().ToArray(), + MimeType = original.MimeType + }; + }); + + // byte array with mime type result + return new FileContentResult(entry.Data, entry.MimeType); + } } \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs b/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs
index 21531e90..133eb8e1 100644 --- a/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs +++ b/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs
@@ -14,7 +14,7 @@ public class ImageController : ControllerBase { Passthrough = Request.Query.ContainsKey("passthrough") && bool.TryParse(Request.Query["passthrough"], out bool pt) && pt, Animated = Request.Query.ContainsKey("animated") && bool.TryParse(Request.Query["animated"], out bool an) && an, SpacebarAllowUpscale = Request.Query.ContainsKey("allowUpscale") && bool.TryParse(Request.Query["allowUpscale"], out bool au) && au, - SpacebarOptimiseGif = Request.Query.ContainsKey("optimiseGif") && bool.TryParse(Request.Query["optimiseGif"], out bool og) && og + SpacebarOptimiseGif = Request.Query.ContainsKey("optimiseGif") && bool.TryParse(Request.Query["optimiseGif"], out bool og) && og, }; } diff --git a/extra/admin-api/Spacebar.Cdn/Helpers/DefaultAvatarRenderer.cs b/extra/admin-api/Spacebar.Cdn/Helpers/DefaultAvatarRenderer.cs new file mode 100644
index 00000000..35b478f0 --- /dev/null +++ b/extra/admin-api/Spacebar.Cdn/Helpers/DefaultAvatarRenderer.cs
@@ -0,0 +1,24 @@ +using ArcaneLibs.Extensions; +using ImageMagick; + +namespace Spacebar.AdminApi.TestClient.Services.Helpers; + +public class DefaultAvatarRenderer { + // Slower at runtime, but doesnt depend on filesystem + private static string GetDefaultAvatarSvg(byte r, byte g, byte b) { + return $""" + <svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg"> + <rect fill="#000115" width="512" height="512"/> + <path fill="#{r:X2}{g:X2}{b:X2}" fill-rule="evenodd" clip-rule="evenodd" d="M419.395 296.205C424.003 317.631 418.678 339.993 404.912 357.042C391.143 374.092 370.407 384 348.497 384H163.949C142.039 384 121.303 374.092 107.536 357.042C93.7677 339.993 88.4431 317.631 93.0509 296.205L125.547 145.08C127.06 138.042 131.891 132.176 138.508 129.344C145.124 126.511 152.703 127.065 158.837 130.829L256.223 190.583L353.609 130.829C359.743 127.065 367.322 126.511 373.938 129.344C380.555 132.176 385.386 138.042 386.899 145.08L419.395 296.205ZM344.729 261.348C344.729 250.399 335.855 241.523 324.91 241.523H286.727C275.782 241.523 266.91 250.399 266.91 261.348V299.542C266.91 310.491 275.782 319.365 286.727 319.365H324.91C335.855 319.365 344.729 310.491 344.729 299.542V261.348ZM245.536 261.348C245.536 250.399 236.664 241.523 225.719 241.523H187.536C176.591 241.523 167.717 250.399 167.717 261.348V299.542C167.717 310.491 176.591 319.365 187.536 319.365H225.719C236.664 319.365 245.536 310.491 245.536 299.542V261.348Z"/> + </svg> + """; + } + + public static async Task<MemoryStream> GetDefaultAvatar(byte r, byte g, byte b, MagickFormat format = MagickFormat.Png, int size = 4096) { + var img = new MagickImageCollection(GetDefaultAvatarSvg(r, g, b).AsBytes().ToArray()); + var ms = new MemoryStream(); + await img.WriteAsync(ms); + ms.Position = 0; + return ms; + } +} \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn/Mimes.cs b/extra/admin-api/Spacebar.Cdn/Mimes.cs
index 508e9a3b..5a281432 100644 --- a/extra/admin-api/Spacebar.Cdn/Mimes.cs +++ b/extra/admin-api/Spacebar.Cdn/Mimes.cs
@@ -1,3 +1,4 @@ +using System.ComponentModel; using ImageMagick; namespace Spacebar.AdminApi.TestClient.Services; @@ -8,6 +9,20 @@ public static class Mimes { return mime; } + public static MagickFormat GetFormatForExtension(string extension) { + extension = extension.ToLower(); + // ban some values... + if (extension == "screenshot") throw new AccessViolationException("Disallowed extension: " + extension); + + var matchingFormat = Enum.GetNames(typeof(MagickFormat)).FirstOrDefault(f => f.ToLower() == extension); + if (string.IsNullOrWhiteSpace(matchingFormat)) throw new InvalidEnumArgumentException("Unknown format: " + extension); + if (Enum.TryParse(matchingFormat, out MagickFormat fmt)) { + return fmt; + } + + throw new InvalidEnumArgumentException("Unknown format: " + extension); + } + public static string GetMime(MagickFormat fmt) => fmt switch { MagickFormat.Png => "image/png", MagickFormat.Jpeg => "image/jpeg", diff --git a/extra/admin-api/Spacebar.Cdn/Properties/launchSettings.json b/extra/admin-api/Spacebar.Cdn/Properties/launchSettings.json
index b9fe4cc3..f3ffeac9 100644 --- a/extra/admin-api/Spacebar.Cdn/Properties/launchSettings.json +++ b/extra/admin-api/Spacebar.Cdn/Properties/launchSettings.json
@@ -18,7 +18,8 @@ "applicationUrl": "http://localhost:5114", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Local", - "LD_LIBRARY_PATH": "/home/Rory/git/spacebar/server-master/extra/admin-api/Spacebar.Cdn/result-lib/lib/" +// "LD_LIBRARY_PATH": "/home/Rory/git/spacebar/server-master/extra/admin-api/Spacebar.Cdn/result-lib/lib/", + "STORAGE_PATH": "./files" } } } diff --git a/extra/admin-api/Spacebar.Cdn/Services/CdnStorageRebuildService.cs b/extra/admin-api/Spacebar.Cdn/Services/CdnStorageRebuildService.cs deleted file mode 100644
index 0cf0ef1a..00000000 --- a/extra/admin-api/Spacebar.Cdn/Services/CdnStorageRebuildService.cs +++ /dev/null
@@ -1,5 +0,0 @@ -namespace Spacebar.AdminApi.TestClient.Services.Services; - -public class CdnFileStorageRebuildService() { - -} \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn/Services/DiscordImageResizeService.cs b/extra/admin-api/Spacebar.Cdn/Services/DiscordImageResizeService.cs
index 2a35c404..382845e2 100644 --- a/extra/admin-api/Spacebar.Cdn/Services/DiscordImageResizeService.cs +++ b/extra/admin-api/Spacebar.Cdn/Services/DiscordImageResizeService.cs
@@ -13,6 +13,10 @@ public class DiscordImageResizeParams { public bool SpacebarAllowUpscale { get; set; } = false; public bool SpacebarOptimiseGif { get; set; } = true; + + public string ToSerializedName() { + return $"{(Animated ? "a_" : "")}{Size}px_{Quality.ToString()}_u.{SpacebarAllowUpscale}_o.{SpacebarOptimiseGif}"; + } } public enum DiscordImageResizeQuality { diff --git a/extra/admin-api/Spacebar.Cdn/Spacebar.Cdn.csproj b/extra/admin-api/Spacebar.Cdn/Spacebar.Cdn.csproj
index d3ea78a6..b56ff51c 100644 --- a/extra/admin-api/Spacebar.Cdn/Spacebar.Cdn.csproj +++ b/extra/admin-api/Spacebar.Cdn/Spacebar.Cdn.csproj
@@ -9,7 +9,7 @@ <ItemGroup> <PackageReference Include="ArcaneLibs" Version="1.0.1-preview.20260126-091403" /> <!-- <PackageReference Include="Magick.NET-Q16-HDRI-AnyCPU" Version="14.10.1" />--> - <PackageReference Include="Magick.NET-Q16-HDRI-OpenMP-x64" Version="14.10.2" /> + <PackageReference Include="Magick.NET-Q16-HDRI-OpenMP-x64" Version="14.10.3" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.3" /> </ItemGroup>