mirror-chatterino2/src/providers/twitch/TwitchParseCheerEmotes.cpp

322 lines
8 KiB
C++
Raw Normal View History

2018-08-02 14:23:27 +02:00
#include "TwitchParseCheerEmotes.hpp"
#include <rapidjson/document.h>
#include <QString>
#include <vector>
namespace chatterino {
namespace {
2018-08-15 22:46:20 +02:00
template <typename Type>
inline bool ReadValue(const rapidjson::Value &object, const char *key,
Type &out)
{
2018-10-21 13:43:02 +02:00
if (!object.HasMember(key))
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
const auto &value = object[key];
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!value.Is<Type>())
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
out = value.Get<Type>();
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
return true;
2018-08-02 14:23:27 +02:00
}
2018-08-15 22:46:20 +02:00
template <>
inline bool ReadValue<QString>(const rapidjson::Value &object,
const char *key, QString &out)
{
2018-10-21 13:43:02 +02:00
if (!object.HasMember(key))
{
2018-08-02 14:23:27 +02:00
return false;
}
2018-08-15 22:46:20 +02:00
const auto &value = object[key];
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!value.IsString())
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
out = value.GetString();
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
return true;
2018-08-02 14:23:27 +02:00
}
2018-08-15 22:46:20 +02:00
template <>
inline bool ReadValue<std::vector<QString>>(const rapidjson::Value &object,
const char *key,
std::vector<QString> &out)
{
2018-10-21 13:43:02 +02:00
if (!object.HasMember(key))
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
const auto &value = object[key];
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!value.IsArray())
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
for (const rapidjson::Value &innerValue : value.GetArray())
{
if (!innerValue.IsString())
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
out.emplace_back(innerValue.GetString());
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
return true;
2018-08-02 14:23:27 +02:00
}
2018-08-15 22:46:20 +02:00
// Parse a single cheermote set (or "action") from the twitch api
inline bool ParseSingleCheermoteSet(JSONCheermoteSet &set,
const rapidjson::Value &action)
{
2018-10-21 13:43:02 +02:00
if (!action.IsObject())
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!ReadValue(action, "prefix", set.prefix))
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!ReadValue(action, "scales", set.scales))
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!ReadValue(action, "backgrounds", set.backgrounds))
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!ReadValue(action, "states", set.states))
{
2018-08-02 14:23:27 +02:00
return false;
}
2018-10-21 13:43:02 +02:00
if (!ReadValue(action, "type", set.type))
{
2018-08-02 14:23:27 +02:00
return false;
}
2018-10-21 13:43:02 +02:00
if (!ReadValue(action, "updated_at", set.updatedAt))
{
2018-08-02 14:23:27 +02:00
return false;
}
2018-10-21 13:43:02 +02:00
if (!ReadValue(action, "priority", set.priority))
{
2018-08-02 14:23:27 +02:00
return false;
}
2018-08-15 22:46:20 +02:00
// Tiers
2018-10-21 13:43:02 +02:00
if (!action.HasMember("tiers"))
{
2018-08-02 14:23:27 +02:00
return false;
}
2018-08-15 22:46:20 +02:00
const auto &tiersValue = action["tiers"];
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!tiersValue.IsArray())
{
2018-08-02 14:23:27 +02:00
return false;
}
2018-10-21 13:43:02 +02:00
for (const rapidjson::Value &tierValue : tiersValue.GetArray())
{
2018-08-15 22:46:20 +02:00
JSONCheermoteSet::CheermoteTier tier;
2018-10-21 13:43:02 +02:00
if (!tierValue.IsObject())
{
2018-08-15 22:46:20 +02:00
return false;
}
2018-10-21 13:43:02 +02:00
if (!ReadValue(tierValue, "min_bits", tier.minBits))
{
2018-08-15 22:46:20 +02:00
return false;
2018-08-02 14:23:27 +02:00
}
2018-10-21 13:43:02 +02:00
if (!ReadValue(tierValue, "id", tier.id))
{
2018-08-15 22:46:20 +02:00
return false;
2018-08-02 14:23:27 +02:00
}
2018-10-21 13:43:02 +02:00
if (!ReadValue(tierValue, "color", tier.color))
{
2018-08-15 22:46:20 +02:00
return false;
2018-08-02 14:23:27 +02:00
}
2018-08-15 22:46:20 +02:00
// Images
2018-10-21 13:43:02 +02:00
if (!tierValue.HasMember("images"))
{
2018-08-15 22:46:20 +02:00
return false;
}
const auto &imagesValue = tierValue["images"];
2018-10-21 13:43:02 +02:00
if (!imagesValue.IsObject())
{
2018-08-15 22:46:20 +02:00
return false;
}
// Read images object
2018-10-21 13:43:02 +02:00
for (const auto &imageBackgroundValue : imagesValue.GetObject())
{
2018-08-15 22:46:20 +02:00
QString background = imageBackgroundValue.name.GetString();
bool backgroundExists = false;
2018-10-21 13:43:02 +02:00
for (const auto &bg : set.backgrounds)
{
if (background == bg)
{
2018-08-15 22:46:20 +02:00
backgroundExists = true;
2018-08-02 14:23:27 +02:00
break;
}
}
2018-10-21 13:43:02 +02:00
if (!backgroundExists)
{
2018-08-02 14:23:27 +02:00
continue;
}
2018-08-15 22:46:20 +02:00
const rapidjson::Value &imageBackgroundStates =
imageBackgroundValue.value;
2018-10-21 13:43:02 +02:00
if (!imageBackgroundStates.IsObject())
{
2018-08-02 14:23:27 +02:00
continue;
}
2018-08-15 22:46:20 +02:00
// Read each key which represents a background
for (const auto &imageBackgroundState :
2018-10-21 13:43:02 +02:00
imageBackgroundStates.GetObject())
{
2018-08-15 22:46:20 +02:00
QString state = imageBackgroundState.name.GetString();
bool stateExists = false;
2018-10-21 13:43:02 +02:00
for (const auto &_state : set.states)
{
if (state == _state)
{
2018-08-15 22:46:20 +02:00
stateExists = true;
2018-08-02 14:23:27 +02:00
break;
}
}
2018-10-21 13:43:02 +02:00
if (!stateExists)
{
2018-08-02 14:23:27 +02:00
continue;
}
2018-08-15 22:46:20 +02:00
const rapidjson::Value &imageScalesValue =
imageBackgroundState.value;
2018-10-21 13:43:02 +02:00
if (!imageScalesValue.IsObject())
{
2018-08-02 14:23:27 +02:00
continue;
}
2018-08-15 22:46:20 +02:00
// Read each key which represents a scale
for (const auto &imageScaleValue :
2018-10-21 13:43:02 +02:00
imageScalesValue.GetObject())
{
2018-08-15 22:46:20 +02:00
QString scale = imageScaleValue.name.GetString();
bool scaleExists = false;
2018-10-21 13:43:02 +02:00
for (const auto &_scale : set.scales)
{
if (scale == _scale)
{
2018-08-15 22:46:20 +02:00
scaleExists = true;
break;
}
}
2018-08-02 14:23:27 +02:00
2018-10-21 13:43:02 +02:00
if (!scaleExists)
{
2018-08-15 22:46:20 +02:00
continue;
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
const rapidjson::Value &imageScaleURLValue =
imageScaleValue.value;
2018-10-21 13:43:02 +02:00
if (!imageScaleURLValue.IsString())
{
2018-08-15 22:46:20 +02:00
continue;
}
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
QString url = imageScaleURLValue.GetString();
2018-08-02 14:23:27 +02:00
2018-08-15 22:46:20 +02:00
bool ok = false;
qreal scaleNumber = scale.toFloat(&ok);
2018-10-21 13:43:02 +02:00
if (!ok)
{
2018-08-15 22:46:20 +02:00
continue;
}
qreal chatterinoScale = 1 / scaleNumber;
auto image = Image::fromUrl({url}, chatterinoScale);
// TODO(pajlada): Fill in name and tooltip
tier.images[background][state][scale] = image;
}
2018-08-02 14:23:27 +02:00
}
}
2018-08-15 22:46:20 +02:00
set.tiers.emplace_back(tier);
2018-08-02 14:23:27 +02:00
}
2018-08-15 22:46:20 +02:00
return true;
2018-08-02 14:23:27 +02:00
}
2018-08-02 14:23:27 +02:00
} // namespace
2018-08-06 21:17:03 +02:00
// Look through the results of
// https://api.twitch.tv/kraken/bits/actions?channel_id=11148817 for cheermote
// sets or "Actions" as they are called in the API
2018-08-02 14:23:27 +02:00
std::vector<JSONCheermoteSet> ParseCheermoteSets(const rapidjson::Document &d)
{
std::vector<JSONCheermoteSet> sets;
2018-10-21 13:43:02 +02:00
if (!d.IsObject())
{
2018-08-02 14:23:27 +02:00
return sets;
}
2018-10-21 13:43:02 +02:00
if (!d.HasMember("actions"))
{
2018-08-02 14:23:27 +02:00
return sets;
}
const auto &actionsValue = d["actions"];
2018-10-21 13:43:02 +02:00
if (!actionsValue.IsArray())
{
2018-08-02 14:23:27 +02:00
return sets;
}
2018-10-21 13:43:02 +02:00
for (const auto &action : actionsValue.GetArray())
{
2018-08-02 14:23:27 +02:00
JSONCheermoteSet set;
bool res = ParseSingleCheermoteSet(set, action);
2018-10-21 13:43:02 +02:00
if (res)
{
2018-08-02 14:23:27 +02:00
sets.emplace_back(set);
}
}
return sets;
}
} // namespace chatterino