fix IGDB resolution: drop broken category filter, match by URL prefix

the IGDB external_games category filter returns empty for all values.
filter steam/gog entries by URL prefix instead (store.steampowered.com,
gog.com). reduce batch size to 50 to stay within 500-result API limit
since each uid can return multiple platform entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 23:40:00 +01:00
parent 109a9f383b
commit 2c8141660c

View File

@@ -2,12 +2,9 @@ import { env } from "../../shared/lib/env.ts"
import { getCacheEntry, getCacheSize, saveCache, setCacheEntry } from "./cache.ts"
import { type IgdbMetadata, getMetadata, setMetadataBatch } from "./metadata-cache.ts"
const CATEGORY_STEAM = 1
const CATEGORY_GOG = 2
const SOURCE_TO_CATEGORY: Record<string, number> = {
steam: CATEGORY_STEAM,
gog: CATEGORY_GOG,
const SOURCE_URL_PREFIX: Record<string, string> = {
steam: "https://store.steampowered.com/app/",
gog: "https://www.gog.com/",
}
let twitchToken: string | null = null
@@ -65,22 +62,28 @@ async function igdbRequest(endpoint: string, query: string): Promise<unknown[]>
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
async function batchResolve(category: number, sourceIds: string[]): Promise<Map<string, number>> {
async function batchResolve(source: string, sourceIds: string[]): Promise<Map<string, number>> {
const results = new Map<string, number>()
const BATCH_SIZE = 500
const urlPrefix = SOURCE_URL_PREFIX[source]
if (!urlPrefix) return results
// Without category filter, each uid may return multiple platform entries,
// so keep batches small to stay within the 500-result API limit
const BATCH_SIZE = 50
for (let i = 0; i < sourceIds.length; i += BATCH_SIZE) {
const batch = sourceIds.slice(i, i + BATCH_SIZE)
const uids = batch.map((id) => `"${id}"`).join(",")
const query = `fields game,uid; where category = ${category} & uid = (${uids}); limit ${BATCH_SIZE};`
const query = `fields game,uid,url; where uid = (${uids}); limit 500;`
const data = (await igdbRequest("/external_games", query)) as Array<{
game?: number
uid?: string
url?: string
}>
for (const entry of data) {
if (entry.game && entry.uid) {
if (entry.game && entry.uid && entry.url?.startsWith(urlPrefix)) {
results.set(entry.uid, entry.game)
}
}
@@ -109,7 +112,7 @@ export async function enrichGamesWithIgdb<T extends GameForEnrichment>(
const uncachedBySource: Record<string, string[]> = {}
for (const game of games) {
const cacheKey = `${game.source}:${game.sourceId}`
if (!getCacheEntry(cacheKey) && SOURCE_TO_CATEGORY[game.source]) {
if (!getCacheEntry(cacheKey) && SOURCE_URL_PREFIX[game.source]) {
if (!uncachedBySource[game.source]) {
uncachedBySource[game.source] = []
}
@@ -120,10 +123,9 @@ export async function enrichGamesWithIgdb<T extends GameForEnrichment>(
let newEntries = 0
try {
for (const [source, sourceIds] of Object.entries(uncachedBySource)) {
const category = SOURCE_TO_CATEGORY[source]
console.log(`[IGDB] Resolving ${sourceIds.length} ${source} games...`)
const resolved = await batchResolve(category, sourceIds)
const resolved = await batchResolve(source, sourceIds)
for (const [uid, igdbId] of resolved) {
setCacheEntry(`${source}:${uid}`, { igdbId })