refactor: load Twitch emotes from Helix (#5239)

This commit is contained in:
nerix
2024-09-01 11:22:54 +02:00
committed by GitHub
parent 03b0e4881f
commit 820aa12af6
40 changed files with 1251 additions and 528 deletions
+96 -96
View File
@@ -26,6 +26,7 @@
#include <QAbstractButton>
#include <QHBoxLayout>
#include <QRegularExpression>
#include <QStringBuilder>
#include <QTabWidget>
#include <utility>
@@ -42,13 +43,14 @@ auto makeTitleMessage(const QString &title)
return builder.release();
}
auto makeEmoteMessage(const EmoteMap &map, const MessageElementFlag &emoteFlag)
auto makeEmoteMessage(std::vector<EmotePtr> emotes,
const MessageElementFlag &emoteFlag)
{
MessageBuilder builder;
builder->flags.set(MessageFlag::Centered);
builder->flags.set(MessageFlag::DisableCompactEmotes);
if (map.empty())
if (emotes.empty())
{
builder.emplace<TextElement>("no emotes available",
MessageElementFlag::Text,
@@ -56,24 +58,41 @@ auto makeEmoteMessage(const EmoteMap &map, const MessageElementFlag &emoteFlag)
return builder.release();
}
std::vector<std::pair<EmoteName, EmotePtr>> vec(map.begin(), map.end());
std::sort(vec.begin(), vec.end(),
[](const std::pair<EmoteName, EmotePtr> &l,
const std::pair<EmoteName, EmotePtr> &r) {
return compareEmoteStrings(l.first.string, r.first.string);
});
for (const auto &emote : vec)
std::sort(emotes.begin(), emotes.end(), [](const auto &l, const auto &r) {
return compareEmoteStrings(l->name.string, r->name.string);
});
for (const auto &emote : emotes)
{
builder
.emplace<EmoteElement>(
emote.second,
emote,
MessageElementFlags{MessageElementFlag::AlwaysShow, emoteFlag})
->setLink(Link(Link::InsertText, emote.first.string));
->setLink(Link(Link::InsertText, emote->name.string));
}
return builder.release();
}
auto makeEmoteMessage(const EmoteMap &map, const MessageElementFlag &emoteFlag)
{
if (map.empty())
{
MessageBuilder builder;
builder.emplace<TextElement>("no emotes available",
MessageElementFlag::Text,
MessageColor::System);
return builder.release();
}
std::vector<EmotePtr> vec;
vec.reserve(map.size());
for (const auto &[_name, ptr] : map)
{
vec.emplace_back(ptr);
}
return makeEmoteMessage(std::move(vec), emoteFlag);
}
auto makeEmojiMessage(const std::vector<EmojiPtr> &emojiMap)
{
MessageBuilder builder;
@@ -94,77 +113,46 @@ auto makeEmojiMessage(const std::vector<EmojiPtr> &emojiMap)
return builder.release();
}
void addTwitchEmoteSets(
std::vector<std::shared_ptr<TwitchAccount::EmoteSet>> sets,
Channel &globalChannel, Channel &subChannel, QString currentChannelName)
void addEmotes(Channel &channel, auto emotes, const QString &title,
const MessageElementFlag &emoteFlag)
{
QMap<QString, QPair<bool, std::vector<MessagePtr>>> mapOfSets;
channel.addMessage(makeTitleMessage(title), MessageContext::Original);
channel.addMessage(makeEmoteMessage(emotes, emoteFlag),
MessageContext::Original);
}
for (const auto &set : sets)
void addTwitchEmoteSets(const std::shared_ptr<const EmoteMap> &local,
const std::shared_ptr<const TwitchEmoteSetMap> &sets,
Channel &globalChannel, Channel &subChannel,
const QString &currentChannelID,
const QString &channelName)
{
if (!local->empty())
{
// Some emotes (e.g. follower ones) are only available in their origin channel
if (set->local && currentChannelName != set->channelName)
addEmotes(subChannel, *local, channelName % u" (follower)",
MessageElementFlag::TwitchEmote);
}
// Put current channel emotes at the top
for (const auto &[_id, set] : *sets)
{
if (set.owner->id == currentChannelID)
{
addEmotes(subChannel, set.emotes, set.title(),
MessageElementFlag::TwitchEmote);
}
}
for (const auto &[id, set] : *sets)
{
if (set.owner->id == currentChannelID)
{
continue;
}
// TITLE
auto channelName = set->channelName;
auto text = set->text.isEmpty() ? "Twitch" : set->text;
// EMOTES
MessageBuilder builder;
builder->flags.set(MessageFlag::Centered);
builder->flags.set(MessageFlag::DisableCompactEmotes);
// If value of map is empty, create init pair and add title.
if (mapOfSets.find(channelName) == mapOfSets.end())
{
std::vector<MessagePtr> b;
b.push_back(makeTitleMessage(text));
mapOfSets[channelName] = qMakePair(set->key == "0", b);
}
for (const auto &emote : set->emotes)
{
builder
.emplace<EmoteElement>(
getApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote(
emote.id, emote.name),
MessageElementFlags{MessageElementFlag::AlwaysShow,
MessageElementFlag::TwitchEmote})
->setLink(Link(Link::InsertText, emote.name.string));
}
mapOfSets[channelName].second.push_back(builder.release());
addEmotes(set.isSubLike ? subChannel : globalChannel, set.emotes,
set.title(), MessageElementFlag::TwitchEmote);
}
// Output to channel all created messages,
// That contain title or emotes.
// Put current channel emotes at the top
auto currentChannelPair = mapOfSets[currentChannelName];
for (const auto &message : currentChannelPair.second)
{
subChannel.addMessage(message, MessageContext::Original);
}
mapOfSets.remove(currentChannelName);
for (const auto &pair : mapOfSets)
{
auto &channel = pair.first ? globalChannel : subChannel;
for (const auto &message : pair.second)
{
channel.addMessage(message, MessageContext::Original);
}
}
}
void addEmotes(Channel &channel, const EmoteMap &map, const QString &title,
const MessageElementFlag &emoteFlag)
{
channel.addMessage(makeTitleMessage(title), MessageContext::Original);
channel.addMessage(makeEmoteMessage(map, emoteFlag),
MessageContext::Original);
}
void loadEmojis(ChannelView &view, const std::vector<EmojiPtr> &emojiMap)
@@ -200,6 +188,22 @@ EmoteMap filterEmoteMap(const QString &text,
return filteredMap;
}
std::vector<EmotePtr> filterEmoteVec(const QString &text,
const std::vector<EmotePtr> &emotes)
{
std::vector<EmotePtr> filtered;
for (const auto &emote : emotes)
{
if (emote->name.string.contains(text, Qt::CaseInsensitive))
{
filtered.emplace_back(emote);
}
}
return filtered;
}
} // namespace
namespace chatterino {
@@ -404,8 +408,10 @@ void EmotePopup::loadChannel(ChannelPtr channel)
// twitch
addTwitchEmoteSets(
getApp()->getAccounts()->twitch.getCurrent()->accessEmotes()->emoteSets,
*globalChannel, *subChannel, this->channel_->getName());
twitchChannel_->localTwitchEmotes(),
*getApp()->getAccounts()->twitch.getCurrent()->accessEmoteSets(),
*globalChannel, *subChannel, twitchChannel_->roomId(),
twitchChannel_->getName());
// global
if (Settings::instance().enableBTTVGlobalEmotes)
@@ -475,24 +481,22 @@ bool EmotePopup::eventFilter(QObject *object, QEvent *event)
void EmotePopup::filterTwitchEmotes(std::shared_ptr<Channel> searchChannel,
const QString &searchText)
{
auto twitchEmoteSets =
getApp()->getAccounts()->twitch.getCurrent()->accessEmotes()->emoteSets;
std::vector<std::shared_ptr<TwitchAccount::EmoteSet>> twitchGlobalEmotes{};
for (const auto &set : twitchEmoteSets)
if (this->twitchChannel_)
{
auto setCopy = std::make_shared<TwitchAccount::EmoteSet>(*set);
auto setIt =
std::remove_if(setCopy->emotes.begin(), setCopy->emotes.end(),
[searchText](auto &emote) {
return !emote.name.string.contains(
searchText, Qt::CaseInsensitive);
});
setCopy->emotes.resize(std::distance(setCopy->emotes.begin(), setIt));
if (!setCopy->emotes.empty())
auto local = filterEmoteMap(searchText,
this->twitchChannel_->localTwitchEmotes());
if (!local.empty())
{
twitchGlobalEmotes.push_back(setCopy);
addEmotes(*searchChannel, local,
this->twitchChannel_->getName() % u" (local)",
MessageElementFlag::TwitchEmote);
}
for (const auto &[_id, set] :
**getApp()->getAccounts()->twitch.getCurrent()->accessEmoteSets())
{
addEmotes(*searchChannel, filterEmoteVec(searchText, set.emotes),
set.title(), MessageElementFlag::TwitchEmote);
}
}
@@ -503,10 +507,6 @@ void EmotePopup::filterTwitchEmotes(std::shared_ptr<Channel> searchChannel,
auto seventvGlobalEmotes = filterEmoteMap(
searchText, getApp()->getSeventvEmotes()->globalEmotes());
// twitch
addTwitchEmoteSets(twitchGlobalEmotes, *searchChannel, *searchChannel,
this->channel_->getName());
// global
if (!bttvGlobalEmotes.empty())
{