From 17015ca0827fa932e7fcb9486b2e8674562f03d1 Mon Sep 17 00:00:00 2001 From: Chris Woelk Date: Sat, 9 Apr 2022 23:33:43 +0200 Subject: [PATCH 1/8] Ignore ClientException on refresher --- src/Listeners/Twitch/Refresher/StandardRefresher.php | 9 ++++++++- src/Models/Twitch/EventSubEvents.php | 2 -- src/Service/Twitch/UsersClient.php | 1 - 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Listeners/Twitch/Refresher/StandardRefresher.php b/src/Listeners/Twitch/Refresher/StandardRefresher.php index a30efcc..f6e23a0 100644 --- a/src/Listeners/Twitch/Refresher/StandardRefresher.php +++ b/src/Listeners/Twitch/Refresher/StandardRefresher.php @@ -2,6 +2,7 @@ namespace Redbeed\OpenOverlay\Listeners\Twitch\Refresher; +use GuzzleHttp\Exception\ClientException; use Illuminate\Contracts\Queue\ShouldQueue; use Redbeed\OpenOverlay\Events\Twitch\RefresherEvent; use Redbeed\OpenOverlay\Exceptions\WrongConnectionTypeException; @@ -22,7 +23,13 @@ public function handle(RefresherEvent $event) } if (parent::saveSubscriber()) { - $this->refreshSubscriber($event->twitchConnection); + try { + $this->refreshSubscriber($event->twitchConnection); + }catch (ClientException $e) { + // ignore exception as it is not critical + // user auth token is not valid + report($e); + } } } } diff --git a/src/Models/Twitch/EventSubEvents.php b/src/Models/Twitch/EventSubEvents.php index c747b40..a4c58e8 100644 --- a/src/Models/Twitch/EventSubEvents.php +++ b/src/Models/Twitch/EventSubEvents.php @@ -5,8 +5,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Redbeed\OpenOverlay\Database\Factories\EventSubEventsFactory; -use Redbeed\OpenOverlay\Models\User\Connection; -use Redbeed\OpenOverlay\OpenOverlay; class EventSubEvents extends Model { diff --git a/src/Service/Twitch/UsersClient.php b/src/Service/Twitch/UsersClient.php index bcbc944..274131b 100644 --- a/src/Service/Twitch/UsersClient.php +++ b/src/Service/Twitch/UsersClient.php @@ -2,7 +2,6 @@ namespace Redbeed\OpenOverlay\Service\Twitch; -use GuzzleHttp\Exception\ClientException; use GuzzleHttp\RequestOptions; class UsersClient extends ApiClient From ff2946aca2efe183e94628d23081f7b2ac4e3d48 Mon Sep 17 00:00:00 2001 From: Chris Woelk Date: Wed, 13 Apr 2022 08:27:52 +0200 Subject: [PATCH 2/8] Introduce "Automations" Automations will replace all the not dynamic functions like "Bot Commands" or "Schuedle Bot Messages". Automations are way more dynamic. An Automations contains a trigger, filters, and actions. - A Trigger can be a Chat Message, Webhook call or any event you can think about - Filters will check if the incoming trigger is valid. (Is the chat message correct?) - Actions are things like a Chat Bot message, Websocket event or anything else Only if all filters are valid the actions will get called. --- composer.json | 4 + config/openoverlay.php | 12 -- .../Actions/TwitchChatBotMessage.php | 29 ++++ src/Automations/Actions/UsesVariables.php | 61 +++++++++ src/Automations/AutomationDispatcher.php | 33 +++++ src/Automations/AutomationHandler.php | 76 +++++++++++ .../AutomationsServiceProvider.php | 36 +++++ .../ChatMessage/ChatMessageContainsFilter.php | 63 +++++++++ .../ChatMessageContainsWithPatternFilter.php | 88 ++++++++++++ src/Automations/Filters/Filter.php | 51 +++++++ src/Automations/Triggers/Trigger.php | 27 ++++ .../Triggers/TwitchChatMessageTrigger.php | 29 ++++ src/ChatBot/Commands/BotCommand.php | 126 ------------------ src/ChatBot/Commands/HelloWorldBotCommand.php | 19 --- src/ChatBot/Commands/ShoutOutBotCommand.php | 48 ------- src/ChatBot/Commands/SimpleBotCommands.php | 49 ------- src/ChatBot/Twitch/ConnectionHandler.php | 21 +-- .../Commands/Make/Stubs/BotCommand.stub | 18 --- src/Console/ConsoleServiceProvider.php | 5 - src/EventServiceProvider.php | 10 ++ src/Exceptions/AutomationFilterNotValid.php | 8 ++ .../Twitch/NewSubscriberListener.php | 2 +- src/OpenOverlayServiceProvider.php | 2 + src/Service/Twitch/ChannelsClient.php | 10 ++ src/Service/Twitch/UsersClient.php | 17 +++ src/Support/Facades/Automation.php | 17 +++ src/{ => Support}/Facades/OpenOverlay.php | 2 +- src/Support/helpers.php | 14 ++ 28 files changed, 579 insertions(+), 298 deletions(-) create mode 100644 src/Automations/Actions/TwitchChatBotMessage.php create mode 100644 src/Automations/Actions/UsesVariables.php create mode 100644 src/Automations/AutomationDispatcher.php create mode 100644 src/Automations/AutomationHandler.php create mode 100644 src/Automations/AutomationsServiceProvider.php create mode 100644 src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php create mode 100644 src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php create mode 100644 src/Automations/Filters/Filter.php create mode 100644 src/Automations/Triggers/Trigger.php create mode 100644 src/Automations/Triggers/TwitchChatMessageTrigger.php delete mode 100644 src/ChatBot/Commands/BotCommand.php delete mode 100644 src/ChatBot/Commands/HelloWorldBotCommand.php delete mode 100644 src/ChatBot/Commands/ShoutOutBotCommand.php delete mode 100644 src/ChatBot/Commands/SimpleBotCommands.php delete mode 100644 src/Console/Commands/Make/Stubs/BotCommand.stub create mode 100644 src/Exceptions/AutomationFilterNotValid.php create mode 100644 src/Support/Facades/Automation.php rename src/{ => Support}/Facades/OpenOverlay.php (85%) create mode 100644 src/Support/helpers.php diff --git a/composer.json b/composer.json index 7a0f50f..35f1f9b 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "homepage": "https://github.com/redbeed/openoverlay", "keywords": ["Laravel", "OpenOverlay", "twitch", "Eventsub", "Bot", "IRC"], "require": { + "php": "^8.0", "illuminate/support": "~8|~9", "guzzlehttp/guzzle": "^7.2", "ext-json": "*", @@ -26,6 +27,9 @@ "nunomaduro/phpinsights": "^1.14" }, "autoload": { + "files": [ + "src/Support/helpers.php" + ], "psr-4": { "Redbeed\\OpenOverlay\\": "src/", "Redbeed\\OpenOverlay\\Database\\": "database/" diff --git a/config/openoverlay.php b/config/openoverlay.php index 8efce82..6d397c2 100644 --- a/config/openoverlay.php +++ b/config/openoverlay.php @@ -72,18 +72,6 @@ ], 'bot' => [ - 'commands' => [ - - 'simple' => [ - '!hello' => 'Hello %username%! How are you doing?', - ], - - 'advanced' => [ - \Redbeed\OpenOverlay\ChatBot\Commands\HelloWorldBotCommand::class, - \Redbeed\OpenOverlay\ChatBot\Commands\ShoutOutBotCommand::class, - ] - ], - 'schedules' => [ \Redbeed\OpenOverlay\Console\Scheduling\MadeWithChatBotScheduling::class, ] diff --git a/src/Automations/Actions/TwitchChatBotMessage.php b/src/Automations/Actions/TwitchChatBotMessage.php new file mode 100644 index 0000000..73f26d1 --- /dev/null +++ b/src/Automations/Actions/TwitchChatBotMessage.php @@ -0,0 +1,29 @@ +connection = $connection; + $this->message = $message; + } + + public function handle() + { + Artisan::call(SendMessageCommand::class, [ + 'userId' => $this->connection->user->id, + 'message' => $this->replaceInString($this->message), + ]); + } +} diff --git a/src/Automations/Actions/UsesVariables.php b/src/Automations/Actions/UsesVariables.php new file mode 100644 index 0000000..c8a78d9 --- /dev/null +++ b/src/Automations/Actions/UsesVariables.php @@ -0,0 +1,61 @@ +variables = array_merge_recursive($this->variables, $variables); + } + + public function getVariables($filterName = ''): array + { + if ($filterName) { + return $this->filterVariables($filterName); + } + + return $this->variables; + } + + private function filterVariables(string $filterName): array + { + $filtered = []; + foreach ($this->variables as $name => $value) { + if (str_contains($name, $filterName)) { + $filtered[$name] = $value; + } + } + + return $filtered; + } + + protected function replaceInString(string $string): string + { + return strtr($string, $this->makeReplacements($string)); + } + + protected function makeReplacements(string $string): array + { + $replacements = []; + foreach ($this->variables as $key => $value) { + $keyPattern = ':' . $key; + + if (Str::contains($string, $keyPattern)) { + + if ($this->variables[$key] instanceof \Closure) { + // If the variable is a closure, we will execute it and replace the key with the result. + $this->variables[$key] = $this->variables[$key](); + } + + $replacements[$keyPattern] = $this->variables[$key]; + } + } + + return $replacements; + } +} diff --git a/src/Automations/AutomationDispatcher.php b/src/Automations/AutomationDispatcher.php new file mode 100644 index 0000000..362d2d9 --- /dev/null +++ b/src/Automations/AutomationDispatcher.php @@ -0,0 +1,33 @@ +each(function ($handler) use ($trigger) { + $this->add($trigger, $handler); + }); + } + + $this->automations[$trigger][] = $handlerClass; + } + + public function trigger(mixed $trigger) + { + if (empty($this->automations[$trigger::class])) { + return; + } + + foreach ($this->automations[$trigger::class] as $automations) { + collect($automations)->each(function ($automation) use ($trigger) { + $automation = new $automation($trigger); + $automation->handle(); + }); + } + } +} diff --git a/src/Automations/AutomationHandler.php b/src/Automations/AutomationHandler.php new file mode 100644 index 0000000..3f828ae --- /dev/null +++ b/src/Automations/AutomationHandler.php @@ -0,0 +1,76 @@ +trigger = $trigger; + } + + /** + * @return Filter[] + */ + public function filters(): array + { + return []; + } + + /** + * @return array + */ + public function actions(): array + { + return []; + } + + public function handle() + { + $variables = []; + + foreach ($this->filters() as $filter) { + $response = $filter->handle($this->trigger); + + if ($response === false) { + // Filter failed stop the automation + return; + } + + $variables = array_merge_recursive( + $variables, $filter->variables() + ); + } + + foreach ($this->actions() as $action) { + $traits = class_uses($action); + + // Check if the action uses the UsesVariables trait and if so, add the variables to the action + if (in_array(UsesVariables::class, $traits)) { + $action->addVariables($variables); + } + + $action->handle(); + } + } + + #[ArrayShape(['trigger' => "string", 'options' => "array"])] + public static function triggerConfig(string $triggerClass, array $options = []) + { + return ['trigger' => $triggerClass, 'options' => $options]; + } + + #[ArrayShape(['action' => "string", 'options' => "array"])] + public static function actionConfig(string $actionClass, array $options = []) + { + return ['action' => $actionClass, 'options' => $options]; + } +} diff --git a/src/Automations/AutomationsServiceProvider.php b/src/Automations/AutomationsServiceProvider.php new file mode 100644 index 0000000..90220d9 --- /dev/null +++ b/src/Automations/AutomationsServiceProvider.php @@ -0,0 +1,36 @@ +app->singleton('automations', function () { + return new AutomationDispatcher(); + }); + + $this->booting(function () { + $automations = $this->getAutomations(); + + foreach ($automations as $trigger => $handler) { + Automation::add($trigger, $handler); + } + }); + } + + public function getAutomations(): array + { + return $this->automations; + } + + public function boot() + { + // + } +} diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php new file mode 100644 index 0000000..28d4fd8 --- /dev/null +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php @@ -0,0 +1,63 @@ +needle = $needle; + } + + #[Pure] + public function validate(): bool + { + return Str::contains($this->trigger->message->message, $this->needle); + } + + /** + * @throws AutomationFilterNotValid + */ + public function validTrigger() + { + parent::validTrigger(); + + if (!($this->trigger instanceof TwitchChatMessageTrigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of TwitchChatMessageTrigger but is ' . get_class($this->trigger)); + } + } + + public function variables(): array + { + return [ + 'username' => $this->trigger->message->username, + 'twitchUrl' => 'https://www.twitch.tv/' . $this->trigger->message->username, + 'game' => function () { + try { + return (new UsersClient())->lastGame($this->trigger->message->username); + } catch (ClientException) { + return ''; + } + }, + ]; + } +} diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php new file mode 100644 index 0000000..1512646 --- /dev/null +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php @@ -0,0 +1,88 @@ +needle = $needle; + $this->regexPatterns = $regexPatterns; + } + + public function validate(): bool + { + if (!Str::contains($this->trigger->message->message, $this->needle)) { + return false; + } + + return preg_match($this->regex(), $this->trigger->message->message); + } + + private function regex(): string + { + $regex = collect($this->regexPatterns) + ->mapWithKeys(function ($regex, $key) { + return [$key => '(?<' . $key . '>' . $regex . ')']; + }) + ->prepend($this->needle) + ->implode(' '); + + return '/' . $regex . '/'; + } + + private function matches(): array + { + $matches = []; + preg_match($this->regex(), $this->trigger->message->message, $matches); + + return array_filter($matches, "is_string", ARRAY_FILTER_USE_KEY); + } + + /** + * @throws AutomationFilterNotValid + */ + public function validTrigger() + { + parent::validTrigger(); + + if (!($this->trigger instanceof TwitchChatMessageTrigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of TwitchChatMessageTrigger but is ' . get_class($this->trigger)); + } + } + + public function variables(): array + { + return array_merge_recursive([ + 'username' => $this->trigger->message->username, + 'game' => function () { + try { + return (new UsersClient())->lastGame($this->trigger->message->username); + } catch (ClientException) { + return ''; + } + }, + ], $this->matches()); + } +} diff --git a/src/Automations/Filters/Filter.php b/src/Automations/Filters/Filter.php new file mode 100644 index 0000000..b7e4b10 --- /dev/null +++ b/src/Automations/Filters/Filter.php @@ -0,0 +1,51 @@ +trigger = $trigger; + $this->validTrigger(); + + return $this->validate(); + } + + public function validate(): bool + { + return true; + } + + /** + * @throws AutomationFilterNotValid + */ + public function validTrigger() + { + if (!($this->trigger instanceof Trigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of Trigger but is ' . get_class($this->trigger)); + } + } + + public function variables(): array + { + return []; + } +} diff --git a/src/Automations/Triggers/Trigger.php b/src/Automations/Triggers/Trigger.php new file mode 100644 index 0000000..ae406f6 --- /dev/null +++ b/src/Automations/Triggers/Trigger.php @@ -0,0 +1,27 @@ +options = $options; + } +} diff --git a/src/Automations/Triggers/TwitchChatMessageTrigger.php b/src/Automations/Triggers/TwitchChatMessageTrigger.php new file mode 100644 index 0000000..bba2b49 --- /dev/null +++ b/src/Automations/Triggers/TwitchChatMessageTrigger.php @@ -0,0 +1,29 @@ +message = $message; + } + + public function valid(): bool + { + if (empty($this->options['message'])) { + return true; + } + + return Str::contains($this->message->message, $this->options['message']); + } +} diff --git a/src/ChatBot/Commands/BotCommand.php b/src/ChatBot/Commands/BotCommand.php deleted file mode 100644 index 71955b7..0000000 --- a/src/ChatBot/Commands/BotCommand.php +++ /dev/null @@ -1,126 +0,0 @@ -connection = $connectionHandler; - } - - public function handle(ChatMessage $chatMessage) - { - if ($this->messageValid($chatMessage->message) === false) { - return; - } - - // build & check parameters - $this->buildParameters($chatMessage->message); - if ($this->parametersValid() === false) { - return; - } - - $this->connection->sendChatMessage( - $chatMessage->channel, - $this->response($chatMessage) - ); - } - - protected function parametersValid(): bool - { - $keys = $this->parametersKeys(); - - return count($keys) === count($this->parameters); - } - - protected function buildParameters(string $message) - { - $keys = $this->parametersKeys(); - if (count($keys) <= 0) { - return; - } - - $valuesOnly = explode(' ', $message, 2); - if (count($valuesOnly) !== 2) { - return; - } - - $values = explode(' ', $valuesOnly[1], count($keys)); - foreach ($values as $valueKey => $value) { - $this->parameters[$keys[$valueKey]] = $value; - } - } - - protected function parameter(string $key): ?string - { - if (isset($this->parameters[$key])) { - return $this->parameters[$key]; - } - - return null; - } - - public function parametersKeys(): array - { - preg_match_all("/\{(.+?)\}/m", $this->signature, $matches); - if (count($matches) < 2) { - return []; - } - - return $matches[1]; - } - - public function response(ChatMessage $chatMessage): string - { - return ''; - } - - protected function command(): string - { - return head(explode(' ', $this->signature)); - } - - protected function messageValid(string $message): bool - { - if ($this->messageStartsWith($message, $this->command())) { - return true; - } - - if (is_array($this->aliasCommands) && count($this->aliasCommands)) { - foreach ($this->aliasCommands as $aliasCommand) { - if ($this->messageStartsWith($message, $aliasCommand)) { - return true; - } - } - } - - return false; - } - - protected function messageStartsWith(string $message, string $command): bool - { - // perfect match - if (trim($command) === trim($message)) { - return true; - } - - // match with space - return substr(trim($message), 0, strlen(trim($command) . ' ')) === trim($command) . ' '; - } -} diff --git a/src/ChatBot/Commands/HelloWorldBotCommand.php b/src/ChatBot/Commands/HelloWorldBotCommand.php deleted file mode 100644 index 1e49dd2..0000000 --- a/src/ChatBot/Commands/HelloWorldBotCommand.php +++ /dev/null @@ -1,19 +0,0 @@ -username, - 'It is ' . Carbon::now()->toString() . '... I think', - ]); - } -} diff --git a/src/ChatBot/Commands/ShoutOutBotCommand.php b/src/ChatBot/Commands/ShoutOutBotCommand.php deleted file mode 100644 index e1ff204..0000000 --- a/src/ChatBot/Commands/ShoutOutBotCommand.php +++ /dev/null @@ -1,48 +0,0 @@ -parameter('username'), '@'); - - $usersClient = new UsersClient(); - try { - $users = $usersClient->byUsername($username); - } catch (ClientException $exception) { - return ''; - } - - $user = head($users['data']); - if ($user['login'] !== strtolower($username)) { - return ''; - } - - $response = [ - 'Don“t forget to checkout ' . $user['display_name'] . ' www.twitch.tv/' . $user['login'] - ]; - - try { - $channelClient = new ChannelsClient(); - $channels = $channelClient->get($user['id']); - $channel = head($channels['data']); - - if (!empty($channel['game_id'])) { - $response[] = '- last playing "' . $channel['game_name'] . '"'; - } - } catch (ClientException $exception) { - // ignore - } - - return implode(' ', $response); - } -} diff --git a/src/ChatBot/Commands/SimpleBotCommands.php b/src/ChatBot/Commands/SimpleBotCommands.php deleted file mode 100644 index e97c0e4..0000000 --- a/src/ChatBot/Commands/SimpleBotCommands.php +++ /dev/null @@ -1,49 +0,0 @@ -simpleCommands = config('openoverlay.bot.commands.simple'); - } - - public function handle(ChatMessage $chatMessage) - { - foreach ($this->simpleCommands as $command => $responseMessage) { - $this->handleSimpleCommand($chatMessage, $command, $responseMessage); - } - } - - public function handleSimpleCommand(ChatMessage $chatMessage, string $command, string $responseMessage): void - { - if ($this->messageStartsWith($chatMessage->message, $command) === false) { - return; - } - - $this->connection->sendChatMessage( - $chatMessage->channel, - $this->responseSimpleCommand($chatMessage, $responseMessage) - ); - } - - public function responseSimpleCommand(ChatMessage $chatMessage, string $message): string - { - $replace = [ - '%username%' => $chatMessage->username, - ]; - - return str_replace(array_keys($replace), array_values($replace), $message); - } -} diff --git a/src/ChatBot/Twitch/ConnectionHandler.php b/src/ChatBot/Twitch/ConnectionHandler.php index cced429..b7ceb53 100644 --- a/src/ChatBot/Twitch/ConnectionHandler.php +++ b/src/ChatBot/Twitch/ConnectionHandler.php @@ -3,13 +3,11 @@ namespace Redbeed\OpenOverlay\ChatBot\Twitch; +use Illuminate\Support\Facades\Log; use Ratchet\Client\WebSocket; -use Redbeed\OpenOverlay\ChatBot\Commands\BotCommand; -use Redbeed\OpenOverlay\ChatBot\Commands\SimpleBotCommands; use Redbeed\OpenOverlay\Events\Twitch\BotTokenExpires; use Redbeed\OpenOverlay\Events\Twitch\ChatMessageReceived; use Redbeed\OpenOverlay\Models\BotConnection; -use Redbeed\OpenOverlay\Models\Twitch\Emote; use Redbeed\OpenOverlay\Models\User\Connection; use Redbeed\OpenOverlay\Service\Twitch\ChatEmotesClient; @@ -23,9 +21,6 @@ class ConnectionHandler /** @var BotConnection */ private $bot; - /** @var BotCommand[] */ - private $customCommands = []; - /** @var string[] */ private $joinedChannel = []; @@ -177,6 +172,7 @@ public function chatMessageReceived(string $message): void try { event(new ChatMessageReceived($model)); } catch (\Exception $exception) { + Log::error($exception); $this->write(" -> EVENT ERROR: " . $exception->getMessage(), 'ERROR'); } } @@ -246,19 +242,6 @@ public function sendChatMessage(string $channelName, string $message): void $this->write($message); } - public function initCustomCommands(): void - { - /** @var BotCommand[] $commandClasses */ - $commandClasses = config('openoverlay.bot.commands.advanced'); - - // add simple command handler - $commandClasses[] = SimpleBotCommands::class; - - foreach ($commandClasses as $commandClass) { - $this->customCommands[] = new $commandClass($this); - } - } - protected function write(string $output, string $title = 'OpenOverlay', $newLine = true) { $title = !empty($title) ? '[' . $title . ']' : ''; diff --git a/src/Console/Commands/Make/Stubs/BotCommand.stub b/src/Console/Commands/Make/Stubs/BotCommand.stub deleted file mode 100644 index 25c91b6..0000000 --- a/src/Console/Commands/Make/Stubs/BotCommand.stub +++ /dev/null @@ -1,18 +0,0 @@ -message)); + }); + return $listen; } + public function autoShoutOutListener() { $modules = config('openoverlay.modules', []); diff --git a/src/Exceptions/AutomationFilterNotValid.php b/src/Exceptions/AutomationFilterNotValid.php new file mode 100644 index 0000000..65395bf --- /dev/null +++ b/src/Exceptions/AutomationFilterNotValid.php @@ -0,0 +1,8 @@ + $subscriberData['user_name'], 'tier' => $subscriberData['user_name'], - 'tier_name' => $subscriberData['plan_name'], + 'tier_name' => $subscriberData['plan_name'] ?? '', 'is_gift' => $subscriberData['is_gift'], ]); } diff --git a/src/OpenOverlayServiceProvider.php b/src/OpenOverlayServiceProvider.php index db6b249..a9fd4d6 100644 --- a/src/OpenOverlayServiceProvider.php +++ b/src/OpenOverlayServiceProvider.php @@ -7,6 +7,7 @@ use Redbeed\OpenOverlay\Console\ConsoleServiceProvider; use Redbeed\OpenOverlay\Console\Scheduling\ChatBotScheduling; use Redbeed\OpenOverlay\Models\BotConnection; +use Redbeed\OpenOverlay\Automations\AutomationsServiceProvider; class OpenOverlayServiceProvider extends ServiceProvider { @@ -38,6 +39,7 @@ public function register(): void { $this->app->register(EventServiceProvider::class); $this->app->register(ConsoleServiceProvider::class); + $this->app->register(AutomationsServiceProvider::class); $this->mergeConfigFrom(__DIR__ . '/../config/openoverlay.php', 'openoverlay'); diff --git a/src/Service/Twitch/ChannelsClient.php b/src/Service/Twitch/ChannelsClient.php index 2a007b4..4bc3267 100644 --- a/src/Service/Twitch/ChannelsClient.php +++ b/src/Service/Twitch/ChannelsClient.php @@ -2,7 +2,10 @@ namespace Redbeed\OpenOverlay\Service\Twitch; +use GuzzleHttp\Exception\ClientException; use GuzzleHttp\RequestOptions; +use Illuminate\Support\Arr; +use Illuminate\Support\Facades\Log; class ChannelsClient extends ApiClient { @@ -17,4 +20,11 @@ public function get(string $broadcasterId): array ]) ->request('GET', 'channels'); } + + public function lastGame(string $broadcasterId) { + $channels = (new self)->get($broadcasterId); + $channel = head($channels['data']); + + return $channel['game_name']; + } } diff --git a/src/Service/Twitch/UsersClient.php b/src/Service/Twitch/UsersClient.php index 274131b..b5fb295 100644 --- a/src/Service/Twitch/UsersClient.php +++ b/src/Service/Twitch/UsersClient.php @@ -3,6 +3,8 @@ namespace Redbeed\OpenOverlay\Service\Twitch; use GuzzleHttp\RequestOptions; +use Illuminate\Support\Arr; +use Illuminate\Support\Facades\Log; class UsersClient extends ApiClient { @@ -77,4 +79,19 @@ public function allFollowers(string $twitchUserId): array return $firstResponse; } + + public static function lastGame(string $username): string + { + $users = (new self)->byUsername($username); + if (empty($users['data']) || count($users['data']) === 0) { + return ''; + } + + $user = Arr::first($users['data']); + if (empty($user) || empty($user['id'])) { + return ''; + } + + return (new ChannelsClient())->lastGame($user['id']); + } } diff --git a/src/Support/Facades/Automation.php b/src/Support/Facades/Automation.php new file mode 100644 index 0000000..1432961 --- /dev/null +++ b/src/Support/Facades/Automation.php @@ -0,0 +1,17 @@ +trigger(...$args); + } +} From d1bf977ca7501df1d8dee3991f540aac9765f872 Mon Sep 17 00:00:00 2001 From: Chris Woelk Date: Wed, 13 Apr 2022 11:45:52 +0200 Subject: [PATCH 3/8] - Add Schedule trigger & filter - Forward Chatmessage (Bot & Channel user) to actions if needed --- .../Actions/TwitchChatBotMessage.php | 11 ++--- .../Actions/TwitchRandomChatBotMessage.php | 33 +++++++++++++++ .../Actions/UseTwitchChatMessage.php | 40 +++++++++++++++++++ .../{UsesVariables.php => UseVariables.php} | 2 +- src/Automations/AutomationHandler.php | 15 +++++-- .../AutomationsServiceProvider.php | 9 ++++- .../ChatMessage/ChatMessageContainsFilter.php | 14 ++++++- .../ChatMessageContainsWithPatternFilter.php | 14 ++++++- src/Automations/Filters/FrequencyFilter.php | 32 +++++++++++++++ src/Automations/Triggers/ScheduleTrigger.php | 15 +++++++ src/ChatBot/Twitch/ChatMessage.php | 36 +++++++++++------ src/ChatBot/Twitch/ConnectionHandler.php | 32 +++++---------- src/Console/Commands/ChatBot/StartCommand.php | 2 - 13 files changed, 204 insertions(+), 51 deletions(-) create mode 100644 src/Automations/Actions/TwitchRandomChatBotMessage.php create mode 100644 src/Automations/Actions/UseTwitchChatMessage.php rename src/Automations/Actions/{UsesVariables.php => UseVariables.php} (98%) create mode 100644 src/Automations/Filters/FrequencyFilter.php create mode 100644 src/Automations/Triggers/ScheduleTrigger.php diff --git a/src/Automations/Actions/TwitchChatBotMessage.php b/src/Automations/Actions/TwitchChatBotMessage.php index 73f26d1..535f5b3 100644 --- a/src/Automations/Actions/TwitchChatBotMessage.php +++ b/src/Automations/Actions/TwitchChatBotMessage.php @@ -8,21 +8,22 @@ class TwitchChatBotMessage { - use UsesVariables; + use UseVariables; + use UseTwitchChatMessage; private Connection $connection; private string $message; - public function __construct(Connection $connection, string $message) + public function __construct(string $message) { - $this->connection = $connection; $this->message = $message; } public function handle() { - Artisan::call(SendMessageCommand::class, [ - 'userId' => $this->connection->user->id, + Artisan::queue(SendMessageCommand::class, [ + 'userId' => $this->getUser()->id, + '--botId' => $this->getBot()->id, 'message' => $this->replaceInString($this->message), ]); } diff --git a/src/Automations/Actions/TwitchRandomChatBotMessage.php b/src/Automations/Actions/TwitchRandomChatBotMessage.php new file mode 100644 index 0000000..e0b4b0f --- /dev/null +++ b/src/Automations/Actions/TwitchRandomChatBotMessage.php @@ -0,0 +1,33 @@ +messages = $messages; + } + + public function handle() + { + Artisan::queue(SendMessageCommand::class, [ + 'userId' => $this->getUser()->id, + '--botId' => $this->getBot()->id, + 'message' => $this->replaceInString(Arr::random($this->messages)), + ]); + } +} diff --git a/src/Automations/Actions/UseTwitchChatMessage.php b/src/Automations/Actions/UseTwitchChatMessage.php new file mode 100644 index 0000000..2112767 --- /dev/null +++ b/src/Automations/Actions/UseTwitchChatMessage.php @@ -0,0 +1,40 @@ +chatMessage = $chatMessage; + } + + public function setBotConnection(BotConnection $botConnection): void + { + $this->botConnection = $botConnection; + } + + public function setUser(User $user): void + { + $this->user = $user; + } + + protected function getBot(): ?BotConnection + { + return $this->botConnection ?: $this->chatMessage?->bot; + } + + protected function getUser(): ?User + { + return $this->user ?: $this->chatMessage?->channelUser; + } +} diff --git a/src/Automations/Actions/UsesVariables.php b/src/Automations/Actions/UseVariables.php similarity index 98% rename from src/Automations/Actions/UsesVariables.php rename to src/Automations/Actions/UseVariables.php index c8a78d9..ad93b06 100644 --- a/src/Automations/Actions/UsesVariables.php +++ b/src/Automations/Actions/UseVariables.php @@ -4,7 +4,7 @@ use Illuminate\Support\Str; -trait UsesVariables +trait UseVariables { private array $variables = []; diff --git a/src/Automations/AutomationHandler.php b/src/Automations/AutomationHandler.php index 3f828ae..0173397 100644 --- a/src/Automations/AutomationHandler.php +++ b/src/Automations/AutomationHandler.php @@ -4,13 +4,17 @@ use Illuminate\Support\Facades\Log; use JetBrains\PhpStorm\ArrayShape; -use Redbeed\OpenOverlay\Automations\Actions\UsesVariables; +use Redbeed\OpenOverlay\Automations\Actions\UseTwitchChatMessage; +use Redbeed\OpenOverlay\Automations\Actions\UseVariables; use Redbeed\OpenOverlay\Automations\Filters\Filter; +use Redbeed\OpenOverlay\Automations\Triggers\Trigger; +use Redbeed\OpenOverlay\Automations\Triggers\TwitchChatMessageTrigger; class AutomationHandler { - private array $trigger = []; + /** @var Trigger */ + private $trigger; public function __construct($trigger) { @@ -54,10 +58,15 @@ public function handle() $traits = class_uses($action); // Check if the action uses the UsesVariables trait and if so, add the variables to the action - if (in_array(UsesVariables::class, $traits)) { + if (in_array(UseVariables::class, $traits)) { $action->addVariables($variables); } + // Check if the action uses the UsesTwitchChatMessage trait and if so, add the message to the action + if (in_array(UseTwitchChatMessage::class, $traits) && $this->trigger instanceof TwitchChatMessageTrigger) { + $action->setChatMessage($this->trigger->message); + } + $action->handle(); } } diff --git a/src/Automations/AutomationsServiceProvider.php b/src/Automations/AutomationsServiceProvider.php index 90220d9..a6b2c34 100644 --- a/src/Automations/AutomationsServiceProvider.php +++ b/src/Automations/AutomationsServiceProvider.php @@ -2,7 +2,10 @@ namespace Redbeed\OpenOverlay\Automations; +use Illuminate\Console\Scheduling\Schedule; +use Illuminate\Support\Facades\Log; use Illuminate\Support\ServiceProvider; +use Redbeed\OpenOverlay\Automations\Triggers\ScheduleTrigger; use Redbeed\OpenOverlay\Support\Facades\Automation; class AutomationsServiceProvider extends ServiceProvider @@ -31,6 +34,10 @@ public function getAutomations(): array public function boot() { - // + $this->callAfterResolving(Schedule::class, function (Schedule $schedule) { + $schedule->call(function () { + \automation(new ScheduleTrigger()); + })->everyMinute(); + }); } } diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php index 28d4fd8..a1b0f2b 100644 --- a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php @@ -17,21 +17,31 @@ class ChatMessageContainsFilter extends Filter public static string $description = 'Filter chat messages by string '; private string $needle; + private bool $caseSensitive; /** * @var TwitchChatMessageTrigger */ protected $trigger; - public function __construct(string $needle) + public function __construct(string $needle, bool $caseSensitive = false) { $this->needle = $needle; + $this->caseSensitive = $caseSensitive; } #[Pure] public function validate(): bool { - return Str::contains($this->trigger->message->message, $this->needle); + $message = $this->trigger->message->message; + $needle = $this->needle; + + if (!$this->caseSensitive) { + $message = Str::lower($message); + $needle = Str::lower($needle); + } + + return Str::contains($message, $needle); } /** diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php index 1512646..b80a883 100644 --- a/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php @@ -15,6 +15,7 @@ class ChatMessageContainsWithPatternFilter extends Filter public static string $description = 'Filter chat messages by string '; private string $needle; + private bool $caseSensitive; /** @var string[] */ private array $regexPatterns; @@ -25,15 +26,24 @@ class ChatMessageContainsWithPatternFilter extends Filter protected $trigger; - public function __construct(string $needle, array $regexPatterns) + public function __construct(string $needle, array $regexPatterns, bool $needleCaseSensitive = false) { $this->needle = $needle; $this->regexPatterns = $regexPatterns; + $this->caseSensitive = $needleCaseSensitive; } public function validate(): bool { - if (!Str::contains($this->trigger->message->message, $this->needle)) { + $message = $this->trigger->message->message; + $needle = $this->needle; + + if (!$this->caseSensitive) { + $message = Str::lower($message); + $needle = Str::lower($needle); + } + + if (!Str::contains($message, $needle)) { return false; } diff --git a/src/Automations/Filters/FrequencyFilter.php b/src/Automations/Filters/FrequencyFilter.php new file mode 100644 index 0000000..f1aa7ae --- /dev/null +++ b/src/Automations/Filters/FrequencyFilter.php @@ -0,0 +1,32 @@ +trigger instanceof ScheduleTrigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of ScheduleTrigger but is ' . get_class($this->trigger)); + } + } + + public function validate(): bool + { + return (new CronExpression($this->expression))->isDue($this->trigger->date->toDateTimeString()); + } +} diff --git a/src/Automations/Triggers/ScheduleTrigger.php b/src/Automations/Triggers/ScheduleTrigger.php new file mode 100644 index 0000000..b92a16c --- /dev/null +++ b/src/Automations/Triggers/ScheduleTrigger.php @@ -0,0 +1,15 @@ +date = now(); + } +} diff --git a/src/ChatBot/Twitch/ChatMessage.php b/src/ChatBot/Twitch/ChatMessage.php index 98e9dd7..266a17e 100644 --- a/src/ChatBot/Twitch/ChatMessage.php +++ b/src/ChatBot/Twitch/ChatMessage.php @@ -2,38 +2,48 @@ namespace Redbeed\OpenOverlay\ChatBot\Twitch; +use http\Client\Curl\User; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; +use Redbeed\OpenOverlay\Models\BotConnection; use Redbeed\OpenOverlay\Models\Twitch\Emote; +use Redbeed\OpenOverlay\Models\User\Connection; class ChatMessage { - /** @var string */ - public $username; + public string $username; - /** @var string */ - public $channel; + public string $channel; - /** @var string */ - public $message; + public string $message; /** @var Emote[] */ - public $possibleEmotes; + public array $possibleEmotes; - public function __construct(string $channel, string $username, string $message) + public ?\Illuminate\Foundation\Auth\User $channelUser; + public ?BotConnection $bot; + + public function __construct(string $channel, string $username, string $message, ?BotConnection $bot = null) { $this->channel = $channel; $this->username = trim($username); $this->message = trim($message); + + $this->bot = $bot; + if ($this->bot) { + $this->channelUser = $this->bot->users()->where('name', $this->channel)->first(); + } } - public static function parseIRCMessage(string $message): ?ChatMessage + public static function parseIRCMessage(BotConnection $bot, string $message): ?ChatMessage { try { preg_match("/:(.*)\!.*#(\S+) :(.*)/", $message, $matches); + $message = new ChatMessage($matches[2], $matches[1], $matches[3], $bot); - return new ChatMessage($matches[2], $matches[1], $matches[3]); + return $message; } catch (\Exception $exception) { - echo $exception->getMessage() . "\r\n"; + Log::error($exception); } return null; @@ -44,7 +54,7 @@ public function toHtml(string $emoteSize = Emote::IMAGE_SIZE_MD): string $emoteList = collect($this->possibleEmotes) ->map(function (Emote $emote) use ($emoteSize) { $name = htmlspecialchars_decode($emote->name); - $regex = '/'.preg_quote($name, '/') . '(\s|$)/'; + $regex = '/' . preg_quote($name, '/') . '(\s|$)/'; if (@preg_match($regex, null) === false) { echo "Emote Regex '" . $regex . "' is invalid \r\n"; @@ -52,7 +62,7 @@ public function toHtml(string $emoteSize = Emote::IMAGE_SIZE_MD): string } return [ - 'name' => $regex, + 'name' => $regex, 'image' => '' . Str::slug($emote->name) . ' ', ]; }); diff --git a/src/ChatBot/Twitch/ConnectionHandler.php b/src/ChatBot/Twitch/ConnectionHandler.php index b7ceb53..e45df3a 100644 --- a/src/ChatBot/Twitch/ConnectionHandler.php +++ b/src/ChatBot/Twitch/ConnectionHandler.php @@ -57,20 +57,20 @@ public static function withPrivateMessageHandler(WebSocket $connection): Connect public function privateMessageHandler(string $message): void { // if is chat message - if (strpos($message, 'PRIVMSG') !== false) { + if (str_contains($message, 'PRIVMSG')) { $this->chatMessageReceived($message); } } public function basicMessageHandler(string $message): void { - // ignore for basic handler - if (strpos($message, 'PRIVMSG') !== false) { + // if is chat message starts with PRIVMSG ignore basic handler + if (str_contains($message, 'PRIVMSG')) { return; } - // get join message - if (strpos($message, 'NOTICE * :Login authentication failed') !== false) { + // if this message contains "Login authentication" reset bot connection + if (str_contains($message, 'NOTICE * :Login authentication failed')) { $this->write("LOGIN | " . $message); event(new BotTokenExpires($this->bot)); @@ -78,15 +78,15 @@ public function basicMessageHandler(string $message): void return; } - // get join message - if (strpos($message, 'PING') !== false) { + // handle ping message from twitch + if (str_contains($message, 'PING')) { $this->pingReceived($message); return; } - // get join message - if (strpos($message, 'JOIN') !== false) { + // handle join confirmation + if (str_contains($message, 'JOIN')) { $this->joinMessageReceived($message); return; @@ -147,7 +147,7 @@ public function addJoinedCallBack(string $channelName, callable $callback): void public function chatMessageReceived(string $message): void { - $model = ChatMessage::parseIRCMessage($message); + $model = ChatMessage::parseIRCMessage($this->bot, $message); if ($model === null) { return; @@ -157,18 +157,6 @@ public function chatMessageReceived(string $message): void $this->write($model->channel . ' | ' . $model->username . ': ' . $model->message, 'Twitch'); - try { - // Check commands - foreach ($this->customCommands as $commandHandler) { - $commandHandler->handle($model); - } - } catch (\Exception $exception) { - $this->write($exception->getMessage(), 'ERROR'); - $this->write($exception->getFile() . ' #' . $exception->getLine(), 'ERROR'); - } - - $this->write($model->channel . ' | ' . $model->username . ': ' . $model->message . ' HANDLED'); - try { event(new ChatMessageReceived($model)); } catch (\Exception $exception) { diff --git a/src/Console/Commands/ChatBot/StartCommand.php b/src/Console/Commands/ChatBot/StartCommand.php index 7118b6a..8f1e376 100644 --- a/src/Console/Commands/ChatBot/StartCommand.php +++ b/src/Console/Commands/ChatBot/StartCommand.php @@ -65,8 +65,6 @@ private function configureChatbot() foreach ($bot->users as $user) { $twitchUsers = $user->connections()->where('service', 'twitch')->get(); - $connectionHandler->initCustomCommands(); - foreach ($twitchUsers as $twitchUser) { $connectionHandler->joinChannel($twitchUser); $connectionHandler->sendChatMessage($twitchUser->service_username, 'Hello'); From 1dba323b42485db153b25d585ebc1ad9779eae5c Mon Sep 17 00:00:00 2001 From: Chris Woelk Date: Wed, 13 Apr 2022 11:47:47 +0200 Subject: [PATCH 4/8] Move --- .../{ => Twitch}/ChatMessage/ChatMessageContainsFilter.php | 2 +- .../ChatMessage/ChatMessageContainsWithPatternFilter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/Automations/Filters/{ => Twitch}/ChatMessage/ChatMessageContainsFilter.php (96%) rename src/Automations/Filters/{ => Twitch}/ChatMessage/ChatMessageContainsWithPatternFilter.php (97%) diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php b/src/Automations/Filters/Twitch/ChatMessage/ChatMessageContainsFilter.php similarity index 96% rename from src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php rename to src/Automations/Filters/Twitch/ChatMessage/ChatMessageContainsFilter.php index a1b0f2b..3311a6a 100644 --- a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php +++ b/src/Automations/Filters/Twitch/ChatMessage/ChatMessageContainsFilter.php @@ -1,6 +1,6 @@ Date: Wed, 13 Apr 2022 11:49:17 +0200 Subject: [PATCH 5/8] Revert "Move" This reverts commit 1dba323b42485db153b25d585ebc1ad9779eae5c. --- .../{Twitch => }/ChatMessage/ChatMessageContainsFilter.php | 2 +- .../ChatMessage/ChatMessageContainsWithPatternFilter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/Automations/Filters/{Twitch => }/ChatMessage/ChatMessageContainsFilter.php (96%) rename src/Automations/Filters/{Twitch => }/ChatMessage/ChatMessageContainsWithPatternFilter.php (97%) diff --git a/src/Automations/Filters/Twitch/ChatMessage/ChatMessageContainsFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php similarity index 96% rename from src/Automations/Filters/Twitch/ChatMessage/ChatMessageContainsFilter.php rename to src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php index 3311a6a..a1b0f2b 100644 --- a/src/Automations/Filters/Twitch/ChatMessage/ChatMessageContainsFilter.php +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php @@ -1,6 +1,6 @@ Date: Wed, 13 Apr 2022 13:49:31 +0200 Subject: [PATCH 6/8] - add twitch channel status check - check if streamer is life - add job to refresh streamer status - remove warning --- README.md | 2 +- config/openoverlay.php | 2 +- .../Filters/Twitch/ChannelStatus.php | 59 +++++++++++++++++++ src/ChatBot/Twitch/ChatMessage.php | 5 +- .../Commands/EventSubListingCommand.php | 12 ++-- src/Console/Commands/SecretCommand.php | 4 +- .../Commands/Twitch/OnlineStatusCommand.php | 48 +++++++++++++++ src/Console/ConsoleServiceProvider.php | 2 + src/OpenOverlayServiceProvider.php | 12 +++- src/Service/Twitch/ChannelsClient.php | 3 - src/Service/Twitch/UsersClient.php | 23 +++++++- src/Support/StreamerOnline.php | 1 - 12 files changed, 150 insertions(+), 23 deletions(-) create mode 100644 src/Automations/Filters/Twitch/ChannelStatus.php create mode 100644 src/Console/Commands/Twitch/OnlineStatusCommand.php diff --git a/README.md b/README.md index 9b76b8a..e90a946 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ To add a bot you need to link your app with the bot twitch account. 1. Open `${APP_URL}/connection/bot/redirect` with your laravel-app. 2. Login into your Twitch-Bot account with your Twitch Application. -3. After redirect you need to manually connect your laravel-Account with a bot. +3. After redirect, you need to manually connect your laravel-Account with a bot. 4. Open Your Database table "bot_connections" and connect your bot with your user. 5. Restart the Bot Artisan Bot diff --git a/config/openoverlay.php b/config/openoverlay.php index 6d397c2..56bf420 100644 --- a/config/openoverlay.php +++ b/config/openoverlay.php @@ -55,7 +55,7 @@ /** * Your personal and unique secret is used to validate a twitch callback - * If you change your secret all previous configures webhook callbacks will be end as invalid + * If you change your secret all previous configures webhook callbacks will be ended as invalid */ 'secret' => env('OVERLAY_SECRET'), diff --git a/src/Automations/Filters/Twitch/ChannelStatus.php b/src/Automations/Filters/Twitch/ChannelStatus.php new file mode 100644 index 0000000..028176d --- /dev/null +++ b/src/Automations/Filters/Twitch/ChannelStatus.php @@ -0,0 +1,59 @@ +connection = $userConnection; + } + + private function setOnlineStatus(string $status): self + { + $this->onlineStatus = $status; + return $this; + } + + public function isOnline(): self + { + return $this->setOnlineStatus(self::IS_ONLINE); + } + + public function isOffline(): self + { + return $this->setOnlineStatus(self::IS_OFFLINE); + } + + protected function validateOnlineStatus(): bool + { + if ($this->onlineStatus === null) { + return true; + } + + $currentStatus = StreamerOnline::isOnline($this->connection->service_user_id) ? self::IS_ONLINE : self::IS_OFFLINE; + + return $currentStatus === $this->onlineStatus; + } + + public function validate(): bool + { + if (!$this->validateOnlineStatus()) { + return false; + } + + return true; + } +} diff --git a/src/ChatBot/Twitch/ChatMessage.php b/src/ChatBot/Twitch/ChatMessage.php index 266a17e..9335684 100644 --- a/src/ChatBot/Twitch/ChatMessage.php +++ b/src/ChatBot/Twitch/ChatMessage.php @@ -2,12 +2,10 @@ namespace Redbeed\OpenOverlay\ChatBot\Twitch; -use http\Client\Curl\User; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; use Redbeed\OpenOverlay\Models\BotConnection; use Redbeed\OpenOverlay\Models\Twitch\Emote; -use Redbeed\OpenOverlay\Models\User\Connection; class ChatMessage { @@ -39,9 +37,8 @@ public static function parseIRCMessage(BotConnection $bot, string $message): ?Ch { try { preg_match("/:(.*)\!.*#(\S+) :(.*)/", $message, $matches); - $message = new ChatMessage($matches[2], $matches[1], $matches[3], $bot); - return $message; + return new ChatMessage($matches[2], $matches[1], $matches[3], $bot); } catch (\Exception $exception) { Log::error($exception); } diff --git a/src/Console/Commands/EventSubListingCommand.php b/src/Console/Commands/EventSubListingCommand.php index 5804808..2d1bf19 100644 --- a/src/Console/Commands/EventSubListingCommand.php +++ b/src/Console/Commands/EventSubListingCommand.php @@ -37,8 +37,6 @@ public function __construct() /** * Execute the console command. - * - * @return int */ public function handle() { @@ -46,7 +44,7 @@ public function handle() $subscriptions = $eventSubClient->subscriptions(); $this->subscriptionsTable($subscriptions); - $this->info('Total EventSub subscriptions: '.$subscriptions->count()); + $this->info('Total EventSub subscriptions: ' . $subscriptions->count()); } protected function subscriptionsTable(Collection $subscriptions): void @@ -55,10 +53,10 @@ protected function subscriptionsTable(Collection $subscriptions): void /** @var EventSubscription $subscription */ return [ - 'id' => $subscription->id, - 'status' => $subscription->status, - 'type' => $subscription->type, - 'condition' => json_encode($subscription->condition), + 'id' => $subscription->id, + 'status' => $subscription->status, + 'type' => $subscription->type, + 'condition' => json_encode($subscription->condition), 'created_at' => $subscription->createdAt->toDateTimeLocalString(), ]; }); diff --git a/src/Console/Commands/SecretCommand.php b/src/Console/Commands/SecretCommand.php index b3678f0..dbf02a5 100644 --- a/src/Console/Commands/SecretCommand.php +++ b/src/Console/Commands/SecretCommand.php @@ -17,7 +17,7 @@ class SecretCommand extends EventSubListingCommand public function handle(): void { - $currentSecret = env(self::ENV_KEY); + $currentSecret = config('openoverlay.webhook.twitch.secret'); if (!empty($currentSecret) && !$this->option('force')) { $this->warn('You already have a secret'); @@ -75,7 +75,7 @@ private function showOption(string $key): void protected function keyReplacementPattern(): string { - $escaped = preg_quote('=' . env(self::ENV_KEY, ''), '/'); + $escaped = preg_quote('=' . config('openoverlay.webhook.twitch.secret'), '/'); return "/^" . self::ENV_KEY . "{$escaped}/m"; } } diff --git a/src/Console/Commands/Twitch/OnlineStatusCommand.php b/src/Console/Commands/Twitch/OnlineStatusCommand.php new file mode 100644 index 0000000..b324914 --- /dev/null +++ b/src/Console/Commands/Twitch/OnlineStatusCommand.php @@ -0,0 +1,48 @@ +option('all') && $this->argument('twitchUserId')) { + $connections = $connections->where('service_user_id', $this->argument('twitchUserId')); + } + + $connections = $connections->get(); + $streamsResponse = (new StreamsClient())->byUserIds($connections->pluck('service_user_id')->toArray()); + $streamsData = collect($streamsResponse['data'] ?? []); + + foreach ($connections as $connection) { + $stream = $streamsData->firstWhere('user_id', $connection->service_user_id); + + if ($stream !== null) { + StreamerOnline::setOnline( + $connection->service_user_id, + Carbon::parse($stream['created_at'] ?? null, 'UTC') + ); + + $this->info('Streamer ' . $connection->service_username . ' is online'); + continue; + } + + $this->info('Streamer ' . $connection->service_username . ' is offline'); + StreamerOnline::setOffline($connection->service_user_id); + } + + } +} diff --git a/src/Console/ConsoleServiceProvider.php b/src/Console/ConsoleServiceProvider.php index b3b0503..476de5d 100644 --- a/src/Console/ConsoleServiceProvider.php +++ b/src/Console/ConsoleServiceProvider.php @@ -10,6 +10,7 @@ use Redbeed\OpenOverlay\Console\Commands\EventSubDeleteCommand; use Redbeed\OpenOverlay\Console\Commands\EventSubListingCommand; use Redbeed\OpenOverlay\Console\Commands\SecretCommand; +use Redbeed\OpenOverlay\Console\Commands\Twitch\OnlineStatusCommand; use Redbeed\OpenOverlay\Console\Commands\Twitch\RefresherCommand; class ConsoleServiceProvider extends ServiceProvider @@ -35,6 +36,7 @@ protected function registerConsoleCommands(): void RestartServerCommand::class, RefresherCommand::class, + OnlineStatusCommand::class, ]); } diff --git a/src/OpenOverlayServiceProvider.php b/src/OpenOverlayServiceProvider.php index a9fd4d6..9bf8a2f 100644 --- a/src/OpenOverlayServiceProvider.php +++ b/src/OpenOverlayServiceProvider.php @@ -4,6 +4,7 @@ use Illuminate\Console\Scheduling\Schedule; use Illuminate\Support\ServiceProvider; +use Redbeed\OpenOverlay\Console\Commands\Twitch\OnlineStatusCommand; use Redbeed\OpenOverlay\Console\ConsoleServiceProvider; use Redbeed\OpenOverlay\Console\Scheduling\ChatBotScheduling; use Redbeed\OpenOverlay\Models\BotConnection; @@ -18,9 +19,6 @@ class OpenOverlayServiceProvider extends ServiceProvider */ public function boot(): void { - // $this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'redbeed'); - // $this->loadViewsFrom(__DIR__.'/../resources/views', 'redbeed'); - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); $this->loadRoutesFrom(__DIR__ . '/../routes/openoverlay.php'); @@ -28,6 +26,14 @@ public function boot(): void if ($this->app->runningInConsole()) { $this->bootForConsole(); } + + // Register schedule + $this->callAfterResolving(Schedule::class, function (Schedule $schedule) { + // check streamer status every hour + $schedule + ->command(OnlineStatusCommand::class, ['--all' => true])->hourly() + ->withoutOverlapping(); + }); } /** diff --git a/src/Service/Twitch/ChannelsClient.php b/src/Service/Twitch/ChannelsClient.php index 4bc3267..5a3ee85 100644 --- a/src/Service/Twitch/ChannelsClient.php +++ b/src/Service/Twitch/ChannelsClient.php @@ -2,10 +2,7 @@ namespace Redbeed\OpenOverlay\Service\Twitch; -use GuzzleHttp\Exception\ClientException; use GuzzleHttp\RequestOptions; -use Illuminate\Support\Arr; -use Illuminate\Support\Facades\Log; class ChannelsClient extends ApiClient { diff --git a/src/Service/Twitch/UsersClient.php b/src/Service/Twitch/UsersClient.php index b5fb295..e2c6ac7 100644 --- a/src/Service/Twitch/UsersClient.php +++ b/src/Service/Twitch/UsersClient.php @@ -2,12 +2,17 @@ namespace Redbeed\OpenOverlay\Service\Twitch; +use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\RequestOptions; use Illuminate\Support\Arr; -use Illuminate\Support\Facades\Log; +use Redbeed\OpenOverlay\Exceptions\AppTokenMissing; class UsersClient extends ApiClient { + /** + * @throws AppTokenMissing + * @throws GuzzleException + */ public function byId(string $id): array { return $this @@ -20,6 +25,10 @@ public function byId(string $id): array ->request('GET', 'users'); } + /** + * @throws AppTokenMissing + * @throws GuzzleException + */ public function byUsername(string $username): array { return $this @@ -32,6 +41,10 @@ public function byUsername(string $username): array ->request('GET', 'users'); } + /** + * @throws AppTokenMissing + * @throws GuzzleException + */ public function followers(string $twitchUserId): array { return $this @@ -44,6 +57,10 @@ public function followers(string $twitchUserId): array ->request('GET', 'users/follows'); } + /** + * @throws AppTokenMissing + * @throws GuzzleException + */ public function allFollowers(string $twitchUserId): array { $firstResponse = $this @@ -80,6 +97,10 @@ public function allFollowers(string $twitchUserId): array return $firstResponse; } + /** + * @throws AppTokenMissing + * @throws GuzzleException + */ public static function lastGame(string $username): string { $users = (new self)->byUsername($username); diff --git a/src/Support/StreamerOnline.php b/src/Support/StreamerOnline.php index 97e17f4..1994030 100644 --- a/src/Support/StreamerOnline.php +++ b/src/Support/StreamerOnline.php @@ -42,5 +42,4 @@ public static function setOffline(string $streamerId, string $platform = 'twitch { Cache::pull(self::cacheKey($streamerId, $platform)); } - } From 6f974619d0cc85c2c69dedfd42d02503987077c2 Mon Sep 17 00:00:00 2001 From: Chris Woelk Date: Thu, 14 Apr 2022 08:03:14 +0200 Subject: [PATCH 7/8] - Add names & description for UI - Add "getter" functions for AutomationDispatcher - Add settings block for automations --- src/Automations/AutomationDispatcher.php | 13 ++++++++++++- src/Automations/AutomationHandler.php | 3 ++- .../ChatMessage/ChatMessageContainsFilter.php | 12 ++++++++++-- .../ChatMessageContainsWithPatternFilter.php | 13 +++++++++++-- src/Automations/Filters/Filter.php | 6 +++++- src/Automations/Filters/Twitch/ChannelStatus.php | 10 ++++++++++ src/Automations/Triggers/ScheduleTrigger.php | 3 +++ src/Automations/Triggers/Trigger.php | 4 ++-- .../Triggers/TwitchChatMessageTrigger.php | 4 ++-- src/Console/Commands/EventSubListingCommand.php | 1 - 10 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/Automations/AutomationDispatcher.php b/src/Automations/AutomationDispatcher.php index 362d2d9..933b780 100644 --- a/src/Automations/AutomationDispatcher.php +++ b/src/Automations/AutomationDispatcher.php @@ -9,14 +9,25 @@ class AutomationDispatcher public function add(string $trigger, string|array $handlerClass) { if (is_array($handlerClass)) { - return collect($handlerClass)->each(function ($handler) use ($trigger) { + collect($handlerClass)->each(function ($handler) use ($trigger) { $this->add($trigger, $handler); }); + + return; } $this->automations[$trigger][] = $handlerClass; } + public function getAutomations(?string $triggerClass = null): array + { + if ($triggerClass) { + return $this->automations[$triggerClass] ?? []; + } + + return $this->automations; + } + public function trigger(mixed $trigger) { if (empty($this->automations[$trigger::class])) { diff --git a/src/Automations/AutomationHandler.php b/src/Automations/AutomationHandler.php index 0173397..215dc5b 100644 --- a/src/Automations/AutomationHandler.php +++ b/src/Automations/AutomationHandler.php @@ -2,7 +2,6 @@ namespace Redbeed\OpenOverlay\Automations; -use Illuminate\Support\Facades\Log; use JetBrains\PhpStorm\ArrayShape; use Redbeed\OpenOverlay\Automations\Actions\UseTwitchChatMessage; use Redbeed\OpenOverlay\Automations\Actions\UseVariables; @@ -12,6 +11,8 @@ class AutomationHandler { + public static string $name = 'Automation Handler'; + public static string $description = 'Will run filters on trigger and execute actions'; /** @var Trigger */ private $trigger; diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php index a1b0f2b..9197f88 100644 --- a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php @@ -13,8 +13,8 @@ class ChatMessageContainsFilter extends Filter { - public static string $name = 'Chat message contains'; - public static string $description = 'Filter chat messages by string '; + public static string $name = 'Chat message check'; + public static string $description = 'Filter chat message by string.'; private string $needle; private bool $caseSensitive; @@ -70,4 +70,12 @@ public function variables(): array }, ]; } + + public function settings(): array + { + return [ + 'needle' => $this->needle, + 'caseSensitive' => $this->caseSensitive, + ]; + } } diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php index b80a883..f6f20db 100644 --- a/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php @@ -11,8 +11,8 @@ class ChatMessageContainsWithPatternFilter extends Filter { - public static string $name = 'Chat message contains'; - public static string $description = 'Filter chat messages by string '; + public static string $name = 'Chat message check with arguments'; + public static string $description = 'Filter chat message by string and pattern. If the message contains the string, it will forward the matches of the pattern to your actions.'; private string $needle; private bool $caseSensitive; @@ -95,4 +95,13 @@ public function variables(): array }, ], $this->matches()); } + + public function settings(): array + { + return [ + 'needle' => $this->needle, + 'regexPatterns' => $this->regexPatterns, + 'caseSensitive' => $this->caseSensitive, + ]; + } } diff --git a/src/Automations/Filters/Filter.php b/src/Automations/Filters/Filter.php index b7e4b10..1b62895 100644 --- a/src/Automations/Filters/Filter.php +++ b/src/Automations/Filters/Filter.php @@ -7,7 +7,6 @@ abstract class Filter { - static public string $name; static public string $description; @@ -34,6 +33,11 @@ public function validate(): bool return true; } + public function settings(): array + { + return []; + } + /** * @throws AutomationFilterNotValid */ diff --git a/src/Automations/Filters/Twitch/ChannelStatus.php b/src/Automations/Filters/Twitch/ChannelStatus.php index 028176d..08a1fbb 100644 --- a/src/Automations/Filters/Twitch/ChannelStatus.php +++ b/src/Automations/Filters/Twitch/ChannelStatus.php @@ -9,6 +9,9 @@ class ChannelStatus extends \Redbeed\OpenOverlay\Automations\Filters\Filter { + public static string $name = 'Twitch Channel Status'; + public static string $description = 'Check if channel is online or offline'; + public const IS_ONLINE = 'online'; public const IS_OFFLINE = 'offline'; @@ -56,4 +59,11 @@ public function validate(): bool return true; } + + public function settings(): array + { + return [ + 'onlineStatus' => $this->onlineStatus, + ]; + } } diff --git a/src/Automations/Triggers/ScheduleTrigger.php b/src/Automations/Triggers/ScheduleTrigger.php index b92a16c..6c884e2 100644 --- a/src/Automations/Triggers/ScheduleTrigger.php +++ b/src/Automations/Triggers/ScheduleTrigger.php @@ -6,6 +6,9 @@ class ScheduleTrigger extends Trigger { + public static string $name = 'Schedule'; + public static string $description = 'Trigger automation when based on time'; + public Carbon $date; public function __construct() diff --git a/src/Automations/Triggers/Trigger.php b/src/Automations/Triggers/Trigger.php index ae406f6..b6a8d8b 100644 --- a/src/Automations/Triggers/Trigger.php +++ b/src/Automations/Triggers/Trigger.php @@ -4,9 +4,9 @@ abstract class Trigger { - static protected string $name; + static public string $name; - static protected string $description; + static public string $description; protected array $options = []; diff --git a/src/Automations/Triggers/TwitchChatMessageTrigger.php b/src/Automations/Triggers/TwitchChatMessageTrigger.php index bba2b49..aa80f9a 100644 --- a/src/Automations/Triggers/TwitchChatMessageTrigger.php +++ b/src/Automations/Triggers/TwitchChatMessageTrigger.php @@ -7,9 +7,9 @@ class TwitchChatMessageTrigger extends Trigger { - static protected string $name = 'Twitch Chat Message'; + static public string $name = 'Twitch Chat Message'; - static protected string $description = 'Trigger when Twitch chat message is received'; + static public string $description = 'Trigger when Twitch chat message is received'; public ChatMessage $message; diff --git a/src/Console/Commands/EventSubListingCommand.php b/src/Console/Commands/EventSubListingCommand.php index 2d1bf19..b61fce5 100644 --- a/src/Console/Commands/EventSubListingCommand.php +++ b/src/Console/Commands/EventSubListingCommand.php @@ -34,7 +34,6 @@ public function __construct() parent::__construct(); } - /** * Execute the console command. */ From 0e81c10447d59e477dece7b0149814cf9c002462 Mon Sep 17 00:00:00 2001 From: Chris Woelk Date: Sun, 10 Jul 2022 12:51:38 +0200 Subject: [PATCH 8/8] Add automations features - add pint for code style - add action names & description --- composer.json | 10 +++- config/openoverlay.php | 10 ++-- database/Factories/EventSubEventsFactory.php | 3 +- ..._000001_create_user_bots_enabled_table.php | 1 - routes/openoverlay.php | 6 --- src/Actions/RegisterUserTwitchWebhooks.php | 4 +- .../Actions/TwitchChatBotMessage.php | 7 ++- .../Actions/TwitchRandomChatBotMessage.php | 6 ++- .../Actions/UseTwitchChatMessage.php | 1 + src/Automations/Actions/UseVariables.php | 3 +- src/Automations/AutomationDispatcher.php | 14 +++++- src/Automations/AutomationHandler.php | 7 ++- .../AutomationsServiceProvider.php | 1 - .../ChatMessage/ChatMessageContainsFilter.php | 17 +++---- .../ChatMessageContainsWithPatternFilter.php | 21 +++++---- src/Automations/Filters/Filter.php | 12 +++-- src/Automations/Filters/FrequencyFilter.php | 4 +- .../Filters/Twitch/ChannelStatus.php | 7 +-- src/Automations/Triggers/ScheduleTrigger.php | 1 + src/Automations/Triggers/Trigger.php | 4 +- .../Triggers/TwitchChatMessageTrigger.php | 4 +- src/ChatBot/Twitch/ChatMessage.php | 10 ++-- src/ChatBot/Twitch/ConnectionHandler.php | 46 ++++++++----------- .../BroadcastFaker/ChannelCheerFake.php | 21 ++++----- .../BroadcastFaker/ChannelFollowFake.php | 11 ++--- .../BroadcastFaker/ChannelRaidFake.php | 15 +++--- .../BroadcastFaker/ChannelSubscribeFake.php | 12 ++--- .../BroadcastFaker/ChannelUpdateFake.php | 17 ++++--- src/Console/Commands/BroadcastFaker/Fake.php | 8 ++-- .../Commands/BroadcastFaker/StreamOffline.php | 6 +-- .../Commands/BroadcastFaker/StreamOnline.php | 12 ++--- .../Commands/ChatBot/RestartServerCommand.php | 1 - .../Commands/ChatBot/RuntimeCommand.php | 3 +- .../Commands/ChatBot/SendMessageCommand.php | 8 ++-- src/Console/Commands/ChatBot/StartCommand.php | 7 +-- src/Console/Commands/EventBroadcastFaker.php | 8 ++-- .../Commands/EventSubDeleteCommand.php | 9 ++-- .../Commands/EventSubListingCommand.php | 11 ++--- .../Make/MakeBotSchedulingCommand.php | 2 - src/Console/Commands/SecretCommand.php | 15 +++--- .../Commands/Twitch/OnlineStatusCommand.php | 8 ++-- .../Commands/Twitch/RefresherCommand.php | 3 +- src/Console/ConsoleServiceProvider.php | 3 +- src/Console/Scheduling/ChatBotScheduling.php | 3 +- src/EventServiceProvider.php | 20 ++++---- src/Events/Twitch/ChatMessageReceived.php | 4 +- src/Events/Twitch/StreamOffline.php | 4 +- src/Events/Twitch/StreamOnline.php | 2 +- src/Events/ViewerEnteredChat.php | 2 +- src/Exceptions/AutomationFilterNotValid.php | 1 - src/Exceptions/TwitchEmoteSetIdException.php | 1 - .../WrongConnectionTypeException.php | 1 - .../Api/Connection/WebhookController.php | 5 +- .../Connection/AppTokenController.php | 1 - .../Controllers/Connection/AuthController.php | 2 - .../Connection/SocialiteController.php | 7 ++- src/Listeners/AutoShoutOutRaid.php | 8 ++-- src/Listeners/Twitch/EventListener.php | 2 - src/Listeners/Twitch/NewFollowerListener.php | 10 ++-- .../Twitch/NewSubscriberListener.php | 8 ++-- .../Twitch/Refresher/LoginRefresher.php | 9 +++- src/Listeners/Twitch/Refresher/Refresher.php | 26 +++++------ .../Twitch/Refresher/StandardRefresher.php | 2 +- src/Listeners/Twitch/UpdateBotToken.php | 2 +- src/Listeners/TwitchSplitReceivedEvents.php | 2 + src/Models/BotConnection.php | 6 ++- src/Models/Twitch/Emote.php | 9 ++-- src/Models/Twitch/EventSubscription.php | 2 - src/Models/Twitch/UserSubscriber.php | 2 +- src/Models/User/Connection.php | 6 ++- src/OpenOverlay.php | 2 - src/OpenOverlayServiceProvider.php | 13 ++---- src/Service/Twitch/ApiClient.php | 24 +++++----- src/Service/Twitch/ChannelsClient.php | 3 +- src/Service/Twitch/ChatEmotesClient.php | 15 +++--- src/Service/Twitch/DateTime.php | 2 +- src/Service/Twitch/EventSubClient.php | 17 ++++--- ...TwitchClientCredentialsExtendSocialite.php | 2 +- src/Support/Facades/Automation.php | 4 +- src/Support/StreamerOnline.php | 2 +- src/Support/ViewerInChat.php | 2 +- src/Support/helpers.php | 4 +- 82 files changed, 301 insertions(+), 315 deletions(-) diff --git a/composer.json b/composer.json index 35f1f9b..b822a89 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "require-dev": { "phpunit/phpunit": "~9.0", "orchestra/testbench": "~5|~6", - "nunomaduro/phpinsights": "^1.14" + "nunomaduro/phpinsights": "^1.14", + "laravel/pint": "^0.2.3" }, "autoload": { "files": [ @@ -51,5 +52,10 @@ } }, "minimum-stability": "dev", - "prefer-stable": true + "prefer-stable": true, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } } diff --git a/config/openoverlay.php b/config/openoverlay.php index 56bf420..18f9429 100644 --- a/config/openoverlay.php +++ b/config/openoverlay.php @@ -33,12 +33,12 @@ * You can use :username, :twitchUrl and :gameName for your message. */ \Redbeed\OpenOverlay\Listeners\AutoShoutOutRaid::class => [ - 'message' => 'Follow :username over at :twitchUrl. They were last playing :gameName' + 'message' => 'Follow :username over at :twitchUrl. They were last playing :gameName', ], \Redbeed\OpenOverlay\Support\ViewerInChat::class => [ - 'reset' => -1 - ] + 'reset' => -1, + ], ], 'webhook' => [ @@ -74,6 +74,6 @@ 'bot' => [ 'schedules' => [ \Redbeed\OpenOverlay\Console\Scheduling\MadeWithChatBotScheduling::class, - ] - ] + ], + ], ]; diff --git a/database/Factories/EventSubEventsFactory.php b/database/Factories/EventSubEventsFactory.php index 895de5e..0d895ae 100644 --- a/database/Factories/EventSubEventsFactory.php +++ b/database/Factories/EventSubEventsFactory.php @@ -7,11 +7,10 @@ class EventSubEventsFactory extends Factory { - protected $model = EventSubEvents::class; /** - * @inheritDoc + * {@inheritDoc} */ public function definition() { diff --git a/database/migrations/2020_12_17_000001_create_user_bots_enabled_table.php b/database/migrations/2020_12_17_000001_create_user_bots_enabled_table.php index 44f7d76..ced6730 100644 --- a/database/migrations/2020_12_17_000001_create_user_bots_enabled_table.php +++ b/database/migrations/2020_12_17_000001_create_user_bots_enabled_table.php @@ -14,7 +14,6 @@ class CreateUserBotsEnabledTable extends Migration public function up() { Schema::create('users_bots_enabled', function (Blueprint $table) { - $table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('bot_id'); $table->timestamps(); diff --git a/routes/openoverlay.php b/routes/openoverlay.php index 78e8990..ae67d12 100644 --- a/routes/openoverlay.php +++ b/routes/openoverlay.php @@ -1,7 +1,6 @@ group(function () { - Route::middleware(['web', 'auth'])->group(function () { - Route::get('/redirect')->uses([AuthController::class, 'redirect']) ->name('connection.redirect'); @@ -27,7 +24,6 @@ Route::get('/callback')->uses([AppTokenController::class, 'handleProviderCallback']) ->name('connection.app-token.callback'); - }); // prefix: /connection/bot @@ -37,7 +33,6 @@ Route::get('/callback')->uses([BotAuthController::class, 'handleProviderCallback']) ->name('connection.bot.callback'); - }); }); @@ -45,6 +40,5 @@ Route::any('/webhook')->uses([WebhookController::class, 'handleProviderCallback']) ->name('connection.webhook'); }); - }); }); diff --git a/src/Actions/RegisterUserTwitchWebhooks.php b/src/Actions/RegisterUserTwitchWebhooks.php index d4f479f..30b4921 100644 --- a/src/Actions/RegisterUserTwitchWebhooks.php +++ b/src/Actions/RegisterUserTwitchWebhooks.php @@ -36,7 +36,7 @@ public static function registerAll(Connection $connection, bool $clearBeforeRegi public function clearBroadcasterSubscriptions() { - $this->apiClient->deleteSubByBroadcasterId((string)$this->connection->service_user_id); + $this->apiClient->deleteSubByBroadcasterId((string) $this->connection->service_user_id); } public function register(string $type): bool @@ -61,7 +61,7 @@ public function register(string $type): bool private function registerCondition($type): array { - $broadcasterId = (string)$this->connection->service_user_id; + $broadcasterId = (string) $this->connection->service_user_id; if ($type === 'channel.raid') { return ['to_broadcaster_user_id' => $broadcasterId]; diff --git a/src/Automations/Actions/TwitchChatBotMessage.php b/src/Automations/Actions/TwitchChatBotMessage.php index 535f5b3..7ae3653 100644 --- a/src/Automations/Actions/TwitchChatBotMessage.php +++ b/src/Automations/Actions/TwitchChatBotMessage.php @@ -11,7 +11,12 @@ class TwitchChatBotMessage use UseVariables; use UseTwitchChatMessage; + public static string $name = 'Send chat message'; + + public static string $description = 'Send chat message via bot'; + private Connection $connection; + private string $message; public function __construct(string $message) @@ -22,7 +27,7 @@ public function __construct(string $message) public function handle() { Artisan::queue(SendMessageCommand::class, [ - 'userId' => $this->getUser()->id, + 'userId' => $this->getUser()->id, '--botId' => $this->getBot()->id, 'message' => $this->replaceInString($this->message), ]); diff --git a/src/Automations/Actions/TwitchRandomChatBotMessage.php b/src/Automations/Actions/TwitchRandomChatBotMessage.php index e0b4b0f..c827cba 100644 --- a/src/Automations/Actions/TwitchRandomChatBotMessage.php +++ b/src/Automations/Actions/TwitchRandomChatBotMessage.php @@ -12,6 +12,10 @@ class TwitchRandomChatBotMessage use UseVariables; use UseTwitchChatMessage; + public static string $name = 'Send one of the random chat messages'; + + public static string $description = 'Send one of the random chat messages via bot'; + private Connection $connection; /** @var string[] */ @@ -25,7 +29,7 @@ public function __construct(array $messages) public function handle() { Artisan::queue(SendMessageCommand::class, [ - 'userId' => $this->getUser()->id, + 'userId' => $this->getUser()->id, '--botId' => $this->getBot()->id, 'message' => $this->replaceInString(Arr::random($this->messages)), ]); diff --git a/src/Automations/Actions/UseTwitchChatMessage.php b/src/Automations/Actions/UseTwitchChatMessage.php index 2112767..178d9d4 100644 --- a/src/Automations/Actions/UseTwitchChatMessage.php +++ b/src/Automations/Actions/UseTwitchChatMessage.php @@ -11,6 +11,7 @@ trait UseTwitchChatMessage private ChatMessage $chatMessage; private ?BotConnection $botConnection = null; + private ?User $user = null; public function setChatMessage(ChatMessage $chatMessage): void diff --git a/src/Automations/Actions/UseVariables.php b/src/Automations/Actions/UseVariables.php index ad93b06..039c13d 100644 --- a/src/Automations/Actions/UseVariables.php +++ b/src/Automations/Actions/UseVariables.php @@ -43,10 +43,9 @@ protected function makeReplacements(string $string): array { $replacements = []; foreach ($this->variables as $key => $value) { - $keyPattern = ':' . $key; + $keyPattern = ':'.$key; if (Str::contains($string, $keyPattern)) { - if ($this->variables[$key] instanceof \Closure) { // If the variable is a closure, we will execute it and replace the key with the result. $this->variables[$key] = $this->variables[$key](); diff --git a/src/Automations/AutomationDispatcher.php b/src/Automations/AutomationDispatcher.php index 933b780..bdf088e 100644 --- a/src/Automations/AutomationDispatcher.php +++ b/src/Automations/AutomationDispatcher.php @@ -2,11 +2,13 @@ namespace Redbeed\OpenOverlay\Automations; +use Closure; + class AutomationDispatcher { protected array $automations = []; - public function add(string $trigger, string|array $handlerClass) + public function add(string $trigger, string|array|Closure $handlerClass) { if (is_array($handlerClass)) { collect($handlerClass)->each(function ($handler) use ($trigger) { @@ -30,12 +32,22 @@ public function getAutomations(?string $triggerClass = null): array public function trigger(mixed $trigger) { + ray('fire '.get_class($trigger)); + if (empty($this->automations[$trigger::class])) { return; } foreach ($this->automations[$trigger::class] as $automations) { collect($automations)->each(function ($automation) use ($trigger) { + // If it's a closure, execute it + if ($automation instanceof Closure) { + $automation = $automation($trigger); + $automation->handle(); + + return; + } + $automation = new $automation($trigger); $automation->handle(); }); diff --git a/src/Automations/AutomationHandler.php b/src/Automations/AutomationHandler.php index 215dc5b..1f03c16 100644 --- a/src/Automations/AutomationHandler.php +++ b/src/Automations/AutomationHandler.php @@ -12,6 +12,7 @@ class AutomationHandler { public static string $name = 'Automation Handler'; + public static string $description = 'Will run filters on trigger and execute actions'; /** @var Trigger */ @@ -45,6 +46,8 @@ public function handle() foreach ($this->filters() as $filter) { $response = $filter->handle($this->trigger); + ray('did i passed? ', $response, $filter->settings()); + if ($response === false) { // Filter failed stop the automation return; @@ -72,13 +75,13 @@ public function handle() } } - #[ArrayShape(['trigger' => "string", 'options' => "array"])] + #[ArrayShape(['trigger' => 'string', 'options' => 'array'])] public static function triggerConfig(string $triggerClass, array $options = []) { return ['trigger' => $triggerClass, 'options' => $options]; } - #[ArrayShape(['action' => "string", 'options' => "array"])] + #[ArrayShape(['action' => 'string', 'options' => 'array'])] public static function actionConfig(string $actionClass, array $options = []) { return ['action' => $actionClass, 'options' => $options]; diff --git a/src/Automations/AutomationsServiceProvider.php b/src/Automations/AutomationsServiceProvider.php index a6b2c34..023abac 100644 --- a/src/Automations/AutomationsServiceProvider.php +++ b/src/Automations/AutomationsServiceProvider.php @@ -3,7 +3,6 @@ namespace Redbeed\OpenOverlay\Automations; use Illuminate\Console\Scheduling\Schedule; -use Illuminate\Support\Facades\Log; use Illuminate\Support\ServiceProvider; use Redbeed\OpenOverlay\Automations\Triggers\ScheduleTrigger; use Redbeed\OpenOverlay\Support\Facades\Automation; diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php index 9197f88..2fd459d 100644 --- a/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsFilter.php @@ -12,11 +12,12 @@ class ChatMessageContainsFilter extends Filter { - public static string $name = 'Chat message check'; + public static string $description = 'Filter chat message by string.'; private string $needle; + private bool $caseSensitive; /** @@ -36,7 +37,7 @@ public function validate(): bool $message = $this->trigger->message->message; $needle = $this->needle; - if (!$this->caseSensitive) { + if (! $this->caseSensitive) { $message = Str::lower($message); $needle = Str::lower($needle); } @@ -51,17 +52,17 @@ public function validTrigger() { parent::validTrigger(); - if (!($this->trigger instanceof TwitchChatMessageTrigger)) { - throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of TwitchChatMessageTrigger but is ' . get_class($this->trigger)); + if (! ($this->trigger instanceof TwitchChatMessageTrigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of TwitchChatMessageTrigger but is '.get_class($this->trigger)); } } public function variables(): array { return [ - 'username' => $this->trigger->message->username, - 'twitchUrl' => 'https://www.twitch.tv/' . $this->trigger->message->username, - 'game' => function () { + 'username' => $this->trigger->message->username, + 'twitchUrl' => 'https://www.twitch.tv/'.$this->trigger->message->username, + 'game' => function () { try { return (new UsersClient())->lastGame($this->trigger->message->username); } catch (ClientException) { @@ -74,7 +75,7 @@ public function variables(): array public function settings(): array { return [ - 'needle' => $this->needle, + 'needle' => $this->needle, 'caseSensitive' => $this->caseSensitive, ]; } diff --git a/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php index f6f20db..f8c4f3d 100644 --- a/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php +++ b/src/Automations/Filters/ChatMessage/ChatMessageContainsWithPatternFilter.php @@ -12,9 +12,11 @@ class ChatMessageContainsWithPatternFilter extends Filter { public static string $name = 'Chat message check with arguments'; + public static string $description = 'Filter chat message by string and pattern. If the message contains the string, it will forward the matches of the pattern to your actions.'; private string $needle; + private bool $caseSensitive; /** @var string[] */ @@ -25,7 +27,6 @@ class ChatMessageContainsWithPatternFilter extends Filter */ protected $trigger; - public function __construct(string $needle, array $regexPatterns, bool $needleCaseSensitive = false) { $this->needle = $needle; @@ -38,12 +39,12 @@ public function validate(): bool $message = $this->trigger->message->message; $needle = $this->needle; - if (!$this->caseSensitive) { + if (! $this->caseSensitive) { $message = Str::lower($message); $needle = Str::lower($needle); } - if (!Str::contains($message, $needle)) { + if (! Str::contains($message, $needle)) { return false; } @@ -54,12 +55,12 @@ private function regex(): string { $regex = collect($this->regexPatterns) ->mapWithKeys(function ($regex, $key) { - return [$key => '(?<' . $key . '>' . $regex . ')']; + return [$key => '(?<'.$key.'>'.$regex.')']; }) ->prepend($this->needle) ->implode(' '); - return '/' . $regex . '/'; + return '/'.$regex.'/'; } private function matches(): array @@ -67,7 +68,7 @@ private function matches(): array $matches = []; preg_match($this->regex(), $this->trigger->message->message, $matches); - return array_filter($matches, "is_string", ARRAY_FILTER_USE_KEY); + return array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY); } /** @@ -77,8 +78,8 @@ public function validTrigger() { parent::validTrigger(); - if (!($this->trigger instanceof TwitchChatMessageTrigger)) { - throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of TwitchChatMessageTrigger but is ' . get_class($this->trigger)); + if (! ($this->trigger instanceof TwitchChatMessageTrigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of TwitchChatMessageTrigger but is '.get_class($this->trigger)); } } @@ -86,7 +87,7 @@ public function variables(): array { return array_merge_recursive([ 'username' => $this->trigger->message->username, - 'game' => function () { + 'game' => function () { try { return (new UsersClient())->lastGame($this->trigger->message->username); } catch (ClientException) { @@ -99,7 +100,7 @@ public function variables(): array public function settings(): array { return [ - 'needle' => $this->needle, + 'needle' => $this->needle, 'regexPatterns' => $this->regexPatterns, 'caseSensitive' => $this->caseSensitive, ]; diff --git a/src/Automations/Filters/Filter.php b/src/Automations/Filters/Filter.php index 1b62895..50387bf 100644 --- a/src/Automations/Filters/Filter.php +++ b/src/Automations/Filters/Filter.php @@ -7,8 +7,9 @@ abstract class Filter { - static public string $name; - static public string $description; + public static string $name; + + public static string $description; /** * @var Trigger|mixed @@ -16,8 +17,9 @@ abstract class Filter protected $trigger; /** - * @param Trigger $trigger + * @param Trigger $trigger * @return bool + * * @throws AutomationFilterNotValid */ public function handle(mixed $trigger): bool @@ -43,8 +45,8 @@ public function settings(): array */ public function validTrigger() { - if (!($this->trigger instanceof Trigger)) { - throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of Trigger but is ' . get_class($this->trigger)); + if (! ($this->trigger instanceof Trigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of Trigger but is '.get_class($this->trigger)); } } diff --git a/src/Automations/Filters/FrequencyFilter.php b/src/Automations/Filters/FrequencyFilter.php index f1aa7ae..22ad499 100644 --- a/src/Automations/Filters/FrequencyFilter.php +++ b/src/Automations/Filters/FrequencyFilter.php @@ -20,8 +20,8 @@ public function validTrigger() { parent::validTrigger(); - if (!($this->trigger instanceof ScheduleTrigger)) { - throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of ScheduleTrigger but is ' . get_class($this->trigger)); + if (! ($this->trigger instanceof ScheduleTrigger)) { + throw new AutomationFilterNotValid('Trigger is not valid. Trigger must be instance of ScheduleTrigger but is '.get_class($this->trigger)); } } diff --git a/src/Automations/Filters/Twitch/ChannelStatus.php b/src/Automations/Filters/Twitch/ChannelStatus.php index 08a1fbb..d28f0a2 100644 --- a/src/Automations/Filters/Twitch/ChannelStatus.php +++ b/src/Automations/Filters/Twitch/ChannelStatus.php @@ -2,17 +2,17 @@ namespace Redbeed\OpenOverlay\Automations\Filters\Twitch; -use Illuminate\Support\Facades\Log; use Redbeed\OpenOverlay\Models\User\Connection; use Redbeed\OpenOverlay\Support\StreamerOnline; class ChannelStatus extends \Redbeed\OpenOverlay\Automations\Filters\Filter { - public static string $name = 'Twitch Channel Status'; + public static string $description = 'Check if channel is online or offline'; public const IS_ONLINE = 'online'; + public const IS_OFFLINE = 'offline'; private Connection $connection; @@ -27,6 +27,7 @@ public function __construct(Connection $userConnection) private function setOnlineStatus(string $status): self { $this->onlineStatus = $status; + return $this; } @@ -53,7 +54,7 @@ protected function validateOnlineStatus(): bool public function validate(): bool { - if (!$this->validateOnlineStatus()) { + if (! $this->validateOnlineStatus()) { return false; } diff --git a/src/Automations/Triggers/ScheduleTrigger.php b/src/Automations/Triggers/ScheduleTrigger.php index 6c884e2..6c69602 100644 --- a/src/Automations/Triggers/ScheduleTrigger.php +++ b/src/Automations/Triggers/ScheduleTrigger.php @@ -7,6 +7,7 @@ class ScheduleTrigger extends Trigger { public static string $name = 'Schedule'; + public static string $description = 'Trigger automation when based on time'; public Carbon $date; diff --git a/src/Automations/Triggers/Trigger.php b/src/Automations/Triggers/Trigger.php index b6a8d8b..3273484 100644 --- a/src/Automations/Triggers/Trigger.php +++ b/src/Automations/Triggers/Trigger.php @@ -4,9 +4,9 @@ abstract class Trigger { - static public string $name; + public static string $name; - static public string $description; + public static string $description; protected array $options = []; diff --git a/src/Automations/Triggers/TwitchChatMessageTrigger.php b/src/Automations/Triggers/TwitchChatMessageTrigger.php index aa80f9a..ce543b4 100644 --- a/src/Automations/Triggers/TwitchChatMessageTrigger.php +++ b/src/Automations/Triggers/TwitchChatMessageTrigger.php @@ -7,9 +7,9 @@ class TwitchChatMessageTrigger extends Trigger { - static public string $name = 'Twitch Chat Message'; + public static string $name = 'Twitch Chat Message'; - static public string $description = 'Trigger when Twitch chat message is received'; + public static string $description = 'Trigger when Twitch chat message is received'; public ChatMessage $message; diff --git a/src/ChatBot/Twitch/ChatMessage.php b/src/ChatBot/Twitch/ChatMessage.php index 9335684..349c0a7 100644 --- a/src/ChatBot/Twitch/ChatMessage.php +++ b/src/ChatBot/Twitch/ChatMessage.php @@ -19,6 +19,7 @@ class ChatMessage public array $possibleEmotes; public ?\Illuminate\Foundation\Auth\User $channelUser; + public ?BotConnection $bot; public function __construct(string $channel, string $username, string $message, ?BotConnection $bot = null) @@ -51,16 +52,17 @@ public function toHtml(string $emoteSize = Emote::IMAGE_SIZE_MD): string $emoteList = collect($this->possibleEmotes) ->map(function (Emote $emote) use ($emoteSize) { $name = htmlspecialchars_decode($emote->name); - $regex = '/' . preg_quote($name, '/') . '(\s|$)/'; + $regex = '/'.preg_quote($name, '/').'(\s|$)/'; if (@preg_match($regex, null) === false) { - echo "Emote Regex '" . $regex . "' is invalid \r\n"; + echo "Emote Regex '".$regex."' is invalid \r\n"; + return null; } return [ - 'name' => $regex, - 'image' => '' . Str::slug($emote->name) . ' ', + 'name' => $regex, + 'image' => ''.Str::slug($emote->name).' ', ]; }); diff --git a/src/ChatBot/Twitch/ConnectionHandler.php b/src/ChatBot/Twitch/ConnectionHandler.php index e45df3a..6a97e79 100644 --- a/src/ChatBot/Twitch/ConnectionHandler.php +++ b/src/ChatBot/Twitch/ConnectionHandler.php @@ -1,6 +1,5 @@ connection = $connection; - $this->connection->on('message', function ($message) use ($connection) { + $this->connection->on('message', function ($message) { $this->basicMessageHandler($message); }); } @@ -71,10 +69,11 @@ public function basicMessageHandler(string $message): void // if this message contains "Login authentication" reset bot connection if (str_contains($message, 'NOTICE * :Login authentication failed')) { - $this->write("LOGIN | " . $message); + $this->write('LOGIN | '.$message); event(new BotTokenExpires($this->bot)); $this->connection->close(); + return; } @@ -92,13 +91,13 @@ public function basicMessageHandler(string $message): void return; } - $this->write("UNKOWN | " . $message . PHP_EOL, ''); + $this->write('UNKOWN | '.$message.PHP_EOL, ''); } public function pingReceived(string $message): void { $this->send('PONG :tmi.twitch.tv'); - $this->write("PING PONG done"); + $this->write('PING PONG done'); } public function joinMessageReceived(string $message): void @@ -106,7 +105,7 @@ public function joinMessageReceived(string $message): void try { preg_match("/:(.*)\!.*#(.*)/", $message, $matches); - $this->write("BOT (" . $matches[1] . ") joined " . $matches[2]); + $this->write('BOT ('.$matches[1].') joined '.$matches[2]); $channelName = trim(strtolower($matches[2])); @@ -114,9 +113,8 @@ public function joinMessageReceived(string $message): void $this->runChannelQueue($channelName); $this->afterJoinCallBacks($channelName); - } catch (\Exception $exception) { - $this->write($exception->getMessage() . ' ' . $exception->getLine() . PHP_EOL, 'ERROR'); + $this->write($exception->getMessage().' '.$exception->getLine().PHP_EOL, 'ERROR'); } } @@ -125,10 +123,8 @@ private function afterJoinCallBacks(string $channelName) $channelName = strtolower($channelName); if (isset($this->joinedCallBack[$channelName])) { - - $this->write('CALL CALLBACK FOR ' . $channelName); + $this->write('CALL CALLBACK FOR '.$channelName); $this->joinedCallBack[$channelName](); - } } @@ -137,7 +133,7 @@ public function addJoinedCallBack(string $channelName, callable $callback): void $channelName = strtolower($channelName); $this->joinedCallBack[$channelName] = $callback; - $this->write('Callback added for ' . $channelName); + $this->write('Callback added for '.$channelName); // channel already joined if (in_array($channelName, $this->joinedChannel)) { @@ -155,13 +151,13 @@ public function chatMessageReceived(string $message): void $model->possibleEmotes = $this->emoteSets[$model->channel] ?? []; - $this->write($model->channel . ' | ' . $model->username . ': ' . $model->message, 'Twitch'); + $this->write($model->channel.' | '.$model->username.': '.$model->message, 'Twitch'); try { event(new ChatMessageReceived($model)); } catch (\Exception $exception) { Log::error($exception); - $this->write(" -> EVENT ERROR: " . $exception->getMessage(), 'ERROR'); + $this->write(' -> EVENT ERROR: '.$exception->getMessage(), 'ERROR'); } } @@ -169,8 +165,8 @@ public function auth(BotConnection $bot) { $this->bot = $bot; - $this->send('PASS oauth:' . $this->bot->service_token); - $this->send('NICK ' . strtolower($this->bot->bot_username)); + $this->send('PASS oauth:'.$this->bot->service_token); + $this->send('NICK '.strtolower($this->bot->bot_username)); } public function send(string $message): void @@ -178,7 +174,6 @@ public function send(string $message): void $this->connection->send($message); } - public function joinChannel(Connection $channel): void { $channelName = strtolower($channel->service_username); @@ -186,8 +181,8 @@ public function joinChannel(Connection $channel): void $this->channelQueue[$channelName] = []; $this->loadEmotes($channel); - $this->send('JOIN #' . strtolower($channelName)); - $this->write('JOIN #' . strtolower($channelName)); + $this->send('JOIN #'.strtolower($channelName)); + $this->write('JOIN #'.strtolower($channelName)); } private function loadEmotes(Connection $channel) @@ -205,7 +200,7 @@ private function runChannelQueue(string $channelName): void { $channelName = trim(strtolower($channelName)); - if (!empty($this->channelQueue[$channelName])) { + if (! empty($this->channelQueue[$channelName])) { foreach ($this->channelQueue[$channelName] as $item) { $this->send($item); } @@ -217,10 +212,10 @@ private function runChannelQueue(string $channelName): void public function sendChatMessage(string $channelName, string $message): void { $lowerChannelName = strtolower($channelName); - $message = 'PRIVMSG #' . $lowerChannelName . ' :' . $message . PHP_EOL; + $message = 'PRIVMSG #'.$lowerChannelName.' :'.$message.PHP_EOL; // send message after channel joined - if (!in_array($lowerChannelName, $this->joinedChannel)) { + if (! in_array($lowerChannelName, $this->joinedChannel)) { $this->channelQueue[$lowerChannelName][] = $message; return; @@ -232,8 +227,7 @@ public function sendChatMessage(string $channelName, string $message): void protected function write(string $output, string $title = 'OpenOverlay', $newLine = true) { - $title = !empty($title) ? '[' . $title . ']' : ''; - echo trim($title . ' ' . $output) . ($newLine ? PHP_EOL : ''); + $title = ! empty($title) ? '['.$title.']' : ''; + echo trim($title.' '.$output).($newLine ? PHP_EOL : ''); } - } diff --git a/src/Console/Commands/BroadcastFaker/ChannelCheerFake.php b/src/Console/Commands/BroadcastFaker/ChannelCheerFake.php index bee8ec6..c7c2913 100644 --- a/src/Console/Commands/BroadcastFaker/ChannelCheerFake.php +++ b/src/Console/Commands/BroadcastFaker/ChannelCheerFake.php @@ -4,24 +4,23 @@ class ChannelCheerFake extends Fake { - protected $eventData = [ - "is_anonymous" => false, - "user_id" => "1234", - "user_login" => null, - "user_name" => null, - "broadcaster_user_id" => "1337", - "broadcaster_user_login" => "cooler_user", - "broadcaster_user_name" => "Cooler_User", - "message" => "This is a bit cheer for you!", - "bits" => 1000, + 'is_anonymous' => false, + 'user_id' => '1234', + 'user_login' => null, + 'user_name' => null, + 'broadcaster_user_id' => '1337', + 'broadcaster_user_login' => 'cooler_user', + 'broadcaster_user_name' => 'Cooler_User', + 'message' => 'This is a bit cheer for you!', + 'bits' => 1000, ]; protected function randomizeEventData(): array { $array = parent::randomizeEventData(); - $anonymous = (bool)random_int(0, 1); + $anonymous = (bool) random_int(0, 1); if ($anonymous === false) { $username = Fake::fakeUsername(); diff --git a/src/Console/Commands/BroadcastFaker/ChannelFollowFake.php b/src/Console/Commands/BroadcastFaker/ChannelFollowFake.php index 1250e84..b4b6467 100644 --- a/src/Console/Commands/BroadcastFaker/ChannelFollowFake.php +++ b/src/Console/Commands/BroadcastFaker/ChannelFollowFake.php @@ -2,14 +2,13 @@ namespace Redbeed\OpenOverlay\Console\Commands\BroadcastFaker; -class ChannelFollowFake extends Fake +class ChannelFollowFake extends Fake { - protected $eventData = [ - "user_id" => "1234", - "user_name" => "cool_user", - "broadcaster_user_id" => "1337", - "broadcaster_user_name" => "cooler_user", + 'user_id' => '1234', + 'user_name' => 'cool_user', + 'broadcaster_user_id' => '1337', + 'broadcaster_user_name' => 'cooler_user', ]; protected function randomizeEventData(): array diff --git a/src/Console/Commands/BroadcastFaker/ChannelRaidFake.php b/src/Console/Commands/BroadcastFaker/ChannelRaidFake.php index c2a8149..86b5cac 100644 --- a/src/Console/Commands/BroadcastFaker/ChannelRaidFake.php +++ b/src/Console/Commands/BroadcastFaker/ChannelRaidFake.php @@ -4,15 +4,14 @@ class ChannelRaidFake extends Fake { - protected $eventData = [ - "from_broadcaster_user_id" => "1234", - "from_broadcaster_user_login" => "cool_user", - "from_broadcaster_user_name" => "Cool_User", - "to_broadcaster_user_id" => "1337", - "to_broadcaster_user_login" => "cooler_user", - "to_broadcaster_user_name" => "Cooler_User", - "viewers" => 9001 + 'from_broadcaster_user_id' => '1234', + 'from_broadcaster_user_login' => 'cool_user', + 'from_broadcaster_user_name' => 'Cool_User', + 'to_broadcaster_user_id' => '1337', + 'to_broadcaster_user_login' => 'cooler_user', + 'to_broadcaster_user_name' => 'Cooler_User', + 'viewers' => 9001, ]; protected function randomizeEventData(): array diff --git a/src/Console/Commands/BroadcastFaker/ChannelSubscribeFake.php b/src/Console/Commands/BroadcastFaker/ChannelSubscribeFake.php index 917db2c..8251cae 100644 --- a/src/Console/Commands/BroadcastFaker/ChannelSubscribeFake.php +++ b/src/Console/Commands/BroadcastFaker/ChannelSubscribeFake.php @@ -5,12 +5,12 @@ class ChannelSubscribeFake extends Fake { protected $eventData = [ - "user_id" => "1234", - "user_name" => "cool_user", - "broadcaster_user_id" => "1337", - "broadcaster_user_name" => "cooler_user", - "tier" => "1000", - "is_gift" => false, + 'user_id' => '1234', + 'user_name' => 'cool_user', + 'broadcaster_user_id' => '1337', + 'broadcaster_user_name' => 'cooler_user', + 'tier' => '1000', + 'is_gift' => false, ]; protected function randomizeEventData(): array diff --git a/src/Console/Commands/BroadcastFaker/ChannelUpdateFake.php b/src/Console/Commands/BroadcastFaker/ChannelUpdateFake.php index 797340b..183075f 100644 --- a/src/Console/Commands/BroadcastFaker/ChannelUpdateFake.php +++ b/src/Console/Commands/BroadcastFaker/ChannelUpdateFake.php @@ -6,15 +6,14 @@ class ChannelUpdateFake extends Fake { - protected $eventData = [ - "user_id" => "1337", - "user_name" => "open_overlay_user", - "title" => "Best Stream Ever", - "language" => "en", - "category_id" => "21779", - "category_name" => "Fortnite", - "is_mature" => false, + 'user_id' => '1337', + 'user_name' => 'open_overlay_user', + 'title' => 'Best Stream Ever', + 'language' => 'en', + 'category_id' => '21779', + 'category_name' => 'Fortnite', + 'is_mature' => false, ]; protected function randomizeEventData(): array @@ -23,7 +22,7 @@ protected function randomizeEventData(): array $array['title'] = implode(' ', [ $array['title'], - '('.Carbon::now()->format('H:i:s').')' + '('.Carbon::now()->format('H:i:s').')', ]); $array['user_name'] = Fake::fakeUsername(); diff --git a/src/Console/Commands/BroadcastFaker/Fake.php b/src/Console/Commands/BroadcastFaker/Fake.php index c92e019..321b6ea 100644 --- a/src/Console/Commands/BroadcastFaker/Fake.php +++ b/src/Console/Commands/BroadcastFaker/Fake.php @@ -1,14 +1,11 @@ randomizeEventData(); } - public static function fakeUsername(): string { + public static function fakeUsername(): string + { return Arr::random([ 'Chris', 'redbeed', @@ -34,7 +32,7 @@ public static function fakeUsername(): string { 'Lethinium', 'kekub', 'Laravel_user', - 'Twitch_user' + 'Twitch_user', ]); } } diff --git a/src/Console/Commands/BroadcastFaker/StreamOffline.php b/src/Console/Commands/BroadcastFaker/StreamOffline.php index 061b0e8..6b98ae2 100644 --- a/src/Console/Commands/BroadcastFaker/StreamOffline.php +++ b/src/Console/Commands/BroadcastFaker/StreamOffline.php @@ -5,8 +5,8 @@ class StreamOffline extends Fake { protected $eventData = [ - "broadcaster_user_id" => "u1337", - "broadcaster_user_login" => "cooler_user", - "broadcaster_user_name" => "Cooler_user", + 'broadcaster_user_id' => 'u1337', + 'broadcaster_user_login' => 'cooler_user', + 'broadcaster_user_name' => 'Cooler_user', ]; } diff --git a/src/Console/Commands/BroadcastFaker/StreamOnline.php b/src/Console/Commands/BroadcastFaker/StreamOnline.php index 1f626fd..a1e2316 100644 --- a/src/Console/Commands/BroadcastFaker/StreamOnline.php +++ b/src/Console/Commands/BroadcastFaker/StreamOnline.php @@ -7,12 +7,12 @@ class StreamOnline extends Fake { protected $eventData = [ - "id" => "1337", - "broadcaster_user_id" => "u1337", - "broadcaster_user_login" => "cooler_user", - "broadcaster_user_name" => "Cooler_user", - "type" => "live", - "started_at" => null, + 'id' => '1337', + 'broadcaster_user_id' => 'u1337', + 'broadcaster_user_login' => 'cooler_user', + 'broadcaster_user_name' => 'Cooler_user', + 'type' => 'live', + 'started_at' => null, ]; protected function randomizeEventData(): array diff --git a/src/Console/Commands/ChatBot/RestartServerCommand.php b/src/Console/Commands/ChatBot/RestartServerCommand.php index b9e5ae3..543bf2f 100644 --- a/src/Console/Commands/ChatBot/RestartServerCommand.php +++ b/src/Console/Commands/ChatBot/RestartServerCommand.php @@ -26,7 +26,6 @@ class RestartServerCommand extends Command public function handle(): void { - Cache::forever( StartCommand::RESTART_CACHE_KEY, $this->currentTime() diff --git a/src/Console/Commands/ChatBot/RuntimeCommand.php b/src/Console/Commands/ChatBot/RuntimeCommand.php index 5464b07..50f5269 100644 --- a/src/Console/Commands/ChatBot/RuntimeCommand.php +++ b/src/Console/Commands/ChatBot/RuntimeCommand.php @@ -24,7 +24,6 @@ protected function softShutdown() { $this->loop->stop(); - echo "Chatbot Service will shutdown." . PHP_EOL; + echo 'Chatbot Service will shutdown.'.PHP_EOL; } - } diff --git a/src/Console/Commands/ChatBot/SendMessageCommand.php b/src/Console/Commands/ChatBot/SendMessageCommand.php index af51cc5..9e9d8e0 100644 --- a/src/Console/Commands/ChatBot/SendMessageCommand.php +++ b/src/Console/Commands/ChatBot/SendMessageCommand.php @@ -2,13 +2,13 @@ namespace Redbeed\OpenOverlay\Console\Commands\ChatBot; +use function Ratchet\Client\connect; use Ratchet\Client\WebSocket; use Redbeed\OpenOverlay\ChatBot\Twitch\ConnectionHandler; use Redbeed\OpenOverlay\Models\BotConnection; use Redbeed\OpenOverlay\Models\User\Connection; use Redbeed\OpenOverlay\Models\User\UserOpenOverlay; use Redbeed\OpenOverlay\OpenOverlay; -use function Ratchet\Client\connect; class SendMessageCommand extends RuntimeCommand { @@ -35,11 +35,13 @@ public function handle(): void if (trim($message) === null) { $this->error('Message not filled'); + return; } if ($user === null) { $this->error('User not found'); + return; } @@ -47,6 +49,7 @@ public function handle(): void if ($bot === null) { $this->error('Bot not found'); + return; } @@ -59,7 +62,6 @@ public function handle(): void $twitchUsers = $user->connections()->where('service', 'twitch')->get(); foreach ($twitchUsers as $twitchUser) { - $connectionHandler->joinChannel($twitchUser); $connectionHandler->sendChatMessage($twitchUser->service_username, $message); @@ -72,7 +74,6 @@ public function handle(): void }); }); } - }, function ($e) { echo "Could not connect: {$e->getMessage()}\n"; }); @@ -90,6 +91,7 @@ private function configureMaxRuntime() private function getUser() { $userId = $this->argument('userId'); + return (OpenOverlay::userModel())::find($userId); } diff --git a/src/Console/Commands/ChatBot/StartCommand.php b/src/Console/Commands/ChatBot/StartCommand.php index 8f1e376..bffa5d4 100644 --- a/src/Console/Commands/ChatBot/StartCommand.php +++ b/src/Console/Commands/ChatBot/StartCommand.php @@ -3,14 +3,13 @@ namespace Redbeed\OpenOverlay\Console\Commands\ChatBot; use Illuminate\Support\Facades\Cache; +use function Ratchet\Client\connect; use Ratchet\Client\WebSocket; use Redbeed\OpenOverlay\ChatBot\Twitch\ConnectionHandler; use Redbeed\OpenOverlay\Models\BotConnection; -use function Ratchet\Client\connect; class StartCommand extends RuntimeCommand { - const RESTART_CACHE_KEY = 'redbeed:open-overlay:chat-bot:restart'; /** @@ -28,13 +27,10 @@ class StartCommand extends RuntimeCommand protected $description = 'Chat Bot worker (loop service)'; /** - * * Timestamp of the last restart - * */ private int $lastRestart; - public function handle(): void { $this->configureRestartTimer(); @@ -74,7 +70,6 @@ private function configureChatbot() $conn->on('close', function ($code = null, $reason = null) { echo "Connection closed ({$code} - {$reason})"; }); - }, function ($e) { echo "Could not connect: {$e->getMessage()}\n"; }); diff --git a/src/Console/Commands/EventBroadcastFaker.php b/src/Console/Commands/EventBroadcastFaker.php index 5fd28fa..0be4583 100644 --- a/src/Console/Commands/EventBroadcastFaker.php +++ b/src/Console/Commands/EventBroadcastFaker.php @@ -2,14 +2,12 @@ namespace Redbeed\OpenOverlay\Console\Commands; -use Carbon\Carbon; -use Illuminate\Database\Eloquent\Model; use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\ChannelCheerFake; +use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\ChannelFollowFake; use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\ChannelRaidFake; use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\ChannelSubscribeFake; use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\ChannelUpdateFake; use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\Fake; -use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\ChannelFollowFake; use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\StreamOffline; use Redbeed\OpenOverlay\Console\Commands\BroadcastFaker\StreamOnline; use Redbeed\OpenOverlay\Events\Twitch\EventReceived; @@ -62,7 +60,7 @@ public function handle(): void return; } - if (!array_key_exists($type, $this->types)) { + if (! array_key_exists($type, $this->types)) { $this->error('Type is not provided'); return; @@ -77,6 +75,6 @@ public function handle(): void ]); broadcast(new EventReceived($fakeEvent)); - $this->info('Event ' . $type . ' for ' . $twitchUserId . ' fired'); + $this->info('Event '.$type.' for '.$twitchUserId.' fired'); } } diff --git a/src/Console/Commands/EventSubDeleteCommand.php b/src/Console/Commands/EventSubDeleteCommand.php index 72088b3..c321b5a 100644 --- a/src/Console/Commands/EventSubDeleteCommand.php +++ b/src/Console/Commands/EventSubDeleteCommand.php @@ -88,10 +88,9 @@ public function handle(): void $this->subscriptionsTable($subscriptions); } - $this->info($subscriptionsCount . ' subscriptions matching your options'); + $this->info($subscriptionsCount.' subscriptions matching your options'); if ($this->confirm('Do you wish to delete them?')) { - $deleteProgress = $this->output->createProgressBar($subscriptionsCount); $deleteProgress->start(); @@ -99,12 +98,10 @@ public function handle(): void foreach ($subscriptions as $subscription) { try { - $eventSubClient->deleteSubscription($subscription['id']); $deleted++; - } catch (RequestException $exception) { - $this->error($subscription['id'] . ' could not deleted'); + $this->error($subscription['id'].' could not deleted'); } $deleteProgress->advance(); @@ -113,7 +110,7 @@ public function handle(): void $deleteProgress->finish(); $this->newLine(2); - $this->info('Total EventSub deleted: ' . $deleted . '/' . $subscriptionsCount); + $this->info('Total EventSub deleted: '.$deleted.'/'.$subscriptionsCount); } } diff --git a/src/Console/Commands/EventSubListingCommand.php b/src/Console/Commands/EventSubListingCommand.php index b61fce5..94807b0 100644 --- a/src/Console/Commands/EventSubListingCommand.php +++ b/src/Console/Commands/EventSubListingCommand.php @@ -3,7 +3,6 @@ namespace Redbeed\OpenOverlay\Console\Commands; use Illuminate\Console\Command; -use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Redbeed\OpenOverlay\Models\Twitch\EventSubscription; use Redbeed\OpenOverlay\Service\Twitch\EventSubClient; @@ -43,7 +42,7 @@ public function handle() $subscriptions = $eventSubClient->subscriptions(); $this->subscriptionsTable($subscriptions); - $this->info('Total EventSub subscriptions: ' . $subscriptions->count()); + $this->info('Total EventSub subscriptions: '.$subscriptions->count()); } protected function subscriptionsTable(Collection $subscriptions): void @@ -52,10 +51,10 @@ protected function subscriptionsTable(Collection $subscriptions): void /** @var EventSubscription $subscription */ return [ - 'id' => $subscription->id, - 'status' => $subscription->status, - 'type' => $subscription->type, - 'condition' => json_encode($subscription->condition), + 'id' => $subscription->id, + 'status' => $subscription->status, + 'type' => $subscription->type, + 'condition' => json_encode($subscription->condition), 'created_at' => $subscription->createdAt->toDateTimeLocalString(), ]; }); diff --git a/src/Console/Commands/Make/MakeBotSchedulingCommand.php b/src/Console/Commands/Make/MakeBotSchedulingCommand.php index b267ae1..15346b7 100644 --- a/src/Console/Commands/Make/MakeBotSchedulingCommand.php +++ b/src/Console/Commands/Make/MakeBotSchedulingCommand.php @@ -3,9 +3,7 @@ namespace Redbeed\OpenOverlay\Console\Commands\Make; use Illuminate\Console\GeneratorCommand; -use Illuminate\Support\Str; use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputOption; class MakeBotSchedulingCommand extends GeneratorCommand { diff --git a/src/Console/Commands/SecretCommand.php b/src/Console/Commands/SecretCommand.php index dbf02a5..61438c5 100644 --- a/src/Console/Commands/SecretCommand.php +++ b/src/Console/Commands/SecretCommand.php @@ -6,7 +6,6 @@ class SecretCommand extends EventSubListingCommand { - private const ENV_KEY = 'OVERLAY_SECRET'; protected $signature = 'overlay:secret @@ -19,8 +18,9 @@ public function handle(): void { $currentSecret = config('openoverlay.webhook.twitch.secret'); - if (!empty($currentSecret) && !$this->option('force')) { + if (! empty($currentSecret) && ! $this->option('force')) { $this->warn('You already have a secret'); + return; } @@ -44,7 +44,7 @@ private function writeSecretKeyInEnvironmentFile($key): void if (preg_match($secretKeyPattern, $envFileContent) === 0) { file_put_contents( $envFilePath, - self::ENV_KEY . '=' . $key . PHP_EOL, + self::ENV_KEY.'='.$key.PHP_EOL, FILE_APPEND ); @@ -57,7 +57,7 @@ private function writeSecretKeyInEnvironmentFile($key): void $envFilePath, preg_replace( $secretKeyPattern, - self::ENV_KEY . '=' . $key, + self::ENV_KEY.'='.$key, $envFileContent ) ); @@ -69,13 +69,14 @@ private function showOption(string $key): void { if ($this->option('show')) { $this->info('New Secret Key:'); - $this->info(self::ENV_KEY . '=' . $key); + $this->info(self::ENV_KEY.'='.$key); } } protected function keyReplacementPattern(): string { - $escaped = preg_quote('=' . config('openoverlay.webhook.twitch.secret'), '/'); - return "/^" . self::ENV_KEY . "{$escaped}/m"; + $escaped = preg_quote('='.config('openoverlay.webhook.twitch.secret'), '/'); + + return '/^'.self::ENV_KEY."{$escaped}/m"; } } diff --git a/src/Console/Commands/Twitch/OnlineStatusCommand.php b/src/Console/Commands/Twitch/OnlineStatusCommand.php index b324914..acfcb54 100644 --- a/src/Console/Commands/Twitch/OnlineStatusCommand.php +++ b/src/Console/Commands/Twitch/OnlineStatusCommand.php @@ -10,7 +10,6 @@ class OnlineStatusCommand extends Command { - protected $signature = 'overlay:twitch:online-status {twitchUserId?} {--all=false}'; protected $description = 'Checks online status of twitch user'; @@ -19,7 +18,7 @@ public function handle(): void { $connections = Connection::where('service', 'twitch'); - if (!$this->option('all') && $this->argument('twitchUserId')) { + if (! $this->option('all') && $this->argument('twitchUserId')) { $connections = $connections->where('service_user_id', $this->argument('twitchUserId')); } @@ -36,13 +35,12 @@ public function handle(): void Carbon::parse($stream['created_at'] ?? null, 'UTC') ); - $this->info('Streamer ' . $connection->service_username . ' is online'); + $this->info('Streamer '.$connection->service_username.' is online'); continue; } - $this->info('Streamer ' . $connection->service_username . ' is offline'); + $this->info('Streamer '.$connection->service_username.' is offline'); StreamerOnline::setOffline($connection->service_user_id); } - } } diff --git a/src/Console/Commands/Twitch/RefresherCommand.php b/src/Console/Commands/Twitch/RefresherCommand.php index 57eeba6..73fe88c 100644 --- a/src/Console/Commands/Twitch/RefresherCommand.php +++ b/src/Console/Commands/Twitch/RefresherCommand.php @@ -8,7 +8,6 @@ class RefresherCommand extends Command { - protected $signature = 'overlay:twitch:refresher'; protected $description = 'Refresh followers and subscriber for all twitch connections'; @@ -18,7 +17,7 @@ public function handle(): void $connections = Connection::where('service', 'twitch')->get(); foreach ($connections as $connection) { - $this->info('Start for ' . $connection->service_username . ' (' . $connection->service_user_id . ')'); + $this->info('Start for '.$connection->service_username.' ('.$connection->service_user_id.')'); event(new RefresherEvent($connection)); } diff --git a/src/Console/ConsoleServiceProvider.php b/src/Console/ConsoleServiceProvider.php index 476de5d..901e9d3 100644 --- a/src/Console/ConsoleServiceProvider.php +++ b/src/Console/ConsoleServiceProvider.php @@ -4,8 +4,8 @@ use Illuminate\Support\ServiceProvider; use Redbeed\OpenOverlay\Console\Commands\ChatBot\RestartServerCommand; -use Redbeed\OpenOverlay\Console\Commands\ChatBot\StartCommand; use Redbeed\OpenOverlay\Console\Commands\ChatBot\SendMessageCommand; +use Redbeed\OpenOverlay\Console\Commands\ChatBot\StartCommand; use Redbeed\OpenOverlay\Console\Commands\EventBroadcastFaker; use Redbeed\OpenOverlay\Console\Commands\EventSubDeleteCommand; use Redbeed\OpenOverlay\Console\Commands\EventSubListingCommand; @@ -15,7 +15,6 @@ class ConsoleServiceProvider extends ServiceProvider { - public function boot(): void { $this->registerGlobalCommands(); diff --git a/src/Console/Scheduling/ChatBotScheduling.php b/src/Console/Scheduling/ChatBotScheduling.php index 5f6405a..261665b 100644 --- a/src/Console/Scheduling/ChatBotScheduling.php +++ b/src/Console/Scheduling/ChatBotScheduling.php @@ -35,11 +35,10 @@ protected function schedule(Event $event): Event public function getJob(Schedule $schedule, $user): ?Event { - if (!$this->valid($user)) { + if (! $this->valid($user)) { return null; } return $this->schedule($schedule->command(SendMessageCommand::class, [$user->id, $this->message()])); } - } diff --git a/src/EventServiceProvider.php b/src/EventServiceProvider.php index b38e79f..99d3af5 100644 --- a/src/EventServiceProvider.php +++ b/src/EventServiceProvider.php @@ -2,22 +2,21 @@ namespace Redbeed\OpenOverlay; -use \Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; +use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Event; -use Illuminate\Support\Facades\Log; use Redbeed\OpenOverlay\Automations\Triggers\TwitchChatMessageTrigger; use Redbeed\OpenOverlay\Events\Twitch\BotTokenExpires; use Redbeed\OpenOverlay\Events\Twitch\ChatMessageReceived; use Redbeed\OpenOverlay\Events\Twitch\EventReceived; use Redbeed\OpenOverlay\Events\Twitch\RefresherEvent; use Redbeed\OpenOverlay\Events\UserConnectionChanged; +use Redbeed\OpenOverlay\Listeners\AutoShoutOutRaid; use Redbeed\OpenOverlay\Listeners\Twitch\NewFollowerListener; use Redbeed\OpenOverlay\Listeners\Twitch\NewSubscriberListener; -use Redbeed\OpenOverlay\Listeners\AutoShoutOutRaid; +use Redbeed\OpenOverlay\Listeners\Twitch\Refresher\NewConnectionRefresher; use Redbeed\OpenOverlay\Listeners\Twitch\Refresher\StandardRefresher; -use Redbeed\OpenOverlay\Listeners\TwitchSplitReceivedEvents; use Redbeed\OpenOverlay\Listeners\Twitch\UpdateBotToken; -use Redbeed\OpenOverlay\Listeners\Twitch\Refresher\NewConnectionRefresher; +use Redbeed\OpenOverlay\Listeners\TwitchSplitReceivedEvents; use Redbeed\OpenOverlay\Listeners\UpdateUserWebhookCalls; use Redbeed\OpenOverlay\Sociallite\TwitchClientCredentialsExtendSocialite; use SocialiteProviders\Manager\SocialiteWasCalled; @@ -25,15 +24,14 @@ class EventServiceProvider extends ServiceProvider { - protected $listen = [ SocialiteWasCalled::class => [ TwitchExtendSocialite::class, TwitchClientCredentialsExtendSocialite::class, ], - BotTokenExpires::class => [ - UpdateBotToken::class - ] + BotTokenExpires::class => [ + UpdateBotToken::class, + ], ]; public function listens(): array @@ -49,7 +47,6 @@ public function listens(): array $listen[UserConnectionChanged::class][] = NewConnectionRefresher::class; $listen[RefresherEvent::class][] = StandardRefresher::class; - if (config('openoverlay.service.twitch.save.follower', false) === true) { $listen[EventReceived::class][] = NewFollowerListener::class; } @@ -58,14 +55,13 @@ public function listens(): array $listen[EventReceived::class][] = NewSubscriberListener::class; } - Event::listen(function (ChatMessageReceived $event){ + Event::listen(function (ChatMessageReceived $event) { automation(new TwitchChatMessageTrigger($event->message)); }); return $listen; } - public function autoShoutOutListener() { $modules = config('openoverlay.modules', []); diff --git a/src/Events/Twitch/ChatMessageReceived.php b/src/Events/Twitch/ChatMessageReceived.php index f3169de..70a3ce0 100644 --- a/src/Events/Twitch/ChatMessageReceived.php +++ b/src/Events/Twitch/ChatMessageReceived.php @@ -2,6 +2,7 @@ namespace Redbeed\OpenOverlay\Events\Twitch; +use function config; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; @@ -11,7 +12,6 @@ use Redbeed\OpenOverlay\Models\Twitch\Emote; use Redbeed\OpenOverlay\Models\User\Connection; use Redbeed\OpenOverlay\Support\ViewerInChat; -use function config; class ChatMessageReceived implements ShouldBroadcastNow { @@ -44,7 +44,7 @@ public function viewerInChatListener() public function broadcastOn(): Channel { - return new Channel('twitch.' . $this->twitchUser->service_user_id); + return new Channel('twitch.'.$this->twitchUser->service_user_id); } public function broadcastAs(): string diff --git a/src/Events/Twitch/StreamOffline.php b/src/Events/Twitch/StreamOffline.php index 243cd0d..97e69ce 100644 --- a/src/Events/Twitch/StreamOffline.php +++ b/src/Events/Twitch/StreamOffline.php @@ -35,7 +35,7 @@ public function __construct(EventSubEvents $twitchEvent) public function broadcastOn(): Channel { - return new Channel('twitch.' . $this->twitchUser->service_user_id); + return new Channel('twitch.'.$this->twitchUser->service_user_id); } public function broadcastAs(): string @@ -47,7 +47,7 @@ public function broadcastWith() { return [ 'started' => $this->streamStarted, - 'ended' => Carbon::now(), + 'ended' => Carbon::now(), ]; } } diff --git a/src/Events/Twitch/StreamOnline.php b/src/Events/Twitch/StreamOnline.php index 79651a8..d97c446 100644 --- a/src/Events/Twitch/StreamOnline.php +++ b/src/Events/Twitch/StreamOnline.php @@ -31,7 +31,7 @@ public function __construct(EventSubEvents $twitchEvent) public function broadcastOn(): Channel { - return new Channel('twitch.' . $this->twitchUser->service_user_id); + return new Channel('twitch.'.$this->twitchUser->service_user_id); } public function broadcastAs(): string diff --git a/src/Events/ViewerEnteredChat.php b/src/Events/ViewerEnteredChat.php index 7eea08d..9d26ce8 100644 --- a/src/Events/ViewerEnteredChat.php +++ b/src/Events/ViewerEnteredChat.php @@ -34,6 +34,6 @@ public function broadcastWith() public function broadcastOn() { - return new Channel('twitch.' . $this->streamer->service_user_id); + return new Channel('twitch.'.$this->streamer->service_user_id); } } diff --git a/src/Exceptions/AutomationFilterNotValid.php b/src/Exceptions/AutomationFilterNotValid.php index 65395bf..bc15c20 100644 --- a/src/Exceptions/AutomationFilterNotValid.php +++ b/src/Exceptions/AutomationFilterNotValid.php @@ -4,5 +4,4 @@ class AutomationFilterNotValid extends \Exception { - } diff --git a/src/Exceptions/TwitchEmoteSetIdException.php b/src/Exceptions/TwitchEmoteSetIdException.php index 2bc1867..9aecf5e 100644 --- a/src/Exceptions/TwitchEmoteSetIdException.php +++ b/src/Exceptions/TwitchEmoteSetIdException.php @@ -6,5 +6,4 @@ class TwitchEmoteSetIdException extends Exception { - } diff --git a/src/Exceptions/WrongConnectionTypeException.php b/src/Exceptions/WrongConnectionTypeException.php index ede56eb..e474bbb 100644 --- a/src/Exceptions/WrongConnectionTypeException.php +++ b/src/Exceptions/WrongConnectionTypeException.php @@ -6,5 +6,4 @@ class WrongConnectionTypeException extends Exception { - } diff --git a/src/Http/Controllers/Api/Connection/WebhookController.php b/src/Http/Controllers/Api/Connection/WebhookController.php index b0303e0..cb9c471 100644 --- a/src/Http/Controllers/Api/Connection/WebhookController.php +++ b/src/Http/Controllers/Api/Connection/WebhookController.php @@ -25,15 +25,13 @@ public function handleProviderCallback(Request $request) } $event = $request->get('event'); - if (!empty($event) && in_array($messageType, config('openoverlay.webhook.twitch.subscribe'), true)) { - + if (! empty($event) && in_array($messageType, config('openoverlay.webhook.twitch.subscribe'), true)) { return $this->receiveNotification( $messageId, $messageType, $messageTimestamp, $event ); - } return $request->get('challenge'); @@ -62,6 +60,5 @@ private function receiveNotification(string $eventId, string $eventType, string } return \response('Event received', $newEvent->wasRecentlyCreated ? Response::HTTP_CREATED : Response::HTTP_OK); - } } diff --git a/src/Http/Controllers/Connection/AppTokenController.php b/src/Http/Controllers/Connection/AppTokenController.php index aacc623..0866f4c 100644 --- a/src/Http/Controllers/Connection/AppTokenController.php +++ b/src/Http/Controllers/Connection/AppTokenController.php @@ -4,7 +4,6 @@ class AppTokenController extends SocialiteController { - protected $socialiteDriver = 'twitch_client_credentials'; public function __construct() diff --git a/src/Http/Controllers/Connection/AuthController.php b/src/Http/Controllers/Connection/AuthController.php index 3da4a4a..c2c5c55 100644 --- a/src/Http/Controllers/Connection/AuthController.php +++ b/src/Http/Controllers/Connection/AuthController.php @@ -6,11 +6,9 @@ use Illuminate\Support\Facades\Auth; use Redbeed\OpenOverlay\Events\UserConnectionChanged; use Redbeed\OpenOverlay\Models\User\Connection; -use Redbeed\OpenOverlay\Service\Twitch\UsersClient; class AuthController extends SocialiteController { - protected function callbackUrl(): string { return route('open_overlay.connection.callback'); diff --git a/src/Http/Controllers/Connection/SocialiteController.php b/src/Http/Controllers/Connection/SocialiteController.php index 4f03bc0..9c29c8d 100644 --- a/src/Http/Controllers/Connection/SocialiteController.php +++ b/src/Http/Controllers/Connection/SocialiteController.php @@ -1,6 +1,5 @@ setScopes($this->scopes()); } - protected function scopes(): array { + protected function scopes(): array + { return config('openoverlay.service.twitch.scopes'); } @@ -26,12 +26,11 @@ public function redirect(): RedirectResponse { $callbackUrl = $this->callbackUrl(); - if (!empty($callbackUrl)) { + if (! empty($callbackUrl)) { /** @var RedirectResponse $redirect */ $redirect = $this->socialite()->redirect(); - $redirectUrl = Url::fromString($redirect->getTargetUrl()); $redirectUrl = $redirectUrl->withQueryParameter('redirect_uri', $callbackUrl); diff --git a/src/Listeners/AutoShoutOutRaid.php b/src/Listeners/AutoShoutOutRaid.php index 3274c34..9cc5427 100644 --- a/src/Listeners/AutoShoutOutRaid.php +++ b/src/Listeners/AutoShoutOutRaid.php @@ -23,12 +23,12 @@ public function handle(EventReceived $event) $connection = Connection::where('service_user_id', $event->event->event_user_id) ->first(); - if (!$connection) { + if (! $connection) { return; } $chatMessage = config( - 'openoverlay.modules' . AutoShoutOutRaid::class . 'message', + 'openoverlay.modules'.AutoShoutOutRaid::class.'message', 'Follow :username over at :twitchUrl. They were last playing :gameName' ); @@ -40,7 +40,7 @@ public function handle(EventReceived $event) $channels = $channelClient->get($eventData['from_broadcaster_user_id']); $channel = head($channels['data']); - if (!empty($channel['game_id'])) { + if (! empty($channel['game_id'])) { $gameName = $channel['game_name']; } } catch (ClientException $exception) { @@ -52,7 +52,7 @@ public function handle(EventReceived $event) 'userId' => $connection->user->id, 'message' => __($chatMessage, [ 'username' => $eventData['from_broadcaster_user_name'], - 'twitchUrl' => 'https://www.twitch.tv/' . $eventData['from_broadcaster_user_login'], + 'twitchUrl' => 'https://www.twitch.tv/'.$eventData['from_broadcaster_user_login'], 'gameName' => $gameName, ]), ]); diff --git a/src/Listeners/Twitch/EventListener.php b/src/Listeners/Twitch/EventListener.php index 5667ea4..6512454 100644 --- a/src/Listeners/Twitch/EventListener.php +++ b/src/Listeners/Twitch/EventListener.php @@ -7,7 +7,6 @@ abstract class EventListener implements ShouldQueue { - protected function eventType(): string { return 'event.type'; // https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types @@ -27,6 +26,5 @@ public function handle(EventReceived $event) $this->handleEvent($event); } - abstract public function handleEvent(EventReceived $event): void; } diff --git a/src/Listeners/Twitch/NewFollowerListener.php b/src/Listeners/Twitch/NewFollowerListener.php index d5aefba..7d698f1 100644 --- a/src/Listeners/Twitch/NewFollowerListener.php +++ b/src/Listeners/Twitch/NewFollowerListener.php @@ -5,11 +5,9 @@ use Carbon\Carbon; use Redbeed\OpenOverlay\Events\Twitch\EventReceived; use Redbeed\OpenOverlay\Models\Twitch\UserFollowers; -use Redbeed\OpenOverlay\Models\Twitch\UserSubscriber; class NewFollowerListener extends EventListener { - protected function eventType(): string { return 'channel.follow'; @@ -26,11 +24,11 @@ public function handleEvent(EventReceived $event): void if (empty($followerModal)) { UserFollowers::create([ - 'twitch_user_id' => $event->event->event_user_id, - 'follower_user_id' => $followerData['user_id'], + 'twitch_user_id' => $event->event->event_user_id, + 'follower_user_id' => $followerData['user_id'], 'follower_username' => $followerData['user_name'], - 'followed_at' => Carbon::parse($followerData['followed_at']), - 'deleted_at' => null, + 'followed_at' => Carbon::parse($followerData['followed_at']), + 'deleted_at' => null, ]); return; diff --git a/src/Listeners/Twitch/NewSubscriberListener.php b/src/Listeners/Twitch/NewSubscriberListener.php index 9bb43ba..7586b1e 100644 --- a/src/Listeners/Twitch/NewSubscriberListener.php +++ b/src/Listeners/Twitch/NewSubscriberListener.php @@ -17,13 +17,13 @@ public function handleEvent(EventReceived $event): void $subscriberData = $event->event->event_data; UserSubscriber::firstOrCreate([ - 'twitch_user_id' => $event->event->event_user_id, + 'twitch_user_id' => $event->event->event_user_id, 'subscriber_user_id' => $subscriberData['user_id'], ], [ 'subscriber_username' => $subscriberData['user_name'], - 'tier' => $subscriberData['user_name'], - 'tier_name' => $subscriberData['plan_name'] ?? '', - 'is_gift' => $subscriberData['is_gift'], + 'tier' => $subscriberData['user_name'], + 'tier_name' => $subscriberData['plan_name'] ?? '', + 'is_gift' => $subscriberData['is_gift'], ]); } } diff --git a/src/Listeners/Twitch/Refresher/LoginRefresher.php b/src/Listeners/Twitch/Refresher/LoginRefresher.php index 88a9efb..c0d8e44 100644 --- a/src/Listeners/Twitch/Refresher/LoginRefresher.php +++ b/src/Listeners/Twitch/Refresher/LoginRefresher.php @@ -2,6 +2,7 @@ namespace Redbeed\OpenOverlay\Listeners\Twitch\Refresher; +use Exception; use Illuminate\Auth\Events\Login; use Illuminate\Contracts\Queue\ShouldQueue; use Redbeed\OpenOverlay\Exceptions\WrongConnectionTypeException; @@ -27,7 +28,13 @@ public function handle(Login $event) } if (parent::saveSubscriber()) { - $this->refreshSubscriber($twitchConnection); + try { + $this->refreshSubscriber($twitchConnection); + } catch (Exception $e) { + // ignore exception as it is not critical + // user auth token is not valid + report($e); + } } } } diff --git a/src/Listeners/Twitch/Refresher/Refresher.php b/src/Listeners/Twitch/Refresher/Refresher.php index 4e122bc..3ad0d88 100644 --- a/src/Listeners/Twitch/Refresher/Refresher.php +++ b/src/Listeners/Twitch/Refresher/Refresher.php @@ -3,6 +3,7 @@ namespace Redbeed\OpenOverlay\Listeners\Twitch\Refresher; use Carbon\Carbon; +use function head; use Illuminate\Support\Arr; use Redbeed\OpenOverlay\Exceptions\WrongConnectionTypeException; use Redbeed\OpenOverlay\Models\Twitch\UserFollowers; @@ -10,7 +11,6 @@ use Redbeed\OpenOverlay\Models\User\Connection; use Redbeed\OpenOverlay\Service\Twitch\SubscriptionsClient; use Redbeed\OpenOverlay\Service\Twitch\UsersClient; -use function head; abstract class Refresher { @@ -19,7 +19,7 @@ public static function saveFollowers(): bool return config('openoverlay.service.twitch.save.follower', false) === true; } - public static function saveSubscriber(): bool + public static function saveSubscriber(): bool { return config('openoverlay.service.twitch.save.subscriber', false) === true; } @@ -49,11 +49,11 @@ protected function refreshFollowers(Connection $twitchConnection) if ($followerModal === null) { UserFollowers::create([ - 'twitch_user_id' => $twitchConnection->service_user_id, - 'follower_user_id' => $followerData['from_id'], + 'twitch_user_id' => $twitchConnection->service_user_id, + 'follower_user_id' => $followerData['from_id'], 'follower_username' => $followerData['from_name'], - 'followed_at' => Carbon::parse($followerData['followed_at']), - 'deleted_at' => null, + 'followed_at' => Carbon::parse($followerData['followed_at']), + 'deleted_at' => null, ]); continue; @@ -107,16 +107,16 @@ protected function refreshSubscriber(Connection $twitchConnection) UserSubscriber::create([ 'twitch_user_id' => $twitchConnection->service_user_id, - 'subscriber_user_id' => $subscriberData['user_id'], - 'subscriber_username' => $subscriberData['user_name'], + 'subscriber_user_id' => $subscriberData['user_id'], + 'subscriber_username' => $subscriberData['user_name'], 'subscriber_login_name' => $subscriberData['user_login'], - 'tier' => $subscriberData['tier'], + 'tier' => $subscriberData['tier'], 'tier_name' => $subscriberData['plan_name'], - 'is_gift' => $subscriberData['is_gift'], - 'gifter_user_id' => $subscriberData['gifter_id'], - 'gifter_username' => $subscriberData['gifter_name'], + 'is_gift' => $subscriberData['is_gift'], + 'gifter_user_id' => $subscriberData['gifter_id'], + 'gifter_username' => $subscriberData['gifter_name'], 'gifter_login_name' => $subscriberData['gifter_login'], ]); @@ -149,7 +149,7 @@ protected function refreshSubscriber(Connection $twitchConnection) private function twitchUser(string $broadcasterId): array { $userClient = new UsersClient(); + return head(Arr::get($userClient->byId($broadcasterId), 'data', [])); } - } diff --git a/src/Listeners/Twitch/Refresher/StandardRefresher.php b/src/Listeners/Twitch/Refresher/StandardRefresher.php index f6e23a0..235db64 100644 --- a/src/Listeners/Twitch/Refresher/StandardRefresher.php +++ b/src/Listeners/Twitch/Refresher/StandardRefresher.php @@ -25,7 +25,7 @@ public function handle(RefresherEvent $event) if (parent::saveSubscriber()) { try { $this->refreshSubscriber($event->twitchConnection); - }catch (ClientException $e) { + } catch (ClientException $e) { // ignore exception as it is not critical // user auth token is not valid report($e); diff --git a/src/Listeners/Twitch/UpdateBotToken.php b/src/Listeners/Twitch/UpdateBotToken.php index d1e269b..d75acbe 100644 --- a/src/Listeners/Twitch/UpdateBotToken.php +++ b/src/Listeners/Twitch/UpdateBotToken.php @@ -20,7 +20,7 @@ public function handle(BotTokenExpires $event) $client = AuthClient::http(); $response = $client->refreshToken($event->botModel->service_refresh_token); } catch (\Exception $exception) { - Log::error("Bot Connection deleted"); + Log::error('Bot Connection deleted'); Log::error($exception); return; diff --git a/src/Listeners/TwitchSplitReceivedEvents.php b/src/Listeners/TwitchSplitReceivedEvents.php index fbb4a46..2543d58 100644 --- a/src/Listeners/TwitchSplitReceivedEvents.php +++ b/src/Listeners/TwitchSplitReceivedEvents.php @@ -12,11 +12,13 @@ public function handle(EventReceived $twitchEvent) { if ($twitchEvent->event->event_type === 'stream.online') { broadcast(new StreamOnline($twitchEvent->event)); + return; } if ($twitchEvent->event->event_type === 'stream.offline') { broadcast(new StreamOffline($twitchEvent->event)); + return; } } diff --git a/src/Models/BotConnection.php b/src/Models/BotConnection.php index 1f43a4a..1efa4ea 100644 --- a/src/Models/BotConnection.php +++ b/src/Models/BotConnection.php @@ -42,11 +42,13 @@ public function setServiceRefreshTokenAttribute($value): void $this->attributes['service_refresh_token'] = $this->encryptString($value); } - private function decryptString(string $key): string { + private function decryptString(string $key): string + { return Crypt::decryptString($key); } - private function encryptString(string $value): string { + private function encryptString(string $value): string + { return Crypt::encryptString($value); } diff --git a/src/Models/Twitch/Emote.php b/src/Models/Twitch/Emote.php index 0afcf7f..56801ef 100644 --- a/src/Models/Twitch/Emote.php +++ b/src/Models/Twitch/Emote.php @@ -5,7 +5,9 @@ class Emote { const IMAGE_SIZE_SM = 'url_1x'; + const IMAGE_SIZE_MD = 'url_2x'; + const IMAGE_SIZE_LG = 'url_4x'; /** @var string */ @@ -34,15 +36,15 @@ public static function fromJson(array $emoteData): Emote $emote->name = $emoteData['name']; $emote->images = $emoteData['images']; - if (!empty($emoteData['tier'])) { + if (! empty($emoteData['tier'])) { $emote->tier = $emoteData['tier']; } - if (!empty($emoteData['emote_type'])) { + if (! empty($emoteData['emote_type'])) { $emote->emoteType = $emoteData['emote_type']; } - if (!empty($emoteData['emote_set_id'])) { + if (! empty($emoteData['emote_set_id'])) { $emote->emoteSetId = $emoteData['emote_set_id']; } @@ -53,5 +55,4 @@ public function image(string $size = Emote::IMAGE_SIZE_MD): string { return $this->images[$size]; } - } diff --git a/src/Models/Twitch/EventSubscription.php b/src/Models/Twitch/EventSubscription.php index 44faaef..ef263b3 100644 --- a/src/Models/Twitch/EventSubscription.php +++ b/src/Models/Twitch/EventSubscription.php @@ -1,9 +1,7 @@ attributes['service_refresh_token'] = $this->encryptString($value); } - private function decryptString(string $key): string { + private function decryptString(string $key): string + { return Crypt::decryptString($key); } - private function encryptString(string $value): string { + private function encryptString(string $value): string + { return Crypt::encryptString($value); } diff --git a/src/OpenOverlay.php b/src/OpenOverlay.php index 1d76f05..db72a1e 100644 --- a/src/OpenOverlay.php +++ b/src/OpenOverlay.php @@ -2,10 +2,8 @@ namespace Redbeed\OpenOverlay; - class OpenOverlay { - public static function userModel(): string { return config('auth.providers.users.model'); diff --git a/src/OpenOverlayServiceProvider.php b/src/OpenOverlayServiceProvider.php index 9bf8a2f..dc2b513 100644 --- a/src/OpenOverlayServiceProvider.php +++ b/src/OpenOverlayServiceProvider.php @@ -4,11 +4,11 @@ use Illuminate\Console\Scheduling\Schedule; use Illuminate\Support\ServiceProvider; +use Redbeed\OpenOverlay\Automations\AutomationsServiceProvider; use Redbeed\OpenOverlay\Console\Commands\Twitch\OnlineStatusCommand; use Redbeed\OpenOverlay\Console\ConsoleServiceProvider; use Redbeed\OpenOverlay\Console\Scheduling\ChatBotScheduling; use Redbeed\OpenOverlay\Models\BotConnection; -use Redbeed\OpenOverlay\Automations\AutomationsServiceProvider; class OpenOverlayServiceProvider extends ServiceProvider { @@ -19,8 +19,8 @@ class OpenOverlayServiceProvider extends ServiceProvider */ public function boot(): void { - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - $this->loadRoutesFrom(__DIR__ . '/../routes/openoverlay.php'); + $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); + $this->loadRoutesFrom(__DIR__.'/../routes/openoverlay.php'); // Publishing is only necessary when using the CLI. if ($this->app->runningInConsole()) { @@ -47,7 +47,7 @@ public function register(): void $this->app->register(ConsoleServiceProvider::class); $this->app->register(AutomationsServiceProvider::class); - $this->mergeConfigFrom(__DIR__ . '/../config/openoverlay.php', 'openoverlay'); + $this->mergeConfigFrom(__DIR__.'/../config/openoverlay.php', 'openoverlay'); // Register the service the package provides. $this->app->singleton('openoverlay', function ($app) { @@ -65,7 +65,6 @@ public function provides() return ['openoverlay']; } - /** * Console-specific booting. * @@ -75,7 +74,7 @@ protected function bootForConsole(): void { // Publishing the configuration file. $this->publishes([ - __DIR__ . '/../config/openoverlay.php' => config_path('openoverlay.php'), + __DIR__.'/../config/openoverlay.php' => config_path('openoverlay.php'), ], 'openoverlay.config'); $this->callAfterResolving(Schedule::class, function (Schedule $schedule) { @@ -93,9 +92,7 @@ private function registerSchedule(Schedule $schedule): void foreach ($bots as $bot) { foreach ($bot->users as $user) { foreach ($scheduledMessages as $message) { - (new $message())->getJob($schedule, $user); - } } } diff --git a/src/Service/Twitch/ApiClient.php b/src/Service/Twitch/ApiClient.php index d217348..e6350de 100644 --- a/src/Service/Twitch/ApiClient.php +++ b/src/Service/Twitch/ApiClient.php @@ -26,7 +26,7 @@ public function __construct() RequestOptions::HEADERS => [ 'Client-ID' => $clientId, 'Accept' => 'application/json', - 'Authorization' => 'Bearer ' . $authCode, + 'Authorization' => 'Bearer '.$authCode, ], ]); } @@ -41,6 +41,7 @@ public static function http() /** * @return static + * * @throws AppTokenMissing */ public function addAppToken() @@ -53,28 +54,26 @@ public function addAppToken() return $this->withOptions([ RequestOptions::HEADERS => [ - 'Authorization' => 'Bearer ' . $appToken, + 'Authorization' => 'Bearer '.$appToken, ], ]); } /** - * @param string $appToken - * + * @param string $appToken * @return static */ public function withAppToken(string $appToken) { return $this->setOptions([ RequestOptions::HEADERS => [ - 'Authorization' => 'Bearer ' . $appToken, + 'Authorization' => 'Bearer '.$appToken, ], ]); } /** - * @param array $options - * + * @param array $options * @return static */ public function withOptions(array $options) @@ -86,8 +85,7 @@ public function withOptions(array $options) } /** - * @param array $options - * + * @param array $options * @return static */ public function setOptions(array $options): self @@ -99,16 +97,16 @@ public function setOptions(array $options): self } /** - * @param string $method - * @param string $url - * + * @param string $method + * @param string $url * @return array + * * @throws \GuzzleHttp\Exception\GuzzleException */ public function request(string $method, string $url) { $response = $this->httpClient->request($method, $url, $this->options); - $json = (string)$response->getBody(); + $json = (string) $response->getBody(); return json_decode($json, true); } diff --git a/src/Service/Twitch/ChannelsClient.php b/src/Service/Twitch/ChannelsClient.php index 5a3ee85..ff34f92 100644 --- a/src/Service/Twitch/ChannelsClient.php +++ b/src/Service/Twitch/ChannelsClient.php @@ -18,7 +18,8 @@ public function get(string $broadcasterId): array ->request('GET', 'channels'); } - public function lastGame(string $broadcasterId) { + public function lastGame(string $broadcasterId) + { $channels = (new self)->get($broadcasterId); $channel = head($channels['data']); diff --git a/src/Service/Twitch/ChatEmotesClient.php b/src/Service/Twitch/ChatEmotesClient.php index 02e1947..7187e33 100644 --- a/src/Service/Twitch/ChatEmotesClient.php +++ b/src/Service/Twitch/ChatEmotesClient.php @@ -2,20 +2,18 @@ namespace Redbeed\OpenOverlay\Service\Twitch; -use Exception; -use GuzzleHttp\Exception\ClientException; use GuzzleHttp\RequestOptions; use Redbeed\OpenOverlay\Exceptions\TwitchEmoteSetIdException; use Redbeed\OpenOverlay\Models\Twitch\Emote; class ChatEmotesClient extends ApiClient { - const MAX_SET_ID = 25; /** - * @param string $broadcasterId + * @param string $broadcasterId * @return Emote[] + * * @throws \GuzzleHttp\Exception\GuzzleException * @throws \Redbeed\OpenOverlay\Exceptions\AppTokenMissing */ @@ -38,8 +36,9 @@ public function get(string $broadcasterId): array } /** - * @param string $broadcasterId + * @param string $broadcasterId * @return Emote[] + * * @throws \GuzzleHttp\Exception\GuzzleException * @throws \Redbeed\OpenOverlay\Exceptions\AppTokenMissing */ @@ -57,8 +56,9 @@ public function global(): array } /** - * @param int $setId + * @param int $setId * @return array + * * @throws TwitchEmoteSetIdException * @throws \GuzzleHttp\Exception\GuzzleException * @throws \Redbeed\OpenOverlay\Exceptions\AppTokenMissing @@ -66,7 +66,7 @@ public function global(): array public function set(int $setId): array { if ($setId > ChatEmotesClient::MAX_SET_ID || $setId < 1) { - throw new TwitchEmoteSetIdException('Set Id minimum: 1 / maximum: ' . ChatEmotesClient::MAX_SET_ID); + throw new TwitchEmoteSetIdException('Set Id minimum: 1 / maximum: '.ChatEmotesClient::MAX_SET_ID); } $json = $this @@ -91,7 +91,6 @@ public function allSets(): array $bulkSize = 10; foreach (range(1, (ChatEmotesClient::MAX_SET_ID / $bulkSize)) as $bulk) { - $to = min(($bulkSize * $bulk), ChatEmotesClient::MAX_SET_ID); $from = ($bulkSize * $bulk) - 9; diff --git a/src/Service/Twitch/DateTime.php b/src/Service/Twitch/DateTime.php index ed52186..00cf663 100644 --- a/src/Service/Twitch/DateTime.php +++ b/src/Service/Twitch/DateTime.php @@ -9,7 +9,7 @@ class DateTime public static function parse($dateString): Carbon { // twitch timestamps sometimes (randomly) to long - $timestamp = substr(trim($dateString, 'Z'), 0, 23) . 'Z'; + $timestamp = substr(trim($dateString, 'Z'), 0, 23).'Z'; return Carbon::createFromFormat(\DateTime::RFC3339_EXTENDED, $timestamp); } diff --git a/src/Service/Twitch/EventSubClient.php b/src/Service/Twitch/EventSubClient.php index 42b43e1..efb2a26 100644 --- a/src/Service/Twitch/EventSubClient.php +++ b/src/Service/Twitch/EventSubClient.php @@ -16,6 +16,7 @@ class EventSubClient extends ApiClient /** * @return EventSubClient + * * @throws AppTokenMissing */ public static function http() @@ -28,7 +29,7 @@ public static function http() return (new self())->setOptions([ RequestOptions::HEADERS => [ - 'Authorization' => 'Bearer ' . $appToken, + 'Authorization' => 'Bearer '.$appToken, ], ]); } @@ -38,14 +39,13 @@ public static function verifySignature( string $messageId, string $messageTimestamp, string $requestBody - ): bool - { + ): bool { if (empty($messageId) || empty($messageSignature) || empty($messageTimestamp) || empty($requestBody)) { throw new WebhookTwitchSignatureMissing('Twitch Eventsub Header infomation missing'); } - $message = $messageId . $messageTimestamp . $requestBody; - $hash = 'sha256=' . hash_hmac('sha256', $message, config('openoverlay.webhook.twitch.secret')); + $message = $messageId.$messageTimestamp.$requestBody; + $hash = 'sha256='.hash_hmac('sha256', $message, config('openoverlay.webhook.twitch.secret')); return $hash === $messageSignature; } @@ -70,7 +70,7 @@ public function subscribe(string $type, string $webhookCallback, array $conditio 'condition' => $condition, 'transport' => [ 'method' => 'webhook', - 'callback' => $webhookCallback . '?' . time(), + 'callback' => $webhookCallback.'?'.time(), 'secret' => $secret, ], ], @@ -84,16 +84,15 @@ public function deleteSubByBroadcasterId(string $broadcasterUserId) ->subscriptions() ->filter(function ($subscription) use ($broadcasterUserId) { /** @var EventSubscription $subscription */ - if (empty($subscription->condition)) { return false; } - if (!empty($subscription->condition['broadcaster_user_id']) && $subscription->condition['broadcaster_user_id'] !== $broadcasterUserId) { + if (! empty($subscription->condition['broadcaster_user_id']) && $subscription->condition['broadcaster_user_id'] !== $broadcasterUserId) { return false; } - if (!empty($subscription->condition['to_broadcaster_user_id']) && $subscription->condition['to_broadcaster_user_id'] !== $broadcasterUserId) { + if (! empty($subscription->condition['to_broadcaster_user_id']) && $subscription->condition['to_broadcaster_user_id'] !== $broadcasterUserId) { return false; } diff --git a/src/Sociallite/TwitchClientCredentialsExtendSocialite.php b/src/Sociallite/TwitchClientCredentialsExtendSocialite.php index 227b3df..2d3d382 100644 --- a/src/Sociallite/TwitchClientCredentialsExtendSocialite.php +++ b/src/Sociallite/TwitchClientCredentialsExtendSocialite.php @@ -9,7 +9,7 @@ class TwitchClientCredentialsExtendSocialite /** * Register the provider. * - * @param \SocialiteProviders\Manager\SocialiteWasCalled $socialiteWasCalled + * @param \SocialiteProviders\Manager\SocialiteWasCalled $socialiteWasCalled */ public function handle(SocialiteWasCalled $socialiteWasCalled) { diff --git a/src/Support/Facades/Automation.php b/src/Support/Facades/Automation.php index 1432961..fe0ed5b 100644 --- a/src/Support/Facades/Automation.php +++ b/src/Support/Facades/Automation.php @@ -2,11 +2,11 @@ namespace Redbeed\OpenOverlay\Support\Facades; +use Closure; use Illuminate\Support\Facades\Facade; -use Redbeed\OpenOverlay\Automations\AutomationHandler; /** - * @method static void add(string $trigger, string|array $handler) + * @method static void add(string $trigger, string|array|Closure $handler) */ class Automation extends Facade { diff --git a/src/Support/StreamerOnline.php b/src/Support/StreamerOnline.php index 1994030..8d0bc1f 100644 --- a/src/Support/StreamerOnline.php +++ b/src/Support/StreamerOnline.php @@ -9,7 +9,7 @@ class StreamerOnline { private static function cacheKey(string $streamerId, string $platform = 'twitch'): string { - return $platform . '.streamer.' . $streamerId . '.online.'; + return $platform.'.streamer.'.$streamerId.'.online.'; } public static function onlineTime(string $streamerId, string $platform = 'twitch'): ?Carbon diff --git a/src/Support/ViewerInChat.php b/src/Support/ViewerInChat.php index b3ec967..33d2d19 100644 --- a/src/Support/ViewerInChat.php +++ b/src/Support/ViewerInChat.php @@ -10,7 +10,7 @@ class ViewerInChat { private static function cacheKey(Connection $streamer, string $platform = 'twitch'): string { - return $platform . '.streamer.' . $streamer->service_user_id . '.viewer.' . StreamerOnline::onlineTime($streamer->service_user_id, $platform); + return $platform.'.streamer.'.$streamer->service_user_id.'.viewer.'.StreamerOnline::onlineTime($streamer->service_user_id, $platform); } public static function list(Connection $streamer, string $platform = 'twitch'): array diff --git a/src/Support/helpers.php b/src/Support/helpers.php index 4b099d2..aed3c3b 100644 --- a/src/Support/helpers.php +++ b/src/Support/helpers.php @@ -1,10 +1,10 @@