TTW_Bot/emoteprovider.cpp

419 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// emoteprovider.cpp
#include "emoteprovider.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
// EmoteProvider implementation
EmoteProvider::EmoteProvider(QObject *parent)
: QObject(parent)
, m_networkManager(new QNetworkAccessManager(this)) {
}
EmoteProvider::~EmoteProvider() {
// QNetworkAccessManager будет удален автоматически как дочерний объект
}
void EmoteProvider::setLogCallback(LogCallback callback) {
m_logCallback = callback;
}
void EmoteProvider::log(const QString &method, const QString &message, LogLevelemt level) {
if (m_logCallback) {
m_logCallback(metaObject()->className(), method, message, level);
}
}
// BTTVProvider implementation
BTTVProvider::BTTVProvider(QObject *parent)
: EmoteProvider(parent) {
}
BTTVProvider::~BTTVProvider() {
m_emotes.clear();
}
void BTTVProvider::fetchGlobal() {
log("fetchGlobal", "Fetching global BTTV emotes", LOG_INFO);
QNetworkRequest request(QUrl(getBaseUrl() + "emotes/global"));
request.setHeader(QNetworkRequest::UserAgentHeader,
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36");
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished,
this, [this, reply]() { onGlobalReplyFinished(reply); });
}
void BTTVProvider::fetchCustom(const QString &userId) {
if (userId.isEmpty()) {
log("fetchCustom", "User ID is empty", LOG_WARNING);
return;
}
log("fetchCustom", QString("Fetching custom BTTV emotes for user: %1").arg(userId), LOG_INFO);
m_lastUserId = userId;
QNetworkRequest request(QUrl(getBaseUrl() + "users/twitch/" + userId));
request.setHeader(QNetworkRequest::UserAgentHeader,
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36");
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished,
this, [this, reply]() { onCustomReplyFinished(reply); });
}
QString BTTVProvider::getEmoteUrl(const QString &emoteName) {
for (const auto &emote : m_emotes) {
if (emote.code == emoteName) {
return emote.url();
}
}
return QString();
}
void BTTVProvider::onGlobalReplyFinished(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError) {
log("onGlobalReplyFinished",
QString("Network error: %1").arg(reply->errorString()),
LOG_ERROR);
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
parseGlobalResponse(data);
reply->deleteLater();
emit emotesLoaded();
}
void BTTVProvider::onCustomReplyFinished(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError) {
log("onCustomReplyFinished",
QString("Network error: %1").arg(reply->errorString()),
LOG_ERROR);
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
parseCustomResponse(data, m_lastUserId);
reply->deleteLater();
emit emotesLoaded();
}
void BTTVProvider::parseGlobalResponse(const QByteArray &data) {
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
log("parseGlobalResponse",
QString("JSON parse error: %1").arg(parseError.errorString()),
LOG_ERROR);
return;
}
if (!doc.isArray()) {
log("parseGlobalResponse", "Expected JSON array", LOG_ERROR);
return;
}
QJsonArray array = doc.array();
m_emotes.clear();
for (const QJsonValue &value : array) {
if (!value.isObject()) continue;
QJsonObject obj = value.toObject();
BTTVEmote emote;
emote.id = obj.value("id").toString();
emote.code = obj.value("code").toString();
if (!emote.id.isEmpty() && !emote.code.isEmpty()) {
m_emotes.append(emote);
}
}
log("parseGlobalResponse",
QString("Loaded %1 global emotes").arg(m_emotes.size()),
LOG_INFO);
}
void BTTVProvider::parseCustomResponse(const QByteArray &data, const QString &userId) {
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
log("parseCustomResponse",
QString("JSON parse error: %1").arg(parseError.errorString()),
LOG_ERROR);
return;
}
if (!doc.isObject()) {
log("parseCustomResponse", "Expected JSON object", LOG_ERROR);
return;
}
QJsonObject root = doc.object();
auto parseEmotesArray = [this](const QJsonArray &array) {
for (const QJsonValue &value : array) {
if (!value.isObject()) continue;
QJsonObject obj = value.toObject();
BTTVEmote emote;
emote.id = obj.value("id").toString();
emote.code = obj.value("code").toString();
if (!emote.id.isEmpty() && !emote.code.isEmpty()) {
m_emotes.append(emote);
}
}
};
// Очищаем только пользовательские эмодзи (можно оптимизировать)
// В реальном приложении нужно хранить отдельно глобальные и пользовательские
// Парсим channelEmotes
if (root.contains("channelEmotes") && root["channelEmotes"].isArray()) {
parseEmotesArray(root["channelEmotes"].toArray());
}
// Парсим sharedEmotes
if (root.contains("sharedEmotes") && root["sharedEmotes"].isArray()) {
parseEmotesArray(root["sharedEmotes"].toArray());
}
log("parseCustomResponse",
QString("Loaded %1 custom emotes for user %2").arg(m_emotes.size()).arg(userId),
LOG_INFO);
}
// SevenTVProvider implementation
SevenTVProvider::SevenTVProvider(QObject *parent)
: EmoteProvider(parent) {
}
SevenTVProvider::~SevenTVProvider() {
m_emotes.clear();
}
void SevenTVProvider::fetchGlobal() {
log("fetchGlobal", "Fetching global 7TV emotes", LOG_INFO);
QNetworkRequest request(QUrl(getBaseUrl() + "emote-sets/global"));
request.setHeader(QNetworkRequest::UserAgentHeader,
"Mozilla/5.0");
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished,
this, [this, reply]() { onGlobalReplyFinished(reply); });
}
void SevenTVProvider::fetchCustom(const QString &userId) {
if (userId.isEmpty()) {
log("fetchCustom", "User ID is empty", LOG_WARNING);
return;
}
log("fetchCustom", QString("Fetching custom 7TV emotes for user: %1").arg(userId), LOG_INFO);
m_lastUserId = userId;
QNetworkRequest request(QUrl(getBaseUrl() + "users/twitch/" + userId));
request.setHeader(QNetworkRequest::UserAgentHeader,
"Mozilla/5.0");
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished,
this, [this, reply]() { onCustomReplyFinished(reply); });
}
QString SevenTVProvider::getEmoteUrl(const QString &emoteName) {
for (const auto &emote : m_emotes) {
if (emote.code == emoteName) {
return emote.url;
}
}
return QString();
}
void SevenTVProvider::onGlobalReplyFinished(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError) {
log("onGlobalReplyFinished",
QString("Network error: %1").arg(reply->errorString()),
LOG_ERROR);
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
parseGlobalResponse(data);
reply->deleteLater();
emit emotesLoaded();
}
void SevenTVProvider::onCustomReplyFinished(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError) {
log("onCustomReplyFinished",
QString("Network error: %1").arg(reply->errorString()),
LOG_ERROR);
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
parseCustomResponse(data, m_lastUserId);
reply->deleteLater();
emit emotesLoaded();
}
void SevenTVProvider::parseGlobalResponse(const QByteArray &data) {
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
log("parseGlobalResponse",
QString("JSON parse error: %1").arg(parseError.errorString()),
LOG_ERROR);
return;
}
if (!doc.isObject()) {
log("parseGlobalResponse", "Expected JSON object", LOG_ERROR);
return;
}
QJsonObject root = doc.object();
m_emotes.clear();
if (!root.contains("emotes") || !root["emotes"].isArray()) {
log("parseGlobalResponse", "No emotes array found", LOG_ERROR);
return;
}
QJsonArray emotesArray = root["emotes"].toArray();
for (const QJsonValue &emoteValue : emotesArray) {
if (!emoteValue.isObject()) continue;
QJsonObject emoteObj = emoteValue.toObject();
SevenTVEmote emote;
emote.id = emoteObj.value("id").toString();
emote.code = emoteObj.value("name").toString();
// Парсим URL
if (emoteObj.contains("data") && emoteObj["data"].isObject()) {
QJsonObject dataObj = emoteObj["data"].toObject();
if (dataObj.contains("host") && dataObj["host"].isObject()) {
QJsonObject hostObj = dataObj["host"].toObject();
if (hostObj.contains("url")) {
QString baseUrl = "https:" + hostObj["url"].toString();
if (hostObj.contains("files") && hostObj["files"].isArray()) {
QJsonArray filesArray = hostObj["files"].toArray();
if (!filesArray.isEmpty() && filesArray[0].isObject()) {
QJsonObject fileObj = filesArray[0].toObject();
if (fileObj.contains("name")) {
emote.url = baseUrl + "/" + fileObj["name"].toString();
}
}
}
}
}
}
if (!emote.id.isEmpty() && !emote.code.isEmpty() && !emote.url.isEmpty()) {
m_emotes.append(emote);
}
}
log("parseGlobalResponse",
QString("Loaded %1 global emotes").arg(m_emotes.size()),
LOG_INFO);
}
void SevenTVProvider::parseCustomResponse(const QByteArray &data, const QString &userId) {
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
log("parseCustomResponse",
QString("JSON parse error: %1").arg(parseError.errorString()),
LOG_ERROR);
return;
}
if (!doc.isObject()) {
log("parseCustomResponse", "Expected JSON object", LOG_ERROR);
return;
}
QJsonObject root = doc.object();
if (!root.contains("emote_set") || !root["emote_set"].isObject()) {
log("parseCustomResponse", "No emote_set found", LOG_ERROR);
return;
}
QJsonObject emoteSet = root["emote_set"].toObject();
if (!emoteSet.contains("emotes") || !emoteSet["emotes"].isArray()) {
log("parseCustomResponse", "No emotes array in emote_set", LOG_ERROR);
return;
}
QJsonArray emotesArray = emoteSet["emotes"].toArray();
for (const QJsonValue &emoteValue : emotesArray) {
if (!emoteValue.isObject()) continue;
QJsonObject emoteObj = emoteValue.toObject();
SevenTVEmote emote;
emote.id = emoteObj.value("id").toString();
emote.code = emoteObj.value("name").toString();
// Парсим URL (аналогично parseGlobalResponse)
if (emoteObj.contains("data") && emoteObj["data"].isObject()) {
QJsonObject dataObj = emoteObj["data"].toObject();
if (dataObj.contains("host") && dataObj["host"].isObject()) {
QJsonObject hostObj = dataObj["host"].toObject();
if (hostObj.contains("url")) {
QString baseUrl = "https:" + hostObj["url"].toString();
if (hostObj.contains("files") && hostObj["files"].isArray()) {
QJsonArray filesArray = hostObj["files"].toArray();
if (!filesArray.isEmpty() && filesArray[0].isObject()) {
QJsonObject fileObj = filesArray[0].toObject();
if (fileObj.contains("name")) {
emote.url = baseUrl + "/" + fileObj["name"].toString();
}
}
}
}
}
}
if (!emote.id.isEmpty() && !emote.code.isEmpty() && !emote.url.isEmpty()) {
m_emotes.append(emote);
}
}
log("parseCustomResponse",
QString("Loaded %1 custom emotes for user %2").arg(m_emotes.size()).arg(userId),
LOG_INFO);
}