diff --git a/app/search/page.tsx b/app/search/page.tsx index bc0f2a3..acf9d79 100644 --- a/app/search/page.tsx +++ b/app/search/page.tsx @@ -39,6 +39,9 @@ interface UnifiedResult { price?: { currency: string; initial: number; final: number } | null platforms?: { windows: boolean; mac: boolean; linux: boolean } | null controllerSupport?: string | null + isRawPerformer?: boolean + bestFps?: number | null + latestVersion?: string | null } function SearchContent() { @@ -86,8 +89,8 @@ function SearchContent() { function handleClick(result: UnifiedResult) { const path = result.appId - ? `/game/${result.appId}` - : `/game/${result.id}` + ? `/game/${result.appId}?sync=1` + : `/game/${result.id}?sync=1` router.push(path) } @@ -244,9 +247,16 @@ function SearchResultCard({ {/* Row 1: Title + metascore/price row */}
-

- {result.title} -

+
+

+ {result.title} +

+ {result.isRawPerformer && ( + + ⚡ RAW PERFORMER + + )} +
{(result.developer || result.publisher) && (

{result.developer} @@ -422,11 +432,19 @@ function SearchResultCard({ color={result.platformSupport ? protonColor(result.platformSupport.protonStatus) : undefined} /> - {/* Avg FPS */} - + {/* Best FPS */} + = 60 ? "text-green-400" : undefined} + /> {/* Version */} - +

diff --git a/lib/api/search-unified.ts b/lib/api/search-unified.ts index 84d2605..fafc4b3 100644 --- a/lib/api/search-unified.ts +++ b/lib/api/search-unified.ts @@ -7,7 +7,7 @@ import { communityPresets, gameComments, } from "@/lib/db/schema" -import { ilike, or, sql, eq, inArray } from "drizzle-orm" +import { ilike, or, sql, eq, inArray, and } from "drizzle-orm" interface SteamSearchItem { id: number @@ -146,6 +146,64 @@ export const searchUnifiedRoutes = new Elysia({ prefix: "/search" }).get( countMap.get(c.gameId)!.comments = c.count } + // ── 2b. Raw Performer + best FPS ──────────────────────────────── + let rawPerformerMap = new Map() + let bestFpsMap = new Map() + + if (localGameIds.length > 0) { + const perfStats = await db + .select({ + gameId: gameVersions.gameId, + bestFps: sql`MAX(${performanceEntries.fpsAvg})::real`, + isRawPerformer: sql`BOOL_OR( + ${performanceEntries.fpsAvg} >= 60 + AND ${performanceEntries.fsrVersion} = 'none' + AND ${performanceEntries.frameGenMethod} = 'none' + )`, + }) + .from(performanceEntries) + .innerJoin( + gameVersions, + eq(performanceEntries.versionId, gameVersions.id), + ) + .where( + and( + inArray(gameVersions.gameId, localGameIds), + eq(performanceEntries.isRemoved, false), + ), + ) + .groupBy(gameVersions.gameId) + + for (const row of perfStats) { + bestFpsMap.set(row.gameId, row.bestFps) + rawPerformerMap.set(row.gameId, row.isRawPerformer) + } + } + + // ── 2c. Latest version ────────────────────────────────────────── + let latestVersionMap = new Map() + + if (localGameIds.length > 0) { + const versionRows = await db + .select({ + gameId: gameVersions.gameId, + versionString: gameVersions.versionString, + }) + .from(gameVersions) + .where( + and( + inArray(gameVersions.gameId, localGameIds), + eq(gameVersions.isLatest, true), + ), + ) + + for (const row of versionRows) { + if (row.versionString) { + latestVersionMap.set(row.gameId, row.versionString) + } + } + } + // ── 3. Search Steam ───────────────────────────────────────────── let steamItems: SteamSearchItem[] = [] try { @@ -214,6 +272,9 @@ export const searchUnifiedRoutes = new Elysia({ prefix: "/search" }).get( antiCheatStatus: platform.antiCheatStatus, } : null, + isRawPerformer: rawPerformerMap.get(g.id) ?? false, + bestFps: bestFpsMap.get(g.id) ?? null, + latestVersion: latestVersionMap.get(g.id) ?? null, }) } @@ -242,6 +303,9 @@ export const searchUnifiedRoutes = new Elysia({ prefix: "/search" }).get( : null, platforms: item.platforms, controllerSupport: item.controller_support || null, + isRawPerformer: false, + bestFps: null, + latestVersion: null, }) }