feat: show BTTV Pro badges (#6625)
Reviewed-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
- Minor: Add categories to the emoji viewer. (#6598)
|
- Minor: Add categories to the emoji viewer. (#6598)
|
||||||
- Minor: Added broadcaster-only `/poll`, `/cancelpoll`, and `/endpoll` commands. (#6583, #6605)
|
- Minor: Added broadcaster-only `/poll`, `/cancelpoll`, and `/endpoll` commands. (#6583, #6605)
|
||||||
- Minor: Added broadcaster-only `/prediction`, `/cancelprediction`, and `/lockprediction` commands. (#6583, #6612)
|
- Minor: Added broadcaster-only `/prediction`, `/cancelprediction`, and `/lockprediction` commands. (#6583, #6612)
|
||||||
|
- Minor: Added support for BetterTTV Pro subscriber badges. (#6625)
|
||||||
- Bugfix: Expose the "Extra extension IDs" setting on non-Windows systems too. (#6509)
|
- Bugfix: Expose the "Extra extension IDs" setting on non-Windows systems too. (#6509)
|
||||||
- Bugfix: Fixed some commands and filters not working as expected in seach popups. (#6539)
|
- Bugfix: Fixed some commands and filters not working as expected in seach popups. (#6539)
|
||||||
- Bugfix: Fixed settings occasionally not opening when clicking on "Manage Accounts" in the account switcher. (#6543)
|
- Bugfix: Fixed settings occasionally not opening when clicking on "Manage Accounts" in the account switcher. (#6543)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "mocks/Logging.hpp"
|
#include "mocks/Logging.hpp"
|
||||||
#include "mocks/TwitchIrcServer.hpp"
|
#include "mocks/TwitchIrcServer.hpp"
|
||||||
#include "mocks/UserData.hpp"
|
#include "mocks/UserData.hpp"
|
||||||
|
#include "providers/bttv/BttvBadges.hpp"
|
||||||
#include "providers/bttv/BttvEmotes.hpp"
|
#include "providers/bttv/BttvEmotes.hpp"
|
||||||
#include "providers/chatterino/ChatterinoBadges.hpp"
|
#include "providers/chatterino/ChatterinoBadges.hpp"
|
||||||
#include "providers/ffz/FfzBadges.hpp"
|
#include "providers/ffz/FfzBadges.hpp"
|
||||||
@@ -71,6 +72,11 @@ public:
|
|||||||
return &this->ffzBadges;
|
return &this->ffzBadges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BttvBadges *getBttvBadges() override
|
||||||
|
{
|
||||||
|
return &this->bttvBadges;
|
||||||
|
}
|
||||||
|
|
||||||
SeventvBadges *getSeventvBadges() override
|
SeventvBadges *getSeventvBadges() override
|
||||||
{
|
{
|
||||||
return &this->seventvBadges;
|
return &this->seventvBadges;
|
||||||
@@ -124,6 +130,7 @@ public:
|
|||||||
mock::EmptyLinkResolver linkResolver;
|
mock::EmptyLinkResolver linkResolver;
|
||||||
ChatterinoBadges chatterinoBadges;
|
ChatterinoBadges chatterinoBadges;
|
||||||
FfzBadges ffzBadges;
|
FfzBadges ffzBadges;
|
||||||
|
BttvBadges bttvBadges;
|
||||||
SeventvBadges seventvBadges;
|
SeventvBadges seventvBadges;
|
||||||
HighlightController highlights;
|
HighlightController highlights;
|
||||||
TwitchBadges twitchBadges;
|
TwitchBadges twitchBadges;
|
||||||
|
|||||||
@@ -436,6 +436,7 @@ c2.MessageElementFlag = {
|
|||||||
BadgeVanity = 0,
|
BadgeVanity = 0,
|
||||||
BadgeChatterino = 0,
|
BadgeChatterino = 0,
|
||||||
BadgeSevenTV = 0,
|
BadgeSevenTV = 0,
|
||||||
|
BadgeBttv = 0,
|
||||||
BadgeFfz = 0,
|
BadgeFfz = 0,
|
||||||
Badges = 0,
|
Badges = 0,
|
||||||
ChannelName = 0,
|
ChannelName = 0,
|
||||||
@@ -503,6 +504,7 @@ c2.MessageFlag = {
|
|||||||
EventSub = 0,
|
EventSub = 0,
|
||||||
ModerationAction = 0,
|
ModerationAction = 0,
|
||||||
InvalidReplyTarget = 0,
|
InvalidReplyTarget = 0,
|
||||||
|
WatchStreak = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- End src/messages/MessageFlag.hpp
|
-- End src/messages/MessageFlag.hpp
|
||||||
|
|||||||
@@ -164,6 +164,12 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BttvBadges *getBttvBadges() override
|
||||||
|
{
|
||||||
|
assert(!"getBttvBadges was called without being initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
SeventvBadges *getSeventvBadges() override
|
SeventvBadges *getSeventvBadges() override
|
||||||
{
|
{
|
||||||
assert(!"getSeventvBadges was called without being initialized");
|
assert(!"getSeventvBadges was called without being initialized");
|
||||||
|
|||||||
+12
-1
@@ -11,6 +11,7 @@
|
|||||||
#include "controllers/ignores/IgnoreController.hpp"
|
#include "controllers/ignores/IgnoreController.hpp"
|
||||||
#include "controllers/notifications/NotificationController.hpp"
|
#include "controllers/notifications/NotificationController.hpp"
|
||||||
#include "controllers/sound/ISoundController.hpp"
|
#include "controllers/sound/ISoundController.hpp"
|
||||||
|
#include "providers/bttv/BttvBadges.hpp"
|
||||||
#include "providers/bttv/BttvEmotes.hpp"
|
#include "providers/bttv/BttvEmotes.hpp"
|
||||||
#include "providers/ffz/FfzEmotes.hpp"
|
#include "providers/ffz/FfzEmotes.hpp"
|
||||||
#include "providers/links/LinkResolver.hpp"
|
#include "providers/links/LinkResolver.hpp"
|
||||||
@@ -99,7 +100,8 @@ ISoundController *makeSoundController(Settings &settings)
|
|||||||
BttvLiveUpdates *makeBttvLiveUpdates(Settings &settings)
|
BttvLiveUpdates *makeBttvLiveUpdates(Settings &settings)
|
||||||
{
|
{
|
||||||
bool enabled =
|
bool enabled =
|
||||||
settings.enableBTTVLiveUpdates && settings.enableBTTVChannelEmotes;
|
settings.enableBTTVLiveUpdates &&
|
||||||
|
(settings.enableBTTVChannelEmotes || settings.showBadgesBttv);
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
@@ -179,6 +181,7 @@ Application::Application(Settings &_settings, const Paths &paths,
|
|||||||
, highlights(new HighlightController(_settings, this->accounts.get()))
|
, highlights(new HighlightController(_settings, this->accounts.get()))
|
||||||
, twitch(new TwitchIrcServer)
|
, twitch(new TwitchIrcServer)
|
||||||
, ffzBadges(new FfzBadges)
|
, ffzBadges(new FfzBadges)
|
||||||
|
, bttvBadges(new BttvBadges)
|
||||||
, seventvBadges(new SeventvBadges)
|
, seventvBadges(new SeventvBadges)
|
||||||
, userData(new UserDataController(paths))
|
, userData(new UserDataController(paths))
|
||||||
, sound(makeSoundController(_settings))
|
, sound(makeSoundController(_settings))
|
||||||
@@ -424,6 +427,14 @@ FfzBadges *Application::getFfzBadges()
|
|||||||
return this->ffzBadges.get();
|
return this->ffzBadges.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BttvBadges *Application::getBttvBadges()
|
||||||
|
{
|
||||||
|
// BttvBadges handles its own locks, so we don't need to assert that this is called in the GUI thread
|
||||||
|
assert(this->bttvBadges);
|
||||||
|
|
||||||
|
return this->bttvBadges.get();
|
||||||
|
}
|
||||||
|
|
||||||
SeventvBadges *Application::getSeventvBadges()
|
SeventvBadges *Application::getSeventvBadges()
|
||||||
{
|
{
|
||||||
// SeventvBadges handles its own locks, so we don't need to assert that this is called in the GUI thread
|
// SeventvBadges handles its own locks, so we don't need to assert that this is called in the GUI thread
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class Toasts;
|
|||||||
class IChatterinoBadges;
|
class IChatterinoBadges;
|
||||||
class ChatterinoBadges;
|
class ChatterinoBadges;
|
||||||
class FfzBadges;
|
class FfzBadges;
|
||||||
|
class BttvBadges;
|
||||||
class SeventvBadges;
|
class SeventvBadges;
|
||||||
class ImageUploader;
|
class ImageUploader;
|
||||||
class SeventvAPI;
|
class SeventvAPI;
|
||||||
@@ -90,6 +91,7 @@ public:
|
|||||||
virtual ILogging *getChatLogger() = 0;
|
virtual ILogging *getChatLogger() = 0;
|
||||||
virtual IChatterinoBadges *getChatterinoBadges() = 0;
|
virtual IChatterinoBadges *getChatterinoBadges() = 0;
|
||||||
virtual FfzBadges *getFfzBadges() = 0;
|
virtual FfzBadges *getFfzBadges() = 0;
|
||||||
|
virtual BttvBadges *getBttvBadges() = 0;
|
||||||
virtual SeventvBadges *getSeventvBadges() = 0;
|
virtual SeventvBadges *getSeventvBadges() = 0;
|
||||||
virtual IUserDataController *getUserData() = 0;
|
virtual IUserDataController *getUserData() = 0;
|
||||||
virtual ISoundController *getSound() = 0;
|
virtual ISoundController *getSound() = 0;
|
||||||
@@ -162,6 +164,7 @@ private:
|
|||||||
std::unique_ptr<HighlightController> highlights;
|
std::unique_ptr<HighlightController> highlights;
|
||||||
std::unique_ptr<TwitchIrcServer> twitch;
|
std::unique_ptr<TwitchIrcServer> twitch;
|
||||||
std::unique_ptr<FfzBadges> ffzBadges;
|
std::unique_ptr<FfzBadges> ffzBadges;
|
||||||
|
std::unique_ptr<BttvBadges> bttvBadges;
|
||||||
std::unique_ptr<SeventvBadges> seventvBadges;
|
std::unique_ptr<SeventvBadges> seventvBadges;
|
||||||
std::unique_ptr<UserDataController> userData;
|
std::unique_ptr<UserDataController> userData;
|
||||||
std::unique_ptr<ISoundController> sound;
|
std::unique_ptr<ISoundController> sound;
|
||||||
@@ -206,6 +209,7 @@ public:
|
|||||||
PubSub *getTwitchPubSub() override;
|
PubSub *getTwitchPubSub() override;
|
||||||
ILogging *getChatLogger() override;
|
ILogging *getChatLogger() override;
|
||||||
FfzBadges *getFfzBadges() override;
|
FfzBadges *getFfzBadges() override;
|
||||||
|
BttvBadges *getBttvBadges() override;
|
||||||
SeventvBadges *getSeventvBadges() override;
|
SeventvBadges *getSeventvBadges() override;
|
||||||
IUserDataController *getUserData() override;
|
IUserDataController *getUserData() override;
|
||||||
ISoundController *getSound() override;
|
ISoundController *getSound() override;
|
||||||
|
|||||||
@@ -353,6 +353,8 @@ set(SOURCE_FILES
|
|||||||
providers/NetworkConfigurationProvider.cpp
|
providers/NetworkConfigurationProvider.cpp
|
||||||
providers/NetworkConfigurationProvider.hpp
|
providers/NetworkConfigurationProvider.hpp
|
||||||
|
|
||||||
|
providers/bttv/BttvBadges.cpp
|
||||||
|
providers/bttv/BttvBadges.hpp
|
||||||
providers/bttv/BttvEmotes.cpp
|
providers/bttv/BttvEmotes.cpp
|
||||||
providers/bttv/BttvEmotes.hpp
|
providers/bttv/BttvEmotes.hpp
|
||||||
providers/bttv/BttvLiveUpdates.cpp
|
providers/bttv/BttvLiveUpdates.cpp
|
||||||
@@ -525,6 +527,8 @@ set(SOURCE_FILES
|
|||||||
util/AbandonObject.hpp
|
util/AbandonObject.hpp
|
||||||
util/AttachToConsole.cpp
|
util/AttachToConsole.cpp
|
||||||
util/AttachToConsole.hpp
|
util/AttachToConsole.hpp
|
||||||
|
util/BadgeRegistry.cpp
|
||||||
|
util/BadgeRegistry.hpp
|
||||||
util/CancellationToken.hpp
|
util/CancellationToken.hpp
|
||||||
util/ChannelHelpers.hpp
|
util/ChannelHelpers.hpp
|
||||||
util/Clipboard.cpp
|
util/Clipboard.cpp
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "messages/MessageColor.hpp"
|
#include "messages/MessageColor.hpp"
|
||||||
#include "messages/MessageElement.hpp"
|
#include "messages/MessageElement.hpp"
|
||||||
#include "messages/MessageThread.hpp"
|
#include "messages/MessageThread.hpp"
|
||||||
|
#include "providers/bttv/BttvBadges.hpp"
|
||||||
#include "providers/bttv/BttvEmotes.hpp"
|
#include "providers/bttv/BttvEmotes.hpp"
|
||||||
#include "providers/chatterino/ChatterinoBadges.hpp"
|
#include "providers/chatterino/ChatterinoBadges.hpp"
|
||||||
#include "providers/colors/ColorProvider.hpp"
|
#include "providers/colors/ColorProvider.hpp"
|
||||||
@@ -1636,6 +1637,7 @@ std::pair<MessagePtrMut, HighlightAlert> MessageBuilder::makeIrcMessage(
|
|||||||
|
|
||||||
builder.appendChatterinoBadges(userID);
|
builder.appendChatterinoBadges(userID);
|
||||||
builder.appendFfzBadges(twitchChannel, userID);
|
builder.appendFfzBadges(twitchChannel, userID);
|
||||||
|
builder.appendBttvBadges(userID);
|
||||||
builder.appendSeventvBadges(userID);
|
builder.appendSeventvBadges(userID);
|
||||||
|
|
||||||
builder.appendUsername(tags, args);
|
builder.appendUsername(tags, args);
|
||||||
@@ -2445,6 +2447,14 @@ void MessageBuilder::appendFfzBadges(TwitchChannel *twitchChannel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageBuilder::appendBttvBadges(const QString &userID)
|
||||||
|
{
|
||||||
|
if (auto badge = getApp()->getBttvBadges()->getBadge({userID}))
|
||||||
|
{
|
||||||
|
this->emplace<BadgeElement>(*badge, MessageElementFlag::BadgeBttv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageBuilder::appendSeventvBadges(const QString &userID)
|
void MessageBuilder::appendSeventvBadges(const QString &userID)
|
||||||
{
|
{
|
||||||
if (auto badge = getApp()->getSeventvBadges()->getBadge({userID}))
|
if (auto badge = getApp()->getSeventvBadges()->getBadge({userID}))
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ private:
|
|||||||
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);
|
||||||
|
void appendBttvBadges(const QString &userID);
|
||||||
void appendSeventvBadges(const QString &userID);
|
void appendSeventvBadges(const QString &userID);
|
||||||
|
|
||||||
[[nodiscard]] static bool isIgnored(const QString &originalMessage,
|
[[nodiscard]] static bool isIgnored(const QString &originalMessage,
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ enum class MessageElementFlag : int64_t {
|
|||||||
EmoteText = (1LL << 5),
|
EmoteText = (1LL << 5),
|
||||||
Emote = EmoteImage | EmoteText,
|
Emote = EmoteImage | EmoteText,
|
||||||
|
|
||||||
// unused: (1LL << 6),
|
|
||||||
// unused: (1LL << 7),
|
// unused: (1LL << 7),
|
||||||
|
|
||||||
ChannelPointReward = (1LL << 8),
|
ChannelPointReward = (1LL << 8),
|
||||||
@@ -105,7 +104,11 @@ enum class MessageElementFlag : int64_t {
|
|||||||
// - 7TV Contributor
|
// - 7TV Contributor
|
||||||
BadgeSevenTV = (1LL << 36),
|
BadgeSevenTV = (1LL << 36),
|
||||||
|
|
||||||
// Slot 7: FrankerFaceZ
|
// Slot 8: BetterTTV
|
||||||
|
// - BetterTTV Pro
|
||||||
|
BadgeBttv = (1LL << 6),
|
||||||
|
|
||||||
|
// Slot 9: FrankerFaceZ
|
||||||
// - FFZ developer badge
|
// - FFZ developer badge
|
||||||
// - FFZ bot badge
|
// - FFZ bot badge
|
||||||
// - FFZ donator badge
|
// - FFZ donator badge
|
||||||
@@ -113,7 +116,7 @@ enum class MessageElementFlag : int64_t {
|
|||||||
|
|
||||||
Badges = BadgeGlobalAuthority | BadgePredictions | BadgeChannelAuthority |
|
Badges = BadgeGlobalAuthority | BadgePredictions | BadgeChannelAuthority |
|
||||||
BadgeSubscription | BadgeVanity | BadgeChatterino | BadgeSevenTV |
|
BadgeSubscription | BadgeVanity | BadgeChatterino | BadgeSevenTV |
|
||||||
BadgeFfz | BadgeSharedChannel,
|
BadgeFfz | BadgeSharedChannel | BadgeBttv,
|
||||||
|
|
||||||
ChannelName = (1LL << 20),
|
ChannelName = (1LL << 20),
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "providers/bttv/BttvBadges.hpp"
|
||||||
|
|
||||||
|
#include "messages/Emote.hpp"
|
||||||
|
#include "messages/Image.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
QString BttvBadges::idForBadge(const QJsonObject &badgeJson) const
|
||||||
|
{
|
||||||
|
return badgeJson["url"].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmotePtr BttvBadges::createBadge(const QString &id,
|
||||||
|
const QJsonObject & /* badgeJson */) const
|
||||||
|
{
|
||||||
|
auto emote = Emote{
|
||||||
|
.name = EmoteName{},
|
||||||
|
.images = ImageSet(Image::fromUrl(Url{id}, 18.0 / 72.0)),
|
||||||
|
.tooltip = Tooltip{"BTTV Pro"},
|
||||||
|
.homePage = Url{},
|
||||||
|
.id = EmoteId{id},
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::make_shared<const Emote>(std::move(emote));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/BadgeRegistry.hpp"
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
struct Emote;
|
||||||
|
using EmotePtr = std::shared_ptr<const Emote>;
|
||||||
|
|
||||||
|
class BttvBadges : public BadgeRegistry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BttvBadges() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString idForBadge(const QJsonObject &badgeJson) const override;
|
||||||
|
EmotePtr createBadge(const QString &id,
|
||||||
|
const QJsonObject &badgeJson) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
@@ -24,6 +24,7 @@ public:
|
|||||||
BttvLiveUpdatesPrivate &operator=(const BttvLiveUpdatesPrivate &&) = delete;
|
BttvLiveUpdatesPrivate &operator=(const BttvLiveUpdatesPrivate &&) = delete;
|
||||||
|
|
||||||
std::shared_ptr<BttvLiveUpdateClient> makeClient();
|
std::shared_ptr<BttvLiveUpdateClient> makeClient();
|
||||||
|
std::shared_ptr<BttvLiveUpdateClient> anyClient();
|
||||||
|
|
||||||
// Contains all joined Twitch channel-ids
|
// Contains all joined Twitch channel-ids
|
||||||
std::unordered_set<QString> joinedChannels;
|
std::unordered_set<QString> joinedChannels;
|
||||||
@@ -50,6 +51,15 @@ std::shared_ptr<BttvLiveUpdateClient> BttvLiveUpdatesPrivate::makeClient()
|
|||||||
return std::make_shared<BttvLiveUpdateClient>(this->parent);
|
return std::make_shared<BttvLiveUpdateClient>(this->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<BttvLiveUpdateClient> BttvLiveUpdatesPrivate::anyClient()
|
||||||
|
{
|
||||||
|
if (this->clients().empty())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return this->clients().begin()->second;
|
||||||
|
}
|
||||||
|
|
||||||
BttvLiveUpdates::BttvLiveUpdates(QString host)
|
BttvLiveUpdates::BttvLiveUpdates(QString host)
|
||||||
: private_(std::make_unique<BttvLiveUpdatesPrivate>(*this, std::move(host)))
|
: private_(std::make_unique<BttvLiveUpdatesPrivate>(*this, std::move(host)))
|
||||||
{
|
{
|
||||||
@@ -77,6 +87,16 @@ void BttvLiveUpdates::partChannel(const QString &id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BttvLiveUpdates::broadcastMe(const QString &channelID,
|
||||||
|
const QString &userID)
|
||||||
|
{
|
||||||
|
auto client = this->private_->anyClient();
|
||||||
|
if (client)
|
||||||
|
{
|
||||||
|
client->broadcastMe(channelID, userID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BttvLiveUpdates::stop()
|
void BttvLiveUpdates::stop()
|
||||||
{
|
{
|
||||||
this->private_->stop();
|
this->private_->stop();
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void joinChannel(const QString &channelID, const QString &userID);
|
void joinChannel(const QString &channelID, const QString &userID);
|
||||||
|
|
||||||
|
void broadcastMe(const QString &channelID, const QString &userID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parts a twitch channel by its id (without any prefix like 'twitch:')
|
* Parts a twitch channel by its id (without any prefix like 'twitch:')
|
||||||
* if it's joined.
|
* if it's joined.
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#include "providers/bttv/liveupdates/BttvLiveUpdateClient.hpp"
|
#include "providers/bttv/liveupdates/BttvLiveUpdateClient.hpp"
|
||||||
|
|
||||||
|
#include "Application.hpp"
|
||||||
|
#include "providers/bttv/BttvBadges.hpp"
|
||||||
#include "providers/bttv/BttvLiveUpdates.hpp"
|
#include "providers/bttv/BttvLiveUpdates.hpp"
|
||||||
#include "providers/bttv/liveupdates/BttvLiveUpdateMessages.hpp"
|
#include "providers/bttv/liveupdates/BttvLiveUpdateMessages.hpp"
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
@@ -67,7 +70,25 @@ void BttvLiveUpdateClient::onMessage(const QByteArray &msg)
|
|||||||
}
|
}
|
||||||
else if (eventType == "lookup_user")
|
else if (eventType == "lookup_user")
|
||||||
{
|
{
|
||||||
// ignored
|
auto message = BttvLiveUpdateUserUpdateMessage(eventData);
|
||||||
|
if (!message.validate())
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoBttv) << "Invalid user update message" << json;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.hasBadge())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *app = tryGetApp();
|
||||||
|
if (app)
|
||||||
|
{
|
||||||
|
auto *bttvBadges = app->getBttvBadges();
|
||||||
|
auto badgeID = bttvBadges->registerBadge(message.badgeObject);
|
||||||
|
bttvBadges->assignBadgeToUser(badgeID, UserId{message.userID});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -75,4 +96,21 @@ void BttvLiveUpdateClient::onMessage(const QByteArray &msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BttvLiveUpdateClient::broadcastMe(const QString &channelID,
|
||||||
|
const QString &userID)
|
||||||
|
{
|
||||||
|
QJsonObject obj{
|
||||||
|
{"name", "broadcast_me"},
|
||||||
|
{"data",
|
||||||
|
QJsonObject{
|
||||||
|
{"provider", "twitch"},
|
||||||
|
{"providerId", userID},
|
||||||
|
{"channel", QString(u"twitch:" % channelID)},
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
QJsonDocument doc(obj);
|
||||||
|
|
||||||
|
this->sendText(doc.toJson(QJsonDocument::Compact));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ public:
|
|||||||
|
|
||||||
void onMessage(const QByteArray &msg) /* override */;
|
void onMessage(const QByteArray &msg) /* override */;
|
||||||
|
|
||||||
|
void broadcastMe(const QString &channelID, const QString &userID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BttvLiveUpdates &manager;
|
BttvLiveUpdates &manager;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using namespace Qt::Literals;
|
||||||
|
|
||||||
bool tryParseChannelId(QString &channelId)
|
bool tryParseChannelId(QString &channelId)
|
||||||
{
|
{
|
||||||
if (!channelId.startsWith("twitch:"))
|
if (!channelId.startsWith("twitch:"))
|
||||||
@@ -49,4 +51,21 @@ bool BttvLiveUpdateEmoteRemoveMessage::validate() const
|
|||||||
!this->channelID.isEmpty();
|
!this->channelID.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BttvLiveUpdateUserUpdateMessage::BttvLiveUpdateUserUpdateMessage(
|
||||||
|
const QJsonObject &json)
|
||||||
|
: userID(json["providerId"_L1].toString())
|
||||||
|
, badgeObject(json["badge"_L1].toObject())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BttvLiveUpdateUserUpdateMessage::validate() const
|
||||||
|
{
|
||||||
|
return !this->userID.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BttvLiveUpdateUserUpdateMessage::hasBadge() const
|
||||||
|
{
|
||||||
|
return !this->badgeObject.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -35,4 +35,14 @@ private:
|
|||||||
bool badChannelID_;
|
bool badChannelID_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BttvLiveUpdateUserUpdateMessage {
|
||||||
|
BttvLiveUpdateUserUpdateMessage(const QJsonObject &json);
|
||||||
|
|
||||||
|
QString userID;
|
||||||
|
QJsonObject badgeObject;
|
||||||
|
|
||||||
|
bool validate() const;
|
||||||
|
bool hasBadge() const;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ public:
|
|||||||
this->ws_.close();
|
this->ws_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendText(const QByteArray &data)
|
||||||
|
{
|
||||||
|
this->ws_.sendText(data);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @return true if this client subscribed to this subscription
|
* @return true if this client subscribed to this subscription
|
||||||
|
|||||||
@@ -4,74 +4,30 @@
|
|||||||
#include "messages/Image.hpp"
|
#include "messages/Image.hpp"
|
||||||
#include "providers/seventv/SeventvEmotes.hpp"
|
#include "providers/seventv/SeventvEmotes.hpp"
|
||||||
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QUrlQuery>
|
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
std::optional<EmotePtr> SeventvBadges::getBadge(const UserId &id) const
|
QString SeventvBadges::idForBadge(const QJsonObject &badgeJson) const
|
||||||
{
|
{
|
||||||
std::shared_lock lock(this->mutex_);
|
return badgeJson["id"].toString();
|
||||||
|
|
||||||
auto it = this->badgeMap_.find(id.string);
|
|
||||||
if (it != this->badgeMap_.end())
|
|
||||||
{
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeventvBadges::assignBadgeToUser(const QString &badgeID,
|
EmotePtr SeventvBadges::createBadge(const QString &id,
|
||||||
const UserId &userID)
|
const QJsonObject &badgeJson) const
|
||||||
{
|
{
|
||||||
const std::unique_lock lock(this->mutex_);
|
|
||||||
|
|
||||||
const auto badgeIt = this->knownBadges_.find(badgeID);
|
|
||||||
if (badgeIt != this->knownBadges_.end())
|
|
||||||
{
|
|
||||||
this->badgeMap_[userID.string] = badgeIt->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SeventvBadges::clearBadgeFromUser(const QString &badgeID,
|
|
||||||
const UserId &userID)
|
|
||||||
{
|
|
||||||
const std::unique_lock lock(this->mutex_);
|
|
||||||
|
|
||||||
const auto it = this->badgeMap_.find(userID.string);
|
|
||||||
if (it != this->badgeMap_.end() && it->second->id.string == badgeID)
|
|
||||||
{
|
|
||||||
this->badgeMap_.erase(userID.string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SeventvBadges::registerBadge(const QJsonObject &badgeJson)
|
|
||||||
{
|
|
||||||
const auto badgeID = badgeJson["id"].toString();
|
|
||||||
|
|
||||||
const std::unique_lock lock(this->mutex_);
|
|
||||||
|
|
||||||
if (this->knownBadges_.find(badgeID) != this->knownBadges_.end())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto emote = Emote{
|
auto emote = Emote{
|
||||||
.name = EmoteName{},
|
.name = EmoteName{},
|
||||||
.images = SeventvEmotes::createImageSet(badgeJson, true),
|
.images = SeventvEmotes::createImageSet(badgeJson, true),
|
||||||
.tooltip = Tooltip{badgeJson["tooltip"].toString()},
|
.tooltip = Tooltip{badgeJson["tooltip"].toString()},
|
||||||
.homePage = Url{},
|
.homePage = Url{},
|
||||||
.id = EmoteId{badgeID},
|
.id = EmoteId{id},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (emote.images.getImage1()->isEmpty())
|
if (emote.images.getImage1()->isEmpty())
|
||||||
{
|
{
|
||||||
return; // Bad images
|
return nullptr; // Bad images
|
||||||
}
|
}
|
||||||
|
|
||||||
this->knownBadges_[badgeID] =
|
return std::make_shared<const Emote>(std::move(emote));
|
||||||
std::make_shared<const Emote>(std::move(emote));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -1,44 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/Aliases.hpp"
|
#include "util/BadgeRegistry.hpp"
|
||||||
#include "util/QStringHash.hpp"
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
|
||||||
#include <shared_mutex>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
struct Emote;
|
struct Emote;
|
||||||
using EmotePtr = std::shared_ptr<const Emote>;
|
using EmotePtr = std::shared_ptr<const Emote>;
|
||||||
|
|
||||||
class SeventvBadges
|
class SeventvBadges : public BadgeRegistry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Return the badge, if any, that is assigned to the user
|
SeventvBadges() = default;
|
||||||
std::optional<EmotePtr> getBadge(const UserId &id) const;
|
|
||||||
|
|
||||||
// Assign the given badge to the user
|
protected:
|
||||||
void assignBadgeToUser(const QString &badgeID, const UserId &userID);
|
QString idForBadge(const QJsonObject &badgeJson) const override;
|
||||||
|
EmotePtr createBadge(const QString &id,
|
||||||
// Remove the given badge from the user
|
const QJsonObject &badgeJson) const override;
|
||||||
void clearBadgeFromUser(const QString &badgeID, const UserId &userID);
|
|
||||||
|
|
||||||
// Register a new known badge
|
|
||||||
// The json object will contain all information about the badge, like its ID & its images
|
|
||||||
void registerBadge(const QJsonObject &badgeJson);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Mutex for both `badgeMap_` and `knownBadges_`
|
|
||||||
mutable std::shared_mutex mutex_;
|
|
||||||
|
|
||||||
// user-id => badge
|
|
||||||
std::unordered_map<QString, EmotePtr> badgeMap_;
|
|
||||||
// badge-id => badge
|
|
||||||
std::unordered_map<QString, EmotePtr> knownBadges_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -831,6 +831,7 @@ void TwitchChannel::sendMessage(const QString &message)
|
|||||||
|
|
||||||
bool messageSent = false;
|
bool messageSent = false;
|
||||||
this->sendMessageSignal.invoke(this->getName(), parsedMessage, messageSent);
|
this->sendMessageSignal.invoke(this->getName(), parsedMessage, messageSent);
|
||||||
|
this->updateBttvActivity();
|
||||||
this->updateSevenTVActivity();
|
this->updateSevenTVActivity();
|
||||||
|
|
||||||
if (messageSent)
|
if (messageSent)
|
||||||
@@ -2256,6 +2257,31 @@ std::optional<CheerEmote> TwitchChannel::cheerEmote(const QString &string) const
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TwitchChannel::updateBttvActivity()
|
||||||
|
{
|
||||||
|
if (!getApp()->getBttvLiveUpdates())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = QDateTime::currentDateTimeUtc();
|
||||||
|
if (this->nextBttvActivity_.isValid() && now < this->nextBttvActivity_)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->nextBttvActivity_ = now.addSecs(60);
|
||||||
|
|
||||||
|
qCDebug(chatterinoBttv) << "Sending activity in" << this->getName();
|
||||||
|
|
||||||
|
auto acc = getApp()->getAccounts()->twitch.getCurrent();
|
||||||
|
if (acc->isAnon())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getApp()->getBttvLiveUpdates()->broadcastMe(this->roomId(),
|
||||||
|
acc->getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
void TwitchChannel::updateSevenTVActivity()
|
void TwitchChannel::updateSevenTVActivity()
|
||||||
{
|
{
|
||||||
static const QString seventvActivityUrl =
|
static const QString seventvActivityUrl =
|
||||||
|
|||||||
@@ -377,6 +377,9 @@ private:
|
|||||||
|
|
||||||
/** Joins (subscribes to) a Twitch channel for updates on BTTV. */
|
/** Joins (subscribes to) a Twitch channel for updates on BTTV. */
|
||||||
void joinBttvChannel() const;
|
void joinBttvChannel() const;
|
||||||
|
|
||||||
|
void updateBttvActivity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates an activity to 7TV in this channel for this user.
|
* Indicates an activity to 7TV in this channel for this user.
|
||||||
* This is done at most once every 60s.
|
* This is done at most once every 60s.
|
||||||
@@ -514,6 +517,8 @@ private:
|
|||||||
*/
|
*/
|
||||||
QDateTime nextSeventvActivity_;
|
QDateTime nextSeventvActivity_;
|
||||||
|
|
||||||
|
QDateTime nextBttvActivity_;
|
||||||
|
|
||||||
/** The platform of the last live emote update ("7TV", "BTTV", "FFZ"). */
|
/** The platform of the last live emote update ("7TV", "BTTV", "FFZ"). */
|
||||||
QString lastLiveUpdateEmotePlatform_;
|
QString lastLiveUpdateEmotePlatform_;
|
||||||
/** The actor name of the last live emote update. */
|
/** The actor name of the last live emote update. */
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ public:
|
|||||||
"/appearance/badges/useCustomFfzModeratorBadges", true};
|
"/appearance/badges/useCustomFfzModeratorBadges", true};
|
||||||
BoolSetting useCustomFfzVipBadges = {
|
BoolSetting useCustomFfzVipBadges = {
|
||||||
"/appearance/badges/useCustomFfzVipBadges", true};
|
"/appearance/badges/useCustomFfzVipBadges", true};
|
||||||
|
BoolSetting showBadgesBttv = {"/appearance/badges/bttv", true};
|
||||||
BoolSetting showBadgesSevenTV = {"/appearance/badges/seventv", true};
|
BoolSetting showBadgesSevenTV = {"/appearance/badges/seventv", true};
|
||||||
QSizeSetting lastPopupSize = {
|
QSizeSetting lastPopupSize = {
|
||||||
"/appearance/lastPopup/size",
|
"/appearance/lastPopup/size",
|
||||||
@@ -386,6 +387,7 @@ public:
|
|||||||
BoolSetting enableBTTVGlobalEmotes = {"/emotes/bttv/global", true};
|
BoolSetting enableBTTVGlobalEmotes = {"/emotes/bttv/global", true};
|
||||||
BoolSetting enableBTTVChannelEmotes = {"/emotes/bttv/channel", true};
|
BoolSetting enableBTTVChannelEmotes = {"/emotes/bttv/channel", true};
|
||||||
BoolSetting enableBTTVLiveUpdates = {"/emotes/bttv/liveupdates", true};
|
BoolSetting enableBTTVLiveUpdates = {"/emotes/bttv/liveupdates", true};
|
||||||
|
BoolSetting sendBTTVActivity = {"/emotes/bttv/sendActivity", true};
|
||||||
BoolSetting enableFFZGlobalEmotes = {"/emotes/ffz/global", true};
|
BoolSetting enableFFZGlobalEmotes = {"/emotes/ffz/global", true};
|
||||||
BoolSetting enableFFZChannelEmotes = {"/emotes/ffz/channel", true};
|
BoolSetting enableFFZChannelEmotes = {"/emotes/ffz/channel", true};
|
||||||
BoolSetting enableSevenTVGlobalEmotes = {"/emotes/seventv/global", true};
|
BoolSetting enableSevenTVGlobalEmotes = {"/emotes/seventv/global", true};
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ void WindowManager::updateWordTypeMask()
|
|||||||
flags.set(settings->showBadgesChatterino ? MEF::BadgeChatterino
|
flags.set(settings->showBadgesChatterino ? MEF::BadgeChatterino
|
||||||
: MEF::None);
|
: MEF::None);
|
||||||
flags.set(settings->showBadgesFfz ? MEF::BadgeFfz : MEF::None);
|
flags.set(settings->showBadgesFfz ? MEF::BadgeFfz : MEF::None);
|
||||||
|
flags.set(settings->showBadgesBttv ? MEF::BadgeBttv : MEF::None);
|
||||||
flags.set(settings->showBadgesSevenTV ? MEF::BadgeSevenTV : MEF::None);
|
flags.set(settings->showBadgesSevenTV ? MEF::BadgeSevenTV : MEF::None);
|
||||||
|
|
||||||
// username
|
// username
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#include "util/BadgeRegistry.hpp"
|
||||||
|
|
||||||
|
#include "messages/Emote.hpp"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QUrlQuery>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
std::optional<EmotePtr> BadgeRegistry::getBadge(const UserId &id) const
|
||||||
|
{
|
||||||
|
std::shared_lock lock(this->mutex_);
|
||||||
|
|
||||||
|
auto it = this->badgeMap_.find(id.string);
|
||||||
|
if (it != this->badgeMap_.end())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BadgeRegistry::assignBadgeToUser(const QString &badgeID,
|
||||||
|
const UserId &userID)
|
||||||
|
{
|
||||||
|
const std::unique_lock lock(this->mutex_);
|
||||||
|
|
||||||
|
const auto badgeIt = this->knownBadges_.find(badgeID);
|
||||||
|
if (badgeIt != this->knownBadges_.end())
|
||||||
|
{
|
||||||
|
this->badgeMap_[userID.string] = badgeIt->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BadgeRegistry::clearBadgeFromUser(const QString &badgeID,
|
||||||
|
const UserId &userID)
|
||||||
|
{
|
||||||
|
const std::unique_lock lock(this->mutex_);
|
||||||
|
|
||||||
|
const auto it = this->badgeMap_.find(userID.string);
|
||||||
|
if (it != this->badgeMap_.end() && it->second->id.string == badgeID)
|
||||||
|
{
|
||||||
|
this->badgeMap_.erase(userID.string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BadgeRegistry::registerBadge(const QJsonObject &badgeJson)
|
||||||
|
{
|
||||||
|
const auto badgeID = this->idForBadge(badgeJson);
|
||||||
|
|
||||||
|
const std::unique_lock lock(this->mutex_);
|
||||||
|
|
||||||
|
if (this->knownBadges_.contains(badgeID))
|
||||||
|
{
|
||||||
|
return badgeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto emote = this->createBadge(badgeID, badgeJson);
|
||||||
|
if (!emote)
|
||||||
|
{
|
||||||
|
return badgeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->knownBadges_[badgeID] = std::move(emote);
|
||||||
|
return badgeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Aliases.hpp"
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
#include <shared_mutex>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
struct Emote;
|
||||||
|
using EmotePtr = std::shared_ptr<const Emote>;
|
||||||
|
|
||||||
|
class BadgeRegistry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~BadgeRegistry() = default;
|
||||||
|
|
||||||
|
/// Return the badge, if any, that is assigned to the user
|
||||||
|
std::optional<EmotePtr> getBadge(const UserId &id) const;
|
||||||
|
|
||||||
|
/// Assign the given badge to the user
|
||||||
|
void assignBadgeToUser(const QString &badgeID, const UserId &userID);
|
||||||
|
|
||||||
|
/// Remove the given badge from the user
|
||||||
|
void clearBadgeFromUser(const QString &badgeID, const UserId &userID);
|
||||||
|
|
||||||
|
/// Register a new known badge
|
||||||
|
/// The json object will contain all information about the badge, like its ID & its images
|
||||||
|
/// @returns The badge's ID
|
||||||
|
QString registerBadge(const QJsonObject &badgeJson);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BadgeRegistry() = default;
|
||||||
|
|
||||||
|
virtual QString idForBadge(const QJsonObject &badgeJson) const = 0;
|
||||||
|
virtual EmotePtr createBadge(const QString &id,
|
||||||
|
const QJsonObject &badgeJson) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Mutex for both `badgeMap_` and `knownBadges_`
|
||||||
|
mutable std::shared_mutex mutex_;
|
||||||
|
|
||||||
|
/// user-id => badge
|
||||||
|
std::unordered_map<QString, EmotePtr> badgeMap_;
|
||||||
|
/// badge-id => badge
|
||||||
|
std::unordered_map<QString, EmotePtr> knownBadges_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
@@ -659,6 +659,14 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
|||||||
s.enableBTTVLiveUpdates)
|
s.enableBTTVLiveUpdates)
|
||||||
->addKeywords({"bttv"})
|
->addKeywords({"bttv"})
|
||||||
->addTo(layout);
|
->addTo(layout);
|
||||||
|
SettingWidget::checkbox("Send activity to BetterTTV", s.sendBTTVActivity)
|
||||||
|
->setTooltip(
|
||||||
|
"When enabled, Chatterino will signal an activity to BetterTTV "
|
||||||
|
"when you send a chat message. This is used for badges, "
|
||||||
|
" and personal emotes. When disabled, no activity "
|
||||||
|
"is sent and others won't see your cosmetics.")
|
||||||
|
->addKeywords({"bttv"})
|
||||||
|
->addTo(layout);
|
||||||
|
|
||||||
SettingWidget::checkbox("Show FrankerFaceZ global emotes",
|
SettingWidget::checkbox("Show FrankerFaceZ global emotes",
|
||||||
s.enableFFZGlobalEmotes)
|
s.enableFFZGlobalEmotes)
|
||||||
@@ -1106,6 +1114,9 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
|||||||
->addKeywords({"seventv"})
|
->addKeywords({"seventv"})
|
||||||
->setTooltip("Badges for 7TV admins, developers, and supporters")
|
->setTooltip("Badges for 7TV admins, developers, and supporters")
|
||||||
->addTo(layout);
|
->addTo(layout);
|
||||||
|
SettingWidget::checkbox("BetterTTV", s.showBadgesBttv)
|
||||||
|
->addKeywords({"bttv"})
|
||||||
|
->addTo(layout);
|
||||||
layout.addSeparator();
|
layout.addSeparator();
|
||||||
SettingWidget::checkbox("Use custom FrankerFaceZ moderator badges",
|
SettingWidget::checkbox("Use custom FrankerFaceZ moderator badges",
|
||||||
s.useCustomFfzModeratorBadges)
|
s.useCustomFfzModeratorBadges)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "mocks/Logging.hpp"
|
#include "mocks/Logging.hpp"
|
||||||
#include "mocks/TwitchIrcServer.hpp"
|
#include "mocks/TwitchIrcServer.hpp"
|
||||||
#include "mocks/UserData.hpp"
|
#include "mocks/UserData.hpp"
|
||||||
|
#include "providers/bttv/BttvBadges.hpp"
|
||||||
#include "providers/ffz/FfzBadges.hpp"
|
#include "providers/ffz/FfzBadges.hpp"
|
||||||
#include "providers/seventv/SeventvBadges.hpp"
|
#include "providers/seventv/SeventvBadges.hpp"
|
||||||
#include "providers/twitch/TwitchBadge.hpp"
|
#include "providers/twitch/TwitchBadge.hpp"
|
||||||
@@ -64,6 +65,11 @@ public:
|
|||||||
return &this->ffzBadges;
|
return &this->ffzBadges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BttvBadges *getBttvBadges() override
|
||||||
|
{
|
||||||
|
return &this->bttvBadges;
|
||||||
|
}
|
||||||
|
|
||||||
SeventvBadges *getSeventvBadges() override
|
SeventvBadges *getSeventvBadges() override
|
||||||
{
|
{
|
||||||
return &this->seventvBadges;
|
return &this->seventvBadges;
|
||||||
@@ -86,6 +92,7 @@ public:
|
|||||||
mock::MockTwitchIrcServer twitch;
|
mock::MockTwitchIrcServer twitch;
|
||||||
mock::ChatterinoBadges chatterinoBadges;
|
mock::ChatterinoBadges chatterinoBadges;
|
||||||
FfzBadges ffzBadges;
|
FfzBadges ffzBadges;
|
||||||
|
BttvBadges bttvBadges;
|
||||||
SeventvBadges seventvBadges;
|
SeventvBadges seventvBadges;
|
||||||
HighlightController highlights;
|
HighlightController highlights;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "mocks/Logging.hpp"
|
#include "mocks/Logging.hpp"
|
||||||
#include "mocks/TwitchIrcServer.hpp"
|
#include "mocks/TwitchIrcServer.hpp"
|
||||||
#include "mocks/UserData.hpp"
|
#include "mocks/UserData.hpp"
|
||||||
|
#include "providers/bttv/BttvBadges.hpp"
|
||||||
#include "providers/ffz/FfzBadges.hpp"
|
#include "providers/ffz/FfzBadges.hpp"
|
||||||
#include "providers/seventv/SeventvBadges.hpp"
|
#include "providers/seventv/SeventvBadges.hpp"
|
||||||
#include "providers/twitch/api/Helix.hpp"
|
#include "providers/twitch/api/Helix.hpp"
|
||||||
@@ -102,6 +103,11 @@ public:
|
|||||||
return &this->ffzBadges;
|
return &this->ffzBadges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BttvBadges *getBttvBadges() override
|
||||||
|
{
|
||||||
|
return &this->bttvBadges;
|
||||||
|
}
|
||||||
|
|
||||||
SeventvBadges *getSeventvBadges() override
|
SeventvBadges *getSeventvBadges() override
|
||||||
{
|
{
|
||||||
return &this->seventvBadges;
|
return &this->seventvBadges;
|
||||||
@@ -154,6 +160,7 @@ public:
|
|||||||
mock::MockTwitchIrcServer twitch;
|
mock::MockTwitchIrcServer twitch;
|
||||||
mock::ChatterinoBadges chatterinoBadges;
|
mock::ChatterinoBadges chatterinoBadges;
|
||||||
FfzBadges ffzBadges;
|
FfzBadges ffzBadges;
|
||||||
|
BttvBadges bttvBadges;
|
||||||
SeventvBadges seventvBadges;
|
SeventvBadges seventvBadges;
|
||||||
HighlightController highlights;
|
HighlightController highlights;
|
||||||
BttvEmotes bttvEmotes;
|
BttvEmotes bttvEmotes;
|
||||||
|
|||||||
@@ -931,6 +931,7 @@ TEST_F(PluginTest, MessageElementFlag)
|
|||||||
)lua");
|
)lua");
|
||||||
|
|
||||||
const char *VALUES = "AlwaysShow=0x2000000,"
|
const char *VALUES = "AlwaysShow=0x2000000,"
|
||||||
|
"BadgeBttv=0x40,"
|
||||||
"BadgeChannelAuthority=0x8000,"
|
"BadgeChannelAuthority=0x8000,"
|
||||||
"BadgeChatterino=0x40000,"
|
"BadgeChatterino=0x40000,"
|
||||||
"BadgeFfz=0x80000,"
|
"BadgeFfz=0x80000,"
|
||||||
|
|||||||
Reference in New Issue
Block a user