namespace App\Console\Commands;
+use App\Models\Channel;
+use App\Models\DiscordBotCommand;
use App\Models\Episode;
+use App\Models\EpisodeCrew;
use App\Models\EpisodePlayer;
use App\Models\Event;
+use App\Models\Organization;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
* @return int
*/
public function handle() {
+ $this->org = Organization::where('name', '=', 'sg')->firstOrFail();
+
$events = Event::where('external_schedule', 'LIKE', 'sg:%')
->where(function (Builder $query) {
$query->whereNull('end');
- $query->orWhere('end', '<', now());
+ $query->orWhere('end', '>', now());
})
->get();
+
foreach ($events as $event) {
try {
$this->line('syncing '.$event->name);
$this->error('error syncing event '.$event->name.': '.$e->getMessage());
}
}
+
return 0;
}
private function syncEvent(Event $event) {
$sgHandle = substr($event->external_schedule, 3);
$from = now()->sub(1, 'day');
- $to = now()->add(6, 'day');
+ $to = now()->add(14, 'day');
$sgSchedule = HTTP::get('https://speedgaming.org/api/schedule/', [
'event' => $sgHandle,
'from' => $from->toIso8601String(),
->where('start', '<=', $to)
->whereNotIn('ext_id', $ext_ids);
foreach ($to_purge->get() as $episode) {
+ $episode->channels()->detach();
+ $episode->crew()->delete();
$episode->players()->delete();
}
$to_purge->delete();
$episode->event()->associate($event);
$episode->title = $sgEntry['match1']['title'];
$start = Carbon::createFromFormat('Y-m-d\TH:i:sP', $sgEntry['when']);
- if ($start->ne($episode->start)) {
+ if ($event->fix_timezone && !$episode->timezone_fix_override) {
+ $sg_zone = new \DateTimeZone('America/Detroit');
+ $event_zone = new \DateTimeZone($event->fix_timezone);
+ // if speedgaming is in DST, it fucks up the timestamp
+ if (Carbon::createFromTimestamp($start->timestamp, $sg_zone)->dst && !Carbon::createFromTimestamp($start->timestamp, $event_zone)->dst) {
+ $start->add(1, 'hour');
+ } else if (!Carbon::createFromTimestamp($start->timestamp, $sg_zone)->dst && Carbon::createFromTimestamp($start->timestamp, $event_zone)->dst) {
+ $start->sub(1, 'hour');
+ }
+ }
+ if (!$episode->start || $start->ne($episode->start)) {
$episode->start = $start;
}
$episode->estimate = $sgEntry['length'] * 60;
$episode->confirmed = $sgEntry['approved'];
$episode->comment = $sgEntry['match1']['note'];
$episode->save();
+
+ $this->purgeChannels($episode, $sgEntry);
+ $channelIds = [];
+ foreach ($sgEntry['channels'] as $sgChannel) {
+ if ($sgChannel['initials'] == 'NONE' || $sgChannel['name'] == 'Undecided, Not SG') continue;
+ try {
+ $channel = $this->syncChannel($episode, $sgChannel);
+ $channelIds[] = $channel->id;
+ } catch (Exception $e) {
+ $this->error('error syncing channel '.$sgChannel['id'].': '.$e->getMessage());
+ }
+ }
+ if (!empty($channelIds)) {
+ $episode->channels()->syncWithoutDetaching($channelIds);
+ }
+
+ $this->purgeCrew($episode, $sgEntry['broadcasters'], 'brd');
+ foreach ($sgEntry['broadcasters'] as $sgCrew) {
+ try {
+ $this->syncCrew($episode, $sgCrew, 'brd', 'setup');
+ } catch (Exception $e) {
+ $this->error('error syncing broadcaster '.$sgCrew['id'].': '.$e->getMessage());
+ }
+ }
+
+ $this->purgeCrew($episode, $sgEntry['commentators'], 'comm');
+ foreach ($sgEntry['commentators'] as $sgCrew) {
+ try {
+ $this->syncCrew($episode, $sgCrew, 'comm', 'commentary');
+ } catch (Exception $e) {
+ $this->error('error syncing commentator '.$sgCrew['id'].': '.$e->getMessage());
+ }
+ }
+
+ $this->purgeCrew($episode, $sgEntry['helpers'], 'help');
+ foreach ($sgEntry['helpers'] as $sgCrew) {
+ try {
+ $this->syncCrew($episode, $sgCrew, 'help', 'setup');
+ } catch (Exception $e) {
+ $this->error('error syncing helper '.$sgCrew['id'].': '.$e->getMessage());
+ }
+ }
+
+ $this->purgeCrew($episode, $sgEntry['trackers'], 'track');
+ foreach ($sgEntry['trackers'] as $sgCrew) {
+ try {
+ $this->syncCrew($episode, $sgCrew, 'track', 'tracking');
+ } catch (Exception $e) {
+ $this->error('error syncing tracker '.$sgCrew['id'].': '.$e->getMessage());
+ }
+ }
+
$this->purgePlayers($episode, $sgEntry);
foreach ($sgEntry['match1']['players'] as $sgPlayer) {
try {
}
}
+ private function purgeChannels(Episode $episode, $sgEntry) {
+ $ext_ids = [];
+ foreach ($sgEntry['channels'] as $sgChannel) {
+ $ext_ids[] = 'sg:'.$sgChannel['id'];
+ }
+ $channels = $episode->channels()
+ ->where('ext_id', 'LIKE', 'sg:%')
+ ->whereNotIn('ext_id', $ext_ids)
+ ->get();
+ if (!$channels->isEmpty()) {
+ $episode->channels()->detach($channels->pluck('id'));
+ }
+ }
+
+ private function syncChannel(Episode $episode, $sgChannel) {
+ $ext_id = 'sg:'.$sgChannel['id'];
+ $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->short_name = $sgChannel['initials'];
+ $channel->title = $sgChannel['name'];
+ $channel->stream_link = 'https://twitch.tv/'.strtolower($sgChannel['name']);
+ $channel->languages = [$sgChannel['language']];
+ $channel->save();
+ return $channel;
+ }
+
+ private function purgeCrew(Episode $episode, $sgCrews, $prefix) {
+ $ext_ids = [];
+ foreach ($sgCrews as $sgCrew) {
+ $ext_ids[] = 'sg:'.$prefix.':'.$sgCrew['id'];
+ }
+ $episode->crew()->where('ext_id', 'LIKE', 'sg:'.$prefix.':%')->whereNotIn('ext_id', $ext_ids)->delete();
+ }
+
+ private function syncCrew(Episode $episode, $sgCrew, $prefix, $role) {
+ $ext_id = 'sg:'.$prefix.':'.$sgCrew['id'];
+ $crew = $episode->crew()->firstWhere('ext_id', '=', $ext_id);
+ if (!$crew) {
+ $crew = new EpisodeCrew();
+ $crew->ext_id = $ext_id;
+ $crew->episode()->associate($episode);
+ }
+ $user = $this->getUserBySGPlayer($sgCrew);
+ if ($user) {
+ $crew->user()->associate($user);
+ } else {
+ $crew->user()->disassociate();
+ }
+ if ($role == 'commentary') {
+ $channel = $this->getChannelByCrew($episode, $sgCrew);
+ if ($channel) {
+ $crew->channel()->associate($channel);
+ } else {
+ $crew->channel()->disassociate();
+ }
+ }
+ $crew->role = $role;
+ $crew->confirmed = $sgCrew['approved'] ?: false;
+ if (!empty($sgCrew['displayName'])) {
+ $crew->name_override = $sgCrew['displayName'];
+ }
+ if (!empty($sgCrew['publicStream'])) {
+ $crew->stream_override = 'https://twitch.tv/'.strtolower($sgCrew['publicStream']);
+ }
+ $crew->save();
+ }
+
private function purgePlayers(Episode $episode, $sgEntry) {
$ext_ids = [];
foreach ($sgEntry['match1']['players'] as $sgPlayer) {
$player->name_override = $sgPlayer['displayName'];
}
if (!empty($sgPlayer['streamingFrom'])) {
- $player->stream_override = $sgPlayer['streamingFrom'];
+ $player->stream_override = 'https://twitch.tv/'.strtolower($sgPlayer['streamingFrom']);
}
$player->save();
}
+ private function getChannelByCrew(Episode $episode, $sgCrew) {
+ $channel = $episode->channels()
+ ->where('ext_id', 'LIKE', 'sg:%')
+ ->whereJsonContains('languages', $sgCrew['language'])
+ ->first();
+ if ($channel) {
+ return $channel;
+ }
+ return $episode->channels()
+ ->where('ext_id', 'LIKE', 'sg:%')
+ ->first();
+ }
+
private function getUserBySGPlayer($player) {
if (!empty($player['discordId'])) {
$user = User::find($player['discordId']);
- if ($user) return $user;
+ if ($user) {
+ if (empty($user->stream_link)) {
+ if (!empty($sgPlayer['publicStream'])) {
+ $user->stream_link = 'https://twitch.tv/'.strtolower($sgPlayer['publicStream']);
+ $user->save();
+ } else if (!empty($sgPlayer['streamingFrom'])) {
+ $user->stream_link = 'https://twitch.tv/'.strtolower($sgPlayer['streamingFrom']);
+ $user->save();
+ }
+ }
+ return $user;
+ }
+ DiscordBotCommand::syncUser($player['discordId']);
}
if (!empty($player['discordTag'])) {
$tag = explode('#', $player['discordTag']);
- $user = User::firstWhere([
- ['username', 'LIKE', $tag[0]],
- ['username', 'LIKE', $tag[1]],
- ]);
+ $user = count($tag) < 2 || $tag[1] == '0'
+ ? User::firstWhere([
+ ['username', 'LIKE', $tag[0]],
+ ])
+ : User::firstWhere([
+ ['username', 'LIKE', $tag[0]],
+ ['discriminator', '=', $tag[1]],
+ ]);
if ($user) return $user;
}
return null;
}
+ private $org;
+
}