From 3d53660319a975b632e0add3e673826f521d26be Mon Sep 17 00:00:00 2001 From: Pihkaal Date: Sun, 22 Feb 2026 14:06:15 +0100 Subject: [PATCH] feat(api): normalize logo name --- server/api/index.ts | 26 ++++++++++++++++++++++++-- server/api/logos.ts | 25 ++++++------------------- server/utils/logos.ts | 29 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 server/utils/logos.ts diff --git a/server/api/index.ts b/server/api/index.ts index d5f985d..6627c15 100644 --- a/server/api/index.ts +++ b/server/api/index.ts @@ -1,4 +1,8 @@ import { resolve } from "path"; +import type { Canvas } from "skia-canvas"; +import { getLogoNames } from "../utils/logos"; + +const normalize = (s: string) => s.toLowerCase().replace(/\s+/g, ""); export default defineEventHandler(async (event) => { const { format, logo, content } = await getValidatedQuery( @@ -6,8 +10,26 @@ export default defineEventHandler(async (event) => { settingsSchema.parse, ); - const logoUrl = logo ? resolve("public", `logos/${logo}.png`) : undefined; - const canvas = await renderQRCodeToCanvas(content, logoUrl); + let canvas: Canvas; + + if (logo) { + const names = await getLogoNames(); + if (!names) + throw createError({ + statusCode: 500, + message: "Could not retrieve logos", + }); + + const match = names.find((n) => normalize(n) === normalize(logo)); + const resolvedLogo = match ?? logo; + + canvas = await renderQRCodeToCanvas( + content, + resolve("public", `logos/${resolvedLogo}.png`), + ); + } else { + canvas = await renderQRCodeToCanvas(content, undefined); + } const image = canvas.toBuffer(format); event.node.res.setHeader("Content-Type", `image/${format}`); diff --git a/server/api/logos.ts b/server/api/logos.ts index 02d825d..e31d6ec 100644 --- a/server/api/logos.ts +++ b/server/api/logos.ts @@ -1,22 +1,9 @@ -import { readdir } from "fs/promises"; -import { join } from "path"; -import { createHash } from "crypto"; +import { getLogoNames } from "../utils/logos"; -const logosDir = import.meta.dev - ? join(process.cwd(), "public/logos") - : join(process.cwd(), ".output/public/logos"); +export default defineEventHandler(async () => { + const names = await getLogoNames(); + if (!names) + throw createError({ statusCode: 500, message: "Could not retrieve logos" }); -export default defineCachedEventHandler(async () => { - const files = await readdir(logosDir); - return files - .filter((f) => f.endsWith(".png")) - .map((f) => f.replace(/\.png$/, "")) - .sort(); -}, { - maxAge: 60 * 60 * 24, - getKey: async () => { - const files = await readdir(logosDir); - const key = files.filter((f) => f.endsWith(".png")).sort().join(","); - return createHash("sha256").update(key).digest("hex"); - }, + return names; }); diff --git a/server/utils/logos.ts b/server/utils/logos.ts new file mode 100644 index 0000000..de6b353 --- /dev/null +++ b/server/utils/logos.ts @@ -0,0 +1,29 @@ +import { readdir } from "fs/promises"; +import { join } from "path"; +import { createHash } from "crypto"; + +const logosDir = import.meta.dev + ? join(process.cwd(), "public/logos") + : join(process.cwd(), ".output/public/logos"); + +export const getLogoNames = cachedFunction( + async () => { + const files = await readdir(logosDir); + return files + .filter((f) => f.endsWith(".png")) + .map((f) => f.replace(/\.png$/, "")) + .sort(); + }, + { + maxAge: 60 * 60 * 24, + name: "logoNames", + getKey: async () => { + const files = await readdir(logosDir); + const key = files + .filter((f) => f.endsWith(".png")) + .sort() + .join(","); + return createHash("sha256").update(key).digest("hex"); + }, + }, +);