From c1959259ce4e96318ebc7c2cd7d91a71041b16f7 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 19 Jan 2025 13:37:58 +0100 Subject: [PATCH] fix: use `serverReceivedTime` over `parseTime` for stacking (#5824) --- CHANGELOG.md | 1 + src/common/Channel.cpp | 4 +- src/common/Channel.hpp | 4 +- src/messages/MessageBuilder.cpp | 16 +- src/messages/MessageBuilder.hpp | 7 +- src/messages/MessageSink.hpp | 6 +- src/providers/twitch/IrcMessageHandler.cpp | 8 +- src/providers/twitch/TwitchIrcServer.cpp | 5 +- src/util/ChannelHelpers.hpp | 17 +- src/util/VectorMessageSink.cpp | 4 +- src/util/VectorMessageSink.hpp | 6 +- .../clearchat-stack-always.json | 2 +- .../clearchat-stack-never.json | 2 +- .../clearchat-stack-no-user.json | 2 +- .../IrcMessageHandler/clearchat.json | 2 +- .../timeout-stack-always.json | 217 +++++++++++++ .../timeout-stack-never.json | 217 +++++++++++++ .../timeout-stack-no-user.json | 294 ++++++++++++++++++ .../snapshots/IrcMessageHandler/timeout.json | 2 +- 19 files changed, 776 insertions(+), 40 deletions(-) create mode 100644 tests/snapshots/IrcMessageHandler/timeout-stack-always.json create mode 100644 tests/snapshots/IrcMessageHandler/timeout-stack-never.json create mode 100644 tests/snapshots/IrcMessageHandler/timeout-stack-no-user.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 89036d70..51b5cd62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Bugfix: Fixed tabs not scaling to the default scale when changing the scale from a non-default value. (#5794, #5833) - Dev: Highlight checks now use non-capturing groups for the boundaries. (#5784) - Dev: Updated Conan dependencies. (#5776) +- Dev: Replaced usage of `parseTime` with `serverReceivedTime` for clearchat messages. (#5824) - Dev: Support Boost 1.87. (#5832) ## 2.5.2 diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index 7923c706..5850d702 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -123,7 +123,7 @@ void Channel::addSystemMessage(const QString &contents) this->addMessage(msg, MessageContext::Original); } -void Channel::addOrReplaceTimeout(MessagePtr message, QTime now) +void Channel::addOrReplaceTimeout(MessagePtr message, const QDateTime &now) { addOrReplaceChannelTimeout( this->getMessageSnapshot(), std::move(message), now, @@ -139,7 +139,7 @@ void Channel::addOrReplaceTimeout(MessagePtr message, QTime now) // WindowManager::instance().repaintVisibleChatWidgets(this); } -void Channel::addOrReplaceClearChat(MessagePtr message, QTime now) +void Channel::addOrReplaceClearChat(MessagePtr message, const QDateTime &now) { addOrReplaceChannelClear( this->getMessageSnapshot(), std::move(message), now, diff --git a/src/common/Channel.hpp b/src/common/Channel.hpp index f6626f12..d7940afb 100644 --- a/src/common/Channel.hpp +++ b/src/common/Channel.hpp @@ -91,8 +91,8 @@ public: /// Inserts the given messages in order by Message::serverReceivedTime. void fillInMissingMessages(const std::vector &messages); - void addOrReplaceTimeout(MessagePtr message, QTime now) final; - void addOrReplaceClearChat(MessagePtr message, QTime now) final; + void addOrReplaceTimeout(MessagePtr message, const QDateTime &now) final; + void addOrReplaceClearChat(MessagePtr message, const QDateTime &now) final; void disableAllMessages() final; void replaceMessage(const MessagePtr &message, const MessagePtr &replacement); diff --git a/src/messages/MessageBuilder.cpp b/src/messages/MessageBuilder.cpp index 8dd852ef..4bdc1563 100644 --- a/src/messages/MessageBuilder.cpp +++ b/src/messages/MessageBuilder.cpp @@ -634,7 +634,7 @@ MessagePtrMut MessageBuilder::makeSubgiftMessage(const QString &text, MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &timeoutUser, const QString &sourceUser, const QString &systemMessageText, int times, - const QTime &time) + const QDateTime &time) : MessageBuilder() { QString usernameText = systemMessageText.split(" ").at(0); @@ -643,7 +643,7 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &timeoutUser, usernameText == "You" || timeoutUser == usernameText; QString messageText; - this->emplace(time); + this->emplace(time.time()); this->emplaceSystemTextAndUpdate(usernameText, messageText) ->setLink( {Link::UserInfo, timeoutUserIsFirst ? timeoutUser : sourceUser}); @@ -670,17 +670,18 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &timeoutUser, this->message().messageText = messageText; this->message().searchText = messageText; + this->message().serverReceivedTime = time; } MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username, const QString &durationInSeconds, - bool multipleTimes, const QTime &time) + bool multipleTimes, const QDateTime &time) : MessageBuilder() { QString fullText; QString text; - this->emplace(time); + this->emplace(time.time()); this->emplaceSystemTextAndUpdate(username, fullText) ->setLink({Link::UserInfo, username}); @@ -718,6 +719,7 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username, this->emplaceSystemTextAndUpdate(text, fullText); this->message().messageText = fullText; this->message().searchText = fullText; + this->message().serverReceivedTime = time; } MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count) @@ -1987,14 +1989,14 @@ MessagePtr MessageBuilder::makeLowTrustUpdateMessage( return builder.release(); } -MessagePtrMut MessageBuilder::makeClearChatMessage(QTime now, +MessagePtrMut MessageBuilder::makeClearChatMessage(const QDateTime &now, const QString &actor, uint32_t count) { MessageBuilder builder; - builder.emplace(now); + builder.emplace(now.time()); builder->count = count; - builder->parseTime = now; + builder->serverReceivedTime = now; builder.message().flags.set(MessageFlag::System, MessageFlag::DoNotTriggerNotification, MessageFlag::ClearChat); diff --git a/src/messages/MessageBuilder.hpp b/src/messages/MessageBuilder.hpp index 76f0ea47..4d0ffbfb 100644 --- a/src/messages/MessageBuilder.hpp +++ b/src/messages/MessageBuilder.hpp @@ -108,10 +108,10 @@ public: const QTime &time = QTime::currentTime()); MessageBuilder(TimeoutMessageTag, const QString &timeoutUser, const QString &sourceUser, const QString &systemMessageText, - int times, const QTime &time = QTime::currentTime()); + int times, const QDateTime &time); MessageBuilder(TimeoutMessageTag, const QString &username, const QString &durationInSeconds, bool multipleTimes, - const QTime &time = QTime::currentTime()); + const QDateTime &time); MessageBuilder(const BanAction &action, uint32_t count = 1); MessageBuilder(const UnbanAction &action); MessageBuilder(const WarnAction &action); @@ -261,7 +261,8 @@ public: /// "Chat has been cleared by a moderator." or "{actor} cleared the chat." /// @param actor The user who cleared the chat (empty if unknown) /// @param count How many times this message has been received already - static MessagePtrMut makeClearChatMessage(QTime now, const QString &actor, + static MessagePtrMut makeClearChatMessage(const QDateTime &now, + const QString &actor, uint32_t count = 1); private: diff --git a/src/messages/MessageSink.hpp b/src/messages/MessageSink.hpp index 0a96f121..14e28f07 100644 --- a/src/messages/MessageSink.hpp +++ b/src/messages/MessageSink.hpp @@ -8,7 +8,7 @@ #include class QStringView; -class QTime; +class QDateTime; namespace chatterino { @@ -46,12 +46,12 @@ public: /// Adds a timeout message or merges it into an existing one virtual void addOrReplaceTimeout(MessagePtr clearchatMessage, - QTime now) = 0; + const QDateTime &now) = 0; /// Adds a clear chat message (for the entire chat) or merges it into an /// existing one virtual void addOrReplaceClearChat(MessagePtr clearchatMessage, - QTime now) = 0; + const QDateTime &now) = 0; /// Flags all messages as `Disabled` virtual void disableAllMessages() = 0; diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp index 075ef6f8..75987f54 100644 --- a/src/providers/twitch/IrcMessageHandler.cpp +++ b/src/providers/twitch/IrcMessageHandler.cpp @@ -198,7 +198,7 @@ std::optional parseClearChatMessage( { return ClearChatMessage{ .message = MessageBuilder::makeClearChatMessage( - calculateMessageTime(message).time(), {}), + calculateMessageTime(message), {}), .disableAllMessages = true, }; } @@ -214,7 +214,7 @@ std::optional parseClearChatMessage( auto timeoutMsg = MessageBuilder(timeoutMessage, username, durationInSeconds, false, - calculateMessageTime(message).time()) + calculateMessageTime(message)) .release(); return ClearChatMessage{.message = timeoutMsg, .disableAllMessages = false}; @@ -319,7 +319,7 @@ void IrcMessageHandler::parseMessageInto(Communi::IrcMessage *message, return; } auto &clearChat = *cc; - auto time = calculateMessageTime(message).time(); + auto time = calculateMessageTime(message); if (clearChat.disableAllMessages) { sink.addOrReplaceClearChat(std::move(clearChat.message), time); @@ -462,7 +462,7 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message) return; } - auto time = calculateMessageTime(message).time(); + auto time = calculateMessageTime(message); // chat has been cleared by a moderator if (clearChat.disableAllMessages) { diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index 6e07346b..b669c502 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -248,7 +248,7 @@ void TwitchIrcServer::initialize() } postToThread([chan, actor{action.source.login}] { - auto now = QTime::currentTime(); + auto now = QDateTime::currentDateTime(); chan->addOrReplaceClearChat( MessageBuilder::makeClearChatMessage(now, actor), now); }); @@ -314,7 +314,8 @@ void TwitchIrcServer::initialize() postToThread([chan, action] { MessageBuilder msg(action); msg->flags.set(MessageFlag::PubSub); - chan->addOrReplaceTimeout(msg.release(), QTime::currentTime()); + chan->addOrReplaceTimeout(msg.release(), + QDateTime::currentDateTime()); }); }); diff --git a/src/util/ChannelHelpers.hpp b/src/util/ChannelHelpers.hpp index 2dbe39b0..6c455b8d 100644 --- a/src/util/ChannelHelpers.hpp +++ b/src/util/ChannelHelpers.hpp @@ -16,7 +16,7 @@ namespace chatterino { /// @param disableUserMessages If set, disables all message by the timed out user. template void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message, - QTime now, Replace replaceMessage, + const QDateTime &now, Replace replaceMessage, Add addMessage, bool disableUserMessages) { // NOTE: This function uses the messages PARSE time to figure out whether they should be replaced @@ -30,7 +30,7 @@ void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message, bool shouldAddMessage = true; - QTime minimumTime = now.addSecs(-5); + QDateTime minimumTime = now.addSecs(-5); auto timeoutStackStyle = static_cast( getSettings()->timeoutStackStyle.getValue()); @@ -39,7 +39,7 @@ void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message, { const MessagePtr &s = buffer[i]; - if (s->parseTime < minimumTime) + if (s->serverReceivedTime < minimumTime) { break; } @@ -82,7 +82,7 @@ void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message, MessageBuilder replacement(timeoutMessage, message->timeoutUser, message->loginName, message->searchText, - count); + count, message->serverReceivedTime); replacement->timeoutUser = message->timeoutUser; replacement->count = count; @@ -126,7 +126,8 @@ void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message, /// - adds the `message`. template void addOrReplaceChannelClear(const Buffer &buffer, MessagePtr message, - QTime now, Replace replaceMessage, Add addMessage) + const QDateTime &now, Replace replaceMessage, + Add addMessage) { // NOTE: This function uses the messages PARSE time to figure out whether they should be replaced // This works as expected for incoming messages, but not for historic messages. @@ -135,7 +136,7 @@ void addOrReplaceChannelClear(const Buffer &buffer, MessagePtr message, auto snapshotLength = static_cast(buffer.size()); auto end = std::max(0, snapshotLength - 20); bool shouldAddMessage = true; - QTime minimumTime = now.addSecs(-5); + QDateTime minimumTime = now.addSecs(-5); auto timeoutStackStyle = static_cast( getSettings()->timeoutStackStyle.getValue()); @@ -149,7 +150,7 @@ void addOrReplaceChannelClear(const Buffer &buffer, MessagePtr message, { const MessagePtr &s = buffer[i]; - if (s->parseTime < minimumTime) + if (s->serverReceivedTime < minimumTime) { break; } @@ -180,7 +181,7 @@ void addOrReplaceChannelClear(const Buffer &buffer, MessagePtr message, uint32_t count = s->count + 1; auto replacement = MessageBuilder::makeClearChatMessage( - message->parseTime, message->timeoutUser, count); + message->serverReceivedTime, message->timeoutUser, count); replacement->flags = message->flags; replaceMessage(i, s, replacement); diff --git a/src/util/VectorMessageSink.cpp b/src/util/VectorMessageSink.cpp index 16aa618c..5286a2ad 100644 --- a/src/util/VectorMessageSink.cpp +++ b/src/util/VectorMessageSink.cpp @@ -24,7 +24,7 @@ void VectorMessageSink::addMessage(MessagePtr message, MessageContext ctx, } void VectorMessageSink::addOrReplaceTimeout(MessagePtr clearchatMessage, - QTime now) + const QDateTime &now) { addOrReplaceChannelTimeout( this->messages_, std::move(clearchatMessage), now, @@ -39,7 +39,7 @@ void VectorMessageSink::addOrReplaceTimeout(MessagePtr clearchatMessage, } void VectorMessageSink::addOrReplaceClearChat(MessagePtr clearchatMessage, - QTime now) + const QDateTime &now) { addOrReplaceChannelClear( this->messages_, std::move(clearchatMessage), now, diff --git a/src/util/VectorMessageSink.hpp b/src/util/VectorMessageSink.hpp index 98ab2419..c8c0dd17 100644 --- a/src/util/VectorMessageSink.hpp +++ b/src/util/VectorMessageSink.hpp @@ -14,8 +14,10 @@ public: void addMessage( MessagePtr message, MessageContext ctx, std::optional overridingFlags = std::nullopt) override; - void addOrReplaceTimeout(MessagePtr clearchatMessage, QTime now) override; - void addOrReplaceClearChat(MessagePtr clearchatMessage, QTime now) override; + void addOrReplaceTimeout(MessagePtr clearchatMessage, + const QDateTime &now) override; + void addOrReplaceClearChat(MessagePtr clearchatMessage, + const QDateTime &now) override; void disableAllMessages() override; diff --git a/tests/snapshots/IrcMessageHandler/clearchat-stack-always.json b/tests/snapshots/IrcMessageHandler/clearchat-stack-always.json index 0eac3e13..702588c5 100644 --- a/tests/snapshots/IrcMessageHandler/clearchat-stack-always.json +++ b/tests/snapshots/IrcMessageHandler/clearchat-stack-always.json @@ -81,7 +81,7 @@ "loginName": "", "messageText": "Chat has been cleared by a moderator. (4 times) ", "searchText": "Chat has been cleared by a moderator. (4 times) ", - "serverReceivedTime": "", + "serverReceivedTime": "2025-01-12T10:41:54Z", "timeoutUser": "", "usernameColor": "#ff000000" }, diff --git a/tests/snapshots/IrcMessageHandler/clearchat-stack-never.json b/tests/snapshots/IrcMessageHandler/clearchat-stack-never.json index 7efa97ce..76786c2f 100644 --- a/tests/snapshots/IrcMessageHandler/clearchat-stack-never.json +++ b/tests/snapshots/IrcMessageHandler/clearchat-stack-never.json @@ -65,7 +65,7 @@ "loginName": "", "messageText": "Chat has been cleared by a moderator. ", "searchText": "Chat has been cleared by a moderator. ", - "serverReceivedTime": "", + "serverReceivedTime": "2025-01-08T20:44:28Z", "timeoutUser": "", "usernameColor": "#ff000000" } diff --git a/tests/snapshots/IrcMessageHandler/clearchat-stack-no-user.json b/tests/snapshots/IrcMessageHandler/clearchat-stack-no-user.json index b159d154..75ae006b 100644 --- a/tests/snapshots/IrcMessageHandler/clearchat-stack-no-user.json +++ b/tests/snapshots/IrcMessageHandler/clearchat-stack-no-user.json @@ -81,7 +81,7 @@ "loginName": "", "messageText": "Chat has been cleared by a moderator. (2 times) ", "searchText": "Chat has been cleared by a moderator. (2 times) ", - "serverReceivedTime": "", + "serverReceivedTime": "2025-01-08T20:44:28Z", "timeoutUser": "", "usernameColor": "#ff000000" } diff --git a/tests/snapshots/IrcMessageHandler/clearchat.json b/tests/snapshots/IrcMessageHandler/clearchat.json index 904d746d..ee019c12 100644 --- a/tests/snapshots/IrcMessageHandler/clearchat.json +++ b/tests/snapshots/IrcMessageHandler/clearchat.json @@ -65,7 +65,7 @@ "loginName": "", "messageText": "Chat has been cleared by a moderator. ", "searchText": "Chat has been cleared by a moderator. ", - "serverReceivedTime": "", + "serverReceivedTime": "2024-10-22T20:06:47Z", "timeoutUser": "", "usernameColor": "#ff000000" } diff --git a/tests/snapshots/IrcMessageHandler/timeout-stack-always.json b/tests/snapshots/IrcMessageHandler/timeout-stack-always.json new file mode 100644 index 00000000..6381146f --- /dev/null +++ b/tests/snapshots/IrcMessageHandler/timeout-stack-always.json @@ -0,0 +1,217 @@ +{ + "input": "@target-user-id=141981764;ban-duration=600;historical=1;room-id=111448817;rm-received-ts=1736968967915;tmi-sent-ts=1736968967813 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev", + "output": [ + { + "badgeInfos": { + }, + "badges": [ + ], + "channelName": "", + "count": 3, + "displayName": "", + "elements": [ + { + "element": { + "color": "System", + "flags": "Timestamp", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "19:22" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "19:22:47", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "UserInfo", + "value": "twitchdev" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "twitchdev" + ] + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "has", + "been", + "timed", + "out", + "for", + "10m.", + "(3", + "times)" + ] + } + ], + "flags": "System|Timeout|DoNotTriggerNotification", + "id": "", + "localizedName": "", + "loginName": "", + "messageText": "twitchdev has been timed out for 10m. (3 times) ", + "searchText": "twitchdev has been timed out for 10m. (3 times) ", + "serverReceivedTime": "2025-01-15T19:22:47Z", + "timeoutUser": "twitchdev", + "usernameColor": "#ff000000" + }, + { + "badgeInfos": { + }, + "badges": [ + ], + "channelName": "pajlada", + "count": 1, + "displayName": "TwitchDev", + "elements": [ + { + "color": "System", + "flags": "ChannelName", + "link": { + "type": "JumpToChannel", + "value": "pajlada" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "#pajlada" + ] + }, + { + "element": { + "color": "System", + "flags": "Timestamp", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "19:22" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "19:22:45", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "flags": "ModeratorTools", + "link": { + "type": "None", + "value": "" + }, + "tooltip": "", + "trailingSpace": true, + "type": "TwitchModerationElement" + }, + { + "color": "#ffff0000", + "flags": "Username", + "link": { + "type": "UserInfo", + "value": "TwitchDev" + }, + "style": "ChatMediumBold", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "TwitchDev:" + ] + }, + { + "color": "Text", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "1" + ] + }, + { + "background": "#ffa0a0a4", + "flags": "ReplyButton", + "link": { + "type": "ReplyToMessage", + "value": "aa1baade-c9c7-4932-b518-07c6b0226914" + }, + "padding": 2, + "tooltip": "", + "trailingSpace": true, + "type": "CircularImageElement", + "url": "" + } + ], + "flags": "Collapsed", + "id": "aa1baade-c9c7-4932-b518-07c6b0226914", + "localizedName": "", + "loginName": "twitchdev", + "messageText": "1", + "searchText": "twitchdev twitchdev: 1 ", + "serverReceivedTime": "2025-01-15T19:22:45Z", + "timeoutUser": "", + "usernameColor": "#ffff0000" + } + ], + "params": { + "nAdditional": 2, + "prevMessages": [ + "@historical=1;rm-received-ts=1736968964054;room-id=111448817;target-user-id=141981764;ban-duration=600;tmi-sent-ts=1736968963960 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev", + "@turbo=0;rm-received-ts=1736968965148;mod=0;color=#FF0000;badges=;id=aa1baade-c9c7-4932-b518-07c6b0226914;badge-info=;tmi-sent-ts=1736968965009;display-name=TwitchDev;first-msg=0;emotes=;user-id=141981764;room-id=111448817;returning-chatter=0;historical=1;user-type=;subscriber=0;flags= :twitchdev!twitchdev@twitchdev.tmi.twitch.tv PRIVMSG #pajlada 1", + "@historical=1;room-id=111448817;ban-duration=600;rm-received-ts=1736968967016;target-user-id=141981764;tmi-sent-ts=1736968966819 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev" + ] + }, + "settings": { + "moderation": { + "timeoutStackStyle": 0 + } + } +} diff --git a/tests/snapshots/IrcMessageHandler/timeout-stack-never.json b/tests/snapshots/IrcMessageHandler/timeout-stack-never.json new file mode 100644 index 00000000..60c9c013 --- /dev/null +++ b/tests/snapshots/IrcMessageHandler/timeout-stack-never.json @@ -0,0 +1,217 @@ +{ + "input": "@target-user-id=141981764;ban-duration=600;historical=1;room-id=111448817;rm-received-ts=1736968967915;tmi-sent-ts=1736968967813 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev", + "output": [ + { + "badgeInfos": { + }, + "badges": [ + ], + "channelName": "", + "count": 3, + "displayName": "", + "elements": [ + { + "element": { + "color": "System", + "flags": "Timestamp", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "19:22" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "19:22:47", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "UserInfo", + "value": "twitchdev" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "twitchdev" + ] + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "has", + "been", + "timed", + "out", + "for", + "10m.", + "(3", + "times)" + ] + } + ], + "flags": "System|Timeout|DoNotTriggerNotification", + "id": "", + "localizedName": "", + "loginName": "", + "messageText": "twitchdev has been timed out for 10m. (3 times) ", + "searchText": "twitchdev has been timed out for 10m. (3 times) ", + "serverReceivedTime": "2025-01-15T19:22:47Z", + "timeoutUser": "twitchdev", + "usernameColor": "#ff000000" + }, + { + "badgeInfos": { + }, + "badges": [ + ], + "channelName": "pajlada", + "count": 1, + "displayName": "TwitchDev", + "elements": [ + { + "color": "System", + "flags": "ChannelName", + "link": { + "type": "JumpToChannel", + "value": "pajlada" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "#pajlada" + ] + }, + { + "element": { + "color": "System", + "flags": "Timestamp", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "19:22" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "19:22:45", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "flags": "ModeratorTools", + "link": { + "type": "None", + "value": "" + }, + "tooltip": "", + "trailingSpace": true, + "type": "TwitchModerationElement" + }, + { + "color": "#ffff0000", + "flags": "Username", + "link": { + "type": "UserInfo", + "value": "TwitchDev" + }, + "style": "ChatMediumBold", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "TwitchDev:" + ] + }, + { + "color": "Text", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "1" + ] + }, + { + "background": "#ffa0a0a4", + "flags": "ReplyButton", + "link": { + "type": "ReplyToMessage", + "value": "aa1baade-c9c7-4932-b518-07c6b0226914" + }, + "padding": 2, + "tooltip": "", + "trailingSpace": true, + "type": "CircularImageElement", + "url": "" + } + ], + "flags": "Collapsed", + "id": "aa1baade-c9c7-4932-b518-07c6b0226914", + "localizedName": "", + "loginName": "twitchdev", + "messageText": "1", + "searchText": "twitchdev twitchdev: 1 ", + "serverReceivedTime": "2025-01-15T19:22:45Z", + "timeoutUser": "", + "usernameColor": "#ffff0000" + } + ], + "params": { + "nAdditional": 2, + "prevMessages": [ + "@historical=1;rm-received-ts=1736968964054;room-id=111448817;target-user-id=141981764;ban-duration=600;tmi-sent-ts=1736968963960 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev", + "@turbo=0;rm-received-ts=1736968965148;mod=0;color=#FF0000;badges=;id=aa1baade-c9c7-4932-b518-07c6b0226914;badge-info=;tmi-sent-ts=1736968965009;display-name=TwitchDev;first-msg=0;emotes=;user-id=141981764;room-id=111448817;returning-chatter=0;historical=1;user-type=;subscriber=0;flags= :twitchdev!twitchdev@twitchdev.tmi.twitch.tv PRIVMSG #pajlada 1", + "@historical=1;room-id=111448817;ban-duration=600;rm-received-ts=1736968967016;target-user-id=141981764;tmi-sent-ts=1736968966819 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev" + ] + }, + "settings": { + "moderation": { + "timeoutStackStyle": 2 + } + } +} diff --git a/tests/snapshots/IrcMessageHandler/timeout-stack-no-user.json b/tests/snapshots/IrcMessageHandler/timeout-stack-no-user.json new file mode 100644 index 00000000..b13b6f02 --- /dev/null +++ b/tests/snapshots/IrcMessageHandler/timeout-stack-no-user.json @@ -0,0 +1,294 @@ +{ + "input": "@target-user-id=141981764;ban-duration=600;historical=1;room-id=111448817;rm-received-ts=1736968967915;tmi-sent-ts=1736968967813 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev", + "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": [ + "19:22" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "19:22:44", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "UserInfo", + "value": "twitchdev" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "twitchdev" + ] + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "has", + "been", + "timed", + "out", + "for", + "10m." + ] + } + ], + "flags": "System|Timeout|DoNotTriggerNotification", + "id": "", + "localizedName": "", + "loginName": "", + "messageText": "twitchdev has been timed out for 10m. ", + "searchText": "twitchdev has been timed out for 10m. ", + "serverReceivedTime": "2025-01-15T19:22:44Z", + "timeoutUser": "twitchdev", + "usernameColor": "#ff000000" + }, + { + "badgeInfos": { + }, + "badges": [ + ], + "channelName": "pajlada", + "count": 1, + "displayName": "TwitchDev", + "elements": [ + { + "color": "System", + "flags": "ChannelName", + "link": { + "type": "JumpToChannel", + "value": "pajlada" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "#pajlada" + ] + }, + { + "element": { + "color": "System", + "flags": "Timestamp", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "19:22" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "19:22:45", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "flags": "ModeratorTools", + "link": { + "type": "None", + "value": "" + }, + "tooltip": "", + "trailingSpace": true, + "type": "TwitchModerationElement" + }, + { + "color": "#ffff0000", + "flags": "Username", + "link": { + "type": "UserInfo", + "value": "TwitchDev" + }, + "style": "ChatMediumBold", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "TwitchDev:" + ] + }, + { + "color": "Text", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "1" + ] + }, + { + "background": "#ffa0a0a4", + "flags": "ReplyButton", + "link": { + "type": "ReplyToMessage", + "value": "aa1baade-c9c7-4932-b518-07c6b0226914" + }, + "padding": 2, + "tooltip": "", + "trailingSpace": true, + "type": "CircularImageElement", + "url": "" + } + ], + "flags": "Collapsed", + "id": "aa1baade-c9c7-4932-b518-07c6b0226914", + "localizedName": "", + "loginName": "twitchdev", + "messageText": "1", + "searchText": "twitchdev twitchdev: 1 ", + "serverReceivedTime": "2025-01-15T19:22:45Z", + "timeoutUser": "", + "usernameColor": "#ffff0000" + }, + { + "badgeInfos": { + }, + "badges": [ + ], + "channelName": "", + "count": 2, + "displayName": "", + "elements": [ + { + "element": { + "color": "System", + "flags": "Timestamp", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "19:22" + ] + }, + "flags": "Timestamp", + "format": "", + "link": { + "type": "None", + "value": "" + }, + "time": "19:22:47", + "tooltip": "", + "trailingSpace": true, + "type": "TimestampElement" + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "UserInfo", + "value": "twitchdev" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "twitchdev" + ] + }, + { + "color": "System", + "flags": "Text", + "link": { + "type": "None", + "value": "" + }, + "style": "ChatMedium", + "tooltip": "", + "trailingSpace": true, + "type": "TextElement", + "words": [ + "has", + "been", + "timed", + "out", + "for", + "10m.", + "(2", + "times)" + ] + } + ], + "flags": "System|Timeout|DoNotTriggerNotification", + "id": "", + "localizedName": "", + "loginName": "", + "messageText": "twitchdev has been timed out for 10m. (2 times) ", + "searchText": "twitchdev has been timed out for 10m. (2 times) ", + "serverReceivedTime": "2025-01-15T19:22:47Z", + "timeoutUser": "twitchdev", + "usernameColor": "#ff000000" + } + ], + "params": { + "nAdditional": 3, + "prevMessages": [ + "@historical=1;rm-received-ts=1736968964054;room-id=111448817;target-user-id=141981764;ban-duration=600;tmi-sent-ts=1736968963960 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev", + "@turbo=0;rm-received-ts=1736968965148;mod=0;color=#FF0000;badges=;id=aa1baade-c9c7-4932-b518-07c6b0226914;badge-info=;tmi-sent-ts=1736968965009;display-name=TwitchDev;first-msg=0;emotes=;user-id=141981764;room-id=111448817;returning-chatter=0;historical=1;user-type=;subscriber=0;flags= :twitchdev!twitchdev@twitchdev.tmi.twitch.tv PRIVMSG #pajlada 1", + "@historical=1;room-id=111448817;ban-duration=600;rm-received-ts=1736968967016;target-user-id=141981764;tmi-sent-ts=1736968966819 :tmi.twitch.tv CLEARCHAT #pajlada twitchdev" + ] + } +} diff --git a/tests/snapshots/IrcMessageHandler/timeout.json b/tests/snapshots/IrcMessageHandler/timeout.json index 1de84089..d6456d31 100644 --- a/tests/snapshots/IrcMessageHandler/timeout.json +++ b/tests/snapshots/IrcMessageHandler/timeout.json @@ -79,7 +79,7 @@ "loginName": "", "messageText": "nerixyz has been timed out for 1s. ", "searchText": "nerixyz has been timed out for 1s. ", - "serverReceivedTime": "", + "serverReceivedTime": "2024-10-22T20:24:18Z", "timeoutUser": "nerixyz", "usernameColor": "#ff000000" }