fix: mark global BTTV emotes as zero-width at creation (#6440)

* fix: mark global BTTV emotes as zero-width at creation

* changelog

* nit: slightly different formatting

---------

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix
2025-09-05 10:01:21 +02:00
committed by GitHub
parent 445865d0d8
commit 5af6626e76
3 changed files with 31 additions and 52 deletions
+2
View File
@@ -2,6 +2,8 @@
## Unversioned ## Unversioned
- Bugfix: Fixed zero-width global BTTV emotes not showing in the `:~` completions. (#6440)
## 2.5.4-beta.1 ## 2.5.4-beta.1
- Minor: Added `Open in custom player` to `twitch.tv/<channel>` link context menus. (#6403) - Minor: Added `Open in custom player` to `twitch.tv/<channel>` link context menus. (#6403)
+11 -43
View File
@@ -78,11 +78,6 @@ const QRegularExpression allUsernamesMentionRegex("^" + regexHelpString);
const QRegularExpression SPACE_REGEX("\\s"); const QRegularExpression SPACE_REGEX("\\s");
const QSet<QString> zeroWidthEmotes{
"SoSnowy", "IceCold", "SantaHat", "TopHat",
"ReinDeer", "CandyCane", "cvMask", "cvHazmat",
};
struct HypeChatPaidLevel { struct HypeChatPaidLevel {
std::chrono::seconds duration; std::chrono::seconds duration;
uint8_t numeric; uint8_t numeric;
@@ -421,7 +416,7 @@ EmotePtr makeSharedChatBadge(const QString &sourceName,
}); });
} }
std::tuple<std::optional<EmotePtr>, MessageElementFlags, bool> parseEmote( std::tuple<std::optional<EmotePtr>, MessageElementFlags> parseEmote(
TwitchChannel *twitchChannel, const EmoteName &name) TwitchChannel *twitchChannel, const EmoteName &name)
{ {
// Emote order: // Emote order:
@@ -445,31 +440,19 @@ std::tuple<std::optional<EmotePtr>, MessageElementFlags, bool> parseEmote(
emote = twitchChannel->ffzEmote(name); emote = twitchChannel->ffzEmote(name);
if (emote) if (emote)
{ {
return { return {emote, MessageElementFlag::FfzEmote};
emote,
MessageElementFlag::FfzEmote,
false,
};
} }
emote = twitchChannel->bttvEmote(name); emote = twitchChannel->bttvEmote(name);
if (emote) if (emote)
{ {
return { return {emote, MessageElementFlag::BttvEmote};
emote,
MessageElementFlag::BttvEmote,
false,
};
} }
emote = twitchChannel->seventvEmote(name); emote = twitchChannel->seventvEmote(name);
if (emote) if (emote)
{ {
return { return {emote, MessageElementFlag::SevenTVEmote};
emote,
MessageElementFlag::SevenTVEmote,
emote.value()->zeroWidth,
};
} }
} }
@@ -478,38 +461,22 @@ std::tuple<std::optional<EmotePtr>, MessageElementFlags, bool> parseEmote(
emote = globalFfzEmotes->emote(name); emote = globalFfzEmotes->emote(name);
if (emote) if (emote)
{ {
return { return {emote, MessageElementFlag::FfzEmote};
emote,
MessageElementFlag::FfzEmote,
false,
};
} }
emote = globalBttvEmotes->emote(name); emote = globalBttvEmotes->emote(name);
if (emote) if (emote)
{ {
return { return {emote, MessageElementFlag::BttvEmote};
emote,
MessageElementFlag::BttvEmote,
zeroWidthEmotes.contains(name.string),
};
} }
emote = globalSeventvEmotes->globalEmote(name); emote = globalSeventvEmotes->globalEmote(name);
if (emote) if (emote)
{ {
return { return {emote, MessageElementFlag::SevenTVEmote};
emote,
MessageElementFlag::SevenTVEmote,
emote.value()->zeroWidth,
};
} }
return { return {{}, {}};
{},
{},
false,
};
} }
} // namespace } // namespace
@@ -2240,14 +2207,15 @@ void MessageBuilder::appendUsername(const QVariantMap &tags,
Outcome MessageBuilder::tryAppendEmote(TwitchChannel *twitchChannel, Outcome MessageBuilder::tryAppendEmote(TwitchChannel *twitchChannel,
const EmoteName &name) const EmoteName &name)
{ {
auto [emote, flags, zeroWidth] = parseEmote(twitchChannel, name); auto [emote, flags] = parseEmote(twitchChannel, name);
if (!emote) if (!emote)
{ {
return Failure; return Failure;
} }
if (zeroWidth && getSettings()->enableZeroWidthEmotes && !this->isEmpty()) if ((*emote)->zeroWidth && getSettings()->enableZeroWidthEmotes &&
!this->isEmpty())
{ {
// Attempt to merge current zero-width emote into any previous emotes // Attempt to merge current zero-width emote into any previous emotes
auto *asEmote = dynamic_cast<EmoteElement *>(&this->back()); auto *asEmote = dynamic_cast<EmoteElement *>(&this->back());
+18 -9
View File
@@ -30,6 +30,11 @@ const QString CHANNEL_HAS_NO_EMOTES(
/// %1 being the emote ID (e.g. 566ca04265dbbdab32ec054a) /// %1 being the emote ID (e.g. 566ca04265dbbdab32ec054a)
constexpr QStringView EMOTE_LINK_FORMAT = u"https://betterttv.com/emotes/%1"; constexpr QStringView EMOTE_LINK_FORMAT = u"https://betterttv.com/emotes/%1";
const QSet<QStringView> ZERO_WIDTH_EMOTES{
u"SoSnowy", u"IceCold", u"SantaHat", u"TopHat",
u"ReinDeer", u"CandyCane", u"cvMask", u"cvHazmat",
};
/// The emote CDN link template. /// The emote CDN link template.
/// ///
/// %1 being the emote ID (e.g. 566ca04265dbbdab32ec054a) /// %1 being the emote ID (e.g. 566ca04265dbbdab32ec054a)
@@ -71,15 +76,19 @@ std::pair<Outcome, EmoteMap> parseGlobalEmotes(const QJsonArray &jsonEmotes,
auto name = EmoteName{jsonEmote.toObject().value("code").toString()}; auto name = EmoteName{jsonEmote.toObject().value("code").toString()};
auto emote = Emote({ auto emote = Emote({
name, .name = name,
ImageSet{ .images =
Image::fromUrl(getEmoteLinkV3(id, "1x"), 1, EMOTE_BASE_SIZE), ImageSet{
Image::fromUrl(getEmoteLinkV3(id, "2x"), 0.5, Image::fromUrl(getEmoteLinkV3(id, "1x"), 1,
EMOTE_BASE_SIZE * 2), EMOTE_BASE_SIZE),
Image::fromUrl(getEmoteLinkV3(id, "3x"), 0.25, Image::fromUrl(getEmoteLinkV3(id, "2x"), 0.5,
EMOTE_BASE_SIZE * 4)}, EMOTE_BASE_SIZE * 2),
Tooltip{name.string + "<br>Global BetterTTV Emote"}, Image::fromUrl(getEmoteLinkV3(id, "3x"), 0.25,
Url{EMOTE_LINK_FORMAT.arg(id.string)}, EMOTE_BASE_SIZE * 4),
},
.tooltip = Tooltip{name.string + "<br>Global BetterTTV Emote"},
.homePage = Url{EMOTE_LINK_FORMAT.arg(id.string)},
.zeroWidth = ZERO_WIDTH_EMOTES.contains(name.string),
}); });
emotes[name] = cachedOrMakeEmotePtr(std::move(emote), currentEmotes); emotes[name] = cachedOrMakeEmotePtr(std::move(emote), currentEmotes);