From cde5d79cf2f09d61fa7b181cd3a1a19050a4aeb3 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 2 Mar 2023 15:11:57 +0100 Subject: [PATCH] first simple twitch commands --- app/Models/Channel.php | 8 ++++ app/Models/EpisodeCrew.php | 25 +++++++++++ app/Models/EpisodePlayer.php | 25 +++++++++++ app/TwitchBot/ChatCommand.php | 44 +++++++++++++++++++ app/TwitchBot/CrewCommand.php | 41 +++++++++++++++++ app/TwitchBot/IRCMessage.php | 8 ++++ app/TwitchBot/RunnerCommand.php | 26 +++++++++++ app/TwitchBot/TwitchBot.php | 17 ++++++- .../2023_03_01_143514_channel_twitch_chat.php | 2 +- .../2023_03_02_084058_channel_commands.php | 32 ++++++++++++++ 10 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 app/TwitchBot/ChatCommand.php create mode 100644 app/TwitchBot/CrewCommand.php create mode 100644 app/TwitchBot/RunnerCommand.php create mode 100644 database/migrations/2023_03_02_084058_channel_commands.php diff --git a/app/Models/Channel.php b/app/Models/Channel.php index 8b5ff90..0536aef 100644 --- a/app/Models/Channel.php +++ b/app/Models/Channel.php @@ -9,6 +9,13 @@ class Channel extends Model { use HasFactory; + public function getCurrentEpisode() { + return $this->episodes() + ->where('start', '<', now()->subMinutes(10)) + ->orderBy('start', 'DESC') + ->first(); + } + public function episodes() { return $this->belongsToMany(Episode::class) ->using(Restream::class) @@ -20,6 +27,7 @@ class Channel extends Model } protected $casts = [ + 'chat_commands' => 'array', 'languages' => 'array', ]; diff --git a/app/Models/EpisodeCrew.php b/app/Models/EpisodeCrew.php index d06276e..04bec5c 100644 --- a/app/Models/EpisodeCrew.php +++ b/app/Models/EpisodeCrew.php @@ -21,6 +21,31 @@ class EpisodeCrew extends Model return $this->belongsTo(User::class); } + public function getName() { + if (!empty($this->name_override)) { + return $this->name_override; + } + if ($this->user) { + if (!empty($this->user->nickname)) { + return $this->user->nickname; + } + if (!empty($this->user->username)) { + return $this->user->username; + } + } + return ''; + } + + public function getStreamLink() { + if (!empty($this->stream_override)) { + return $this->stream_override; + } + if ($this->user && !empty($this->user->stream_link)) { + return $this->user->stream_link; + } + return ''; + } + protected $casts = [ 'confirmed' => 'boolean', 'user_id' => 'string', diff --git a/app/Models/EpisodePlayer.php b/app/Models/EpisodePlayer.php index 1125701..26ccc04 100644 --- a/app/Models/EpisodePlayer.php +++ b/app/Models/EpisodePlayer.php @@ -17,6 +17,31 @@ class EpisodePlayer extends Model return $this->belongsTo(User::class); } + public function getName() { + if (!empty($this->name_override)) { + return $this->name_override; + } + if ($this->user) { + if (!empty($this->user->nickname)) { + return $this->user->nickname; + } + if (!empty($this->user->username)) { + return $this->user->username; + } + } + return ''; + } + + public function getStreamLink() { + if (!empty($this->stream_override)) { + return $this->stream_override; + } + if ($this->user && !empty($this->user->stream_link)) { + return $this->user->stream_link; + } + return ''; + } + protected $casts = [ 'user_id' => 'string', ]; diff --git a/app/TwitchBot/ChatCommand.php b/app/TwitchBot/ChatCommand.php new file mode 100644 index 0000000..feea8ab --- /dev/null +++ b/app/TwitchBot/ChatCommand.php @@ -0,0 +1,44 @@ +bot = $bot; + $cmd->channel = $channel; + $cmd->config = $config; + return $cmd; + } + + public abstract function execute($args); + + protected function getBooleanConfig($name, $default = false) { + return array_key_exists($name, $this->config) ? $this->config[$name] : $default; + } + + protected function messageChannel($str) { + $msg = IRCMessage::privmsg($this->channel->twitch_chat, $str); + $this->bot->sendIRCMessage($msg); + } + + protected $bot; + protected $channel; + protected $config; + +} + +?> diff --git a/app/TwitchBot/CrewCommand.php b/app/TwitchBot/CrewCommand.php new file mode 100644 index 0000000..2fd0426 --- /dev/null +++ b/app/TwitchBot/CrewCommand.php @@ -0,0 +1,41 @@ +channel->getCurrentEpisode(); + if (!$episode) return; + $links = []; + foreach ($episode->crew as $crew) { + $link = $crew->getStreamLink(); + if (empty($link)) { + $link = $crew->getName(); + } + if (!empty($link)) { + if (!isset($links[$crew->role])) { + $links[$crew->role] = []; + } + $links[$crew->role][] = $link; + } + } + $parts = []; + if (!empty($links['commentary']) && $this->getBooleanConfig('commentary', true)) { + $parts[] = 'Kommentar: '.implode(' ', $links['commentary']); + } + if (!empty($links['tracking']) && $this->getBooleanConfig('tracking', true)) { + $parts[] = 'Tracking: '.implode(' ', $links['tracking']); + } + if (!empty($links['setup']) && $this->getBooleanConfig('setup', false)) { + $parts[] = 'Setup: '.implode(' ', $links['setup']); + } + if (!empty($parts)) { + $message = implode(' ', $parts); + $this->messageChannel($message); + } + } + +} + +?> diff --git a/app/TwitchBot/IRCMessage.php b/app/TwitchBot/IRCMessage.php index c0acfbb..00217dc 100644 --- a/app/TwitchBot/IRCMessage.php +++ b/app/TwitchBot/IRCMessage.php @@ -132,6 +132,14 @@ class IRCMessage { return $msg; } + public static function privmsg($target, $message) { + $msg = new IRCMessage(); + $msg->command = 'PRIVMSG'; + $msg->params[] = $target; + $msg->params[] = $message; + return $msg; + } + public function getPrivMsgTarget() { if (!empty($this->params)) { return $this->params[0]; diff --git a/app/TwitchBot/RunnerCommand.php b/app/TwitchBot/RunnerCommand.php new file mode 100644 index 0000000..2cc41b2 --- /dev/null +++ b/app/TwitchBot/RunnerCommand.php @@ -0,0 +1,26 @@ +channel->getCurrentEpisode(); + if (!$episode) return; + $links = []; + foreach ($episode->players as $player) { + $link = $player->getStreamLink(); + if (empty($link)) { + $link = $player->getName(); + } + if (!empty($link)) { + $links[] = $link; + } + } + $message = 'Runner: '.implode(' ', $links); + $this->messageChannel($message); + } + +} + +?> diff --git a/app/TwitchBot/TwitchBot.php b/app/TwitchBot/TwitchBot.php index 3ca2db9..3cba5d9 100644 --- a/app/TwitchBot/TwitchBot.php +++ b/app/TwitchBot/TwitchBot.php @@ -15,7 +15,7 @@ class TwitchBot { public function __construct() { $this->logger = new Logger('TwitchBot'); - $this->logger->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG)); + $this->logger->pushHandler(new StreamHandler('php://stdout', Logger::INFO)); $this->token = TwitchToken::firstWhere('nick', 'localhorsttv'); if (!$this->token) { @@ -122,7 +122,20 @@ class TwitchBot { if ($text[0] != '!') return; $channel = Channel::firstWhere('twitch_chat', '=', $target); if (!$channel) return; - $this->logger->info('got command '.$text.' on channel '.$channel->title); + $this->handleChatCommand($channel, $msg); + } + + public function handleChatCommand(Channel $channel, IRCMessage $msg) { + $cmd = explode(' ', ltrim($msg->getText(), '!'), 2); + if (!isset($channel->chat_commands[$cmd[0]])) return; + $config = $channel->chat_commands[$cmd[0]]; + $this->logger->info('got command '.$cmd[0].' on channel '.$channel->title); + try { + $command = ChatCommand::create($this, $channel, $config); + $command->execute($cmd[1] ?? ''); + } catch (\Exception $e) { + $this->logger->warning('error executing command '.$cmd[0].' on channel '.$channel->title.': '.$e->getMessage()); + } } public function login() { diff --git a/database/migrations/2023_03_01_143514_channel_twitch_chat.php b/database/migrations/2023_03_01_143514_channel_twitch_chat.php index b9d3901..6429063 100644 --- a/database/migrations/2023_03_01_143514_channel_twitch_chat.php +++ b/database/migrations/2023_03_01_143514_channel_twitch_chat.php @@ -25,7 +25,7 @@ return new class extends Migration */ public function down() { - Schema::table('events', function(Blueprint $table) { + Schema::table('channels', function(Blueprint $table) { $table->dropColumn('twitch_chat'); }); } diff --git a/database/migrations/2023_03_02_084058_channel_commands.php b/database/migrations/2023_03_02_084058_channel_commands.php new file mode 100644 index 0000000..df639b1 --- /dev/null +++ b/database/migrations/2023_03_02_084058_channel_commands.php @@ -0,0 +1,32 @@ +text('chat_commands')->default('{}'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('channels', function(Blueprint $table) { + $table->dropColumn('chat_commands'); + }); + } +}; -- 2.39.2