diff --git a/CHANGELOG.md b/CHANGELOG.md index c22fdf9e7..b254bc6b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ - Bugfix: Fixed automod queue pubsub topic persisting after user change. (#3718) - Bugfix: Fixed viewer list not closing after pressing escape key. (#3734) - Bugfix: Fixed links with no thumbnail having previous link's thumbnail. (#3720) +- Bugfix: Fixed message only showing a maximum of one global FrankerFaceZ badge even if the user has multiple. (#3818) - Bugfix: Add icon in the CMake macOS bundle. (#3832) - Bugfix: Adopt popup windows in order to force floating behavior on some window managers. (#3836) - Bugfix: Fix split focusing being broken in certain circumstances when the "Show input when it's empty" setting was disabled. (#3838) diff --git a/src/messages/MessageElement.cpp b/src/messages/MessageElement.cpp index b369d18b9..3d3f4cde6 100644 --- a/src/messages/MessageElement.cpp +++ b/src/messages/MessageElement.cpp @@ -263,10 +263,10 @@ MessageLayoutElement *VipBadgeElement::makeImageLayoutElement( // FFZ Badge FfzBadgeElement::FfzBadgeElement(const EmotePtr &data, - MessageElementFlags flags_, QColor &color) + MessageElementFlags flags_, QColor color_) : BadgeElement(data, flags_) + , color(std::move(color_)) { - this->color = color; } MessageLayoutElement *FfzBadgeElement::makeImageLayoutElement( diff --git a/src/messages/MessageElement.hpp b/src/messages/MessageElement.hpp index 5739aada2..c26df48fc 100644 --- a/src/messages/MessageElement.hpp +++ b/src/messages/MessageElement.hpp @@ -296,12 +296,12 @@ class FfzBadgeElement : public BadgeElement { public: FfzBadgeElement(const EmotePtr &data, MessageElementFlags flags_, - QColor &color); + QColor color_); protected: MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image, const QSize &size) override; - QColor color; + const QColor color; }; // contains a text, formated depending on the preferences diff --git a/src/providers/ffz/FfzBadges.cpp b/src/providers/ffz/FfzBadges.cpp index 51c754042..bff84cac2 100644 --- a/src/providers/ffz/FfzBadges.cpp +++ b/src/providers/ffz/FfzBadges.cpp @@ -15,38 +15,42 @@ namespace chatterino { void FfzBadges::initialize(Settings &settings, Paths &paths) { - this->loadFfzBadges(); + this->load(); } -boost::optional FfzBadges::getBadge(const UserId &id) +std::vector FfzBadges::getUserBadges(const UserId &id) { + std::vector badges; + std::shared_lock lock(this->mutex_); - auto it = this->badgeMap.find(id.string); - if (it != this->badgeMap.end()) + auto it = this->userBadges.find(id.string); + if (it != this->userBadges.end()) { - return this->badges[it->second]; - } - return boost::none; -} -boost::optional FfzBadges::getBadgeColor(const UserId &id) -{ - std::shared_lock lock(this->mutex_); - - auto badgeIt = this->badgeMap.find(id.string); - if (badgeIt != this->badgeMap.end()) - { - auto colorIt = this->colorMap.find(badgeIt->second); - if (colorIt != this->colorMap.end()) + for (const auto &badgeID : it->second) { - return colorIt->second; + if (auto badge = this->getBadge(badgeID); badge) + { + badges.emplace_back(*badge); + } } - return boost::none; } + + return badges; +} + +boost::optional FfzBadges::getBadge(const int badgeID) +{ + auto it = this->badges.find(badgeID); + if (it != this->badges.end()) + { + return it->second; + } + return boost::none; } -void FfzBadges::loadFfzBadges() +void FfzBadges::load() { static QUrl url("https://api.frankerfacez.com/v1/badges/ids"); @@ -55,7 +59,6 @@ void FfzBadges::loadFfzBadges() std::unique_lock lock(this->mutex_); auto jsonRoot = result.parseJson(); - int index = 0; for (const auto &jsonBadge_ : jsonRoot.value("badges").toArray()) { auto jsonBadge = jsonBadge_.toObject(); @@ -70,20 +73,33 @@ void FfzBadges::loadFfzBadges() jsonUrls.value("4").toString()}}, Tooltip{jsonBadge.value("title").toString()}, Url{}}; - this->badges.push_back( - std::make_shared(std::move(emote))); - this->colorMap[index] = - QColor(jsonBadge.value("color").toString()); + Badge badge; - auto badgeId = QString::number(jsonBadge.value("id").toInt()); + int badgeID = jsonBadge.value("id").toInt(); + + this->badges[badgeID] = Badge{ + std::make_shared(std::move(emote)), + QColor(jsonBadge.value("color").toString()), + }; + + // Find users with this badge + auto badgeIDString = QString::number(badgeID); for (const auto &user : jsonRoot.value("users") .toObject() - .value(badgeId) + .value(badgeIDString) .toArray()) { - this->badgeMap[QString::number(user.toInt())] = index; + auto userIDString = QString::number(user.toInt()); + + auto [userBadges, created] = this->userBadges.emplace( + std::make_pair>( + std::move(userIDString), {badgeID})); + if (!created) + { + // User already had a badge assigned + userBadges->second.push_back(badgeID); + } } - ++index; } return Success; diff --git a/src/providers/ffz/FfzBadges.hpp b/src/providers/ffz/FfzBadges.hpp index 846d3f976..4e08a3428 100644 --- a/src/providers/ffz/FfzBadges.hpp +++ b/src/providers/ffz/FfzBadges.hpp @@ -4,6 +4,7 @@ #include #include "common/Aliases.hpp" +#include "common/UniqueAccess.hpp" #include "util/QStringHash.hpp" #include @@ -25,17 +26,25 @@ public: virtual void initialize(Settings &settings, Paths &paths) override; FfzBadges() = default; - boost::optional getBadge(const UserId &id); - boost::optional getBadgeColor(const UserId &id); + struct Badge { + EmotePtr emote; + QColor color; + }; + + std::vector getUserBadges(const UserId &id); private: - void loadFfzBadges(); + boost::optional getBadge(int badgeID); + + void load(); std::shared_mutex mutex_; - std::unordered_map badgeMap; - std::vector badges; - std::unordered_map colorMap; + // userBadges points a user ID to the list of badges they have + std::unordered_map> userBadges; + + // badges points a badge ID to the information about the badge + std::unordered_map badges; }; } // namespace chatterino diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index aadaa4119..c4fcd156f 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -1107,13 +1107,11 @@ void TwitchMessageBuilder::appendChatterinoBadges() void TwitchMessageBuilder::appendFfzBadges() { - if (auto badge = getApp()->ffzBadges->getBadge({this->userId_})) + for (const auto &badge : + getApp()->ffzBadges->getUserBadges({this->userId_})) { - if (auto color = getApp()->ffzBadges->getBadgeColor({this->userId_})) - { - this->emplace(*badge, MessageElementFlag::BadgeFfz, - color.get()); - } + this->emplace( + badge.emote, MessageElementFlag::BadgeFfz, badge.color); } }