Expand IGDB data: collections, game modes, themes, perspectives, videos, websites, age ratings, similar games; add backfill command

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mark
2026-06-01 00:24:05 +03:00
co-authored by Claude Sonnet 4.6
parent 0eab3e8dbf
commit 2a724c0ae2
21 changed files with 768 additions and 57 deletions
@@ -0,0 +1,95 @@
<?php
namespace App\Console\Commands;
use App\Models\Game;
use App\Services\IgdbService;
use Illuminate\Console\Command;
class BackfillExtendedDataCommand extends Command
{
protected $signature = 'igdb:backfill-extended
{--limit=100 : Max number of games to process}
{--offset=0 : Skip the first N games (ordered by id)}';
protected $description = 'Backfill extended IGDB data (collections, modes, themes, videos, etc.) for existing games';
public function handle(IgdbService $igdb): int
{
$limit = (int) $this->option('limit');
$offset = (int) $this->option('offset');
$games = Game::whereNotNull('igdb_id')
->orderBy('id')
->skip($offset)
->take($limit)
->get();
$total = $games->count();
if ($total === 0) {
$this->info('No games found to process.');
return self::SUCCESS;
}
$this->info("Processing {$total} games (offset: {$offset})…");
$this->newLine();
$n = 0;
foreach ($games->chunk(10) as $batch) {
$igdbIds = $batch->pluck('igdb_id')->all();
try {
$igdbResults = $igdb->getGamesByIds($igdbIds);
} catch (\Exception $e) {
$this->error('IGDB request failed: ' . $e->getMessage());
return self::FAILURE;
}
$indexed = collect($igdbResults)->keyBy('id');
foreach ($batch as $game) {
$n++;
$igdbData = $indexed->get($game->igdb_id);
if (!$igdbData) {
$this->warn(" [{$n}/{$total}] No IGDB data for: {$game->title} (igdb_id={$game->igdb_id})");
continue;
}
try {
$igdb->syncExtendedData($game, $igdbData);
$this->line(" [{$n}/{$total}] Processed: {$game->title}");
} catch (\Exception $e) {
$this->warn(" [{$n}/{$total}] Failed {$game->title}: " . $e->getMessage());
}
}
usleep(250000); // 250ms between IGDB batches
}
$this->newLine();
$this->info('Extended data sync complete. Resolving similar_games pivot…');
$this->resolveSimilarGames();
$this->info('Done.');
return self::SUCCESS;
}
private function resolveSimilarGames(): void
{
$resolved = 0;
Game::whereNotNull('similar_game_igdb_ids')->chunk(100, function ($games) use (&$resolved) {
foreach ($games as $game) {
$ids = $game->similar_game_igdb_ids;
if (empty($ids)) continue;
$similarIds = Game::whereIn('igdb_id', $ids)->pluck('id');
$game->similarGames()->sync($similarIds);
$resolved++;
}
});
$this->line(" Resolved similar_games for {$resolved} games.");
}
}
@@ -89,5 +89,7 @@ trait UpsertsGames
]);
}
}
$igdb->syncExtendedData($game, $data);
}
}