From 06fbdc15c8db57590c9b6a38ee1f00d5f349cff9 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Sun, 21 Jan 2024 13:54:38 +0100 Subject: [PATCH] twitch chat bot controls --- app/Http/Controllers/ChannelController.php | 28 ++++++-- app/Models/TwitchBotCommand.php | 9 ++- app/TwitchBot/TwitchAppBot.php | 15 ---- app/TwitchBot/TwitchBot.php | 15 ++++ app/TwitchBot/TwitchChatBot.php | 1 + .../2024_01_21_115350_chat_bot_commands.php | 32 +++++++++ .../js/components/twitch-bot/Controls.js | 71 +++++++++++++------ resources/js/i18n/de.js | 8 ++- resources/js/i18n/en.js | 5 +- 9 files changed, 137 insertions(+), 47 deletions(-) create mode 100644 database/migrations/2024_01_21_115350_chat_bot_commands.php diff --git a/app/Http/Controllers/ChannelController.php b/app/Http/Controllers/ChannelController.php index da1f5ef..b735a6f 100644 --- a/app/Http/Controllers/ChannelController.php +++ b/app/Http/Controllers/ChannelController.php @@ -47,10 +47,12 @@ class ChannelController extends Controller { throw new \Exception('channel has no twitch chat set'); } $validatedData = $request->validate([ + 'bot_nick' => 'string', 'text' => 'string|required', ]); $this->authorize('editRestream', $channel); - TwitchBotCommand::chat($channel->twitch_chat, $validatedData['text'], $request->user()); + $nick = empty($validatedData['bot_nick']) ? 'localhorsttv' : $validatedData['bot_nick']; + TwitchBotCommand::chat($channel->twitch_chat, $validatedData['text'], $request->user(), $nick); return $channel->toJson(); } @@ -58,10 +60,18 @@ class ChannelController extends Controller { if (!$channel->twitch_chat) { throw new \Exception('channel has no twitch chat set'); } + $validatedData = $request->validate([ + 'bot_nick' => 'string', + ]); $this->authorize('editRestream', $channel); - $channel->join = true; + $nick = empty($validatedData['bot_nick']) ? 'localhorsttv' : $validatedData['bot_nick']; + if ($nick == 'localhorsttv') { + $channel->join = true; + } else if ($nick == 'horstiebot') { + $channel->chat = true; + } $channel->save(); - TwitchBotCommand::join($channel->twitch_chat, $request->user()); + TwitchBotCommand::join($channel->twitch_chat, $request->user(), $nick); return $channel->toJson(); } @@ -69,10 +79,18 @@ class ChannelController extends Controller { if (!$channel->twitch_chat) { throw new \Exception('channel has no twitch chat set'); } + $validatedData = $request->validate([ + 'bot_nick' => 'string', + ]); $this->authorize('editRestream', $channel); - $channel->join = false; + $nick = empty($validatedData['bot_nick']) ? 'localhorsttv' : $validatedData['bot_nick']; + if ($nick == 'localhorsttv') { + $channel->join = false; + } else if ($nick == 'horstiebot') { + $channel->chat = false; + } $channel->save(); - TwitchBotCommand::part($channel->twitch_chat, $request->user()); + TwitchBotCommand::part($channel->twitch_chat, $request->user(), $nick); return $channel->toJson(); } diff --git a/app/Models/TwitchBotCommand.php b/app/Models/TwitchBotCommand.php index 14cabf7..716b8d5 100644 --- a/app/Models/TwitchBotCommand.php +++ b/app/Models/TwitchBotCommand.php @@ -11,7 +11,7 @@ class TwitchBotCommand extends Model { use HasFactory; - public static function chat($channel, $text, User $user = null) { + public static function chat($channel, $text, User $user = null, $nick = 'localhorsttv') { $cmd = new TwitchBotCommand(); $cmd->command = 'chat'; $cmd->parameters = [ @@ -20,10 +20,11 @@ class TwitchBotCommand extends Model ]; $cmd->status = 'pending'; $cmd->user()->associate($user); + $cmd->bot_nick = $nick; $cmd->save(); } - public static function join($channel, User $user = null) { + public static function join($channel, User $user = null, $nick = 'localhorsttv') { $cmd = new TwitchBotCommand(); $cmd->command = 'join'; $cmd->parameters = [ @@ -31,10 +32,11 @@ class TwitchBotCommand extends Model ]; $cmd->status = 'pending'; $cmd->user()->associate($user); + $cmd->bot_nick = $nick; $cmd->save(); } - public static function part($channel, User $user = null) { + public static function part($channel, User $user = null, $nick = 'localhorsttv') { $cmd = new TwitchBotCommand(); $cmd->command = 'part'; $cmd->parameters = [ @@ -42,6 +44,7 @@ class TwitchBotCommand extends Model ]; $cmd->status = 'pending'; $cmd->user()->associate($user); + $cmd->bot_nick = $nick; $cmd->save(); } diff --git a/app/TwitchBot/TwitchAppBot.php b/app/TwitchBot/TwitchAppBot.php index 4e2c7d4..ce0f751 100644 --- a/app/TwitchBot/TwitchAppBot.php +++ b/app/TwitchBot/TwitchAppBot.php @@ -3,7 +3,6 @@ namespace App\TwitchBot; use App\Models\Channel; -use App\Models\TwitchBotCommand; class TwitchAppBot extends TwitchBot { @@ -52,18 +51,4 @@ class TwitchAppBot extends TwitchBot { } } - - private function listenCommands() { - $this->getLoop()->addPeriodicTimer(1, function () { - if (!$this->isReady()) return; - $command = TwitchBotCommand::where('status', '=', 'pending')->oldest()->first(); - if ($command) { - try { - $command->execute($this); - } catch (\Exception $e) { - } - } - }); - } - } diff --git a/app/TwitchBot/TwitchBot.php b/app/TwitchBot/TwitchBot.php index 79b6bf1..bb3724d 100644 --- a/app/TwitchBot/TwitchBot.php +++ b/app/TwitchBot/TwitchBot.php @@ -3,6 +3,7 @@ namespace App\TwitchBot; use App\Models\Channel; +use App\Models\TwitchBotCommand; use App\Models\TwitchToken; use Monolog\Handler\StreamHandler; use Monolog\Logger; @@ -169,6 +170,20 @@ class TwitchBot { } + protected function listenCommands() { + $this->getLoop()->addPeriodicTimer(1, function () { + if (!$this->isReady()) return; + $command = TwitchBotCommand::where('bot_nick', '=', $this->nick)->where('status', '=', 'pending')->oldest()->first(); + if ($command) { + try { + $command->execute($this); + } catch (\Exception $e) { + } + } + }); + } + + private $logger; private $nick; diff --git a/app/TwitchBot/TwitchChatBot.php b/app/TwitchBot/TwitchChatBot.php index 576bf04..7a6eb1c 100644 --- a/app/TwitchBot/TwitchChatBot.php +++ b/app/TwitchBot/TwitchChatBot.php @@ -20,6 +20,7 @@ class TwitchChatBot extends TwitchBot { ]; } $this->startTimer(); + $this->listenCommands(); } public function joinChannels() { diff --git a/database/migrations/2024_01_21_115350_chat_bot_commands.php b/database/migrations/2024_01_21_115350_chat_bot_commands.php new file mode 100644 index 0000000..513484c --- /dev/null +++ b/database/migrations/2024_01_21_115350_chat_bot_commands.php @@ -0,0 +1,32 @@ +string('bot_nick')->default('localhorsttv'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('twitch_bot_commands', function(Blueprint $table) { + $table->dropColumn('bot_nick'); + }); + } +}; diff --git a/resources/js/components/twitch-bot/Controls.js b/resources/js/components/twitch-bot/Controls.js index 1faa912..cc062e8 100644 --- a/resources/js/components/twitch-bot/Controls.js +++ b/resources/js/components/twitch-bot/Controls.js @@ -13,10 +13,11 @@ const Controls = () => { const { t } = useTranslation(); - const chat = React.useCallback(async text => { + const chat = React.useCallback(async (text, bot_nick) => { try { await axios.post(`/api/channels/${channel.id}/chat`, { text, + bot_nick, }); toastr.success(t('twitchBot.chatSuccess')); } catch (e) { @@ -24,9 +25,9 @@ const Controls = () => { } }, [channel, chatText, t]); - const join = React.useCallback(async () => { + const join = React.useCallback(async (bot_nick) => { try { - const rsp = await axios.post(`/api/channels/${channel.id}/join`); + const rsp = await axios.post(`/api/channels/${channel.id}/join`, { bot_nick }); setChannel(rsp.data); toastr.success(t('twitchBot.joinSuccess')); } catch (e) { @@ -34,9 +35,9 @@ const Controls = () => { } }, [channel, t]); - const part = React.useCallback(async () => { + const part = React.useCallback(async (bot_nick) => { try { - const rsp = await axios.post(`/api/channels/${channel.id}/part`); + const rsp = await axios.post(`/api/channels/${channel.id}/part`, { bot_nick }); setChannel(rsp.data); toastr.success(t('twitchBot.partSuccess')); } catch (e) { @@ -56,24 +57,40 @@ const Controls = () => { value={channel ? channel.id : ''} /> - {channel ? - - {t('twitchBot.join')} + {channel ? <> + + {t('twitchBot.joinApp')}
{ if (value) { - join(); + join('localhorsttv'); } else { - part(); + part('localhorsttv'); } }} value={channel.join} />
- : null} + + {t('twitchBot.joinChat')} +
+ { + if (value) { + join('horstiebot'); + } else { + part('horstiebot'); + } + }} + value={channel.chat} + /> +
+
+ : null} {channel ? @@ -86,16 +103,28 @@ const Controls = () => { }} value={chatText} /> - +
+ + +
: diff --git a/resources/js/i18n/de.js b/resources/js/i18n/de.js index 4b7e8dd..bb5c08c 100644 --- a/resources/js/i18n/de.js +++ b/resources/js/i18n/de.js @@ -487,18 +487,22 @@ export default { }, twitchBot: { channel: 'Channel', - chat: 'Chat', + chatApp: 'Chat als App Bot', + chatChat: 'Chat als Chat Bot', chatError: 'Fehler beim Senden', chatSuccess: 'Nachricht in Warteschlange', controls: 'Controls', heading: 'Twitch Bot', - join: 'Join', + joinApp: 'Join als App Bot', + joinChat: 'Join als Chat Bot', joinError: 'Fehler beim Betreten', joinSuccess: 'Betreten', noManagePermission: 'Du verfügst nicht über die notwendigen Berechtigungen, um den Twitch Bot zu administrieren.', partError: 'Fehler beim Verlassen', partSuccess: 'Verlassen', selectChannel: 'Bitte wählen einen Channel, den du verändern möchtest.', + sendApp: 'Als App Bot senden', + sendChat: 'Als Chat Bot senden', }, users: { discordTag: 'Discord Tag', diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js index 133f1dc..669c56e 100644 --- a/resources/js/i18n/en.js +++ b/resources/js/i18n/en.js @@ -492,13 +492,16 @@ export default { chatSuccess: 'Message queued', controls: 'Controls', heading: 'Twitch Bot', - join: 'Join', + joinApp: 'Join as App Bot', + joinChat: 'Join as Chat Bot', joinError: 'Error joining channel', joinSuccess: 'Joined', noManagePermission: 'You lack the required privileges to manage the twitch bot.', partError: 'Error parting channel', partSuccess: 'Parted', selectChannel: 'Please select a channel to manage.', + sendApp: 'Send as App Bot', + sendChat: 'Send as Chat Bot', }, users: { discordTag: 'Discord tag', -- 2.39.2