deps: Update libcommuni and use Communi::TagsRef (#7134)

This updates `libcommuni` to include
https://github.com/Chatterino/libcommuni/pull/13 which refactors the tag
handling (see PR for the reasons).

The only change here is the replacement of the map and the lookup
functions.

Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
Nerixyz
2026-07-26 17:23:17 +00:00
committed by GitHub
parent 1e5dd7363b
commit 772c291196
8 changed files with 187 additions and 208 deletions
+80 -95
View File
@@ -523,15 +523,15 @@ EmotePtr parseEmote(TwitchChannel *twitchChannel, const EmoteName &name)
return {}; return {};
} }
std::pair<QString, bool> parseMessageType(const QVariantMap &tags) std::pair<QString, bool> parseMessageType(Communi::TagsRef tags)
{ {
auto msgId = tags.value("msg-id").toString(); auto msgId = tags.getOrEmpty("msg-id");
bool mirrored = msgId == "sharedchatnotice"; bool mirrored = msgId == "sharedchatnotice";
if (mirrored) if (mirrored)
{ {
msgId = tags.value("source-msg-id").toString(); msgId = tags.getOrEmpty("source-msg-id");
} }
// TODO: room-id & source-room-id comparison? // TODO: room-id & source-room-id comparison?
@@ -618,33 +618,30 @@ MessagePtrMut MessageBuilder::makeSystemMessageWithUser(
return builder.release(); return builder.release();
} }
MessagePtrMut MessageBuilder::makeSubgiftMessage(const QVariantMap &tags, MessagePtrMut MessageBuilder::makeSubgiftMessage(Communi::TagsRef tags,
const QTime &time, const QTime &time,
TwitchChannel *channel) TwitchChannel *channel)
{ {
auto text = parseTagString(tags.value("system-msg").toString()); auto text = parseTagString(tags.getOrEmpty("system-msg"));
if (auto monthsIt = tags.find("msg-param-gift-months"); if (auto monthsStr = tags.get("msg-param-gift-months"))
monthsIt != tags.end())
{ {
int months = monthsIt.value().toInt(); int months = monthsStr->toInt();
if (months > 1) if (months > 1)
{ {
auto plan = tags.value("msg-param-sub-plan").toString(); auto plan = tags.getOrEmpty("msg-param-sub-plan");
QString name = QString name = ANONYMOUS_GIFTER_ID == tags.getOrEmpty("user-id")
ANONYMOUS_GIFTER_ID == tags.value("user-id").toString() ? "An anonymous user"
? "An anonymous user" : tags.getOrEmpty("display-name");
: tags.value("display-name").toString(); text =
text = QString("%1 gifted %2 months of a Tier %3 sub to %4!") QString("%1 gifted %2 months of a Tier %3 sub to %4!")
.arg(name, QString::number(months), .arg(name, QString::number(months),
plan.isEmpty() ? '1' : plan.at(0), plan.isEmpty() ? '1' : plan.at(0),
tags.value("msg-param-recipient-display-name") tags.getOrEmpty("msg-param-recipient-display-name"));
.toString());
if (auto countIt = tags.find("msg-param-sender-count"); if (auto countStr = tags.get("msg-param-sender-count"))
countIt != tags.end())
{ {
int count = countIt.value().toInt(); int count = countStr->toInt();
if (count > months) if (count > months)
{ {
text += QString(" They've gifted %1 months in the channel.") text += QString(" They've gifted %1 months in the channel.")
@@ -660,31 +657,31 @@ MessagePtrMut MessageBuilder::makeSubgiftMessage(const QVariantMap &tags,
MessageBuilder builder; MessageBuilder builder;
builder.emplace<TimestampElement>(time); builder.emplace<TimestampElement>(time);
auto gifterLogin = tags.value("login").toString(); auto gifterLogin = tags.getOrEmpty("login");
auto gifterDisplayName = tags.value("display-name").toString(); auto gifterDisplayName = tags.getOrEmpty("display-name");
if (gifterDisplayName.isEmpty()) if (gifterDisplayName.isEmpty())
{ {
gifterDisplayName = gifterLogin; gifterDisplayName = gifterLogin;
} }
auto gifterColor = auto gifterColor =
twitch::getUserColor({ twitch::getUserColor(
.userLogin = gifterLogin, {
.userID = tags.value("user-id").toString(), .userLogin = gifterLogin,
.userDataController = userDataController, .userID = tags.getOrEmpty("user-id"),
.channelChatters = channel, .userDataController = userDataController,
.color = tags.value("color").value<QColor>(), .channelChatters = channel,
}) .color = QColor::fromString(tags.getOrEmpty("color")),
})
.value_or(MessageColor::System); .value_or(MessageColor::System);
auto recipientLogin = auto recipientLogin = tags.getOrEmpty("msg-param-recipient-user-name");
tags.value("msg-param-recipient-user-name").toString();
if (recipientLogin.isEmpty()) if (recipientLogin.isEmpty())
{ {
recipientLogin = tags.value("msg-param-recipient-name").toString(); recipientLogin = tags.getOrEmpty("msg-param-recipient-name");
} }
auto recipientDisplayName = auto recipientDisplayName =
tags.value("msg-param-recipient-display-name").toString(); tags.getOrEmpty("msg-param-recipient-display-name");
if (recipientDisplayName.isEmpty()) if (recipientDisplayName.isEmpty())
{ {
recipientDisplayName = recipientLogin; recipientDisplayName = recipientLogin;
@@ -694,7 +691,7 @@ MessagePtrMut MessageBuilder::makeSubgiftMessage(const QVariantMap &tags,
twitch::getUserColor( twitch::getUserColor(
{ {
.userLogin = recipientLogin, .userLogin = recipientLogin,
.userID = tags.value("msg-param-recipient-id").toString(), .userID = tags.getOrEmpty("msg-param-recipient-id"),
.userDataController = userDataController, .userDataController = userDataController,
.channelChatters = channel, .channelChatters = channel,
@@ -1673,7 +1670,7 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
if (args.allowIgnore) if (args.allowIgnore)
{ {
bool ignored = MessageBuilder::isIgnored( bool ignored = MessageBuilder::isIgnored(
content, tags.value("user-id").toString(), channel); content, tags.getOrEmpty("user-id"), channel);
if (ignored) if (ignored)
{ {
return {}; return {};
@@ -1682,7 +1679,7 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel); auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel);
auto userID = tags.value("user-id").toString(); auto userID = tags.getOrEmpty("user-id");
MessageBuilder builder; MessageBuilder builder;
builder.parseUsernameColor(tags, userID); builder.parseUsernameColor(tags, userID);
@@ -1725,22 +1722,22 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
builder.appendChannelName(channel); builder.appendChannelName(channel);
if (tags.contains("rm-deleted")) if (tags.has("rm-deleted"))
{ {
builder->flags.set(MessageFlag::Disabled); builder->flags.set(MessageFlag::Disabled);
} }
builder.parseMessageTags(tags); builder.parseMessageTags(tags);
if (tags.contains("first-msg") && tags["first-msg"].toString() == "1") if (tags.getOrEmpty("first-msg") == "1")
{ {
builder->flags.set(MessageFlag::FirstMessage); builder->flags.set(MessageFlag::FirstMessage);
} }
if (tags.contains("bits")) if (auto bits = tags.get("bits"))
{ {
builder->flags.set(MessageFlag::CheerMessage); builder->flags.set(MessageFlag::CheerMessage);
builder->bits = tags["bits"].toInt(); builder->bits = bits->toInt();
} }
// reply threads // reply threads
@@ -1757,8 +1754,7 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
return false; return false;
} }
if (tags.value("user-type").toString() == "mod" && if (tags.getOrEmpty("user-type") == "mod" && !userIsStaffOrBroadcaster)
!userIsStaffOrBroadcaster)
{ {
// You cannot timeout moderators UNLESS you are Twitch Staff or the broadcaster of the channel // You cannot timeout moderators UNLESS you are Twitch Staff or the broadcaster of the channel
// TODO: This is actually incorrect now - Twitch Staff do not have universal permission to timeout moderators anymore // TODO: This is actually incorrect now - Twitch Staff do not have universal permission to timeout moderators anymore
@@ -1782,14 +1778,11 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
builder.appendUsername(tags, args); builder.appendUsername(tags, args);
TextState textState{.twitchChannel = twitchChannel}; TextState textState{.twitchChannel = twitchChannel};
QString bits;
auto iterator = tags.find("bits"); if (auto optBits = tags.get("bits"))
if (iterator != tags.end())
{ {
textState.hasBits = true; textState.hasBits = true;
textState.bitsLeft = iterator.value().toInt(); textState.bitsLeft = optBits->toInt();
bits = iterator.value().toString();
} }
// Twitch emotes // Twitch emotes
@@ -1824,7 +1817,7 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
// highlights // highlights
HighlightAlert highlight = builder.parseHighlights(tags, content, args); HighlightAlert highlight = builder.parseHighlights(tags, content, args);
if (tags.contains("historical")) if (tags.has("historical"))
{ {
highlight.playSound = false; highlight.playSound = false;
highlight.windowAlert = false; highlight.windowAlert = false;
@@ -1838,7 +1831,7 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
ColorProvider::instance().color(ColorType::Whisper); ColorProvider::instance().color(ColorType::Whisper);
} }
if (!args.isReceivedWhisper && tags.value("msg-id") != "announcement") if (!args.isReceivedWhisper && tags.getOrEmpty("msg-id") != "announcement")
{ {
if (thread) if (thread)
{ {
@@ -1994,7 +1987,7 @@ TextElement *MessageBuilder::emplaceSystemTextAndUpdate(const QString &text,
MessageColor::System); MessageColor::System);
} }
void MessageBuilder::parseUsernameColor(const QVariantMap &tags, void MessageBuilder::parseUsernameColor(Communi::TagsRef tags,
const QString &userID) const QString &userID)
{ {
const auto *userData = getApp()->getUserData(); const auto *userData = getApp()->getUserData();
@@ -2010,21 +2003,20 @@ void MessageBuilder::parseUsernameColor(const QVariantMap &tags,
} }
} }
const auto iterator = tags.find("color"); if (const auto color = tags.getOrEmpty("color"); !color.isEmpty())
if (iterator != tags.end())
{ {
if (const auto color = iterator.value().toString(); !color.isEmpty()) this->usernameColor_ = QColor(color);
{ this->message().usernameColor = this->usernameColor_;
this->usernameColor_ = QColor(color); return;
this->message().usernameColor = this->usernameColor_;
return;
}
} }
if (getSettings()->colorizeNicknames && tags.contains("user-id")) if (getSettings()->colorizeNicknames)
{ {
this->usernameColor_ = getRandomColor(tags.value("user-id").toString()); if (auto userID = tags.get("user-id"))
this->message().usernameColor = this->usernameColor_; {
this->usernameColor_ = getRandomColor(*userID);
this->message().usernameColor = this->usernameColor_;
}
} }
} }
@@ -2054,17 +2046,15 @@ void MessageBuilder::parseUsername(const Communi::IrcMessage *ircMessage,
} }
} }
void MessageBuilder::parseMessageID(const QVariantMap &tags) void MessageBuilder::parseMessageID(Communi::TagsRef tags)
{ {
auto iterator = tags.find("id"); if (auto id = tags.get("id"))
if (iterator != tags.end())
{ {
this->message().id = iterator.value().toString(); this->message().id = *id;
} }
} }
void MessageBuilder::parseMessageTags(const QVariantMap &tags) void MessageBuilder::parseMessageTags(Communi::TagsRef tags)
{ {
const auto [messageType, mirrored] = parseMessageType(tags); const auto [messageType, mirrored] = parseMessageType(tags);
@@ -2082,11 +2072,11 @@ void MessageBuilder::parseMessageTags(const QVariantMap &tags)
{ {
this->message().flags.set(MessageFlag::Announcement); this->message().flags.set(MessageFlag::Announcement);
if (auto cit = tags.constFind("msg-param-color"); cit != tags.end()) if (auto color = tags.get("msg-param-color"))
{ {
this->message().announcementColor = this->message().announcementColor =
qmagicenum::enumCast<HelixAnnouncementColor>( qmagicenum::enumCast<HelixAnnouncementColor>(
cit->toString(), qmagicenum::CASE_INSENSITIVE) *color, qmagicenum::CASE_INSENSITIVE)
.value_or(HelixAnnouncementColor::Primary); .value_or(HelixAnnouncementColor::Primary);
} }
} }
@@ -2107,7 +2097,7 @@ void MessageBuilder::parseMessageTags(const QVariantMap &tags)
} }
} }
QString MessageBuilder::parseRoomID(const QVariantMap &tags, QString MessageBuilder::parseRoomID(Communi::TagsRef tags,
TwitchChannel *twitchChannel) TwitchChannel *twitchChannel)
{ {
if (twitchChannel == nullptr) if (twitchChannel == nullptr)
@@ -2115,11 +2105,9 @@ QString MessageBuilder::parseRoomID(const QVariantMap &tags,
return {}; return {};
} }
auto iterator = tags.find("room-id"); if (auto optRoomID = tags.get("room-id"))
if (iterator != std::end(tags))
{ {
auto roomID = iterator->toString(); const auto &roomID = *optRoomID;
if (twitchChannel->roomId() != roomID) if (twitchChannel->roomId() != roomID)
{ {
if (twitchChannel->roomId().isEmpty()) if (twitchChannel->roomId().isEmpty())
@@ -2140,7 +2128,7 @@ QString MessageBuilder::parseRoomID(const QVariantMap &tags,
return {}; return {};
} }
TwitchChannel *MessageBuilder::parseSharedChatInfo(const QVariantMap &tags, TwitchChannel *MessageBuilder::parseSharedChatInfo(Communi::TagsRef tags,
TwitchChannel *twitchChannel) TwitchChannel *twitchChannel)
{ {
if (!twitchChannel) if (!twitchChannel)
@@ -2148,9 +2136,9 @@ TwitchChannel *MessageBuilder::parseSharedChatInfo(const QVariantMap &tags,
return twitchChannel; return twitchChannel;
} }
if (auto it = tags.find("source-room-id"); it != tags.end()) if (auto optSourceRoom = tags.get("source-room-id"))
{ {
auto sourceRoom = it.value().toString(); const auto &sourceRoom = *optSourceRoom;
if (twitchChannel->roomId() != sourceRoom) if (twitchChannel->roomId() != sourceRoom)
{ {
this->message().flags.set(MessageFlag::SharedMessage); this->message().flags.set(MessageFlag::SharedMessage);
@@ -2175,8 +2163,7 @@ TwitchChannel *MessageBuilder::parseSharedChatInfo(const QVariantMap &tags,
} }
void MessageBuilder::parseThread(const QString &messageContent, void MessageBuilder::parseThread(const QString &messageContent,
const QVariantMap &tags, Communi::TagsRef tags, const Channel *channel,
const Channel *channel,
const std::shared_ptr<MessageThread> &thread, const std::shared_ptr<MessageThread> &thread,
const MessagePtr &parent) const MessagePtr &parent)
{ {
@@ -2235,15 +2222,15 @@ void MessageBuilder::parseThread(const QString &messageContent,
color, FontStyle::ChatMediumSmall) color, FontStyle::ChatMediumSmall)
->setLink({Link::ViewThread, thread->rootId()}); ->setLink({Link::ViewThread, thread->rootId()});
} }
else if (tags.find("reply-parent-msg-id") != tags.end()) else if (tags.has("reply-parent-msg-id"))
{ {
// Message is a reply but we couldn't find the original message. // Message is a reply but we couldn't find the original message.
// Render the message using the additional reply tags // Render the message using the additional reply tags
auto replyDisplayName = tags.find("reply-parent-display-name"); auto replyDisplayName = tags.get("reply-parent-display-name");
auto replyBody = tags.find("reply-parent-msg-body"); auto replyBody = tags.get("reply-parent-msg-body");
if (replyDisplayName != tags.end() && replyBody != tags.end()) if (replyDisplayName && replyBody)
{ {
QString body; QString body;
@@ -2253,7 +2240,7 @@ void MessageBuilder::parseThread(const QString &messageContent,
MessageColor::System, FontStyle::ChatMediumSmall); MessageColor::System, FontStyle::ChatMediumSmall);
bool ignored = MessageBuilder::isIgnored( bool ignored = MessageBuilder::isIgnored(
messageContent, tags.value("reply-parent-user-id").toString(), messageContent, tags.getOrEmpty("reply-parent-user-id"),
channel); channel);
if (ignored) if (ignored)
{ {
@@ -2261,8 +2248,8 @@ void MessageBuilder::parseThread(const QString &messageContent,
} }
else else
{ {
auto name = replyDisplayName->toString(); const auto &name = *replyDisplayName;
body = parseTagString(replyBody->toString()); body = parseTagString(*replyBody);
this->emplace<TextElement>( this->emplace<TextElement>(
"@" + name + ":", MessageElementFlag::RepliedMessage, "@" + name + ":", MessageElementFlag::RepliedMessage,
@@ -2279,7 +2266,7 @@ void MessageBuilder::parseThread(const QString &messageContent,
} }
} }
HighlightAlert MessageBuilder::parseHighlights(const QVariantMap &tags, HighlightAlert MessageBuilder::parseHighlights(Communi::TagsRef tags,
const QString &originalMessage, const QString &originalMessage,
const MessageParseArgs &args) const MessageParseArgs &args)
{ {
@@ -2334,7 +2321,7 @@ void MessageBuilder::appendChannelName(const Channel *channel)
->setLink(link); ->setLink(link);
} }
void MessageBuilder::appendUsername(const QVariantMap &tags, void MessageBuilder::appendUsername(Communi::TagsRef tags,
const MessageParseArgs &args) const MessageParseArgs &args)
{ {
auto *app = getApp(); auto *app = getApp();
@@ -2342,11 +2329,9 @@ void MessageBuilder::appendUsername(const QVariantMap &tags,
QString username = this->message_->loginName; QString username = this->message_->loginName;
QString localizedName; QString localizedName;
auto iterator = tags.find("display-name"); if (auto optDisplayName = tags.get("display-name"))
if (iterator != tags.end())
{ {
QString displayName = QString displayName = parseTagString(*optDisplayName).trimmed();
parseTagString(iterator.value().toString()).trimmed();
if (QString::compare(displayName, username, Qt::CaseInsensitive) == 0) if (QString::compare(displayName, username, Qt::CaseInsensitive) == 0)
{ {
@@ -2551,7 +2536,7 @@ void MessageBuilder::addWords(
} }
} }
void MessageBuilder::appendTwitchBadges(const QVariantMap &tags, void MessageBuilder::appendTwitchBadges(Communi::TagsRef tags,
TwitchChannel *twitchChannel) TwitchChannel *twitchChannel)
{ {
if (twitchChannel == nullptr) if (twitchChannel == nullptr)
@@ -2565,7 +2550,7 @@ void MessageBuilder::appendTwitchBadges(const QVariantMap &tags,
(getSettings()->sharedChatAlwaysShowBadge && (getSettings()->sharedChatAlwaysShowBadge &&
!twitchChannel->getSharedChatSessionParticipants().empty())) !twitchChannel->getSharedChatSessionParticipants().empty()))
{ {
const QString sourceId = tags["source-room-id"].toString(); const QString sourceId = tags.getOrEmpty("source-room-id");
QString sourceName; QString sourceName;
QString sourceProfilePicture; QString sourceProfilePicture;
QString sourceLogin; QString sourceLogin;
+11 -10
View File
@@ -10,6 +10,7 @@
#include "messages/MessageFlag.hpp" #include "messages/MessageFlag.hpp"
#include <IrcMessage> #include <IrcMessage>
#include <IrcTagsRef>
#include <QRegularExpression> #include <QRegularExpression>
#include <QString> #include <QString>
#include <QTime> #include <QTime>
@@ -241,7 +242,7 @@ public:
const QString &displayName, const MessageColor &userColor, const QString &displayName, const MessageColor &userColor,
const QTime &time, const Communi::IrcMessage &ircMessage); const QTime &time, const Communi::IrcMessage &ircMessage);
static MessagePtrMut makeSubgiftMessage(const QVariantMap &tags, static MessagePtrMut makeSubgiftMessage(Communi::TagsRef tags,
const QTime &time, const QTime &time,
TwitchChannel *channel); TwitchChannel *channel);
@@ -277,18 +278,18 @@ private:
std::unique_ptr<MessageElement> releaseBack(); std::unique_ptr<MessageElement> releaseBack();
void parse(); void parse();
void parseUsernameColor(const QVariantMap &tags, const QString &userID); void parseUsernameColor(Communi::TagsRef tags, const QString &userID);
void parseUsername(const Communi::IrcMessage *ircMessage, void parseUsername(const Communi::IrcMessage *ircMessage,
TwitchChannel *twitchChannel, TwitchChannel *twitchChannel,
bool trimSubscriberUsername); bool trimSubscriberUsername);
void parseMessageID(const QVariantMap &tags); void parseMessageID(Communi::TagsRef tags);
/// Parses most of them message flags based on the given tags /// Parses most of them message flags based on the given tags
void parseMessageTags(const QVariantMap &tags); void parseMessageTags(Communi::TagsRef tags);
/// Parses the room-ID this message was received in /// Parses the room-ID this message was received in
/// ///
/// @returns The room-ID /// @returns The room-ID
static QString parseRoomID(const QVariantMap &tags, static QString parseRoomID(Communi::TagsRef tags,
TwitchChannel *twitchChannel); TwitchChannel *twitchChannel);
/// Parses the shared-chat information from this message. /// Parses the shared-chat information from this message.
@@ -298,28 +299,28 @@ private:
/// @returns The source channel - the channel this message originated from. /// @returns The source channel - the channel this message originated from.
/// If there's no channel currently open, @a twitchChannel is /// If there's no channel currently open, @a twitchChannel is
/// returned. /// returned.
TwitchChannel *parseSharedChatInfo(const QVariantMap &tags, TwitchChannel *parseSharedChatInfo(Communi::TagsRef tags,
TwitchChannel *twitchChannel); TwitchChannel *twitchChannel);
// Parse & build thread information into the message // Parse & build thread information into the message
// Will read information from thread_ or from IRC tags // Will read information from thread_ or from IRC tags
void parseThread(const QString &messageContent, const QVariantMap &tags, void parseThread(const QString &messageContent, Communi::TagsRef tags,
const Channel *channel, const Channel *channel,
const std::shared_ptr<MessageThread> &thread, const std::shared_ptr<MessageThread> &thread,
const MessagePtr &parent); const MessagePtr &parent);
// parseHighlights only updates the visual state of the message, but leaves the playing of alerts and sounds to the triggerHighlights function // parseHighlights only updates the visual state of the message, but leaves the playing of alerts and sounds to the triggerHighlights function
HighlightAlert parseHighlights(const QVariantMap &tags, HighlightAlert parseHighlights(Communi::TagsRef tags,
const QString &originalMessage, const QString &originalMessage,
const MessageParseArgs &args); const MessageParseArgs &args);
void appendChannelName(const Channel *channel); void appendChannelName(const Channel *channel);
void appendUsername(const QVariantMap &tags, const MessageParseArgs &args); void appendUsername(Communi::TagsRef tags, const MessageParseArgs &args);
void addWords(const QStringList &words, void addWords(const QStringList &words,
const std::vector<TwitchEmoteOccurrence> &twitchEmotes, const std::vector<TwitchEmoteOccurrence> &twitchEmotes,
TextState &state); TextState &state);
void appendTwitchBadges(const QVariantMap &tags, void appendTwitchBadges(Communi::TagsRef tags,
TwitchChannel *twitchChannel); TwitchChannel *twitchChannel);
void appendChatterinoBadges(const QString &userID); void appendChatterinoBadges(const QString &userID);
void appendFfzBadges(TwitchChannel *twitchChannel, const QString &userID); void appendFfzBadges(TwitchChannel *twitchChannel, const QString &userID);
+2 -3
View File
@@ -56,11 +56,10 @@ std::vector<MessagePtr> buildRecentMessages(
for (auto *message : messages) for (auto *message : messages)
{ {
if (message->tags().contains("rm-received-ts")) if (auto optReceivedTs = message->tags().get("rm-received-ts"))
{ {
const auto msgDate = const auto msgDate =
QDateTime::fromMSecsSinceEpoch( QDateTime::fromMSecsSinceEpoch(optReceivedTs->toLongLong())
message->tags().value("rm-received-ts").toLongLong())
.date(); .date();
// Check if we need to insert a message stating that a new day began // Check if we need to insert a message stating that a new day began
+69 -74
View File
@@ -97,7 +97,7 @@ MessagePtr generateBannedMessage(bool confirmedBan)
return builder.release(); return builder.release();
} }
int stripLeadingReplyMention(const QVariantMap &tags, QString &content) int stripLeadingReplyMention(Communi::TagsRef tags, QString &content)
{ {
if (!getSettings()->stripReplyMention) if (!getSettings()->stripReplyMention)
{ {
@@ -109,10 +109,9 @@ int stripLeadingReplyMention(const QVariantMap &tags, QString &content)
return 0; return 0;
} }
if (const auto it = tags.find("reply-parent-display-name"); if (auto optDisplayName = tags.get("reply-parent-display-name"))
it != tags.end())
{ {
auto displayName = parseTagString(it.value().toString()); auto displayName = parseTagString(*optDisplayName);
if (content.length() <= 1 + displayName.length()) if (content.length() <= 1 + displayName.length())
{ {
@@ -133,8 +132,7 @@ int stripLeadingReplyMention(const QVariantMap &tags, QString &content)
return 0; return 0;
} }
void checkThreadSubscription(const QVariantMap &tags, void checkThreadSubscription(Communi::TagsRef tags, const QString &senderLogin,
const QString &senderLogin,
std::shared_ptr<MessageThread> &thread) std::shared_ptr<MessageThread> &thread)
{ {
if (thread->subscribed() || thread->unsubscribed()) if (thread->subscribed() || thread->unsubscribed())
@@ -151,11 +149,9 @@ void checkThreadSubscription(const QVariantMap &tags,
{ {
thread->markSubscribed(); thread->markSubscribed();
} }
else if (const auto it = tags.find("reply-parent-user-login"); else if (auto optName = tags.get("reply-parent-user-login"))
it != tags.end())
{ {
auto name = it.value().toString(); if (*optName == currentLogin)
if (name == currentLogin)
{ {
thread->markSubscribed(); thread->markSubscribed();
} }
@@ -275,7 +271,7 @@ MessagePtr parseNoticeMessage(Communi::IrcNoticeMessage *message)
return {generateBannedMessage(true)}; return {generateBannedMessage(true)};
} }
if (message->tags().value("msg-id") == "msg_timedout") if (message->tags().getOrEmpty("msg-id") == "msg_timedout")
{ {
QString remainingTime = QString remainingTime =
formatTime(message->content().split(" ").value(5)); formatTime(message->content().split(" ").value(5));
@@ -360,7 +356,7 @@ void IrcMessageHandler::parseMessageInto(Communi::IrcMessage *message,
auto tags = message->tags(); auto tags = message->tags();
QString targetID = tags.value("target-msg-id").toString(); QString targetID = tags.getOrEmpty("target-msg-id");
auto msg = sink.findMessageByID(targetID); auto msg = sink.findMessageByID(targetID);
if (msg == nullptr) if (msg == nullptr)
@@ -458,35 +454,34 @@ void IrcMessageHandler::handleRoomStateMessage(Communi::IrcMessage *message)
// room-id // room-id
if (auto it = tags.find("room-id"); it != tags.end()) if (auto optRoomId = tags.get("room-id"))
{ {
auto roomId = it.value().toString(); twitchChannel->setRoomId(*std::move(optRoomId));
twitchChannel->setRoomId(roomId);
} }
// Room modes // Room modes
{ {
auto roomModes = *twitchChannel->accessRoomModes(); auto roomModes = *twitchChannel->accessRoomModes();
if (auto it = tags.find("emote-only"); it != tags.end()) if (auto value = tags.get("emote-only"))
{ {
roomModes.emoteOnly = it.value() == "1"; roomModes.emoteOnly = *value == "1";
} }
if (auto it = tags.find("subs-only"); it != tags.end()) if (auto value = tags.get("subs-only"))
{ {
roomModes.submode = it.value() == "1"; roomModes.submode = *value == "1";
} }
if (auto it = tags.find("slow"); it != tags.end()) if (auto value = tags.get("slow"))
{ {
roomModes.slowMode = it.value().toInt(); roomModes.slowMode = value->toInt();
} }
if (auto it = tags.find("r9k"); it != tags.end()) if (auto value = tags.get("r9k"))
{ {
roomModes.r9k = it.value() == "1"; roomModes.r9k = *value == "1";
} }
if (auto it = tags.find("followers-only"); it != tags.end()) if (auto value = tags.get("followers-only"))
{ {
roomModes.followerOnly = it.value().toInt(); roomModes.followerOnly = value->toInt();
} }
twitchChannel->setRoomModes(roomModes); twitchChannel->setRoomModes(roomModes);
} }
@@ -536,7 +531,7 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message)
{ {
bool ok = false; bool ok = false;
int remainingTime = int remainingTime =
message->tags().value("ban-duration").toInt(&ok); message->tags().getOrEmpty("ban-duration").toInt(&ok);
if (ok) if (ok)
{ {
auto *tc = dynamic_cast<TwitchChannel *>(chan.get()); auto *tc = dynamic_cast<TwitchChannel *>(chan.get());
@@ -587,7 +582,7 @@ void IrcMessageHandler::handleClearMessageMessage(Communi::IrcMessage *message)
auto tags = message->tags(); auto tags = message->tags();
QString targetID = tags.value("target-msg-id").toString(); QString targetID = tags.getOrEmpty("target-msg-id");
auto msg = chan->findMessageByID(targetID); auto msg = chan->findMessageByID(targetID);
if (msg == nullptr) if (msg == nullptr)
@@ -603,7 +598,7 @@ void IrcMessageHandler::handleClearMessageMessage(Communi::IrcMessage *message)
MessageContext::Original); MessageContext::Original);
} }
if (getSettings()->hideModerated && !tags.contains("historical")) if (getSettings()->hideModerated && !tags.has("historical"))
{ {
// XXX: This is expensive. We could use a layout request if the layout // XXX: This is expensive. We could use a layout request if the layout
// would store the previous message flags. // would store the previous message flags.
@@ -735,19 +730,19 @@ void IrcMessageHandler::parseUserNoticeMessageInto(Communi::IrcMessage *message,
auto tags = message->tags(); auto tags = message->tags();
auto parameters = message->parameters(); auto parameters = message->parameters();
QString msgType = tags.value("msg-id").toString(); QString msgType = tags.getOrEmpty("msg-id");
bool mirrored = msgType == "sharedchatnotice"; bool mirrored = msgType == "sharedchatnotice";
if (mirrored) if (mirrored)
{ {
msgType = tags.value("source-msg-id").toString(); msgType = tags.getOrEmpty("source-msg-id");
} }
else else
{ {
auto rIt = tags.find("room-id"); auto rID = tags.get("room-id");
auto sIt = tags.find("source-room-id"); auto sID = tags.get("source-room-id");
if (rIt != tags.end() && sIt != tags.end()) if (rID && sID)
{ {
mirrored = rIt.value().toString() != sIt.value().toString(); mirrored = *rID != *sID;
} }
} }
@@ -765,7 +760,7 @@ void IrcMessageHandler::parseUserNoticeMessageInto(Communi::IrcMessage *message,
if (isIgnoredMessage({ if (isIgnoredMessage({
.message = content, .message = content,
.twitchUserID = tags.value("user-id").toString(), .twitchUserID = tags.getOrEmpty("user-id"),
.isMod = channel->isMod(), .isMod = channel->isMod(),
.isBroadcaster = channel->isBroadcaster(), .isBroadcaster = channel->isBroadcaster(),
})) }))
@@ -787,21 +782,19 @@ void IrcMessageHandler::parseUserNoticeMessageInto(Communi::IrcMessage *message,
} }
} }
auto it = tags.find("system-msg"); if (auto optSystemMsg = tags.get("system-msg"))
if (it != tags.end())
{ {
// By default, we return value of system-msg tag // By default, we return value of system-msg tag
QString messageText = it.value().toString(); QString messageText = *std::move(optSystemMsg);
auto displayName = [&] { auto displayName = [&] {
if (msgType == u"raid") if (msgType == u"raid")
{ {
return tags.value("msg-param-displayName").toString(); return tags.getOrEmpty("msg-param-displayName");
} }
return tags.value("display-name").toString(); return tags.getOrEmpty("display-name");
}(); }();
auto login = tags.value("login").toString(); auto login = tags.getOrEmpty("login");
if (displayName.isEmpty()) if (displayName.isEmpty())
{ {
displayName = login; displayName = login;
@@ -811,9 +804,9 @@ void IrcMessageHandler::parseUserNoticeMessageInto(Communi::IrcMessage *message,
{ {
messageText = messageText =
QString("%1 just earned a new %2 Bits badge!") QString("%1 just earned a new %2 Bits badge!")
.arg(tags.value("display-name").toString(), .arg(tags.getOrEmpty("display-name"),
kFormatNumbers( kFormatNumbers(
tags.value("msg-param-threshold").toInt())); tags.getOrEmpty("msg-param-threshold").toInt()));
} }
else if (msgType == "announcement") else if (msgType == "announcement")
{ {
@@ -830,24 +823,26 @@ void IrcMessageHandler::parseUserNoticeMessageInto(Communi::IrcMessage *message,
} }
else if (msgType == "sub" || msgType == "resub") else if (msgType == "sub" || msgType == "resub")
{ {
if (auto tenure = tags.find("msg-param-multimonth-tenure"); if (auto tenure = tags.get("msg-param-multimonth-tenure");
tenure != tags.end() && tenure.value().toInt() == 0) tenure && tenure->toInt() == 0)
{ {
int months = int months =
tags.value("msg-param-multimonth-duration").toInt(); tags.getOrEmpty("msg-param-multimonth-duration").toInt();
if (months > 1) if (months > 1)
{ {
int tier = tags.value("msg-param-sub-plan").toInt() / 1000; int tier =
tags.getOrEmpty("msg-param-sub-plan").toInt() / 1000;
messageText = messageText =
QString( QString(
"%1 subscribed at Tier %2 for %3 months in advance") "%1 subscribed at Tier %2 for %3 months in advance")
.arg(tags.value("display-name").toString(), .arg(tags.getOrEmpty("display-name"),
QString::number(tier), QString::number(tier),
QString::number(months)); QString::number(months));
if (msgType == "resub") if (msgType == "resub")
{ {
int cumulative = int cumulative =
tags.value("msg-param-cumulative-months").toInt(); tags.getOrEmpty("msg-param-cumulative-months")
.toInt();
messageText += messageText +=
QString(", reaching %1 months cumulatively so far!") QString(", reaching %1 months cumulatively so far!")
.arg(QString::number(cumulative)); .arg(QString::number(cumulative));
@@ -861,9 +856,10 @@ void IrcMessageHandler::parseUserNoticeMessageInto(Communi::IrcMessage *message,
} }
else if (msgType == "socialsharingbadge") else if (msgType == "socialsharingbadge")
{ {
int level = tags.value("msg-param-current-badge-level").toInt(); int level =
tags.getOrEmpty("msg-param-current-badge-level").toInt();
messageText = QString("%1 earned a Level %2 Social Media Badge!") messageText = QString("%1 earned a Level %2 Social Media Badge!")
.arg(tags.value("display-name").toString(), .arg(tags.getOrEmpty("display-name"),
QString::number(level)); QString::number(level));
} }
else if (msgType == "modiversary") else if (msgType == "modiversary")
@@ -877,16 +873,17 @@ void IrcMessageHandler::parseUserNoticeMessageInto(Communi::IrcMessage *message,
} }
} }
auto userID = tags.value("user-id").toString(); auto userID = tags.getOrEmpty("user-id");
auto userColor = twitch::getUserColor( auto userColor =
{ twitch::getUserColor(
.userLogin = login, {
.userID = userID, .userLogin = login,
.userDataController = userDataController, .userID = userID,
.channelChatters = channel, .userDataController = userDataController,
.color = tags.value("color").value<QColor>(), .channelChatters = channel,
}) .color = QColor::fromString(tags.getOrEmpty("color")),
.value_or(MessageColor::System); })
.value_or(MessageColor::System);
auto msg = MessageBuilder::makeSystemMessageWithUser( auto msg = MessageBuilder::makeSystemMessageWithUser(
parseTagString(messageText), login, displayName, userColor, parseTagString(messageText), login, displayName, userColor,
@@ -929,7 +926,7 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message)
return; return;
} }
QString tags = message->tags().value("msg-id").toString(); QString tags = message->tags().getOrEmpty("msg-id");
if (tags == "usage_delete") if (tags == "usage_delete")
{ {
channel->addSystemMessage( channel->addSystemMessage(
@@ -1096,16 +1093,16 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message,
args.isAction = isAction; args.isAction = isAction;
const auto &tags = message->tags(); auto tags = message->tags();
QString rewardId; QString rewardId;
if (const auto it = tags.find("custom-reward-id"); it != tags.end()) if (auto optRewardId = tags.get("custom-reward-id"))
{ {
rewardId = it.value().toString(); rewardId = *std::move(optRewardId);
} }
else if (const auto typeIt = tags.find("msg-id"); typeIt != tags.end()) else if (auto optMsgId = tags.get("msg-id"))
{ {
// slight hack to treat bits power-ups as channel point redemptions // slight hack to treat bits power-ups as channel point redemptions
const auto msgId = typeIt.value().toString(); const auto msgId = *std::move(optMsgId);
if (msgId == "animated-message" || msgId == "gigantified-emote-message") if (msgId == "animated-message" || msgId == "gigantified-emote-message")
{ {
rewardId = msgId; rewardId = msgId;
@@ -1129,10 +1126,9 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message,
ReplyContext replyCtx; ReplyContext replyCtx;
if (const auto it = tags.find("reply-thread-parent-msg-id"); if (auto optReplyID = tags.get("reply-thread-parent-msg-id"))
it != tags.end())
{ {
const QString replyID = it.value().toString(); const QString replyID = *std::move(optReplyID);
auto threadIt = chan->threads().find(replyID); auto threadIt = chan->threads().find(replyID);
std::shared_ptr<MessageThread> rootThread; std::shared_ptr<MessageThread> rootThread;
if (threadIt != chan->threads().end() && !threadIt->second.expired()) if (threadIt != chan->threads().end() && !threadIt->second.expired())
@@ -1160,10 +1156,9 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message,
} }
} }
if (const auto parentIt = tags.find("reply-parent-msg-id"); if (auto optParentID = tags.get("reply-parent-msg-id"))
parentIt != tags.end())
{ {
const QString parentID = parentIt.value().toString(); const QString parentID = *std::move(optParentID);
if (replyID == parentID) if (replyID == parentID)
{ {
if (rootThread) if (rootThread)
+12 -12
View File
@@ -90,17 +90,17 @@ void appendTwitchEmoteOccurrences(const QString &emote,
namespace chatterino { namespace chatterino {
std::unordered_map<QString, QString> parseBadgeInfoTag(const QVariantMap &tags) std::unordered_map<QString, QString> parseBadgeInfoTag(Communi::TagsRef tags)
{ {
std::unordered_map<QString, QString> infoMap; std::unordered_map<QString, QString> infoMap;
auto infoIt = tags.constFind("badge-info"); auto infoIt = tags.get("badge-info");
if (infoIt == tags.end()) if (!infoIt)
{ {
return infoMap; return infoMap;
} }
auto info = infoIt.value().toString().split(',', Qt::SkipEmptyParts); auto info = infoIt->split(',', Qt::SkipEmptyParts);
for (const QString &badge : info) for (const QString &badge : info)
{ {
@@ -110,18 +110,18 @@ std::unordered_map<QString, QString> parseBadgeInfoTag(const QVariantMap &tags)
return infoMap; return infoMap;
} }
std::vector<TwitchBadge> parseBadgeTag(const QVariantMap &tags, std::vector<TwitchBadge> parseBadgeTag(Communi::TagsRef tags,
const QString &tagName) const QString &tagName)
{ {
std::vector<TwitchBadge> b; std::vector<TwitchBadge> b;
auto badgesIt = tags.constFind(tagName); auto badgesIt = tags.get(tagName);
if (badgesIt == tags.end()) if (!badgesIt)
{ {
return b; return b;
} }
auto badges = badgesIt.value().toString().split(',', Qt::SkipEmptyParts); auto badges = badgesIt->split(',', Qt::SkipEmptyParts);
for (const QString &badge : badges) for (const QString &badge : badges)
{ {
@@ -137,21 +137,21 @@ std::vector<TwitchBadge> parseBadgeTag(const QVariantMap &tags,
return b; return b;
} }
std::vector<TwitchEmoteOccurrence> parseTwitchEmotes(const QVariantMap &tags, std::vector<TwitchEmoteOccurrence> parseTwitchEmotes(Communi::TagsRef tags,
const QString &content, const QString &content,
int messageOffset) int messageOffset)
{ {
// Twitch emotes // Twitch emotes
std::vector<TwitchEmoteOccurrence> twitchEmotes; std::vector<TwitchEmoteOccurrence> twitchEmotes;
auto emotesTag = tags.find("emotes"); auto emotesTag = tags.get("emotes");
if (emotesTag == tags.end()) if (!emotesTag)
{ {
return twitchEmotes; return twitchEmotes;
} }
QStringList emoteString = emotesTag.value().toString().split('/'); QStringList emoteString = emotesTag->split('/');
std::vector<int> correctPositions; std::vector<int> correctPositions;
for (int i = 0; i < content.size(); ++i) for (int i = 0; i < content.size(); ++i)
{ {
+4 -3
View File
@@ -7,6 +7,7 @@
#include "messages/Emote.hpp" #include "messages/Emote.hpp"
#include "providers/twitch/TwitchBadge.hpp" #include "providers/twitch/TwitchBadge.hpp"
#include <IrcTagsRef>
#include <QString> #include <QString>
#include <QVariantMap> #include <QVariantMap>
@@ -37,7 +38,7 @@ struct TwitchEmoteOccurrence {
/// ///
/// @param tags The tags of the IRC message /// @param tags The tags of the IRC message
/// @returns A map of badge-names to their values /// @returns A map of badge-names to their values
std::unordered_map<QString, QString> parseBadgeInfoTag(const QVariantMap &tags); std::unordered_map<QString, QString> parseBadgeInfoTag(Communi::TagsRef tags);
/// @brief Parses the badges from the specified tag of an IRC message /// @brief Parses the badges from the specified tag of an IRC message
/// ///
@@ -51,7 +52,7 @@ std::unordered_map<QString, QString> parseBadgeInfoTag(const QVariantMap &tags);
/// @param tags The tags of the IRC message /// @param tags The tags of the IRC message
/// @param tagName The name of the tag to read badges from /// @param tagName The name of the tag to read badges from
/// @returns A list of badges (name and version) /// @returns A list of badges (name and version)
std::vector<TwitchBadge> parseBadgeTag(const QVariantMap &tags, std::vector<TwitchBadge> parseBadgeTag(Communi::TagsRef tags,
const QString &tagName = "badges"); const QString &tagName = "badges");
/// @brief Parses Twitch emotes in an IRC message /// @brief Parses Twitch emotes in an IRC message
@@ -66,7 +67,7 @@ std::vector<TwitchBadge> parseBadgeTag(const QVariantMap &tags,
/// original message (`@a foo` (original message) -> `foo` /// original message (`@a foo` (original message) -> `foo`
/// (content)). /// (content)).
/// @returns A list of emotes and their positions /// @returns A list of emotes and their positions
std::vector<TwitchEmoteOccurrence> parseTwitchEmotes(const QVariantMap &tags, std::vector<TwitchEmoteOccurrence> parseTwitchEmotes(Communi::TagsRef tags,
const QString &content, const QString &content,
int messageOffset); int messageOffset);
+8 -10
View File
@@ -13,33 +13,31 @@ using namespace chatterino;
QDateTime calculateMessageTimeBase(const Communi::IrcMessage *message) QDateTime calculateMessageTimeBase(const Communi::IrcMessage *message)
{ {
// Check if message is from recent-messages API // Check if message is from recent-messages API
if (message->tags().contains("historical")) auto tags = message->tags();
if (tags.has("historical"))
{ {
bool customReceived = false; bool customReceived = false;
auto ts = auto ts = tags.getOrEmpty("rm-received-ts").toLongLong(&customReceived);
message->tags().value("rm-received-ts").toLongLong(&customReceived);
if (!customReceived) if (!customReceived)
{ {
ts = message->tags().value("tmi-sent-ts").toLongLong(); ts = tags.getOrEmpty("tmi-sent-ts").toLongLong();
} }
return QDateTime::fromMSecsSinceEpoch(ts); return QDateTime::fromMSecsSinceEpoch(ts);
} }
// If present, handle tmi-sent-ts tag and use it as timestamp // If present, handle tmi-sent-ts tag and use it as timestamp
if (message->tags().contains("tmi-sent-ts")) if (auto tmiSentTs = tags.get("tmi-sent-ts"))
{ {
auto ts = message->tags().value("tmi-sent-ts").toLongLong(); auto ts = tmiSentTs->toLongLong();
return QDateTime::fromMSecsSinceEpoch(ts); return QDateTime::fromMSecsSinceEpoch(ts);
} }
// Some IRC Servers might have server-time tag containing UTC date in ISO format, use it as timestamp // Some IRC Servers might have server-time tag containing UTC date in ISO format, use it as timestamp
// See: https://ircv3.net/irc/#server-time // See: https://ircv3.net/irc/#server-time
if (message->tags().contains("time")) if (auto optTime = message->tags().get("time"))
{ {
QString timedate = message->tags().value("time").toString(); auto date = QDateTime::fromString(*optTime, Qt::ISODate);
auto date = QDateTime::fromString(timedate, Qt::ISODate);
date.setTimeZone(QTimeZone::utc()); date.setTimeZone(QTimeZone::utc());
return date.toLocalTime(); return date.toLocalTime();
} }