3 namespace App\TwitchBot;
5 use App\Models\Channel;
6 use App\Models\ChatLog;
8 class TwitchChatBot extends TwitchBot {
10 public function __construct() {
11 parent::__construct('horstiebot');
12 $this->updateChannels();
14 $this->listenCommands();
17 public function joinChannels() {
18 $this->getLogger()->info('joining channels');
20 foreach ($this->channels as $channel) {
21 $names[] = $channel->twitch_chat;
23 $chunks = array_chunk($names, 10);
24 foreach ($chunks as $chunk) {
25 $this->sendIRCMessage(IRCMessage::join($chunk));
29 public function logMessage(IRCMessage $msg) {
30 $channel = $this->getMessageChannel($msg);
31 if ($channel && !$channel->join) {
36 public function handlePrivMsg(IRCMessage $msg) {
37 if ($msg->nick == 'horstiebot') return;
38 $channel = $this->getMessageChannel($msg);
39 if (!$channel) return;
40 $this->tagChannelRead($channel);
44 private function startTimer() {
45 $this->getLoop()->addPeriodicTimer(1, function () {
46 if (!$this->isReady()) return;
47 foreach ($this->channels as $channel) {
48 $this->decideSend($channel);
51 $this->getLoop()->addPeriodicTimer(60, function () {
52 $this->updateChannels();
56 private function updateChannels() {
57 $this->channels = Channel::where('twitch_chat', '!=', '')->where('chat', '=', true)->get();
60 private function decideSend(Channel $channel) {
61 $notes = $this->getNotes($channel);
62 if ($notes['read_since_last_write'] < $notes['wait_msgs']) {
65 if (time() - $notes['last_write'] < $notes['wait_time']) {
68 if ($notes['read_since_last_write'] == $notes['wait_msgs'] && time() - $notes['last_read'] < 3) {
69 // don't immediately respond if we crossed the msg threshold last
72 $text = $this->randomMsg($channel);
74 $this->tagChannelWrite($channel);
75 $this->sendIRCMessage(IRCMessage::privmsg($channel->twitch_chat, $text));
78 private function getChatSetting(Channel $channel, $name, $default = null) {
79 if (array_key_exists($name, $channel->chat_settings)) {
80 return $channel->chat_settings[$name];
85 private function getNotes(Channel $channel) {
86 if (!isset($this->notes[$channel->id])) {
87 $this->notes[$channel->id] = [
89 'last_write' => time(),
90 'read_since_last_write' => 0,
91 'wait_msgs' => $this->randomWaitMsgs($channel),
92 'wait_time' => $this->randomWaitTime($channel),
95 return $this->notes[$channel->id];
98 private function randomMsg(Channel $channel) {
99 $line = ChatLog::where('type', '=', 'chat')
100 ->where('banned', '=', false)
101 ->where('created_at', '<', now()->sub(1, 'day'))
102 ->where(function ($query) use ($channel) {
103 $query->whereNull('detected_language');
104 $query->orWhereIn('detected_language', $channel->languages);
108 return $line->text_content;
111 private function randomWaitMsgs(Channel $channel) {
112 $min = $this->getChatSetting($channel, 'wait_msgs_min', 1);
113 $max = $this->getChatSetting($channel, 'wait_msgs_max', 10);
114 return random_int($min, $max);
117 private function randomWaitTime(Channel $channel) {
118 $min = $this->getChatSetting($channel, 'wait_time_min', 1);
119 $max = $this->getChatSetting($channel, 'wait_time_max', 900);
120 return random_int($min, $max);
123 private function tagChannelRead(Channel $channel) {
124 $this->getNotes($channel);
125 $this->notes[$channel->id]['last_read'] = time();
126 ++$this->notes[$channel->id]['read_since_last_write'];
129 private function tagChannelWrite(Channel $channel) {
130 $this->getNotes($channel);
131 $this->notes[$channel->id]['last_write'] = time();
132 $this->notes[$channel->id]['read_since_last_write'] = 0;
133 $this->notes[$channel->id]['wait_msgs'] = $this->randomWaitMsgs($channel);
134 $this->notes[$channel->id]['wait_time'] = $this->randomWaitTime($channel);