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."); } }