Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split list of emote sets into bunches when performing Ivr API reqeusts #2856

Merged
merged 14 commits into from Jun 6, 2021
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,7 @@
- Minor: Added `/popout` command. Usage: `/popout [channel]`. It opens browser chat for the provided channel. Can also be used without arguments to open current channels browser chat. (#2556, #2812)
- Minor: Improved matching of game names when using `/setgame` command (#2636)
- Bugfix: Fixed FFZ emote links for global emotes (#2807, #2808)
- Bugfix: Fixed bit emotes not loading in some rare cases. (#2856)

## 2.3.2

Expand Down
3 changes: 1 addition & 2 deletions src/providers/IvrApi.hpp
Expand Up @@ -74,8 +74,7 @@ class IvrApi final : boost::noncopyable
ResultCallback<IvrSubage> resultCallback,
IvrFailureCallback failureCallback);

// https://api.ivr.fi/docs#tag/Twitch/paths/~1twitch~1emoteset~1{setid}/get
// however, we use undocumented endpoint, which takes ?set_id=1,2,3,4,... as query parameter
// https://api.ivr.fi/docs#tag/Twitch/paths/~1twitch~1emoteset/get
void getBulkEmoteSets(QString emoteSetList,
ResultCallback<QJsonArray> successCallback,
IvrFailureCallback failureCallback);
Expand Down
102 changes: 64 additions & 38 deletions src/providers/twitch/TwitchAccount.cpp
Expand Up @@ -301,54 +301,80 @@ void TwitchAccount::loadUserstateEmotes(QStringList emoteSetKeys)
return;
}

getIvr()->getBulkEmoteSets(
newEmoteSetKeys.join(","),
[this](QJsonArray emoteSetArray) {
auto emoteData = this->emotes_.access();
for (auto emoteSet : emoteSetArray)
{
auto newUserEmoteSet = std::make_shared<EmoteSet>();
// splitting newEmoteSetKeys to batches of 100, because Ivr API endpoint accepts a maximum of 100 emotesets at once
constexpr int batchSize = 100;

IvrEmoteSet ivrEmoteSet(emoteSet.toObject());
std::vector<std::vector<QString>> batches;

newUserEmoteSet->key = ivrEmoteSet.setId;
auto newEmoteSetKeysVector = newEmoteSetKeys.toVector();
batches.reserve((newEmoteSetKeysVector.size() + 1) / batchSize);

auto name = ivrEmoteSet.login;
name.detach();
name[0] = name[0].toUpper();
for (int i = 0; i < newEmoteSetKeysVector.size(); i += batchSize)
{
auto last = std::min(newEmoteSetKeysVector.size(), i + batchSize);
batches.emplace_back(newEmoteSetKeysVector.begin() + i,
newEmoteSetKeysVector.begin() + last);
}

newUserEmoteSet->text = name;
newUserEmoteSet->type = QString();
newUserEmoteSet->channelName = ivrEmoteSet.login;
for (const auto &batch : batches)
{
QStringList emoteSetBatch;

for (const auto &el : batch)
{
emoteSetBatch.push_back(el);
}
zneix marked this conversation as resolved.
Show resolved Hide resolved

for (const auto &emote : ivrEmoteSet.emotes)
getIvr()->getBulkEmoteSets(
emoteSetBatch.join(","),
[this](QJsonArray emoteSetArray) {
auto emoteData = this->emotes_.access();
for (auto emoteSet : emoteSetArray)
{
IvrEmote ivrEmote(emote.toObject());
auto newUserEmoteSet = std::make_shared<EmoteSet>();

auto id = EmoteId{ivrEmote.id};
auto code = EmoteName{ivrEmote.code};
auto cleanCode =
EmoteName{TwitchEmotes::cleanUpEmoteCode(code)};
newUserEmoteSet->emotes.emplace_back(
TwitchEmote{id, cleanCode});
IvrEmoteSet ivrEmoteSet(emoteSet.toObject());

emoteData->allEmoteNames.push_back(cleanCode);
newUserEmoteSet->key = ivrEmoteSet.setId;

auto twitchEmote =
getApp()->emotes->twitch.getOrCreateEmote(id, code);
emoteData->emotes.emplace(code, twitchEmote);
auto name = ivrEmoteSet.login;
name.detach();
zneix marked this conversation as resolved.
Show resolved Hide resolved
name[0] = name[0].toUpper();

newUserEmoteSet->text = name;
newUserEmoteSet->type = QString();
newUserEmoteSet->channelName = ivrEmoteSet.login;

for (const auto &emote : ivrEmoteSet.emotes)
{
IvrEmote ivrEmote(emote.toObject());

auto id = EmoteId{ivrEmote.id};
auto code = EmoteName{ivrEmote.code};
auto cleanCode =
EmoteName{TwitchEmotes::cleanUpEmoteCode(code)};
newUserEmoteSet->emotes.emplace_back(
TwitchEmote{id, cleanCode});
zneix marked this conversation as resolved.
Show resolved Hide resolved

emoteData->allEmoteNames.push_back(cleanCode);

auto twitchEmote =
getApp()->emotes->twitch.getOrCreateEmote(id, code);
emoteData->emotes.emplace(code, twitchEmote);
}
std::sort(newUserEmoteSet->emotes.begin(),
newUserEmoteSet->emotes.end(),
[](const TwitchEmote &l, const TwitchEmote &r) {
return l.name.string < r.name.string;
});
emoteData->emoteSets.emplace_back(newUserEmoteSet);
}
std::sort(newUserEmoteSet->emotes.begin(),
newUserEmoteSet->emotes.end(),
[](const TwitchEmote &l, const TwitchEmote &r) {
return l.name.string < r.name.string;
});
emoteData->emoteSets.emplace_back(newUserEmoteSet);
}
},
[] {
// fetching emotes failed, ivr API might be down
});
},
[] {
// fetching emotes failed, ivr API might be down
});
};
return;
}

SharedAccessGuard<const TwitchAccount::TwitchAccountEmoteData>
Expand Down