feat: notate power-up automatic reward redemptions (#5471)

This commit is contained in:
iProdigy 2024-06-22 06:03:49 -05:00 committed by GitHub
parent c01bfcfffe
commit 2ef3306d1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 94 additions and 12 deletions

View file

@ -14,6 +14,7 @@
- Minor: Moderators can now see when users are warned. (#5441)
- Minor: Added support for Brave & google-chrome-stable browsers. (#5452)
- Minor: Added drop indicator line while dragging in tables. (#5256)
- Minor: Add channel points indication for new bits power-up redemptions. (#5471)
- Minor: Added `/warn <username> <reason>` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474)
- Minor: Introduce HTTP API for plugins. (#5383)
- Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426)

View file

@ -14,6 +14,47 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption)
this->title = reward.value("title").toString();
this->cost = reward.value("cost").toInt();
this->isUserInputRequired = reward.value("is_user_input_required").toBool();
this->isBits = reward.value("pricing_type").toString() == "BITS";
// accommodate idiosyncrasies of automatic reward redemptions
const auto rewardType = reward.value("reward_type").toString();
if (rewardType == "SEND_ANIMATED_MESSAGE")
{
this->id = "animated-message";
this->isUserInputRequired = true;
this->title = "Message Effects";
}
else if (rewardType == "SEND_GIGANTIFIED_EMOTE")
{
this->id = "gigantified-emote-message";
this->isUserInputRequired = true;
this->title = "Gigantify an Emote";
}
else if (rewardType == "CELEBRATION")
{
this->id = rewardType;
this->title = "On-Screen Celebration";
const auto metadata =
redemption.value("redemption_metadata").toObject();
const auto emote = metadata.value("celebration_emote_metadata")
.toObject()
.value("emote")
.toObject();
this->emoteId = emote.value("id").toString();
this->emoteName = emote.value("token").toString();
}
// use bits cost when channel points were not used
if (cost == 0)
{
this->cost = reward.value("bits_cost").toInt();
}
// workaround twitch bug where bits_cost is always 0 in practice
if (cost == 0)
{
this->cost = reward.value("default_bits_cost").toInt();
}
// We don't need to store user information for rewards with user input
// because we will get the user info from a corresponding IRC message
@ -27,6 +68,13 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption)
}
auto imageValue = reward.value("image");
// automatic reward redemptions have specialized default images
if (imageValue.isNull() && this->isBits)
{
imageValue = reward.value("default_image");
}
// From Twitch docs
// The size is only an estimation, the actual size might vary.
constexpr QSize baseSize(28, 28);

View file

@ -19,6 +19,9 @@ struct ChannelPointReward {
int cost;
ImageSet image;
bool isUserInputRequired = false;
bool isBits = false;
QString emoteId; // currently only for celebrations
QString emoteName; // currently only for celebrations
struct {
QString id;

View file

@ -1338,21 +1338,30 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message,
auto *channel = dynamic_cast<TwitchChannel *>(chan.get());
const auto &tags = message->tags();
QString rewardId;
if (const auto it = tags.find("custom-reward-id"); it != tags.end())
{
const auto rewardId = it.value().toString();
if (!rewardId.isEmpty() &&
!channel->isChannelPointRewardKnown(rewardId))
{
// Need to wait for pubsub reward notification
qCDebug(chatterinoTwitch) << "TwitchChannel reward added ADD "
"callback since reward is not known:"
<< rewardId;
channel->addQueuedRedemption(rewardId, originalContent, message);
return;
}
args.channelPointRewardId = rewardId;
rewardId = it.value().toString();
}
else if (const auto typeIt = tags.find("msg-id"); typeIt != tags.end())
{
// slight hack to treat bits power-ups as channel point redemptions
const auto msgId = typeIt.value().toString();
if (msgId == "animated-message" || msgId == "gigantified-emote-message")
{
rewardId = msgId;
}
}
if (!rewardId.isEmpty() && !channel->isChannelPointRewardKnown(rewardId))
{
// Need to wait for pubsub reward notification
qCDebug(chatterinoTwitch) << "TwitchChannel reward added ADD "
"callback since reward is not known:"
<< rewardId;
channel->addQueuedRedemption(rewardId, originalContent, message);
return;
}
args.channelPointRewardId = rewardId;
QString content = originalContent;
int messageOffset = stripLeadingReplyMention(tags, content);

View file

@ -1181,6 +1181,8 @@ void PubSub::handleMessageResponse(const PubSubMessageMessage &message)
switch (innerMessage.type)
{
case PubSubCommunityPointsChannelV1Message::Type::
AutomaticRewardRedeemed:
case PubSubCommunityPointsChannelV1Message::Type::RewardRedeemed: {
auto redemption =
innerMessage.data.value("redemption").toObject();

View file

@ -1594,6 +1594,15 @@ void TwitchMessageBuilder::appendChannelPointRewardMessage(
}
builder->emplace<TextElement>(redeemed,
MessageElementFlag::ChannelPointReward);
if (reward.id == "CELEBRATION")
{
const auto emotePtr =
getIApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote(
EmoteId{reward.emoteId}, EmoteName{reward.emoteName});
builder->emplace<EmoteElement>(emotePtr,
MessageElementFlag::ChannelPointReward,
MessageColor::Text);
}
builder->emplace<TextElement>(
reward.title, MessageElementFlag::ChannelPointReward,
MessageColor::Text, FontStyle::ChatMediumBold);
@ -1602,6 +1611,12 @@ void TwitchMessageBuilder::appendChannelPointRewardMessage(
builder->emplace<TextElement>(
QString::number(reward.cost), MessageElementFlag::ChannelPointReward,
MessageColor::Text, FontStyle::ChatMediumBold);
if (reward.isBits)
{
builder->emplace<TextElement>(
"bits", MessageElementFlag::ChannelPointReward, MessageColor::Text,
FontStyle::ChatMediumBold);
}
if (reward.isUserInputRequired)
{
builder->emplace<LinebreakElement>(

View file

@ -8,6 +8,7 @@ namespace chatterino {
struct PubSubCommunityPointsChannelV1Message {
enum class Type {
AutomaticRewardRedeemed,
RewardRedeemed,
INVALID,
@ -30,6 +31,9 @@ constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<
{
switch (value)
{
case chatterino::PubSubCommunityPointsChannelV1Message::Type::
AutomaticRewardRedeemed:
return "automatic-reward-redeemed";
case chatterino::PubSubCommunityPointsChannelV1Message::Type::
RewardRedeemed:
return "reward-redeemed";