diff --git a/CHANGELOG.md b/CHANGELOG.md index a9402312..25cd90ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ - Bugfix: Fixed the input font not immediately updating when zooming in/out. (#5960) - Bugfix: Fixed color input thinking blue is also red. (#5982) - Dev: Subscriptions to PubSub channel points redemption topics now use no auth token, making it continue to work during PubSub shutdown. (#5947) -- Dev: Add initial experimental EventSub support. (#5837, #5895, #5897, #5904, #5910, #5903, #5915, #5916, #5930, #5935, #5932, #5943, #5952, #5953, #5968, #5973, #5974, #5980) +- Dev: Add initial experimental EventSub support. (#5837, #5895, #5897, #5904, #5910, #5903, #5915, #5916, #5930, #5935, #5932, #5943, #5952, #5953, #5968, #5973, #5974, #5980, #5981) - Dev: Remove unneeded platform specifier for toasts. (#5914) - Dev: Highlight checks now use non-capturing groups for the boundaries. (#5784) - Dev: Removed unused PubSub whisper code. (#5898) diff --git a/src/Application.cpp b/src/Application.cpp index bac97052..1e3d671d 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -502,8 +502,6 @@ Updates &Application::getUpdates() ITwitchIrcServer *Application::getTwitch() { - assertInGuiThread(); - return this->twitch.get(); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 952f62f7..3612c34f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -434,6 +434,8 @@ set(SOURCE_FILES providers/twitch/eventsub/Controller.hpp providers/twitch/eventsub/MessageBuilder.cpp providers/twitch/eventsub/MessageBuilder.hpp + providers/twitch/eventsub/MessageHandlers.cpp + providers/twitch/eventsub/MessageHandlers.hpp providers/twitch/eventsub/SubscriptionHandle.cpp providers/twitch/eventsub/SubscriptionHandle.hpp providers/twitch/eventsub/SubscriptionRequest.cpp diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index 1c949de5..19322b3a 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -1303,6 +1303,8 @@ const IndirectChannel &TwitchIrcServer::getWatchingChannel() const void TwitchIrcServer::setWatchingChannel(ChannelPtr newWatchingChannel) { + assertInGuiThread(); + this->watchingChannel.reset(newWatchingChannel); } @@ -1333,6 +1335,8 @@ QString TwitchIrcServer::getLastUserThatWhisperedMe() const void TwitchIrcServer::setLastUserThatWhisperedMe(const QString &user) { + assertInGuiThread(); + this->lastUserThatWhisperedMe.set(user); } @@ -1451,6 +1455,8 @@ void TwitchIrcServer::markChannelsConnected() void TwitchIrcServer::addFakeMessage(const QString &data) { + assertInGuiThread(); + auto *fakeMessage = Communi::IrcMessage::fromData( data.toUtf8(), this->readConnection_.get()); @@ -1502,6 +1508,8 @@ void TwitchIrcServer::forEachChannel(std::function func) void TwitchIrcServer::connect() { + assertInGuiThread(); + this->disconnect(); this->initializeConnection(this->writeConnection_.get(), diff --git a/src/providers/twitch/eventsub/Connection.cpp b/src/providers/twitch/eventsub/Connection.cpp index 1ab18619..213eb93b 100644 --- a/src/providers/twitch/eventsub/Connection.cpp +++ b/src/providers/twitch/eventsub/Connection.cpp @@ -6,9 +6,12 @@ #include "messages/Message.hpp" #include "messages/MessageBuilder.hpp" #include "providers/twitch/eventsub/MessageBuilder.hpp" +#include "providers/twitch/eventsub/MessageHandlers.hpp" #include "providers/twitch/PubSubActions.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchIrcServer.hpp" +#include "singletons/Settings.hpp" +#include "singletons/WindowManager.hpp" #include "util/PostToThread.hpp" #include @@ -23,15 +26,24 @@ namespace { using namespace chatterino; using namespace chatterino::eventsub; +namespace channel_moderate = lib::payload::channel_moderate::v2; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) const auto &LOG = chatterinoTwitchEventSub; template -concept CanMakeModMessage = - requires(EventSubMessageBuilder &builder, - const lib::payload::channel_moderate::v2::Event &event, +concept CanMakeModMessage = requires( + EventSubMessageBuilder &builder, const channel_moderate::Event &event, + const std::remove_cvref_t &action) { + makeModerateMessage(builder, event, action); +}; + +template +concept CanHandleModMessage = + requires(TwitchChannel *channel, const QDateTime &time, + const channel_moderate::Event &event, const std::remove_cvref_t &action) { - makeModerateMessage(builder, event, action); + handleModerateMessage(channel, time, event, action); }; } // namespace @@ -199,6 +211,11 @@ void Connection::onChannelModerate( channel->addMessage(msg, MessageContext::Original); }); } + + if constexpr (CanHandleModMessage) + { + handleModerateMessage(channel, now, payload.event, action); + } }, payload.event.action); } diff --git a/src/providers/twitch/eventsub/MessageHandlers.cpp b/src/providers/twitch/eventsub/MessageHandlers.cpp new file mode 100644 index 00000000..2f27c5d0 --- /dev/null +++ b/src/providers/twitch/eventsub/MessageHandlers.cpp @@ -0,0 +1,29 @@ +#include "providers/twitch/eventsub/MessageHandlers.hpp" + +#include "Application.hpp" +#include "messages/MessageBuilder.hpp" +#include "providers/twitch/TwitchChannel.hpp" +#include "singletons/Settings.hpp" +#include "singletons/WindowManager.hpp" +#include "util/PostToThread.hpp" + +namespace chatterino::eventsub { + +void handleModerateMessage( + TwitchChannel *chan, const QDateTime &time, + const lib::payload::channel_moderate::v2::Event &event, + const lib::payload::channel_moderate::v2::Clear & /*action*/) +{ + runInGuiThread([chan, actor{event.moderatorUserLogin.qt()}, time] { + chan->addOrReplaceClearChat( + MessageBuilder::makeClearChatMessage(time, actor), time); + if (getSettings()->hideModerated) + { + // XXX: This is expensive. We could use a layout request if the layout + // would store the previous message flags. + getApp()->getWindows()->forceLayoutChannelViews(); + } + }); +} + +} // namespace chatterino::eventsub diff --git a/src/providers/twitch/eventsub/MessageHandlers.hpp b/src/providers/twitch/eventsub/MessageHandlers.hpp new file mode 100644 index 00000000..c28dc56b --- /dev/null +++ b/src/providers/twitch/eventsub/MessageHandlers.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "twitch-eventsub-ws/payloads/channel-moderate-v2.hpp" + +class QDateTime; + +namespace chatterino { +class TwitchChannel; +} // namespace chatterino + +namespace chatterino::eventsub { + +void handleModerateMessage( + TwitchChannel *chan, const QDateTime &time, + const lib::payload::channel_moderate::v2::Event &event, + const lib::payload::channel_moderate::v2::Clear &action); + +} // namespace chatterino::eventsub diff --git a/tests/snapshots/EventSub/channel-moderate/clear.json b/tests/snapshots/EventSub/channel-moderate/clear.json new file mode 100644 index 00000000..8f10e386 --- /dev/null +++ b/tests/snapshots/EventSub/channel-moderate/clear.json @@ -0,0 +1,120 @@ +{ + "input": { + "action": "clear", + "automod_terms": null, + "ban": null, + "broadcaster_user_id": "11148817", + "broadcaster_user_login": "pajlada", + "broadcaster_user_name": "pajlada", + "delete": null, + "followers": null, + "mod": null, + "moderator_user_id": "129546453", + "moderator_user_login": "nerixyz", + "moderator_user_name": "nerixyz", + "raid": null, + "shared_chat_ban": null, + "shared_chat_delete": null, + "shared_chat_timeout": null, + "shared_chat_unban": null, + "shared_chat_untimeout": null, + "slow": null, + "source_broadcaster_user_id": null, + "source_broadcaster_user_login": null, + "source_broadcaster_user_name": null, + "timeout": null, + "unban": null, + "unban_request": null, + "unmod": null, + "unraid": null, + "untimeout": null, + "unvip": null, + "vip": null, + "warn": null + }, + "output": [ + { + "badgeInfos": { + }, + "badges": [ + ], + "channelName": "", + "count": 1, + "displayName": "", + "elements": [ + { + "element": { + "color": "System", + "flags": "Timestamp", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "0:00" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "00:00:00", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "color": "Text", + "fallbackColor": "System", + "flags": "Text|Mention", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "MentionElement", + "userColor": "System", + "userLoginName": "nerixyz", + "words": [ + "nerixyz" + ] + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "cleared", + "the", + "chat." + ] + } + ], + "flags": "System|DoNotTriggerNotification|PubSub|ClearChat", + "id": "", + "localizedName": "", + "loginName": "", + "messageText": "nerixyz cleared the chat. ", + "searchText": "nerixyz cleared the chat. ", + "serverReceivedTime": "1970-01-01T00:00:00Z", + "timeoutUser": "nerixyz", + "userID": "", + "usernameColor": "#ff000000" + } + ] +}