Load mod badge information from the FFZ API instead of assuming the URL.
This lets us load all sizes of the emote if they are available. Channel with all versions of the mod badge: https://api.frankerfacez.com/v1/room/pajlada Channel with only one version of the mod badge: https://api.frankerfacez.com/v1/room/apa420 Channel with no mod badge: https://api.frankerfacez.com/v1/room/forsen
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
#include "providers/ffz/FfzEmotes.hpp"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QImageReader>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QPainter>
|
||||
#include <QString>
|
||||
|
||||
#include "common/NetworkRequest.hpp"
|
||||
#include "common/Outcome.hpp"
|
||||
@@ -10,6 +15,30 @@
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
Outcome addModBadgeBackground(ImagePtr image, NetworkResult result)
|
||||
{
|
||||
auto data = result.getData();
|
||||
|
||||
QBuffer buffer(const_cast<QByteArray *>(&data));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
QImageReader reader(&buffer);
|
||||
if (reader.imageCount() == 0)
|
||||
return Failure;
|
||||
|
||||
QPixmap badgeOverlay = QPixmap::fromImageReader(&reader);
|
||||
QPixmap badgePixmap(badgeOverlay.width(), badgeOverlay.height());
|
||||
|
||||
// the default mod badge green color
|
||||
badgePixmap.fill(QColor("#34AE0A"));
|
||||
QPainter painter(&badgePixmap);
|
||||
QRectF rect(0, 0, badgeOverlay.width(), badgeOverlay.height());
|
||||
painter.drawPixmap(rect, badgeOverlay, rect);
|
||||
|
||||
image->setPixmap(badgePixmap);
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Url getEmoteLink(const QJsonObject &urls, const QString &emoteScale)
|
||||
{
|
||||
auto emote = urls.value(emoteScale);
|
||||
@@ -79,8 +108,42 @@ namespace {
|
||||
|
||||
return {Success, std::move(emotes)};
|
||||
}
|
||||
std::pair<Outcome, EmoteMap> parseChannelEmotes(const QJsonObject &jsonRoot)
|
||||
std::tuple<Outcome, EmoteMap, boost::optional<EmotePtr>>
|
||||
parseChannelResponse(const QJsonObject &jsonRoot)
|
||||
{
|
||||
boost::optional<EmotePtr> modBadge;
|
||||
|
||||
// Parse mod badge
|
||||
auto room = jsonRoot.value("room").toObject();
|
||||
auto modUrls = room.value("mod_urls").toObject();
|
||||
if (!modUrls.isEmpty())
|
||||
{
|
||||
auto modBadge1x = getEmoteLink(modUrls, "1");
|
||||
auto modBadge2x = getEmoteLink(modUrls, "2");
|
||||
auto modBadge3x = getEmoteLink(modUrls, "4");
|
||||
|
||||
auto modBadgeImageSet = ImageSet{
|
||||
Image::fromUrl(modBadge1x, 1)
|
||||
->setCustomOnSuccess(addModBadgeBackground),
|
||||
modBadge2x.string.isEmpty()
|
||||
? Image::getEmpty()
|
||||
: Image::fromUrl(modBadge2x, 0.5)
|
||||
->setCustomOnSuccess(addModBadgeBackground),
|
||||
modBadge3x.string.isEmpty()
|
||||
? Image::getEmpty()
|
||||
: Image::fromUrl(modBadge3x, 0.25)
|
||||
->setCustomOnSuccess(addModBadgeBackground),
|
||||
};
|
||||
|
||||
modBadge = std::make_shared<Emote>(Emote{
|
||||
{""},
|
||||
modBadgeImageSet,
|
||||
Tooltip{"Twitch Channel Moderator"},
|
||||
modBadge1x,
|
||||
});
|
||||
}
|
||||
|
||||
// Parse emotes
|
||||
auto jsonSets = jsonRoot.value("sets").toObject();
|
||||
auto emotes = EmoteMap();
|
||||
|
||||
@@ -110,7 +173,7 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
return {Success, std::move(emotes)};
|
||||
return {Success, std::move(emotes), modBadge};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -151,19 +214,29 @@ void FfzEmotes::loadEmotes()
|
||||
.execute();
|
||||
}
|
||||
|
||||
void FfzEmotes::loadChannel(const QString &channelId,
|
||||
std::function<void(EmoteMap &&)> callback)
|
||||
void FfzEmotes::loadChannel(
|
||||
const QString &channelId, std::function<void(EmoteMap &&)> emoteCallback,
|
||||
std::function<void(boost::optional<EmotePtr>)> modBadgeCallback)
|
||||
{
|
||||
log("[FFZEmotes] Reload FFZ Channel Emotes for channel {}\n", channelId);
|
||||
|
||||
NetworkRequest("https://api.frankerfacez.com/v1/room/id/" + channelId)
|
||||
|
||||
.timeout(20000)
|
||||
.onSuccess([callback = std::move(callback)](auto result) -> Outcome {
|
||||
auto pair = parseChannelEmotes(result.parseJson());
|
||||
if (pair.first)
|
||||
callback(std::move(pair.second));
|
||||
return pair.first;
|
||||
.onSuccess([emoteCallback = std::move(emoteCallback),
|
||||
modBadgeCallback =
|
||||
std::move(modBadgeCallback)](auto result) -> Outcome {
|
||||
auto [success, emoteMap, modBadge] =
|
||||
parseChannelResponse(result.parseJson());
|
||||
if (!success)
|
||||
{
|
||||
return success;
|
||||
}
|
||||
|
||||
emoteCallback(std::move(emoteMap));
|
||||
modBadgeCallback(std::move(modBadge));
|
||||
|
||||
return success;
|
||||
})
|
||||
.onError([channelId](int result) {
|
||||
if (result == 203)
|
||||
|
||||
Reference in New Issue
Block a user