From 74fe0447ee56903ef17768e2baa49c6a37d809f8 Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Tue, 28 Apr 2026 23:36:00 +0800 Subject: [PATCH] feat: add SteamGridDB proxy API for non-Steam game images --- .env.example | 8 +++- app/api/[[...slugs]]/route.ts | 3 ++ lib/api/index.ts | 1 + lib/api/steamgrid-proxy.ts | 80 +++++++++++++++++++++++++++++++++++ next.config.ts | 4 ++ 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 lib/api/steamgrid-proxy.ts diff --git a/.env.example b/.env.example index 0f58fe9..8a215d5 100644 --- a/.env.example +++ b/.env.example @@ -80,4 +80,10 @@ EMAIL_FROM="DeckyVault " # CONTACT FORM # ----------------------------------------------------------------------------- # Discord webhook URL for contact/report submissions -DISCORD_WEBHOOK_URL="" \ No newline at end of file +DISCORD_WEBHOOK_URL="" + +# ----------------------------------------------------------------------------- +# STEAMGRIDDB +# ----------------------------------------------------------------------------- +# API key for SteamGridDB image search proxy (optional — non-Steam game wizard will show no images without it) +STEAMGRIDDB_API_KEY="" \ No newline at end of file diff --git a/app/api/[[...slugs]]/route.ts b/app/api/[[...slugs]]/route.ts index 594ddeb..809d7ee 100644 --- a/app/api/[[...slugs]]/route.ts +++ b/app/api/[[...slugs]]/route.ts @@ -24,6 +24,7 @@ import { searchUnifiedRoutes } from "@/lib/api/search-unified" import { gameStubRoutes } from "@/lib/api/game-stub" import { gameStatsRoutes } from "@/lib/api/game-stats" import { gamesListingRoutes } from "@/lib/api/games-listing" +import { steamgridProxyRoutes } from "@/lib/api/steamgrid-proxy" const betterAuth = new Elysia({ name: "better-auth" }) .mount(auth.handler) @@ -84,6 +85,8 @@ export const app = new Elysia({ prefix: "/api" }) .use(searchUnifiedRoutes) // Game stub creation .use(gameStubRoutes) + // SteamGridDB proxy + .use(steamgridProxyRoutes) // Game stats aggregation .use(gameStatsRoutes) // Saved games diff --git a/lib/api/index.ts b/lib/api/index.ts index 9ab8fae..afe7973 100644 --- a/lib/api/index.ts +++ b/lib/api/index.ts @@ -14,3 +14,4 @@ export { contactRoutes } from "./contact" export { adminReportRoutes } from "./admin-reports" export { adminPerformanceRoutes } from "./admin-performance" export { adminCommentRoutes } from "./admin-comments" +export { steamgridProxyRoutes } from "./steamgrid-proxy" diff --git a/lib/api/steamgrid-proxy.ts b/lib/api/steamgrid-proxy.ts new file mode 100644 index 0000000..70bc08b --- /dev/null +++ b/lib/api/steamgrid-proxy.ts @@ -0,0 +1,80 @@ +import { Elysia, t } from "elysia" + +const STEAMGRIDDB_BASE = "https://www.steamgriddb.com/api/v2" + +export const steamgridProxyRoutes = new Elysia({ prefix: "/steamgrid" }) + .get( + "/search", + async ({ query, set }) => { + const apiKey = process.env.STEAMGRIDDB_API_KEY + if (!apiKey) { + set.status = 503 + return { error: "SteamGridDB API key not configured" } + } + + try { + const res = await fetch( + `${STEAMGRIDDB_BASE}/search/autocomplete/${encodeURIComponent(query.q)}`, + { + headers: { Authorization: `Bearer ${apiKey}` }, + } + ) + + if (!res.ok) { + set.status = res.status + return { error: "SteamGridDB search failed" } + } + + const data = await res.json() + return data + } catch (err) { + console.error("SteamGridDB search error:", err) + set.status = 500 + return { error: "SteamGridDB search failed" } + } + }, + { + query: t.Object({ q: t.String({ minLength: 2 }) }), + } + ) + .get( + "/grids/:gameId", + async ({ params, query, set }) => { + const apiKey = process.env.STEAMGRIDDB_API_KEY + if (!apiKey) { + set.status = 503 + return { error: "SteamGridDB API key not configured" } + } + + try { + const url = new URL(`${STEAMGRIDDB_BASE}/grids/game/${params.gameId}`) + // Add dimensions filter for capsule-style images + url.searchParams.set("dimensions", "600x900,342x482") + if (query.styles) { + url.searchParams.set("styles", query.styles) + } + + const res = await fetch(url.toString(), { + headers: { Authorization: `Bearer ${apiKey}` }, + }) + + if (!res.ok) { + set.status = res.status + return { error: "SteamGridDB grids fetch failed" } + } + + const data = await res.json() + return data + } catch (err) { + console.error("SteamGridDB grids fetch error:", err) + set.status = 500 + return { error: "SteamGridDB grids fetch failed" } + } + }, + { + params: t.Object({ gameId: t.String() }), + query: t.Object({ + styles: t.Optional(t.String()), + }), + } + ) \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index dc03687..f1d95ea 100644 --- a/next.config.ts +++ b/next.config.ts @@ -17,6 +17,10 @@ const nextConfig: NextConfig = { port: "", pathname: "/store_item_assets/**", }, + { + protocol: "https", + hostname: "cdn.steamgriddb.com", + }, ], }, };