diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index 9c1967f60..f9ac3ac50 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -160,13 +160,14 @@ void Channel::disableAllMessages() LimitedQueueSnapshot snapshot = this->getMessageSnapshot(); int snapshotLength = snapshot.getLength(); for (int i = 0; i < snapshotLength; i++) { - auto &s = snapshot[i]; - if (s->flags.hasAny({MessageFlag::System, MessageFlag::Timeout})) { + auto &message = snapshot[i]; + if (message->flags.hasAny( + {MessageFlag::System, MessageFlag::Timeout})) { continue; } // FOURTF: disabled for now - // s->flags.EnableFlag(MessageFlag::Disabled); + const_cast(message.get())->flags.set(MessageFlag::Disabled); } } diff --git a/src/providers/twitch/PubsubHelpers.hpp b/src/providers/twitch/PubsubHelpers.hpp index f9bc28a05..fe7056dc8 100644 --- a/src/providers/twitch/PubsubHelpers.hpp +++ b/src/providers/twitch/PubsubHelpers.hpp @@ -1,5 +1,6 @@ #pragma once +#include "debug/Log.hpp" #include "util/RapidjsonHelpers.hpp" #include "debug/Log.hpp" #include diff --git a/src/providers/twitch/TwitchBadges.cpp b/src/providers/twitch/TwitchBadges.cpp index 8853f1add..0e515d627 100644 --- a/src/providers/twitch/TwitchBadges.cpp +++ b/src/providers/twitch/TwitchBadges.cpp @@ -4,21 +4,14 @@ #include #include #include + #include "common/NetworkRequest.hpp" #include "common/Outcome.hpp" +#include "debug/Log.hpp" #include "messages/Emote.hpp" namespace chatterino { -TwitchBadges::TwitchBadges() -{ -} - -void TwitchBadges::initialize(Settings &settings, Paths &paths) -{ - this->loadTwitchBadges(); -} - void TwitchBadges::loadTwitchBadges() { static QString url( @@ -28,32 +21,34 @@ void TwitchBadges::loadTwitchBadges() req.setCaller(QThread::currentThread()); req.onSuccess([this](auto result) -> Outcome { auto root = result.parseJson(); - QJsonObject sets = root.value("badge_sets").toObject(); + auto badgeSets = this->badgeSets_.access(); - for (QJsonObject::iterator it = sets.begin(); it != sets.end(); ++it) { - QJsonObject versions = - it.value().toObject().value("versions").toObject(); + auto jsonSets = root.value("badge_sets").toObject(); + for (auto sIt = jsonSets.begin(); sIt != jsonSets.end(); ++sIt) { + auto key = sIt.key(); + auto versions = sIt.value().toObject().value("versions").toObject(); + + for (auto vIt = versions.begin(); vIt != versions.end(); ++vIt) { + auto versionObj = vIt.value().toObject(); - for (auto versionIt = std::begin(versions); - versionIt != std::end(versions); ++versionIt) { auto emote = Emote{ {""}, ImageSet{ - Image::fromUrl({root.value("image_url_1x").toString()}, - 1), - Image::fromUrl({root.value("image_url_2x").toString()}, - 0.5), - Image::fromUrl({root.value("image_url_4x").toString()}, - 0.25), + Image::fromUrl( + {versionObj.value("image_url_1x").toString()}, 1), + Image::fromUrl( + {versionObj.value("image_url_2x").toString()}, .5), + Image::fromUrl( + {versionObj.value("image_url_4x").toString()}, .25), }, Tooltip{root.value("description").toString()}, Url{root.value("clickURL").toString()}}; // "title" // "clickAction" - QJsonObject versionObj = versionIt.value().toObject(); - this->badges.emplace(versionIt.key(), - std::make_shared(emote)); + log("{} {}", key, vIt.key()); + + (*badgeSets)[key][vIt.key()] = std::make_shared(emote); } } @@ -63,4 +58,18 @@ void TwitchBadges::loadTwitchBadges() req.execute(); } +boost::optional TwitchBadges::badge(const QString &set, + const QString &version) const +{ + auto badgeSets = this->badgeSets_.access(); + auto it = badgeSets->find(set); + if (it != badgeSets->end()) { + auto it2 = it->second.find(version); + if (it2 != it->second.end()) { + return it2->second; + } + } + return boost::none; +} + } // namespace chatterino diff --git a/src/providers/twitch/TwitchBadges.hpp b/src/providers/twitch/TwitchBadges.hpp index 62196f8d8..d9023855d 100644 --- a/src/providers/twitch/TwitchBadges.hpp +++ b/src/providers/twitch/TwitchBadges.hpp @@ -1,7 +1,10 @@ #pragma once #include +#include #include + +#include "common/UniqueAccess.hpp" #include "util/QStringHash.hpp" namespace chatterino { @@ -15,14 +18,15 @@ class Paths; class TwitchBadges { public: - TwitchBadges(); - - void initialize(Settings &settings, Paths &paths); - -private: void loadTwitchBadges(); - std::unordered_map badges; + boost::optional badge(const QString &set, + const QString &version) const; + +private: + UniqueAccess< + std::unordered_map>> + badgeSets_; // "bits": { "100": ... "500": ... }; } // namespace chatterino diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 346ed1476..06ed13739 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -69,12 +69,14 @@ std::pair parseChatters(const QJsonObject &jsonRoot) } } // namespace -TwitchChannel::TwitchChannel(const QString &name, BttvEmotes &bttv, +TwitchChannel::TwitchChannel(const QString &name, + TwitchBadges &globalTwitchBadges, BttvEmotes &bttv, FfzEmotes &ffz) : Channel(name, Channel::Type::Twitch) , subscriptionUrl_("https://www.twitch.tv/subs/" + name) , channelUrl_("https://twitch.tv/" + name) , popoutPlayerUrl_("https://player.twitch.tv/?channel=" + name) + , globalTwitchBadges_(globalTwitchBadges) , globalBttv_(bttv) , globalFfz_(ffz) , bttvEmotes_(std::make_shared()) @@ -317,6 +319,11 @@ AccessGuard TwitchChannel::accessChatters() const return this->chatters_.accessConst(); } +const TwitchBadges &TwitchChannel::globalTwitchBadges() const +{ + return this->globalTwitchBadges_; +} + const BttvEmotes &TwitchChannel::globalBttv() const { return this->globalBttv_; diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index ea95c0df3..82ae58d40 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -23,6 +23,7 @@ struct Emote; using EmotePtr = std::shared_ptr; class EmoteMap; +class TwitchBadges; class FfzEmotes; class BttvEmotes; @@ -70,6 +71,7 @@ public: AccessGuard accessChatters() const; // Emotes + const TwitchBadges &globalTwitchBadges() const; const BttvEmotes &globalBttv() const; const FfzEmotes &globalFfz() const; boost::optional bttvEmote(const EmoteName &name) const; @@ -98,8 +100,9 @@ private: QString localizedName; }; - explicit TwitchChannel(const QString &channelName, BttvEmotes &globalBttv, - FfzEmotes &globalFfz); + explicit TwitchChannel(const QString &channelName, + TwitchBadges &globalTwitchBadges, + BttvEmotes &globalBttv, FfzEmotes &globalFfz); // Methods void refreshLiveStatus(); @@ -126,6 +129,7 @@ private: UniqueAccess chatters_; // maps 2 char prefix to set of names // Emotes + TwitchBadges &globalTwitchBadges_; BttvEmotes &globalBttv_; FfzEmotes &globalFfz_; Atomic> bttvEmotes_; diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 97b41561a..26ea07dec 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -6,6 +6,7 @@ #include "controllers/ignores/IgnoreController.hpp" #include "debug/Log.hpp" #include "messages/Message.hpp" +#include "providers/twitch/TwitchBadges.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "singletons/Emotes.hpp" #include "singletons/Resources.hpp" @@ -91,13 +92,6 @@ MessagePtr TwitchMessageBuilder::build() this->senderIsBroadcaster = true; } - //#ifdef XD - // if (this->originalMessage.length() > 100) { - // this->message->flags.has(MessageFlag::Collapsed); - // this->emplace(getApp()->resources->badgeCollapsed, - // MessageElementFlag::Collapsed); - // } - //#endif this->message().flags.has(MessageFlag::Collapsed); // PARSING @@ -203,11 +197,7 @@ void TwitchMessageBuilder::addWords( // split words for (auto &variant : getApp()->emotes->emojis.parse(word)) { - boost::apply_visitor(/*overloaded{[&](EmotePtr arg) { - this->addTextOrEmoji(arg); }, - [&](const QString &arg) { - this->addTextOrEmoji(arg); }}*/ - [&](auto &&arg) { this->addTextOrEmoji(arg); }, + boost::apply_visitor([&](auto &&arg) { this->addTextOrEmoji(arg); }, variant); } @@ -659,32 +649,15 @@ Outcome TwitchMessageBuilder::tryAppendEmote(const EmoteName &name) } // fourtf: this is ugly -// maybe put the individual badges into a map instead of this -// mess void TwitchMessageBuilder::appendTwitchBadges() { auto app = getApp(); auto iterator = this->tags.find("badges"); + if (iterator == this->tags.end()) return; - if (iterator == this->tags.end()) { - // No badges in this message - return; - } - - QStringList badges = iterator.value().toString().split(','); - - for (QString badge : badges) { - if (badge.isEmpty()) { - continue; - } - + for (QString badge : iterator.value().toString().split(',')) { if (badge.startsWith("bits/")) { - // if (!app->resources->dynamicBadgesLoaded) { - // // Do nothing - // continue; - // } - QString cheerAmount = badge.mid(5); QString tooltip = QString("Twitch cheer ") + cheerAmount; @@ -703,16 +676,12 @@ void TwitchMessageBuilder::appendTwitchBadges() } // Use default bit badge - // try { - // const auto &badge = - // app->resources->badgeSets.at("bits").versions.at(cheerAmount); - // this->emplace(badge.badgeImage1x, - // MessageElementFlag::BadgeVanity) - // ->setTooltip(tooltip); - //} catch (const std::out_of_range &) { - // Log("No default bit badge for version {} found", cheerAmount); - // continue; - //} + if (auto badge = this->twitchChannel->globalTwitchBadges().badge( + "bits", cheerAmount)) { + this->emplace(badge.get(), + MessageElementFlag::BadgeVanity) + ->setTooltip(tooltip); + } } else if (badge == "staff/1") { this->emplace( Image::fromPixmap(app->resources->twitch.staff), @@ -766,80 +735,30 @@ void TwitchMessageBuilder::appendTwitchBadges() } break; } } else if (badge.startsWith("subscriber/")) { - // if (channelResources.loaded == false) { - // // qDebug() << "Channel resources are not loaded, - // can't add the subscriber - // // badge"; - // continue; - // } + if (auto badgeEmote = this->twitchChannel->twitchBadge( + "subscriber", badge.mid(11))) { + this->emplace( + badgeEmote.get(), MessageElementFlag::BadgeSubscription) + ->setTooltip((*badgeEmote)->tooltip.string); + continue; + } - // auto badgeSetIt = channelResources.badgeSets.find("subscriber"); - // if (badgeSetIt == channelResources.badgeSets.end()) { - // // Fall back to default badge - // this->emplace(app->resources->badgeSubscriber, - // MessageElementFlag::BadgeSubscription) - // ->setTooltip("Twitch Subscriber"); - // continue; - //} - - // const auto &badgeSet = badgeSetIt->second; - - // std::string versionKey = badge.mid(11).toStdString(); - - // auto badgeVersionIt = badgeSet.versions.find(versionKey); - - // if (badgeVersionIt == badgeSet.versions.end()) { - // // Fall back to default badge - // this->emplace(app->resources->badgeSubscriber, - // MessageElementFlag::BadgeSubscription) - // ->setTooltip("Twitch Subscriber"); - // continue; - //} - - // auto &badgeVersion = badgeVersionIt->second; - - // this->emplace(badgeVersion.badgeImage1x, - // MessageElementFlag::BadgeSubscription) - // ->setTooltip("Twitch " + - // QString::fromStdString(badgeVersion.title)); + // use default subscriber badge if custom one not found + this->emplace( + Image::fromPixmap(app->resources->twitch.subscriber, 0.25), + MessageElementFlag::BadgeSubscription) + ->setTooltip("Twitch Subscriber"); } else { - // if (!app->resources->dynamicBadgesLoaded) { - // // Do nothing - // continue; - //} + auto splits = badge.split('/'); + if (splits.size() != 2) continue; - // QStringList parts = badge.split('/'); - - // if (parts.length() != 2) { - // qDebug() << "Bad number of parts: " << parts.length() << " in - // " << parts; continue; - //} - - // MessageElementFlags badgeType = - // MessageElementFlag::BadgeVanity; - - // std::string badgeSetKey = parts[0].toStdString(); - // std::string versionKey = parts[1].toStdString(); - - // try { - // auto &badgeSet = app->resources->badgeSets.at(badgeSetKey); - - // try { - // auto &badgeVersion = badgeSet.versions.at(versionKey); - - // this->emplace(badgeVersion.badgeImage1x, - // badgeType) - // ->setTooltip("Twitch " + - // QString::fromStdString(badgeVersion.title)); - // } catch (const std::exception &e) { - // qDebug() << "Exception caught:" << e.what() - // << "when trying to fetch badge version " << - // versionKey.c_str(); - // } - //} catch (const std::exception &e) { - // qDebug() << "No badge set with key" << badgeSetKey.c_str() - // << ". Exception: " << e.what(); - //} + if (auto badgeEmote = + this->twitchChannel->twitchBadge(splits[0], splits[1])) { + this->emplace(badgeEmote.get(), + MessageElementFlag::BadgeVanity) + ->setTooltip((*badgeEmote)->tooltip.string); + continue; + } } } } diff --git a/src/providers/twitch/TwitchServer.cpp b/src/providers/twitch/TwitchServer.cpp index 465fe3315..d1e03b63b 100644 --- a/src/providers/twitch/TwitchServer.cpp +++ b/src/providers/twitch/TwitchServer.cpp @@ -13,7 +13,6 @@ #include "util/PostToThread.hpp" #include - #include // using namespace Communi; @@ -41,6 +40,7 @@ void TwitchServer::initialize(Settings &settings, Paths &paths) getApp()->accounts->twitch.currentUserChanged.connect( [this]() { postToThread([this] { this->connect(); }); }); + this->twitchBadges.loadTwitchBadges(); this->bttv.loadEmotes(); this->ffz.loadEmotes(); } @@ -83,8 +83,8 @@ void TwitchServer::initializeConnection(IrcConnection *connection, bool isRead, std::shared_ptr TwitchServer::createChannel(const QString &channelName) { - auto channel = std::shared_ptr( - new TwitchChannel(channelName, this->bttv, this->ffz)); + auto channel = std::shared_ptr(new TwitchChannel( + channelName, this->twitchBadges, this->bttv, this->ffz)); channel->initialize(); channel->sendMessageSignal.connect( diff --git a/src/providers/twitch/TwitchServer.hpp b/src/providers/twitch/TwitchServer.hpp index e097cc365..60026a142 100644 --- a/src/providers/twitch/TwitchServer.hpp +++ b/src/providers/twitch/TwitchServer.hpp @@ -7,6 +7,7 @@ #include "providers/bttv/BttvEmotes.hpp" #include "providers/ffz/FfzEmotes.hpp" #include "providers/irc/AbstractIrcServer.hpp" +#include "providers/twitch/TwitchBadges.hpp" #include #include @@ -68,6 +69,7 @@ private: std::chrono::steady_clock::time_point lastErrorTimeAmount_; bool singleConnection_ = false; + TwitchBadges twitchBadges; BttvEmotes bttv; FfzEmotes ffz; diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index d99448221..0c713c996 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -92,10 +92,10 @@ auto formatTitle(const TwitchChannel::StreamStatus &s, Settings &settings) // description if (settings.showViewerCount) - title += " - " + QString::number(s.viewerCount) + " viewers"; + title += " - " + QString::number(s.viewerCount); if (settings.showTitle) title += " - " + s.title; if (settings.showGame) title += " - " + s.game; - if (settings.showUptime) title += " - uptime: " + s.uptime; + if (settings.showUptime) title += " - " + s.uptime; return title; }