diff --git a/components/game-profile-modal.tsx b/components/game-profile-modal.tsx index 7100f89..b7f7bd8 100644 --- a/components/game-profile-modal.tsx +++ b/components/game-profile-modal.tsx @@ -161,6 +161,7 @@ export function GameProfileModal({ const name = profile?.name ?? fallbackName; const best = profile?.itad?.prices ?? null; const low = profile?.itad?.historyLow ?? null; + const isFree = !!best && best.price === 0; const hero = useMemo(() => { if (bannerPick) { return bannerPick; @@ -539,38 +540,44 @@ export function GameProfileModal({

{dict.prices}

-
- {best ? ( - -

- {dict.bestPrice} · {best.shop} -

-

- {formatPrice(best, tag)}{" "} - {discountPercent(best) ? ( - - -%{discountPercent(best)} - - ) : null} -

-
- ) : null} - {low ? ( -
-

- {dict.historyLow} · {low.shop} -

-

- {formatPrice(low, tag)} -

-
- ) : null} -
+ {isFree ? ( +

+ {dict.free} +

+ ) : ( +
+ {best ? ( + +

+ {dict.bestPrice} · {best.shop} +

+

+ {formatPrice(best, tag)}{" "} + {discountPercent(best) ? ( + + -%{discountPercent(best)} + + ) : null} +

+
+ ) : null} + {low ? ( +
+

+ {dict.historyLow} · {low.shop} +

+

+ {formatPrice(low, tag)} +

+
+ ) : null} +
+ )} ) : null} diff --git a/lib/game-profile.ts b/lib/game-profile.ts index c39c25d..53b9ab3 100644 --- a/lib/game-profile.ts +++ b/lib/game-profile.ts @@ -88,9 +88,7 @@ async function getDetectables(): Promise { return detectablesCache.data; } try { - const response = await fetch("https://cdn.discordapp.com/detectables/games-v1.json", { - next: { revalidate: 86_400 }, - }); + const response = await fetch("https://cdn.discordapp.com/detectables/games-v1.json"); if (!response.ok) { console.error(`detectables failed: ${response.status}`); return detectablesCache?.data ?? []; @@ -104,10 +102,6 @@ async function getDetectables(): Promise { } const DISTRIBUTOR_PLATFORM: Record = { - steam: "PC", - battlenet: "PC", - gog: "PC", - epic: "PC", xbox: "Xbox", xbox_title: "Xbox", xbox_game_pass: "Xbox", @@ -220,10 +214,16 @@ interface IgdbGame { let igdbTokenCache: { token: string; expires: number } | null = null; +let igdbKeyWarned = false; + async function getIgdbToken(): Promise { const clientId = process.env.TWITCH_CLIENT_ID; const clientSecret = process.env.TWITCH_CLIENT_SECRET; if (!clientId || !clientSecret) { + if (!igdbKeyWarned) { + igdbKeyWarned = true; + console.error("igdb keys missing: set TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET"); + } return null; } if (igdbTokenCache && Date.now() < igdbTokenCache.expires) { @@ -386,9 +386,15 @@ interface ItadOverviewPrice { } | null; } +let itadKeyWarned = false; + async function itadFetch(path: string, init?: RequestInit): Promise { const key = process.env.ITAD_API_KEY; if (!key) { + if (!itadKeyWarned) { + itadKeyWarned = true; + console.error("itad key missing: set ITAD_API_KEY"); + } return null; } try { @@ -499,24 +505,28 @@ export async function getGameProfile( const igdbPlatforms = new Set(); for (const p of igdb?.platforms ?? []) { - const label = `${p.abbreviation ?? ""} ${p.name ?? ""}`.toUpperCase(); - if (/PS|PLAYSTATION/.test(label)) { - igdbPlatforms.add("PlayStation"); - } else if (/XBOX|XONE|XSX/.test(label)) { - igdbPlatforms.add("Xbox"); - } else if (/PC|WIN|MAC|LIN/.test(label)) { - igdbPlatforms.add("PC"); - } else if (/SWITCH/.test(label)) { - igdbPlatforms.add("Switch"); + const raw = (p.name ?? "").trim(); + if (!raw) { + continue; + } + if (raw === "PC (Microsoft Windows)") { + igdbPlatforms.add("Windows"); + } else if (raw === "Mac") { + igdbPlatforms.add("MacOS"); + } else { + igdbPlatforms.add(raw); } } const platforms = new Set(igdbPlatforms); - if (platforms.size === 0) { - if ( - steam?.platforms && - (steam.platforms.windows || steam.platforms.mac || steam.platforms.linux) - ) { - platforms.add("PC"); + if (platforms.size === 0 && steam?.platforms) { + if (steam.platforms.windows) { + platforms.add("Windows"); + } + if (steam.platforms.mac) { + platforms.add("MacOS"); + } + if (steam.platforms.linux) { + platforms.add("Linux"); } for (const sku of entry?.third_party_skus ?? []) { const mapped = DISTRIBUTOR_PLATFORM[sku.distributor]; diff --git a/lib/i18n/dictionaries/de.json b/lib/i18n/dictionaries/de.json index 74d9c50..c70cd21 100644 --- a/lib/i18n/dictionaries/de.json +++ b/lib/i18n/dictionaries/de.json @@ -37,6 +37,7 @@ "links": "Links", "reviews": "Bewertungen", "prices": "Preise", + "free": "Kostenlos", "bestPrice": "Bester Preis", "historyLow": "Historischer Tiefstpreis", "allPrices": "ITAD", diff --git a/lib/i18n/dictionaries/en.json b/lib/i18n/dictionaries/en.json index c29bc89..906dff1 100644 --- a/lib/i18n/dictionaries/en.json +++ b/lib/i18n/dictionaries/en.json @@ -37,6 +37,7 @@ "links": "Links", "reviews": "Reviews", "prices": "Prices", + "free": "Free", "bestPrice": "Best Price", "historyLow": "All-Time Low", "allPrices": "ITAD", diff --git a/lib/i18n/dictionaries/tr.json b/lib/i18n/dictionaries/tr.json index 7840c4e..0a4ec08 100644 --- a/lib/i18n/dictionaries/tr.json +++ b/lib/i18n/dictionaries/tr.json @@ -37,6 +37,7 @@ "links": "Bağlantılar", "reviews": "İncelemeler", "prices": "Fiyatlar", + "free": "Ücretsiz", "bestPrice": "En İyi Fiyat", "historyLow": "Tarihi En Düşük", "allPrices": "ITAD",