org = Organization::where('name', '=', 'zsr')->firstOrFail(); $events = Event::where('external_schedule', 'LIKE', 'zsr:%') ->where(function (Builder $query) { $query->whereNull('end'); $query->orWhere('end', '<', now()); }) ->get(); $from = now()->sub(1, 'day'); $to = now()->add(14, 'day'); $schedule = Http::get('https://www.googleapis.com/calendar/v3/calendars/zsrstaff%40gmail.com/events', [ 'alt' => 'json', 'key' => config('google.api_key'), 'timeMax' => $to->toIso8601String(), 'timeMin' => $from->toIso8601String(), ])->json(); foreach ($events as $event) { try { $this->line('syncing '.$event->name); $this->syncEvent($event, $schedule['items']); } catch (\Exception $e) { $this->error('error syncing event '.$event->name.': '.$e->getMessage()); } } return Command::SUCCESS; } private function syncEvent(Event $event, $schedule) { $tag = substr($event->external_schedule, 4); foreach ($schedule as $entry) { if (!Str::startsWith($entry['summary'], $tag)) continue; $this->syncSchedule($event, $entry); } } private function syncSchedule(Event $event, $entry) { $ext_id = 'zsr:'.$entry['id']; $episode = Episode::firstWhere('ext_id', '=', $ext_id); if (!$episode) { $episode = new Episode(); $episode->ext_id = $ext_id; } $episode->event()->associate($event); if (strlen($entry['summary']) > (strlen($event->external_schedule) - 4)) { $episode->title = substr($entry['summary'], strlen($event->external_schedule) - 4); } else { $episode->title = $entry['summary']; } if (preg_match('/Restream: https?:\/\/(www\.)?twitch\.tv\/(\w+)/u', $entry['description'], $matches)) { $channel = $this->syncChannel($episode, $matches[2]); if ($channel) { $episode->channels()->syncWithoutDetaching([$channel->id]); } } if (preg_match('/^(.*) - (.*?) vs (.*?)$/u', $episode->title, $matches)) { $episode->title = $matches[1]; $this->syncPlayer($episode, $matches[2]); $this->syncPlayer($episode, $matches[3]); } $start = Carbon::parse($entry['start']['dateTime'])->setTimezone('UTC'); if (!$episode->start || $start->ne($episode->start)) { $episode->start = $start; } $end = Carbon::parse($entry['end']['dateTime'])->setTimezone('UTC'); $episode->estimate = $start->diffInSeconds($end); $episode->confirmed = true; $episode->save(); } private function syncChannel(Episode $episode, $zsrChannel) { $ext_id = 'zsr:'.$zsrChannel; $channel = $this->org->channels()->firstWhere('ext_id', '=', $ext_id); if (!$channel) { $channel = new Channel(); $channel->ext_id = $ext_id; $channel->organization()->associate($this->org); $channel->languages = ['en']; $channel->short_name = ''; } $channel->title = $zsrChannel; $channel->stream_link = 'https://twitch.tv/'.strtolower($zsrChannel); $channel->save(); return $channel; } private function syncPlayer(Episode $episode, $zsrPlayer) { $ext_id = 'zsr:'.$zsrPlayer; $player = $episode->players()->firstWhere('ext_id', '=', $ext_id); if (!$player) { $player = new EpisodePlayer(); $player->ext_id = $ext_id; $player->episode()->associate($episode); } $user = $this->getUserByZSRPlayer($zsrPlayer); if ($user) { $player->user()->associate($user); } else { $player->user()->disassociate(); } $player->name_override = $zsrPlayer; $player->save(); return $player; } private function getUserByZSRPlayer($player) { $user = User::firstWhere('discord_nickname', '=', $player); if ($user) { return $user; } $user = User::firstWhere('username', '=', strtolower($player)); if ($user) { return $user; } return null; } private $org; }