Add a local backup of the Twitch Badges API (#4463)

This commit is contained in:
pajlada 2023-03-19 12:28:28 +01:00 committed by GitHub
parent 1ad93b7acc
commit 130b23edaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 44 deletions

View file

@ -1,5 +1,5 @@
# emoji.json should remain minified # JSON resources should not be prettified
resources/emoji.json resources/*.json
# Ignore submodule files # Ignore submodule files
lib/*/ lib/*/

View file

@ -3,6 +3,7 @@
## Unversioned ## Unversioned
- Minor: Added support for FrankerFaceZ animated emotes. (#4434) - Minor: Added support for FrankerFaceZ animated emotes. (#4434)
- Minor: Added a local backup of the Twitch Badges API in case the request fails. (#4463)
- Bugfix: Fixed an issue where animated emotes would render on top of zero-width emotes. (#4314) - Bugfix: Fixed an issue where animated emotes would render on top of zero-width emotes. (#4314)
- Bugfix: Fixed an issue where it was difficult to hover a zero-width emote. (#4314) - Bugfix: Fixed an issue where it was difficult to hover a zero-width emote. (#4314)
- Bugfix: Fixed an issue where context-menu items for zero-width emotes displayed the wrong provider. (#4460) - Bugfix: Fixed an issue where context-menu items for zero-width emotes displayed the wrong provider. (#4460)

File diff suppressed because one or more lines are too long

View file

@ -9,10 +9,11 @@
#include "util/DisplayBadge.hpp" #include "util/DisplayBadge.hpp"
#include <QBuffer> #include <QBuffer>
#include <QFile>
#include <QIcon> #include <QIcon>
#include <QImageReader> #include <QImageReader>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonDocument>
#include <QJsonValue> #include <QJsonValue>
#include <QThread> #include <QThread>
#include <QUrlQuery> #include <QUrlQuery>
@ -36,58 +37,71 @@ void TwitchBadges::loadTwitchBadges()
NetworkRequest(url) NetworkRequest(url)
.onSuccess([this](auto result) -> Outcome { .onSuccess([this](auto result) -> Outcome {
{ auto root = result.parseJson();
auto root = result.parseJson();
auto badgeSets = this->badgeSets_.access();
auto jsonSets = root.value("badge_sets").toObject(); this->parseTwitchBadges(root);
for (auto sIt = jsonSets.begin(); sIt != jsonSets.end(); ++sIt)
{
auto key = sIt.key();
auto versions =
sIt.value().toObject().value("versions").toObject();
for (auto vIt = versions.begin(); vIt != versions.end();
++vIt)
{
auto versionObj = vIt.value().toObject();
auto emote = Emote{
{""},
ImageSet{
Image::fromUrl({versionObj.value("image_url_1x")
.toString()},
1),
Image::fromUrl({versionObj.value("image_url_2x")
.toString()},
.5),
Image::fromUrl({versionObj.value("image_url_4x")
.toString()},
.25),
},
Tooltip{versionObj.value("title").toString()},
Url{versionObj.value("click_url").toString()}};
// "title"
// "clickAction"
(*badgeSets)[key][vIt.key()] =
std::make_shared<Emote>(emote);
}
}
}
this->loaded(); this->loaded();
return Success; return Success;
}) })
.onError([this](auto res) { .onError([this](auto res) {
qCDebug(chatterinoTwitch) qCWarning(chatterinoTwitch)
<< "Error loading Twitch Badges:" << res.status(); << "Error loading Twitch Badges from the badges API:"
// Despite erroring out, we still want to reach the same point << res.status() << " - falling back to backup";
// Loaded should still be set to true to not build up an endless queue, and the quuee should still be flushed. QFile file(":/twitch-badges.json");
if (!file.open(QFile::ReadOnly))
{
// Despite erroring out, we still want to reach the same point
// Loaded should still be set to true to not build up an endless queue, and the quuee should still be flushed.
qCWarning(chatterinoTwitch)
<< "Error loading Twitch Badges from the local backup file";
this->loaded();
return;
}
auto bytes = file.readAll();
auto doc = QJsonDocument::fromJson(bytes);
this->parseTwitchBadges(doc.object());
this->loaded(); this->loaded();
}) })
.execute(); .execute();
} }
void TwitchBadges::parseTwitchBadges(QJsonObject root)
{
auto badgeSets = this->badgeSets_.access();
auto jsonSets = root.value("badge_sets").toObject();
for (auto sIt = jsonSets.begin(); sIt != jsonSets.end(); ++sIt)
{
auto key = sIt.key();
auto versions = sIt.value().toObject().value("versions").toObject();
for (auto vIt = versions.begin(); vIt != versions.end(); ++vIt)
{
auto versionObj = vIt.value().toObject();
auto emote = Emote{
{""},
ImageSet{
Image::fromUrl(
{versionObj.value("image_url_1x").toString()}, 1),
Image::fromUrl(
{versionObj.value("image_url_2x").toString()}, .5),
Image::fromUrl(
{versionObj.value("image_url_4x").toString()}, .25),
},
Tooltip{versionObj.value("title").toString()},
Url{versionObj.value("click_url").toString()}};
// "title"
// "clickAction"
(*badgeSets)[key][vIt.key()] = std::make_shared<Emote>(emote);
}
}
}
void TwitchBadges::loaded() void TwitchBadges::loaded()
{ {
std::unique_lock loadedLock(this->loadedMutex_); std::unique_lock loadedLock(this->loadedMutex_);

View file

@ -6,6 +6,7 @@
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <pajlada/signals/signal.hpp> #include <pajlada/signals/signal.hpp>
#include <QIcon> #include <QIcon>
#include <QJsonObject>
#include <QMap> #include <QMap>
#include <QString> #include <QString>
@ -49,6 +50,10 @@ private:
TwitchBadges(); TwitchBadges();
void loadTwitchBadges(); void loadTwitchBadges();
/**
* @brief Accepts a JSON blob from https://badges.twitch.tv/v1/badges/global/display and updates our badges with it
**/
void parseTwitchBadges(QJsonObject root);
void loaded(); void loaded();
void loadEmoteImage(const QString &name, ImagePtr image, void loadEmoteImage(const QString &name, ImagePtr image,
BadgeIconCallback &&callback); BadgeIconCallback &&callback);