From: Daniel Karbach Date: Thu, 10 Jul 2025 09:45:27 +0000 (+0200) Subject: nmg league sync X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;h=ba67f0badbb1e5a885d4254f66eff95661e44d70;p=alttp.git nmg league sync --- diff --git a/app/Console/Commands/SyncNmgLeague.php b/app/Console/Commands/SyncNmgLeague.php new file mode 100644 index 0000000..cbf6653 --- /dev/null +++ b/app/Console/Commands/SyncNmgLeague.php @@ -0,0 +1,225 @@ +where(function (Builder $query) { + $query->whereNull('end'); + $query->orWhere('end', '>', now()); + }) + ->get(); + + foreach ($events as $event) { + try { + $this->line('syncing '.$event->name); + $this->syncEvent($event); + } catch (\Exception $e) { + $this->error('error syncing event '.$event->name.': '.$e->getMessage()); + } + } + + return 0; + } + + private function syncEvent(Event $event) { + $nmgHandle = substr($event->external_schedule, 10); + $nmgSchedule = Http::get('https://nmg-league.foxlisk.com/api/v1/season/'.$nmgHandle.'/races')->json(); + if (!$nmgSchedule) { + return; + } + $this->purgeSchedule($event, $nmgSchedule['Ok']); + $this->loadBrackets($nmgHandle); + $this->loadPlayers(); + foreach ($nmgSchedule['Ok'] as $nmgEntry) { + try { + $this->syncSchedule($event, $nmgEntry); + } catch (\Exception $e) { + $this->error('error syncing episode '.$nmgEntry['id'].': '.$e->getMessage()); + } + } + } + + private function purgeSchedule(Event $event, $nmgSchedule): void { + $ext_ids = []; + foreach ($nmgSchedule as $nmgEntry) { + if ($nmgEntry['scheduled_for']) { + $ext_ids[] = 'nmgleague:'.$nmgEntry['id']; + } + } + $to_purge = $event->episodes() + ->whereNotIn('ext_id', $ext_ids) + ->where('ext_id', 'LIKE', 'nmgleague:%'); + foreach ($to_purge->get() as $episode) { + $episode->channels()->detach(); + $episode->crew()->delete(); + $episode->players()->delete(); + } + $to_purge->delete(); + } + + private function syncSchedule(Event $event, $nmgEntry): void { + if (!$nmgEntry['scheduled_for']) { + return; + } + $ext_id = 'nmgleague:'.$nmgEntry['id']; + $episode = $event->episodes()->firstWhere('ext_id', '=', $ext_id); + if (!$episode) { + $episode = new Episode(); + $episode->ext_id = $ext_id; + $episode->event()->associate($event); + } + $bracket = $this->getNmgBracket($nmgEntry['bracket_id']); + $episode->title = $bracket['name']; + if ($bracket['bracket_type'] == 'Swiss') { + $episode->title .= ' Swiss'; + } else { + $episode->title .= ' Bracket'; + } + if ($nmgEntry['round'] && $bracket['bracket_type'] != 'RoundRobin') { + $episode->title .= ' Round '.$nmgEntry['round']; + } + $start = Carbon::createFromTimestamp($nmgEntry['scheduled_for']); + if (!$episode->start || $start->ne($episode->start)) { + $episode->start = $start; + } + $episode->estimate = 90 * 60; + $episode->confirmed = true; + if ($nmgEntry['racetime_gg_url']) { + $episode->raceroom = $nmgEntry['racetime_gg_url']; + } + $episode->save(); + + $this->purgePlayers($episode, $nmgEntry); + $this->syncPlayer($episode, $this->getNmgPlayer($nmgEntry['player_1_id'])); + $this->syncPlayer($episode, $this->getNmgPlayer($nmgEntry['player_2_id'])); + + if ($nmgEntry['restream_channel']) { + $channel = $this->syncChannel($episode, $nmgEntry['restream_channel']); + $episode->channels()->syncWithoutDetaching([$channel->id]); + } + } + + private function purgePlayers(Episode $episode, $nmgEntry): void { + $ext_ids = []; + $ext_ids[] = 'nmgleague:'.$nmgEntry['player_1_id']; + $ext_ids[] = 'nmgleague:'.$nmgEntry['player_2_id']; + $episode->players()->whereNotIn('ext_id', $ext_ids)->delete(); + } + + private function syncPlayer(Episode $episode, $nmgPlayer) { + $ext_id = 'nmgleague:'.$nmgPlayer['id']; + $player = $episode->players()->firstWhere('ext_id', '=', $ext_id); + if (!$player) { + $player = new EpisodePlayer(); + $player->ext_id = $ext_id; + $player->episode()->associate($episode); + } + $user = $this->getUserByNmgPlayer($nmgPlayer); + if ($user) { + $player->user()->associate($user); + } else { + $player->user()->disassociate(); + } + if (!empty($nmgPlayer['name'])) { + $player->name_override = $nmgPlayer['name']; + } + if (!empty($nmgPlayer['twitch_user_login'])) { + $player->stream_override = 'https://twitch.tv/'.strtolower($nmgPlayer['twitch_user_login']); + } + $player->save(); + } + + private function syncChannel(Episode $episode, string $channel_url): Channel { + $normalized_url = str_replace('http://', 'https://', strtolower($channel_url)); + $normalized_url = str_replace('www.twitch.tv', 'twitch.tv', $normalized_url); + $channel = Channel::firstWhere('stream_link', 'LIKE', $normalized_url); + if (!$channel) { + $channel = new Channel(); + $channel->stream_link = $normalized_url; + $channel->title = Str::afterLast($channel_url, '/'); + $channel->languages = ['en']; + $channel->save(); + } + return $channel; + } + + private function getUserByNmgPlayer($player): ?User { + if (!empty($player['discord_id'])) { + $user = User::find($player['discord_id']); + if ($user) { + if (!$user->stream_link) { + if (!empty($player['twitch_user_login'])) { + $user->stream_link = 'https://twitch.tv/'.strtolower($player['twitch_user_login']); + $user->save(); + } + } + return $user; + } + DiscordBotCommand::syncUser($player['discord_id']); + } + return null; + } + + private function loadBrackets($season): void { + $nmgBrackets = Http::get('https://nmg-league.foxlisk.com/api/v1/season/'.$season.'/brackets')->json(); + foreach ($nmgBrackets['Ok'] as $nmgBracket) { + $this->brackets[$nmgBracket['id']] = $nmgBracket; + } + } + + private function loadPlayers(): void { + if (!empty($this->players)) { + return; + } + $nmgPlayers = Http::get('https://nmg-league.foxlisk.com/api/v1/players')->json(); + foreach ($nmgPlayers['Ok'] as $nmgPlayer) { + $this->players[$nmgPlayer['id']] = $nmgPlayer; + } + } + + private function getNmgBracket($id) { + return $this->brackets[$id]; + } + + private function getNmgPlayer($id) { + return $this->players[$id]; + } + + private $brackets = []; + private $players = []; + +} diff --git a/app/Console/Commands/SyncSpeedGaming.php b/app/Console/Commands/SyncSpeedGaming.php index 9dac52e..1d44020 100644 --- a/app/Console/Commands/SyncSpeedGaming.php +++ b/app/Console/Commands/SyncSpeedGaming.php @@ -71,7 +71,7 @@ class SyncSpeedGaming extends Command { foreach ($sgSchedule as $sgEntry) { try { $this->syncSchedule($event, $sgEntry); - } catch (Exception $e) { + } catch (\Exception $e) { $this->error('error syncing episode '.$sgEntry['id'].': '.$e->getMessage()); } }