id), ]; if (!empty($this->access_key)) { $channels[] = new PublicChannel('ChannelKey.'.$this->access_key); } return $channels; } public function getCurrentEpisode() { return $this->episodes() ->where('start', '<', now()->subMinutes(10)) ->orderBy('start', 'DESC') ->first(); } public function getGuessingLeaderboard() { $query = $this->winners() ->selectRaw('(select t2.uname from guessing_winners t2 where t2.uid = guessing_winners.uid order by created_at desc limit 1) as name, sum(score) as score') ->where('score', '!=', 0) ->groupBy('uid') ->orderBy('score', 'desc') ->limit(10); $type = $this->getGuessingSetting('leaderboard_type', 'all'); if ($type == 'month') { $query->where('created_at', '>=', now()->startOfMonth()); } else if ($type == 'year') { $query->where('created_at', '>=', now()->startOfYear()); } else if (is_numeric($type)) { $query->where('created_at', '>=', now()->sub($type, 'days')); } return $query->get(); } public function hasActiveGuessing() { return !is_null($this->guessing_start); } public function isAcceptingGuesses() { return !is_null($this->guessing_start) && is_null($this->guessing_end); } public function startGuessing($type) { $this->guessing_type = $type; $this->guessing_start = now(); $this->save(); } public function stopGuessing() { $this->guessing_end = now(); $this->save(); } public function getGuessingSetting($name, $default = null) { if (empty($this->guessing_settings) || empty($this->guessing_type) || !array_key_exists($this->guessing_type, $this->guessing_settings) || !array_key_exists($name, $this->guessing_settings[$this->guessing_type]) ) { return $default; } return $this->guessing_settings[$this->guessing_type][$name]; } public function solveGuessing($solution) { $start = $this->guessing_start; $end = is_null($this->guessing_end) ? now() : $this->guessing_end; $guesses = $this->guesses()->whereBetween('created_at', [$start, $end])->orderBy('created_at', 'ASC')->get(); $unique_guesses = []; foreach ($guesses as $guess) { $unique_guesses[$guess->uid] = $guess; } $candidates = []; foreach ($unique_guesses as $guess) { if ($guess->guess == $solution) { $candidates[] = $guess; } } if (empty($candidates) && is_numeric($solution)) { $min_distance = null; foreach ($unique_guesses as $guess) { $distance = abs(intval($guess->guess) - intval($solution)); if (is_null($min_distance) || $distance == $min_distance) { $candidates[] = $guess; if (is_null($min_distance)) { $min_distance = $distance; } } else if ($distance < $min_distance) { $candidates = [$guess]; $min_distance = $distance; } } } $winners = []; $first = true; foreach ($candidates as $candidate) { $score = $this->scoreGuessing($solution, $candidate->guess, $first); $winner = new GuessingWinner(); $winner->channel()->associate($this); $winner->pod = $start; $winner->uid = $candidate->uid; $winner->uname = $candidate->uname; $winner->guess = $candidate->guess; $winner->solution = $solution; $winner->score = $score; $winner->save(); $winners[] = $winner; $first = false; } return $winners; } public function clearGuessing() { $this->guessing_start = null; $this->guessing_end = null; $this->save(); } public function transformGuess($original) { $transformed = trim($original); if ($this->guessing_type == 'gtbk') { $transformed = str_replace(['roodyo1Gtbigkey'], ['2'], $transformed); $transformed = str_ireplace(['vier 4Head'], ['4'], $transformed); } return $transformed; } public function registerGuess($uid, $uname, $guess) { $model = new GuessingGuess(); $model->channel()->associate($this); $model->uid = $uid; $model->uname = $uname; $model->guess = $this->transformGuess($guess); $model->save(); } public function scoreGuessing($solution, $guess, $first) { $transformed = $this->transformGuess($guess); if ($transformed == $solution) { if ($first) { return $this->getGuessingSetting('points_exact_first', 1); } return $this->getGuessingSetting('points_exact_other', 1); } $distance = abs(intval($transformed) - intval($solution)); if ($distance <= $this->getGuessingSetting('points_close_max', 3)) { if ($first) { return $this->getGuessingSetting('points_close_first', 1); } return $this->getGuessingSetting('points_close_other', 1); } return 0; } public function isValidGuess($solution) { $transformed = $this->transformGuess($solution); if ($this->guessing_type == 'gtbk') { $int_solution = intval($transformed); return is_numeric($transformed) && $int_solution > 0 && $int_solution < 23; } return false; } public function listGuessingWinners($winners) { $names = []; $distance = 0; foreach ($winners as $winner) { if ($winner->score > 0) { $names[] = $winner->uname; $distance = abs(intval($winner->guess) - intval($winner->solution)); } } $msg = ''; if (empty($names)) { $msg = $this->getGuessingSetting('no_winners_message'); } else { $msg = $this->getGuessingSetting($distance ? 'close_winners_message' : 'winners_message', $this->getGuessingSetting('winners_message')); $msg = str_replace(['{distance}', '{names}'], [$distance, $this->listAnd($names)], $msg); } return $msg; } public function listAnd($entries) { $lang = empty($this->languages) ? 'en' : $this->languages[0]; if ($lang == 'de') { return Arr::join($entries, ', ', ' und '); } return Arr::join($entries, ', ', ' and '); } public function crews() { return $this->hasMany(ChannelCrew::class); } public function episodes() { return $this->belongsToMany(Episode::class) ->using(Restream::class) ->withPivot('accept_comms', 'accept_tracker'); } public function guesses() { return $this->hasMany(GuessingGuess::class); } public function organization() { return $this->belongsTo(Organization::class); } public function winners() { return $this->hasMany(GuessingWinner::class); } protected $casts = [ 'chat' => 'boolean', 'chat_commands' => 'array', 'chat_settings' => 'array', 'guessing_end' => 'datetime', 'guessing_settings' => 'array', 'guessing_start' => 'datetime', 'languages' => 'array', 'join' => 'boolean', ]; protected $hidden = [ 'access_key', 'chat', 'chat_commands', 'chat_settings', 'created_at', 'ext_id', 'guessing_settings', 'join', 'twitch_chat', 'updated_at', ]; }