fix: use serverReceivedTime over parseTime for stacking (#5824)

This commit is contained in:
nerix
2025-01-19 13:37:58 +01:00
committed by GitHub
parent f85543381f
commit c1959259ce
19 changed files with 776 additions and 40 deletions
+1
View File
@@ -12,6 +12,7 @@
- Bugfix: Fixed tabs not scaling to the default scale when changing the scale from a non-default value. (#5794, #5833) - 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: Highlight checks now use non-capturing groups for the boundaries. (#5784)
- Dev: Updated Conan dependencies. (#5776) - Dev: Updated Conan dependencies. (#5776)
- Dev: Replaced usage of `parseTime` with `serverReceivedTime` for clearchat messages. (#5824)
- Dev: Support Boost 1.87. (#5832) - Dev: Support Boost 1.87. (#5832)
## 2.5.2 ## 2.5.2
+2 -2
View File
@@ -123,7 +123,7 @@ void Channel::addSystemMessage(const QString &contents)
this->addMessage(msg, MessageContext::Original); this->addMessage(msg, MessageContext::Original);
} }
void Channel::addOrReplaceTimeout(MessagePtr message, QTime now) void Channel::addOrReplaceTimeout(MessagePtr message, const QDateTime &now)
{ {
addOrReplaceChannelTimeout( addOrReplaceChannelTimeout(
this->getMessageSnapshot(), std::move(message), now, this->getMessageSnapshot(), std::move(message), now,
@@ -139,7 +139,7 @@ void Channel::addOrReplaceTimeout(MessagePtr message, QTime now)
// WindowManager::instance().repaintVisibleChatWidgets(this); // WindowManager::instance().repaintVisibleChatWidgets(this);
} }
void Channel::addOrReplaceClearChat(MessagePtr message, QTime now) void Channel::addOrReplaceClearChat(MessagePtr message, const QDateTime &now)
{ {
addOrReplaceChannelClear( addOrReplaceChannelClear(
this->getMessageSnapshot(), std::move(message), now, this->getMessageSnapshot(), std::move(message), now,
+2 -2
View File
@@ -91,8 +91,8 @@ public:
/// Inserts the given messages in order by Message::serverReceivedTime. /// Inserts the given messages in order by Message::serverReceivedTime.
void fillInMissingMessages(const std::vector<MessagePtr> &messages); void fillInMissingMessages(const std::vector<MessagePtr> &messages);
void addOrReplaceTimeout(MessagePtr message, QTime now) final; void addOrReplaceTimeout(MessagePtr message, const QDateTime &now) final;
void addOrReplaceClearChat(MessagePtr message, QTime now) final; void addOrReplaceClearChat(MessagePtr message, const QDateTime &now) final;
void disableAllMessages() final; void disableAllMessages() final;
void replaceMessage(const MessagePtr &message, void replaceMessage(const MessagePtr &message,
const MessagePtr &replacement); const MessagePtr &replacement);
+9 -7
View File
@@ -634,7 +634,7 @@ MessagePtrMut MessageBuilder::makeSubgiftMessage(const QString &text,
MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &timeoutUser, MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &timeoutUser,
const QString &sourceUser, const QString &sourceUser,
const QString &systemMessageText, int times, const QString &systemMessageText, int times,
const QTime &time) const QDateTime &time)
: MessageBuilder() : MessageBuilder()
{ {
QString usernameText = systemMessageText.split(" ").at(0); QString usernameText = systemMessageText.split(" ").at(0);
@@ -643,7 +643,7 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &timeoutUser,
usernameText == "You" || timeoutUser == usernameText; usernameText == "You" || timeoutUser == usernameText;
QString messageText; QString messageText;
this->emplace<TimestampElement>(time); this->emplace<TimestampElement>(time.time());
this->emplaceSystemTextAndUpdate(usernameText, messageText) this->emplaceSystemTextAndUpdate(usernameText, messageText)
->setLink( ->setLink(
{Link::UserInfo, timeoutUserIsFirst ? timeoutUser : sourceUser}); {Link::UserInfo, timeoutUserIsFirst ? timeoutUser : sourceUser});
@@ -670,17 +670,18 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &timeoutUser,
this->message().messageText = messageText; this->message().messageText = messageText;
this->message().searchText = messageText; this->message().searchText = messageText;
this->message().serverReceivedTime = time;
} }
MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username, MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username,
const QString &durationInSeconds, const QString &durationInSeconds,
bool multipleTimes, const QTime &time) bool multipleTimes, const QDateTime &time)
: MessageBuilder() : MessageBuilder()
{ {
QString fullText; QString fullText;
QString text; QString text;
this->emplace<TimestampElement>(time); this->emplace<TimestampElement>(time.time());
this->emplaceSystemTextAndUpdate(username, fullText) this->emplaceSystemTextAndUpdate(username, fullText)
->setLink({Link::UserInfo, username}); ->setLink({Link::UserInfo, username});
@@ -718,6 +719,7 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username,
this->emplaceSystemTextAndUpdate(text, fullText); this->emplaceSystemTextAndUpdate(text, fullText);
this->message().messageText = fullText; this->message().messageText = fullText;
this->message().searchText = fullText; this->message().searchText = fullText;
this->message().serverReceivedTime = time;
} }
MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count) MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count)
@@ -1987,14 +1989,14 @@ MessagePtr MessageBuilder::makeLowTrustUpdateMessage(
return builder.release(); return builder.release();
} }
MessagePtrMut MessageBuilder::makeClearChatMessage(QTime now, MessagePtrMut MessageBuilder::makeClearChatMessage(const QDateTime &now,
const QString &actor, const QString &actor,
uint32_t count) uint32_t count)
{ {
MessageBuilder builder; MessageBuilder builder;
builder.emplace<TimestampElement>(now); builder.emplace<TimestampElement>(now.time());
builder->count = count; builder->count = count;
builder->parseTime = now; builder->serverReceivedTime = now;
builder.message().flags.set(MessageFlag::System, builder.message().flags.set(MessageFlag::System,
MessageFlag::DoNotTriggerNotification, MessageFlag::DoNotTriggerNotification,
MessageFlag::ClearChat); MessageFlag::ClearChat);
+4 -3
View File
@@ -108,10 +108,10 @@ public:
const QTime &time = QTime::currentTime()); const QTime &time = QTime::currentTime());
MessageBuilder(TimeoutMessageTag, const QString &timeoutUser, MessageBuilder(TimeoutMessageTag, const QString &timeoutUser,
const QString &sourceUser, const QString &systemMessageText, const QString &sourceUser, const QString &systemMessageText,
int times, const QTime &time = QTime::currentTime()); int times, const QDateTime &time);
MessageBuilder(TimeoutMessageTag, const QString &username, MessageBuilder(TimeoutMessageTag, const QString &username,
const QString &durationInSeconds, bool multipleTimes, const QString &durationInSeconds, bool multipleTimes,
const QTime &time = QTime::currentTime()); const QDateTime &time);
MessageBuilder(const BanAction &action, uint32_t count = 1); MessageBuilder(const BanAction &action, uint32_t count = 1);
MessageBuilder(const UnbanAction &action); MessageBuilder(const UnbanAction &action);
MessageBuilder(const WarnAction &action); MessageBuilder(const WarnAction &action);
@@ -261,7 +261,8 @@ public:
/// "Chat has been cleared by a moderator." or "{actor} cleared the chat." /// "Chat has been cleared by a moderator." or "{actor} cleared the chat."
/// @param actor The user who cleared the chat (empty if unknown) /// @param actor The user who cleared the chat (empty if unknown)
/// @param count How many times this message has been received already /// @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); uint32_t count = 1);
private: private:
+3 -3
View File
@@ -8,7 +8,7 @@
#include <optional> #include <optional>
class QStringView; class QStringView;
class QTime; class QDateTime;
namespace chatterino { namespace chatterino {
@@ -46,12 +46,12 @@ public:
/// Adds a timeout message or merges it into an existing one /// Adds a timeout message or merges it into an existing one
virtual void addOrReplaceTimeout(MessagePtr clearchatMessage, 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 /// Adds a clear chat message (for the entire chat) or merges it into an
/// existing one /// existing one
virtual void addOrReplaceClearChat(MessagePtr clearchatMessage, virtual void addOrReplaceClearChat(MessagePtr clearchatMessage,
QTime now) = 0; const QDateTime &now) = 0;
/// Flags all messages as `Disabled` /// Flags all messages as `Disabled`
virtual void disableAllMessages() = 0; virtual void disableAllMessages() = 0;
+4 -4
View File
@@ -198,7 +198,7 @@ std::optional<ClearChatMessage> parseClearChatMessage(
{ {
return ClearChatMessage{ return ClearChatMessage{
.message = MessageBuilder::makeClearChatMessage( .message = MessageBuilder::makeClearChatMessage(
calculateMessageTime(message).time(), {}), calculateMessageTime(message), {}),
.disableAllMessages = true, .disableAllMessages = true,
}; };
} }
@@ -214,7 +214,7 @@ std::optional<ClearChatMessage> parseClearChatMessage(
auto timeoutMsg = auto timeoutMsg =
MessageBuilder(timeoutMessage, username, durationInSeconds, false, MessageBuilder(timeoutMessage, username, durationInSeconds, false,
calculateMessageTime(message).time()) calculateMessageTime(message))
.release(); .release();
return ClearChatMessage{.message = timeoutMsg, .disableAllMessages = false}; return ClearChatMessage{.message = timeoutMsg, .disableAllMessages = false};
@@ -319,7 +319,7 @@ void IrcMessageHandler::parseMessageInto(Communi::IrcMessage *message,
return; return;
} }
auto &clearChat = *cc; auto &clearChat = *cc;
auto time = calculateMessageTime(message).time(); auto time = calculateMessageTime(message);
if (clearChat.disableAllMessages) if (clearChat.disableAllMessages)
{ {
sink.addOrReplaceClearChat(std::move(clearChat.message), time); sink.addOrReplaceClearChat(std::move(clearChat.message), time);
@@ -462,7 +462,7 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message)
return; return;
} }
auto time = calculateMessageTime(message).time(); auto time = calculateMessageTime(message);
// chat has been cleared by a moderator // chat has been cleared by a moderator
if (clearChat.disableAllMessages) if (clearChat.disableAllMessages)
{ {
+3 -2
View File
@@ -248,7 +248,7 @@ void TwitchIrcServer::initialize()
} }
postToThread([chan, actor{action.source.login}] { postToThread([chan, actor{action.source.login}] {
auto now = QTime::currentTime(); auto now = QDateTime::currentDateTime();
chan->addOrReplaceClearChat( chan->addOrReplaceClearChat(
MessageBuilder::makeClearChatMessage(now, actor), now); MessageBuilder::makeClearChatMessage(now, actor), now);
}); });
@@ -314,7 +314,8 @@ void TwitchIrcServer::initialize()
postToThread([chan, action] { postToThread([chan, action] {
MessageBuilder msg(action); MessageBuilder msg(action);
msg->flags.set(MessageFlag::PubSub); msg->flags.set(MessageFlag::PubSub);
chan->addOrReplaceTimeout(msg.release(), QTime::currentTime()); chan->addOrReplaceTimeout(msg.release(),
QDateTime::currentDateTime());
}); });
}); });
+9 -8
View File
@@ -16,7 +16,7 @@ namespace chatterino {
/// @param disableUserMessages If set, disables all message by the timed out user. /// @param disableUserMessages If set, disables all message by the timed out user.
template <typename Buf, typename Replace, typename Add> template <typename Buf, typename Replace, typename Add>
void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message, void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message,
QTime now, Replace replaceMessage, const QDateTime &now, Replace replaceMessage,
Add addMessage, bool disableUserMessages) Add addMessage, bool disableUserMessages)
{ {
// NOTE: This function uses the messages PARSE time to figure out whether they should be replaced // 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; bool shouldAddMessage = true;
QTime minimumTime = now.addSecs(-5); QDateTime minimumTime = now.addSecs(-5);
auto timeoutStackStyle = static_cast<TimeoutStackStyle>( auto timeoutStackStyle = static_cast<TimeoutStackStyle>(
getSettings()->timeoutStackStyle.getValue()); getSettings()->timeoutStackStyle.getValue());
@@ -39,7 +39,7 @@ void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message,
{ {
const MessagePtr &s = buffer[i]; const MessagePtr &s = buffer[i];
if (s->parseTime < minimumTime) if (s->serverReceivedTime < minimumTime)
{ {
break; break;
} }
@@ -82,7 +82,7 @@ void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message,
MessageBuilder replacement(timeoutMessage, message->timeoutUser, MessageBuilder replacement(timeoutMessage, message->timeoutUser,
message->loginName, message->searchText, message->loginName, message->searchText,
count); count, message->serverReceivedTime);
replacement->timeoutUser = message->timeoutUser; replacement->timeoutUser = message->timeoutUser;
replacement->count = count; replacement->count = count;
@@ -126,7 +126,8 @@ void addOrReplaceChannelTimeout(const Buf &buffer, MessagePtr message,
/// - adds the `message`. /// - adds the `message`.
template <typename Buffer, typename Replace, typename Add> template <typename Buffer, typename Replace, typename Add>
void addOrReplaceChannelClear(const Buffer &buffer, MessagePtr message, 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 // 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. // 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<qsizetype>(buffer.size()); auto snapshotLength = static_cast<qsizetype>(buffer.size());
auto end = std::max<qsizetype>(0, snapshotLength - 20); auto end = std::max<qsizetype>(0, snapshotLength - 20);
bool shouldAddMessage = true; bool shouldAddMessage = true;
QTime minimumTime = now.addSecs(-5); QDateTime minimumTime = now.addSecs(-5);
auto timeoutStackStyle = static_cast<TimeoutStackStyle>( auto timeoutStackStyle = static_cast<TimeoutStackStyle>(
getSettings()->timeoutStackStyle.getValue()); getSettings()->timeoutStackStyle.getValue());
@@ -149,7 +150,7 @@ void addOrReplaceChannelClear(const Buffer &buffer, MessagePtr message,
{ {
const MessagePtr &s = buffer[i]; const MessagePtr &s = buffer[i];
if (s->parseTime < minimumTime) if (s->serverReceivedTime < minimumTime)
{ {
break; break;
} }
@@ -180,7 +181,7 @@ void addOrReplaceChannelClear(const Buffer &buffer, MessagePtr message,
uint32_t count = s->count + 1; uint32_t count = s->count + 1;
auto replacement = MessageBuilder::makeClearChatMessage( auto replacement = MessageBuilder::makeClearChatMessage(
message->parseTime, message->timeoutUser, count); message->serverReceivedTime, message->timeoutUser, count);
replacement->flags = message->flags; replacement->flags = message->flags;
replaceMessage(i, s, replacement); replaceMessage(i, s, replacement);
+2 -2
View File
@@ -24,7 +24,7 @@ void VectorMessageSink::addMessage(MessagePtr message, MessageContext ctx,
} }
void VectorMessageSink::addOrReplaceTimeout(MessagePtr clearchatMessage, void VectorMessageSink::addOrReplaceTimeout(MessagePtr clearchatMessage,
QTime now) const QDateTime &now)
{ {
addOrReplaceChannelTimeout( addOrReplaceChannelTimeout(
this->messages_, std::move(clearchatMessage), now, this->messages_, std::move(clearchatMessage), now,
@@ -39,7 +39,7 @@ void VectorMessageSink::addOrReplaceTimeout(MessagePtr clearchatMessage,
} }
void VectorMessageSink::addOrReplaceClearChat(MessagePtr clearchatMessage, void VectorMessageSink::addOrReplaceClearChat(MessagePtr clearchatMessage,
QTime now) const QDateTime &now)
{ {
addOrReplaceChannelClear( addOrReplaceChannelClear(
this->messages_, std::move(clearchatMessage), now, this->messages_, std::move(clearchatMessage), now,
+4 -2
View File
@@ -14,8 +14,10 @@ public:
void addMessage( void addMessage(
MessagePtr message, MessageContext ctx, MessagePtr message, MessageContext ctx,
std::optional<MessageFlags> overridingFlags = std::nullopt) override; std::optional<MessageFlags> overridingFlags = std::nullopt) override;
void addOrReplaceTimeout(MessagePtr clearchatMessage, QTime now) override; void addOrReplaceTimeout(MessagePtr clearchatMessage,
void addOrReplaceClearChat(MessagePtr clearchatMessage, QTime now) override; const QDateTime &now) override;
void addOrReplaceClearChat(MessagePtr clearchatMessage,
const QDateTime &now) override;
void disableAllMessages() override; void disableAllMessages() override;
@@ -81,7 +81,7 @@
"loginName": "", "loginName": "",
"messageText": "Chat has been cleared by a moderator. (4 times) ", "messageText": "Chat has been cleared by a moderator. (4 times) ",
"searchText": "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": "", "timeoutUser": "",
"usernameColor": "#ff000000" "usernameColor": "#ff000000"
}, },
@@ -65,7 +65,7 @@
"loginName": "", "loginName": "",
"messageText": "Chat has been cleared by a moderator. ", "messageText": "Chat has been cleared by a moderator. ",
"searchText": "Chat has been cleared by a moderator. ", "searchText": "Chat has been cleared by a moderator. ",
"serverReceivedTime": "", "serverReceivedTime": "2025-01-08T20:44:28Z",
"timeoutUser": "", "timeoutUser": "",
"usernameColor": "#ff000000" "usernameColor": "#ff000000"
} }
@@ -81,7 +81,7 @@
"loginName": "", "loginName": "",
"messageText": "Chat has been cleared by a moderator. (2 times) ", "messageText": "Chat has been cleared by a moderator. (2 times) ",
"searchText": "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": "", "timeoutUser": "",
"usernameColor": "#ff000000" "usernameColor": "#ff000000"
} }
@@ -65,7 +65,7 @@
"loginName": "", "loginName": "",
"messageText": "Chat has been cleared by a moderator. ", "messageText": "Chat has been cleared by a moderator. ",
"searchText": "Chat has been cleared by a moderator. ", "searchText": "Chat has been cleared by a moderator. ",
"serverReceivedTime": "", "serverReceivedTime": "2024-10-22T20:06:47Z",
"timeoutUser": "", "timeoutUser": "",
"usernameColor": "#ff000000" "usernameColor": "#ff000000"
} }
@@ -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
}
}
}
@@ -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
}
}
}
@@ -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"
]
}
}
@@ -79,7 +79,7 @@
"loginName": "", "loginName": "",
"messageText": "nerixyz has been timed out for 1s. ", "messageText": "nerixyz has been timed out for 1s. ",
"searchText": "nerixyz has been timed out for 1s. ", "searchText": "nerixyz has been timed out for 1s. ",
"serverReceivedTime": "", "serverReceivedTime": "2024-10-22T20:24:18Z",
"timeoutUser": "nerixyz", "timeoutUser": "nerixyz",
"usernameColor": "#ff000000" "usernameColor": "#ff000000"
} }