httpClient = new Client([ 'timeout' => 30, 'headers' => [ 'User-Agent' => 'MediaCollector/1.0' ] ]); $this->apiKey = $source['api_key']; // Steam ID can be configured in source config or use a default test account $this->steamId = $source['config']['steam_id'] ?? '76561198000000000'; // Default test Steam ID } protected function executeSync(string $syncType): void { if (empty($this->apiKey)) { throw new Exception('Steam API key not configured'); } $this->logProgress('Starting Steam library sync...'); // Get Steam user game library $games = $this->getSteamLibrary(); foreach ($games as $gameData) { $this->syncGame($gameData); $this->processedCount++; } $this->logProgress("Processed {$this->processedCount} Steam games"); } private function getSteamLibrary(): array { try { // Steam Web API: GetOwnedGames $response = $this->httpClient->get('https://api.steampowered.com/IPlayerService/GetOwnedGames/v1/', [ 'query' => [ 'key' => $this->apiKey, 'steamid' => $this->steamId, 'format' => 'json', 'include_appinfo' => 'true', 'include_played_free_games' => 'true' ] ]); $data = json_decode($response->getBody(), true); if (!isset($data['response']['games'])) { throw new Exception('No games found in Steam library'); } return $data['response']['games']; } catch (Exception $e) { throw new Exception('Failed to fetch Steam library: ' . $e->getMessage()); } } private function syncGame(array $gameData): void { $gameModel = new Game($this->pdo); // Check if game already exists $existingGame = $gameModel->findAll([ 'steam_app_id' => $gameData['appid'], 'source_id' => $this->source['id'] ]); // Get additional game details from Steam API $gameDetails = $this->getGameDetails($gameData['appid']); $gameData = [ 'title' => $gameData['name'], 'game_key' => Game::generateGameKey($gameData['name'], 'steam'), 'steam_app_id' => $gameData['appid'], 'playtime_minutes' => intval($gameData['playtime_forever']), 'platform' => 'PC', 'source_id' => $this->source['id'], 'last_played_at' => isset($gameData['rt_time_last_played']) && $gameData['rt_time_last_played'] > 0 ? date('Y-m-d H:i:s', $gameData['rt_time_last_played']) : null, 'metadata' => json_encode([ 'appid' => $gameData['appid'], 'playtime_windows' => $gameData['playtime_windows_forever'] ?? 0, 'playtime_mac' => $gameData['playtime_mac_forever'] ?? 0, 'playtime_linux' => $gameData['playtime_linux_forever'] ?? 0, 'img_icon_url' => $gameDetails['img_icon_url'] ?? null, 'img_logo_url' => $gameDetails['img_logo_url'] ?? null, 'has_community_visible_stats' => $gameDetails['has_community_visible_stats'] ?? false ]) ]; if (empty($existingGame)) { $gameModel->create($gameData); $this->newCount++; } else { $gameModel->update($existingGame[0]['id'], $gameData); $this->updatedCount++; } } private function getGameDetails(int $appId): array { try { // Steam Web API: GetAppDetails $response = $this->httpClient->get('https://store.steampowered.com/api/appdetails/', [ 'query' => [ 'appids' => $appId, 'cc' => 'US', 'l' => 'english' ] ]); $data = json_decode($response->getBody(), true); $appData = $data[$appId] ?? []; if (!$appData['success']) { return []; } return $appData['data'] ?? []; } catch (Exception $e) { // Return empty array if details can't be fetched return []; } } protected function getProcessedCount(): int { return $this->processedCount; } protected function getNewCount(): int { return $this->newCount; } protected function getUpdatedCount(): int { return $this->updatedCount; } protected function getDeletedCount(): int { return 0; // Steam doesn't provide deletion info in this context } }