mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
refactor: mini reorganization of FfzEmotes.cpp (#5117)
This commit is contained in:
parent
075a7c5af0
commit
65d3e73c5d
1 changed files with 125 additions and 123 deletions
|
@ -10,147 +10,151 @@
|
||||||
#include "providers/twitch/TwitchChannel.hpp"
|
#include "providers/twitch/TwitchChannel.hpp"
|
||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const QString CHANNEL_HAS_NO_EMOTES(
|
using namespace chatterino;
|
||||||
"This channel has no FrankerFaceZ channel emotes.");
|
|
||||||
|
|
||||||
Url getEmoteLink(const QJsonObject &urls, const QString &emoteScale)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
const auto &LOG = chatterinoFfzemotes;
|
||||||
|
|
||||||
|
const QString CHANNEL_HAS_NO_EMOTES(
|
||||||
|
"This channel has no FrankerFaceZ channel emotes.");
|
||||||
|
|
||||||
|
Url getEmoteLink(const QJsonObject &urls, const QString &emoteScale)
|
||||||
|
{
|
||||||
|
auto emote = urls[emoteScale];
|
||||||
|
if (emote.isUndefined() || emote.isNull())
|
||||||
{
|
{
|
||||||
auto emote = urls[emoteScale];
|
return {""};
|
||||||
if (emote.isUndefined() || emote.isNull())
|
}
|
||||||
|
|
||||||
|
assert(emote.isString());
|
||||||
|
|
||||||
|
return parseFfzUrl(emote.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillInEmoteData(const QJsonObject &urls, const EmoteName &name,
|
||||||
|
const QString &tooltip, Emote &emoteData)
|
||||||
|
{
|
||||||
|
auto url1x = getEmoteLink(urls, "1");
|
||||||
|
auto url2x = getEmoteLink(urls, "2");
|
||||||
|
auto url3x = getEmoteLink(urls, "4");
|
||||||
|
|
||||||
|
//, code, tooltip
|
||||||
|
emoteData.name = name;
|
||||||
|
emoteData.images = ImageSet{
|
||||||
|
Image::fromUrl(url1x, 1),
|
||||||
|
url2x.string.isEmpty() ? Image::getEmpty() : Image::fromUrl(url2x, 0.5),
|
||||||
|
url3x.string.isEmpty() ? Image::getEmpty()
|
||||||
|
: Image::fromUrl(url3x, 0.25)};
|
||||||
|
emoteData.tooltip = {tooltip};
|
||||||
|
}
|
||||||
|
|
||||||
|
EmotePtr cachedOrMake(Emote &&emote, const EmoteId &id)
|
||||||
|
{
|
||||||
|
static std::unordered_map<EmoteId, std::weak_ptr<const Emote>> cache;
|
||||||
|
static std::mutex mutex;
|
||||||
|
|
||||||
|
return cachedOrMakeEmotePtr(std::move(emote), cache, mutex, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseEmoteSetInto(const QJsonObject &emoteSet, const QString &kind,
|
||||||
|
EmoteMap &map)
|
||||||
|
{
|
||||||
|
for (const auto emoteRef : emoteSet["emoticons"].toArray())
|
||||||
|
{
|
||||||
|
const auto emoteJson = emoteRef.toObject();
|
||||||
|
|
||||||
|
// margins
|
||||||
|
auto id = EmoteId{QString::number(emoteJson["id"].toInt())};
|
||||||
|
auto name = EmoteName{emoteJson["name"].toString()};
|
||||||
|
auto author =
|
||||||
|
EmoteAuthor{emoteJson["owner"]["display_name"].toString()};
|
||||||
|
auto urls = emoteJson["urls"].toObject();
|
||||||
|
if (emoteJson["animated"].isObject())
|
||||||
{
|
{
|
||||||
return {""};
|
// prefer animated images if available
|
||||||
|
urls = emoteJson["animated"].toObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(emote.isString());
|
Emote emote;
|
||||||
|
fillInEmoteData(urls, name,
|
||||||
|
QString("%1<br>%2 FFZ Emote<br>By: %3")
|
||||||
|
.arg(name.string, kind, author.string),
|
||||||
|
emote);
|
||||||
|
emote.homePage =
|
||||||
|
Url{QString("https://www.frankerfacez.com/emoticon/%1-%2")
|
||||||
|
.arg(id.string)
|
||||||
|
.arg(name.string)};
|
||||||
|
|
||||||
return parseFfzUrl(emote.toString());
|
map[name] = cachedOrMake(std::move(emote), id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmoteMap parseGlobalEmotes(const QJsonObject &jsonRoot)
|
||||||
|
{
|
||||||
|
// Load default sets from the `default_sets` object
|
||||||
|
std::unordered_set<int> defaultSets{};
|
||||||
|
auto jsonDefaultSets = jsonRoot["default_sets"].toArray();
|
||||||
|
for (auto jsonDefaultSet : jsonDefaultSets)
|
||||||
|
{
|
||||||
|
defaultSets.insert(jsonDefaultSet.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
void fillInEmoteData(const QJsonObject &urls, const EmoteName &name,
|
auto emotes = EmoteMap();
|
||||||
const QString &tooltip, Emote &emoteData)
|
|
||||||
|
for (const auto emoteSetRef : jsonRoot["sets"].toObject())
|
||||||
{
|
{
|
||||||
auto url1x = getEmoteLink(urls, "1");
|
const auto emoteSet = emoteSetRef.toObject();
|
||||||
auto url2x = getEmoteLink(urls, "2");
|
auto emoteSetID = emoteSet["id"].toInt();
|
||||||
auto url3x = getEmoteLink(urls, "4");
|
if (!defaultSets.contains(emoteSetID))
|
||||||
|
|
||||||
//, code, tooltip
|
|
||||||
emoteData.name = name;
|
|
||||||
emoteData.images =
|
|
||||||
ImageSet{Image::fromUrl(url1x, 1),
|
|
||||||
url2x.string.isEmpty() ? Image::getEmpty()
|
|
||||||
: Image::fromUrl(url2x, 0.5),
|
|
||||||
url3x.string.isEmpty() ? Image::getEmpty()
|
|
||||||
: Image::fromUrl(url3x, 0.25)};
|
|
||||||
emoteData.tooltip = {tooltip};
|
|
||||||
}
|
|
||||||
|
|
||||||
EmotePtr cachedOrMake(Emote &&emote, const EmoteId &id)
|
|
||||||
{
|
|
||||||
static std::unordered_map<EmoteId, std::weak_ptr<const Emote>> cache;
|
|
||||||
static std::mutex mutex;
|
|
||||||
|
|
||||||
return cachedOrMakeEmotePtr(std::move(emote), cache, mutex, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void parseEmoteSetInto(const QJsonObject &emoteSet, const QString &kind,
|
|
||||||
EmoteMap &map)
|
|
||||||
{
|
|
||||||
for (const auto emoteRef : emoteSet["emoticons"].toArray())
|
|
||||||
{
|
{
|
||||||
const auto emoteJson = emoteRef.toObject();
|
qCDebug(LOG) << "Skipping global emote set" << emoteSetID
|
||||||
|
<< "as it's not part of the default sets";
|
||||||
// margins
|
continue;
|
||||||
auto id = EmoteId{QString::number(emoteJson["id"].toInt())};
|
|
||||||
auto name = EmoteName{emoteJson["name"].toString()};
|
|
||||||
auto author =
|
|
||||||
EmoteAuthor{emoteJson["owner"]["display_name"].toString()};
|
|
||||||
auto urls = emoteJson["urls"].toObject();
|
|
||||||
if (emoteJson["animated"].isObject())
|
|
||||||
{
|
|
||||||
// prefer animated images if available
|
|
||||||
urls = emoteJson["animated"].toObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
Emote emote;
|
|
||||||
fillInEmoteData(urls, name,
|
|
||||||
QString("%1<br>%2 FFZ Emote<br>By: %3")
|
|
||||||
.arg(name.string, kind, author.string),
|
|
||||||
emote);
|
|
||||||
emote.homePage =
|
|
||||||
Url{QString("https://www.frankerfacez.com/emoticon/%1-%2")
|
|
||||||
.arg(id.string)
|
|
||||||
.arg(name.string)};
|
|
||||||
|
|
||||||
map[name] = cachedOrMake(std::move(emote), id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EmoteMap parseGlobalEmotes(const QJsonObject &jsonRoot)
|
|
||||||
{
|
|
||||||
// Load default sets from the `default_sets` object
|
|
||||||
std::unordered_set<int> defaultSets{};
|
|
||||||
auto jsonDefaultSets = jsonRoot["default_sets"].toArray();
|
|
||||||
for (auto jsonDefaultSet : jsonDefaultSets)
|
|
||||||
{
|
|
||||||
defaultSets.insert(jsonDefaultSet.toInt());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto emotes = EmoteMap();
|
parseEmoteSetInto(emoteSet, "Global", emotes);
|
||||||
|
|
||||||
for (const auto emoteSetRef : jsonRoot["sets"].toObject())
|
|
||||||
{
|
|
||||||
const auto emoteSet = emoteSetRef.toObject();
|
|
||||||
auto emoteSetID = emoteSet["id"].toInt();
|
|
||||||
if (!defaultSets.contains(emoteSetID))
|
|
||||||
{
|
|
||||||
qCDebug(chatterinoFfzemotes)
|
|
||||||
<< "Skipping global emote set" << emoteSetID
|
|
||||||
<< "as it's not part of the default sets";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
parseEmoteSetInto(emoteSet, "Global", emotes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return emotes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<EmotePtr> parseAuthorityBadge(const QJsonObject &badgeUrls,
|
return emotes;
|
||||||
const QString &tooltip)
|
}
|
||||||
|
|
||||||
|
std::optional<EmotePtr> parseAuthorityBadge(const QJsonObject &badgeUrls,
|
||||||
|
const QString &tooltip)
|
||||||
|
{
|
||||||
|
std::optional<EmotePtr> authorityBadge;
|
||||||
|
|
||||||
|
if (!badgeUrls.isEmpty())
|
||||||
{
|
{
|
||||||
std::optional<EmotePtr> authorityBadge;
|
auto authorityBadge1x = getEmoteLink(badgeUrls, "1");
|
||||||
|
auto authorityBadge2x = getEmoteLink(badgeUrls, "2");
|
||||||
|
auto authorityBadge3x = getEmoteLink(badgeUrls, "4");
|
||||||
|
|
||||||
if (!badgeUrls.isEmpty())
|
auto authorityBadgeImageSet = ImageSet{
|
||||||
{
|
Image::fromUrl(authorityBadge1x, 1),
|
||||||
auto authorityBadge1x = getEmoteLink(badgeUrls, "1");
|
authorityBadge2x.string.isEmpty()
|
||||||
auto authorityBadge2x = getEmoteLink(badgeUrls, "2");
|
? Image::getEmpty()
|
||||||
auto authorityBadge3x = getEmoteLink(badgeUrls, "4");
|
: Image::fromUrl(authorityBadge2x, 0.5),
|
||||||
|
authorityBadge3x.string.isEmpty()
|
||||||
|
? Image::getEmpty()
|
||||||
|
: Image::fromUrl(authorityBadge3x, 0.25),
|
||||||
|
};
|
||||||
|
|
||||||
auto authorityBadgeImageSet = ImageSet{
|
authorityBadge = std::make_shared<Emote>(Emote{
|
||||||
Image::fromUrl(authorityBadge1x, 1),
|
.name = {""},
|
||||||
authorityBadge2x.string.isEmpty()
|
.images = authorityBadgeImageSet,
|
||||||
? Image::getEmpty()
|
.tooltip = Tooltip{tooltip},
|
||||||
: Image::fromUrl(authorityBadge2x, 0.5),
|
.homePage = authorityBadge1x,
|
||||||
authorityBadge3x.string.isEmpty()
|
});
|
||||||
? Image::getEmpty()
|
|
||||||
: Image::fromUrl(authorityBadge3x, 0.25),
|
|
||||||
};
|
|
||||||
|
|
||||||
authorityBadge = std::make_shared<Emote>(Emote{
|
|
||||||
{""},
|
|
||||||
authorityBadgeImageSet,
|
|
||||||
Tooltip{tooltip},
|
|
||||||
authorityBadge1x,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return authorityBadge;
|
|
||||||
}
|
}
|
||||||
|
return authorityBadge;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
using namespace ffz::detail;
|
using namespace ffz::detail;
|
||||||
|
|
||||||
EmoteMap ffz::detail::parseChannelEmotes(const QJsonObject &jsonRoot)
|
EmoteMap ffz::detail::parseChannelEmotes(const QJsonObject &jsonRoot)
|
||||||
|
@ -218,8 +222,7 @@ void FfzEmotes::loadChannel(
|
||||||
std::function<void(std::optional<EmotePtr>)> vipBadgeCallback,
|
std::function<void(std::optional<EmotePtr>)> vipBadgeCallback,
|
||||||
bool manualRefresh)
|
bool manualRefresh)
|
||||||
{
|
{
|
||||||
qCDebug(chatterinoFfzemotes)
|
qCDebug(LOG) << "Reload FFZ Channel Emotes for channel" << channelID;
|
||||||
<< "[FFZEmotes] Reload FFZ Channel Emotes for channel" << channelID;
|
|
||||||
|
|
||||||
NetworkRequest("https://api.frankerfacez.com/v1/room/id/" + channelID)
|
NetworkRequest("https://api.frankerfacez.com/v1/room/id/" + channelID)
|
||||||
|
|
||||||
|
@ -275,9 +278,8 @@ void FfzEmotes::loadChannel(
|
||||||
{
|
{
|
||||||
// TODO: Auto retry in case of a timeout, with a delay
|
// TODO: Auto retry in case of a timeout, with a delay
|
||||||
auto errorString = result.formatError();
|
auto errorString = result.formatError();
|
||||||
qCWarning(chatterinoFfzemotes)
|
qCWarning(LOG) << "Error fetching FFZ emotes for channel"
|
||||||
<< "Error fetching FFZ emotes for channel" << channelID
|
<< channelID << ", error" << errorString;
|
||||||
<< ", error" << errorString;
|
|
||||||
shared->addMessage(makeSystemMessage(
|
shared->addMessage(makeSystemMessage(
|
||||||
QStringLiteral("Failed to fetch FrankerFaceZ channel "
|
QStringLiteral("Failed to fetch FrankerFaceZ channel "
|
||||||
"emotes. (Error: %1)")
|
"emotes. (Error: %1)")
|
||||||
|
|
Loading…
Reference in a new issue