updateChannels(); $this->startTimer(); $this->listenCommands(); } public function joinChannels() { $this->getLogger()->info('joining channels'); $names = []; foreach ($this->channels as $channel) { $names[] = $channel->twitch_chat; } $chunks = array_chunk($names, 10); foreach ($chunks as $chunk) { $this->sendIRCMessage(IRCMessage::join($chunk)); } } public function logMessage(IRCMessage $msg) { $channel = $this->getMessageChannel($msg); if ($channel && !$channel->join) { $msg->log(); } } public function handlePrivMsg(IRCMessage $msg) { if ($msg->nick == 'horstiebot') return; $channel = $this->getMessageChannel($msg); if (!$channel) return; $this->tagChannelRead($channel, $msg); } private function startTimer() { $this->getLoop()->addPeriodicTimer(1, function () { if (!$this->isReady()) return; foreach ($this->channels as $channel) { $this->decideSend($channel); } }); $this->getLoop()->addPeriodicTimer(60, function () { $this->updateChannels(); }); } private function updateChannels() { $this->channels = Channel::where('twitch_chat', '!=', '')->where('chat', '=', true)->get(); } private function decideSend(Channel $channel) { $notes = $this->getNotes($channel); if ($notes['read_since_last_write'] < $notes['wait_msgs']) { return; } if (time() - $notes['last_write'] < $notes['wait_time']) { return; } if ($notes['read_since_last_write'] == $notes['wait_msgs'] && time() - $notes['last_read'] < 3) { // don't immediately respond if we crossed the msg threshold last return; } $text = $this->contextualMsg($channel); if (!$text) $text = $this->randomMsg($channel); if (!$text) return; $this->tagChannelWrite($channel); $this->sendIRCMessage(IRCMessage::privmsg($channel->twitch_chat, $text)); } private function getChatSetting(Channel $channel, $name, $default = null) { if (array_key_exists($name, $channel->chat_settings)) { return $channel->chat_settings[$name]; } return $default; } private function getNotes(Channel $channel) { if (!isset($this->notes[$channel->id])) { $this->notes[$channel->id] = [ 'last_read' => 0, 'last_special' => '', 'last_write' => time(), 'latest_msgs' => [], 'read_since_last_write' => 0, 'wait_msgs' => $this->randomWaitMsgs($channel), 'wait_time' => $this->randomWaitTime($channel), ]; } return $this->notes[$channel->id]; } private function getNote(Channel $channel, $name, $default = null) { $notes = $this->getNotes($channel); if (array_key_exists($name, $notes)) { return $notes[$name]; } return $default; } private function setNote(Channel $channel, $name, $value) { $this->getNotes($channel); $this->notes[$channel->id][$name] = $value; } private function checkForGG(Channel $channel) { $notes = $this->getNotes($channel); $ggs = 0; foreach ($notes['latest_msgs'] as $text) { if (ChatLog::classify($text) == 'gg') { ++$ggs; } } return $ggs > 2; } private function checkForGLHF(Channel $channel) { $notes = $this->getNotes($channel); $gls = 0; foreach ($notes['latest_msgs'] as $text) { if (ChatLog::classify($text) == 'gl') { ++$gls; } } return $gls > 2; } private function checkForGreeting(Channel $channel) { $notes = $this->getNotes($channel); $his = 0; foreach ($notes['latest_msgs'] as $text) { if (ChatLog::classify($text) == 'hi') { ++$his; } } return $his > 2; } private function checkForHype(Channel $channel) { $notes = $this->getNotes($channel); $hypes = 0; foreach ($notes['latest_msgs'] as $text) { if (ChatLog::classify($text) == 'hype') { ++$hypes; } } return $hypes > 2; } private function checkForLaughter(Channel $channel) { $notes = $this->getNotes($channel); $lulz = 0; foreach ($notes['latest_msgs'] as $text) { if (ChatLog::classify($text) == 'lol') { ++$lulz; } } return $lulz > 2; } private function checkForNumbers(Channel $channel) { $notes = $this->getNotes($channel); $numbers = 0; foreach ($notes['latest_msgs'] as $text) { if (is_numeric(trim($text))) { ++$numbers; } } return $numbers > 2; } private function checkForPog(Channel $channel) { $notes = $this->getNotes($channel); $pogs = 0; foreach ($notes['latest_msgs'] as $text) { if (ChatLog::classify($text) == 'pog') { ++$pogs; } } return $pogs > 2; } private function checkForSalute(Channel $channel) { $notes = $this->getNotes($channel); $o7s = 0; foreach ($notes['latest_msgs'] as $text) { if (ChatLog::classify($text) == 'o7') { ++$o7s; } } return $o7s > 2; } private function contextualMsg(Channel $channel) { $last = $this->getNote($channel, 'last_special'); if ($last != 'gg' && $this->checkForGG($channel)) { $this->setNote($channel, 'last_special', 'gg'); return $this->randomOfClass($channel, 'gg'); } if ($last != 'number' && $this->checkForNumbers($channel)) { $this->setNote($channel, 'last_special', 'number'); return $this->randomContextualNumber($channel); } if ($last != 'lol' && $this->checkForLaughter($channel)) { $this->setNote($channel, 'last_special', 'lol'); return $this->randomLaughter($channel); } if ($last != 'glhf' && $this->checkForGLHF($channel)) { $this->setNote($channel, 'last_special', 'glhf'); return $this->randomOfClass($channel, 'gl'); } if ($last != 'hi' && $this->checkForGreeting($channel)) { $this->setNote($channel, 'last_special', 'hi'); return $this->randomOfClass($channel, 'hi'); } if ($last != 'hype' && $this->checkForHype($channel)) { $this->setNote($channel, 'last_special', 'hype'); return $this->randomOfClass($channel, 'hype'); } if ($last != 'pog' && $this->checkForPog($channel)) { $this->setNote($channel, 'last_special', 'pog'); return $this->randomOfClass($channel, 'pog'); } if ($last != 'o7' && $this->checkForSalute($channel)) { $this->setNote($channel, 'last_special', 'o7'); return $this->randomOfClass($channel, 'o7'); } return false; } private function queryChatlog(Channel $channel) { return ChatLog::where('type', '=', 'chat') ->where('banned', '=', false) ->where('created_at', '<', now()->sub(1, 'day')) ->where(function ($query) use ($channel) { $query->whereNull('detected_language'); $query->orWhereIn('detected_language', $channel->languages); }) ->inRandomOrder(); } private function randomChat(Channel $channel) { $line = $this->queryChatlog($channel) ->whereIn('classification', ['hi', 'hype', 'lol', 'pog', 'unclassified']) ->first(); return $line->text_content; } private function randomContextualNumber(Channel $channel) { $notes = $this->getNotes($channel); $min = 100000; $max = 0; foreach ($notes['latest_msgs'] as $text) { if (is_numeric(trim($text))) { $number = intval(trim($text)); $min = min($min, $number); $max = max($max, $number); } } return random_int($min, $max); } private function randomOfClass(Channel $channel, $class) { $line = $this->queryChatlog($channel) ->where('classification', '=', $class) ->first(); return $line->text_content; } private function randomLaughter(Channel $channel) { return Arr::random([ ':tf:', '4Head', 'CarlSmile', 'CruW', 'DendiFace', 'EleGiggle', 'GunRun', 'heh', 'Hhhehehe', 'HypeLUL', 'Jebaited', 'Jebasted', 'KEKW', 'KEKHeim', 'KKona', 'KomodoHype', 'MaxLOL', 'MingLee', 'lol', 'LOL!', 'LUL', 'OneHand', 'SeemsGood', 'ShadyLulu', 'SoonerLater', 'SUBprise', 'xD', 'YouDontSay', $this->randomOfClass($channel, 'lol'), ]); } private function randomMsg(Channel $channel) { $line = $this->queryChatlog($channel)->first(); return $line->text_content; } private function randomWaitMsgs(Channel $channel) { $min = $this->getChatSetting($channel, 'wait_msgs_min', 1); $max = $this->getChatSetting($channel, 'wait_msgs_max', 10); return random_int($min, $max); } private function randomWaitTime(Channel $channel) { $min = $this->getChatSetting($channel, 'wait_time_min', 1); $max = $this->getChatSetting($channel, 'wait_time_max', 900); return random_int($min, $max); } private function tagChannelRead(Channel $channel, IRCMessage $msg) { $this->getNotes($channel); $this->notes[$channel->id]['last_read'] = time(); ++$this->notes[$channel->id]['read_since_last_write']; if (!ChatLog::isKnownBot($msg->nick) && !ChatLog::spammyText($msg->getText())) { $this->notes[$channel->id]['latest_msgs'][] = $msg->getText(); if (count($this->notes[$channel->id]['latest_msgs']) > 10) { array_shift($this->notes[$channel->id]['latest_msgs']); } } } private function tagChannelWrite(Channel $channel) { $this->getNotes($channel); $this->notes[$channel->id]['last_write'] = time(); $this->notes[$channel->id]['read_since_last_write'] = 0; $this->notes[$channel->id]['wait_msgs'] = $this->randomWaitMsgs($channel); $this->notes[$channel->id]['wait_time'] = $this->randomWaitTime($channel); } private $channels; private $notes = []; }