Game profile: IGDB platforms, IGDB link, sparse-profile fix
Build & Push / Lint & Build (push) Successful in 1m32s
Build & Push / Build & Push Image (push) Successful in 48s
Build & Push / Trigger Deploy (push) Successful in 2s

- Source platforms from IGDB first, fall back to Steam and
  detectables only when IGDB has none
- Add IGDB page button next to Steam, SteamDB, Discord and ITAD
- Hide the details box when a profile has no details instead
  of rendering it empty
- ITAD lookup matches titles ignoring punctuation and marks
This commit is contained in:
fristy committed 2026-09-11 06:21:54 +03:00
1 parent 66be7a71a7
commit cbbbc3effa
5 files changed
+35 -16

No files matched your search

+10
View File
@@ -322,6 +322,16 @@ export function GameProfileModal({
{dict.openOnSteamDb} ↗ {dict.openOnSteamDb} ↗
</a> </a>
) : null} ) : null}
{profile?.igdbUrl ? (
<a
href={profile.igdbUrl}
target="_blank"
rel="noopener noreferrer"
className="rounded-full border border-white/15 px-4 py-1.5 text-xs text-zinc-300 transition-colors hover:border-blurple hover:text-white"
>
{dict.openOnIgdb} ↗
</a>
) : null}
<a <a
href={gameUrl} href={gameUrl}
target="_blank" target="_blank"
+22 -16
View File
@@ -59,6 +59,7 @@ export interface GameProfile {
screenshots: string[]; screenshots: string[];
steamId: string | null; steamId: string | null;
steamUrl: string | null; steamUrl: string | null;
igdbUrl: string | null;
steamReviews: GameReviewSummary | null; steamReviews: GameReviewSummary | null;
itad: { itad: {
prices: GamePricePoint | null; prices: GamePricePoint | null;
@@ -197,6 +198,7 @@ async function getSteamReviewSummary(steamId: string): Promise<GameReviewSummary
interface IgdbGame { interface IgdbGame {
name?: string; name?: string;
slug?: string;
genres?: Array<{ name?: string }>; genres?: Array<{ name?: string }>;
summary?: string; summary?: string;
storyline?: string; storyline?: string;
@@ -275,7 +277,7 @@ async function igdbQuery<T>(token: string, endpoint: string, body: string): Prom
} }
const IGDB_GAME_FIELDS = const IGDB_GAME_FIELDS =
"name,genres.name,summary,storyline,cover.url,artworks.url,screenshots.url," + "name,slug,genres.name,summary,storyline,cover.url,artworks.url,screenshots.url," +
"websites.url,websites.category,involved_companies.developer," + "websites.url,websites.category,involved_companies.developer," +
"involved_companies.publisher,involved_companies.company.name," + "involved_companies.publisher,involved_companies.company.name," +
"platforms.abbreviation,platforms.name,first_release_date;"; "platforms.abbreviation,platforms.name,first_release_date;";
@@ -491,29 +493,32 @@ export async function getGameProfile(
: (steam?.publishers ?? : (steam?.publishers ??
(itadInfo?.publishers?.map((d) => d.name).filter((n): n is string => !!n) || [])); (itadInfo?.publishers?.map((d) => d.name).filter((n): n is string => !!n) || []));
const platforms = new Set<string>(); const igdbPlatforms = new Set<string>();
for (const p of igdb?.platforms ?? []) { for (const p of igdb?.platforms ?? []) {
const label = `${p.abbreviation ?? ""} ${p.name ?? ""}`.toUpperCase(); const label = `${p.abbreviation ?? ""} ${p.name ?? ""}`.toUpperCase();
if (/PS|PLAYSTATION/.test(label)) { if (/PS|PLAYSTATION/.test(label)) {
platforms.add("PlayStation"); igdbPlatforms.add("PlayStation");
} else if (/XBOX|XONE|XSX/.test(label)) { } else if (/XBOX|XONE|XSX/.test(label)) {
platforms.add("Xbox"); igdbPlatforms.add("Xbox");
} else if (/PC|WIN|MAC|LIN/.test(label)) { } else if (/PC|WIN|MAC|LIN/.test(label)) {
platforms.add("PC"); igdbPlatforms.add("PC");
} else if (/SWITCH/.test(label)) { } else if (/SWITCH/.test(label)) {
platforms.add("Switch"); igdbPlatforms.add("Switch");
} }
} }
if ( const platforms = new Set<string>(igdbPlatforms);
steam?.platforms && if (platforms.size === 0) {
(steam.platforms.windows || steam.platforms.mac || steam.platforms.linux) if (
) { steam?.platforms &&
platforms.add("PC"); (steam.platforms.windows || steam.platforms.mac || steam.platforms.linux)
} ) {
for (const sku of entry?.third_party_skus ?? []) { platforms.add("PC");
const mapped = DISTRIBUTOR_PLATFORM[sku.distributor]; }
if (mapped) { for (const sku of entry?.third_party_skus ?? []) {
platforms.add(mapped); const mapped = DISTRIBUTOR_PLATFORM[sku.distributor];
if (mapped) {
platforms.add(mapped);
}
} }
} }
@@ -588,6 +593,7 @@ export async function getGameProfile(
screenshots, screenshots,
steamId, steamId,
steamUrl: steamId ? `https://store.steampowered.com/app/${steamId}/` : null, steamUrl: steamId ? `https://store.steampowered.com/app/${steamId}/` : null,
igdbUrl: igdb?.slug ? `https://www.igdb.com/games/${igdb.slug}` : null,
steamReviews, steamReviews,
itad: itad:
process.env.ITAD_API_KEY && (itadInfo || priceEntry) process.env.ITAD_API_KEY && (itadInfo || priceEntry)
+1
View File
@@ -43,6 +43,7 @@
"openOnDiscord": "Discord-Profil", "openOnDiscord": "Discord-Profil",
"openOnSteam": "Steam", "openOnSteam": "Steam",
"openOnSteamDb": "SteamDB", "openOnSteamDb": "SteamDB",
"openOnIgdb": "IGDB",
"loading": "Spieldaten werden geladen...", "loading": "Spieldaten werden geladen...",
"loadError": "Spieldaten konnten nicht geladen werden.", "loadError": "Spieldaten konnten nicht geladen werden.",
"screenshots": "Screenshots", "screenshots": "Screenshots",
+1
View File
@@ -43,6 +43,7 @@
"openOnDiscord": "Discord Profile", "openOnDiscord": "Discord Profile",
"openOnSteam": "Steam", "openOnSteam": "Steam",
"openOnSteamDb": "SteamDB", "openOnSteamDb": "SteamDB",
"openOnIgdb": "IGDB",
"loading": "Loading game info...", "loading": "Loading game info...",
"loadError": "Couldn't load game info.", "loadError": "Couldn't load game info.",
"screenshots": "Screenshots", "screenshots": "Screenshots",
+1
View File
@@ -43,6 +43,7 @@
"openOnDiscord": "Discord Profili", "openOnDiscord": "Discord Profili",
"openOnSteam": "Steam", "openOnSteam": "Steam",
"openOnSteamDb": "SteamDB", "openOnSteamDb": "SteamDB",
"openOnIgdb": "IGDB",
"loading": "Oyun bilgileri yükleniyor...", "loading": "Oyun bilgileri yükleniyor...",
"loadError": "Oyun bilgileri yüklenemedi.", "loadError": "Oyun bilgileri yüklenemedi.",
"screenshots": "Görseller", "screenshots": "Görseller",