From a4cf2636e7adf5bd6857f91d7f28e6f34c83b2e2 Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Wed, 29 Apr 2026 11:36:38 +0800 Subject: [PATCH] feat: add image validation and SteamGridDB fallback to game stub creation --- lib/api/game-stub.ts | 15 ++++++++++++++- lib/steam/sync.ts | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/api/game-stub.ts b/lib/api/game-stub.ts index f1c9dbf..347d5bb 100644 --- a/lib/api/game-stub.ts +++ b/lib/api/game-stub.ts @@ -2,6 +2,7 @@ import { Elysia, t } from "elysia" import { db } from "@/lib/db/index" import { games } from "@/lib/db/schema" import { eq } from "drizzle-orm" +import { validateImageUrl, fetchSteamGridDBCover } from "@/lib/steam/sync" interface SteamAppDetails { type?: string @@ -77,6 +78,18 @@ export const gameStubRoutes = new Elysia({ prefix: "/games" }).post( const capsuleImage = `https://cdn.akamai.steamstatic.com/steam/apps/${body.steamAppId}/library_600x900.jpg` + let finalCapsuleImage: string | null = capsuleImage + const imageValid = await validateImageUrl(capsuleImage) + + if (!imageValid) { + const fallbackImage = await fetchSteamGridDBCover(title) + if (fallbackImage) { + finalCapsuleImage = fallbackImage + } else { + finalCapsuleImage = null + } + } + const [game] = await db .insert(games) .values({ @@ -87,7 +100,7 @@ export const gameStubRoutes = new Elysia({ prefix: "/games" }).post( publisher, genres, headerImage, - capsuleImage, + capsuleImage: finalCapsuleImage, storeUrl: `https://store.steampowered.com/app/${body.steamAppId}`, systemRequirements: details?.pc_requirements ? { minimum: details.pc_requirements.minimum || null, recommended: details.pc_requirements.recommended || null } diff --git a/lib/steam/sync.ts b/lib/steam/sync.ts index d4dd980..4a2810f 100644 --- a/lib/steam/sync.ts +++ b/lib/steam/sync.ts @@ -30,7 +30,7 @@ export function isSyncStale(lastSync: Date | null): boolean { return Date.now() - new Date(lastSync).getTime() > SEVEN_DAYS_MS } -async function validateImageUrl(url: string): Promise { +export async function validateImageUrl(url: string): Promise { try { const res = await fetch(url, { method: "HEAD", signal: AbortSignal.timeout(5000) }); return res.ok; @@ -39,7 +39,7 @@ async function validateImageUrl(url: string): Promise { } } -async function fetchSteamGridDBCover(gameTitle: string): Promise { +export async function fetchSteamGridDBCover(gameTitle: string): Promise { try { const apiKey = process.env.STEAMGRIDDB_API_KEY; if (!apiKey) return null;