3 namespace App\Console\Commands;
6 use App\Models\Episode;
8 use Illuminate\Console\Command;
9 use Illuminate\Database\Eloquent\Builder;
10 use Illuminate\Support\Facades\Http;
12 class SyncRacetime extends Command {
15 * The name and signature of the console command.
19 protected $signature = 'sync:racetime';
22 * The console command description.
26 protected $description = 'Link racetime rooms with episodes';
29 * Execute the console command.
33 public function handle() {
34 $events = Event::whereNotNull('racetime_category')
35 ->where(function (Builder $query) {
36 $query->whereNull('end');
37 $query->orWhere('end', '>', now());
41 foreach ($events as $event) {
43 $this->line('syncing '.$event->name);
44 $this->syncEvent($event);
45 } catch (\Exception $e) {
46 $this->error('error syncing event '.$event->name.': '.$e->getMessage());
50 return Command::SUCCESS;
53 private function syncEvent(Event $event) {
54 $episodes = $event->episodes()->whereBetween('start', [now()->sub(1, 'hour'), now()->add(30, 'minute')])->get();
55 if ($episodes->isEmpty()) return;
56 $racerooms = $this->getRacetime($event->racetime_category);
57 foreach ($episodes as $episode) {
58 $rooms = $this->filterID($episode, $racerooms);
59 if (count($rooms) > 1) {
60 $rooms = $this->filterStartTime($episode, $rooms);
62 if (count($rooms) > 1) {
63 $rooms = $this->filterPlayerNames($episode, $rooms);
65 if (count($rooms) == 1) {
66 $this->line(' - linking episode '.$episode->id.' with room '.$rooms[0]['name']);
67 $episode->raceroom = 'https://racetime.gg'.$rooms[0]['url'];
73 private function getRacetime($category) {
74 if (isset($this->cat_cache[$category])) {
75 return $this->cat_cache[$category];
77 $category_data = HTTP::get('https://racetime.gg/'.$category.'/data');
78 $races_data = HTTP::get('https://racetime.gg/'.$category.'/races/data');
79 $this->cat_cache[$category] = array_merge(array_values($category_data['current_races']), array_values($races_data['races']));
80 return $this->cat_cache[$category];
83 private function filterID(Episode $episode, $racerooms) {
84 if (empty($episode->ext_id) || substr($episode->ext_id, 0, 3) != 'sg:') {
88 $id = substr($episode->ext_id, 3);
89 foreach ($racerooms as $room) {
90 if (strpos($room['info'], $id) !== false) {
94 return empty($rooms) ? $racerooms : $rooms;
97 private function filterStartTime(Episode $episode, $racerooms) {
98 if (empty($episode->start)) {
102 $from = Carbon::createFromFormat('Y-m-d H:i:s', $episode->start, 'UTC')->sub(1, 'hour');
103 $till = Carbon::createFromFormat('Y-m-d H:i:s', $episode->start, 'UTC')->add(1, 'hour');
104 foreach ($racerooms as $room) {
105 $created = Carbon::createFromFormat('Y-m-d\TH:i:s.uP', $room['opened_at']);
106 if ($created->isAfter($from) && $created->isBefore($till)) {
110 return empty($rooms) ? $racerooms : $rooms;
113 private function filterPlayerNames(Episode $episode, $racerooms) {
115 foreach ($episode->players as $player) {
116 $pname = trim($player->getName());
117 if (!empty($pname)) {
121 if (empty($pnames)) {
125 foreach ($racerooms as $room) {
127 foreach ($pnames as $pname) {
128 if (stripos($room['info'], $pname) === false) {
137 return empty($rooms) ? $racerooms : $rooms;
140 private $cat_cache = [];