diff --git a/src/twitch/twitchchannel.cpp b/src/twitch/twitchchannel.cpp index c65b95636..9fef671e3 100644 --- a/src/twitch/twitchchannel.cpp +++ b/src/twitch/twitchchannel.cpp @@ -39,7 +39,7 @@ TwitchChannel::TwitchChannel(IrcManager &ircManager, const QString &channelName, }); this->fetchMessages.connect([this] { - this->fetchRecentMessages(); + this->fetchRecentMessages(); // }); } @@ -109,22 +109,49 @@ void TwitchChannel::refreshLiveStatus() QString url("https://api.twitch.tv/kraken/streams/" + this->roomID); - util::twitch::get(url, QThread::currentThread(), [this](QJsonObject obj) { - if (obj.value("stream").isNull()) { - this->setLive(false); - } else { - auto stream = obj.value("stream").toObject(); - this->streamViewerCount = QString::number(stream.value("viewers").toDouble()); - this->streamGame = stream.value("game").toString(); - this->streamStatus = stream.value("channel").toObject().value("status").toString(); - QDateTime since = - QDateTime::fromString(stream.value("created_at").toString(), Qt::ISODate); - auto diff = since.secsTo(QDateTime::currentDateTime()); - this->streamUptime = - QString::number(diff / 3600) + "h " + QString::number(diff % 3600 / 60) + "m"; - - this->setLive(true); + util::twitch::get2(url, QThread::currentThread(), [this](rapidjson::Document &d) { + if (!d.IsObject()) { + debug::Log("[TwitchChannel:refreshLiveStatus] root is not an object"); + return; } + + if (!d.HasMember("stream")) { + debug::Log("[TwitchChannel:refreshLiveStatus] Missing stream in root"); + return; + } + + const auto &stream = d["stream"]; + + if (!stream.IsObject()) { + // Stream is offline (stream is most likely null) + this->setLive(false); + return; + } + + if (!stream.HasMember("viewers") || !stream.HasMember("game") || + !stream.HasMember("channel") || !stream.HasMember("created_at")) { + debug::Log("[TwitchChannel:refreshLiveStatus] Missing members in stream"); + this->setLive(false); + return; + } + + const rapidjson::Value &streamChannel = stream["channel"]; + + if (!streamChannel.IsObject() || !streamChannel.HasMember("status")) { + debug::Log("[TwitchChannel:refreshLiveStatus] Missing member \"status\" in channel"); + return; + } + + // Stream is live + this->streamViewerCount = QString::number(stream["viewers"].GetInt()); + this->streamGame = stream["game"].GetString(); + this->streamStatus = streamChannel["status"].GetString(); + QDateTime since = QDateTime::fromString(stream["created_at"].GetString(), Qt::ISODate); + auto diff = since.secsTo(QDateTime::currentDateTime()); + this->streamUptime = + QString::number(diff / 3600) + "h " + QString::number(diff % 3600 / 60) + "m"; + + this->setLive(true); }); } diff --git a/src/util/urlfetch.hpp b/src/util/urlfetch.hpp index 343bf1311..3240ca13e 100644 --- a/src/util/urlfetch.hpp +++ b/src/util/urlfetch.hpp @@ -5,6 +5,9 @@ #include "debug/log.hpp" #include "util/networkmanager.hpp" +#include +#include +#include #include #include #include @@ -35,6 +38,26 @@ static QJsonObject parseJSONFromReply(QNetworkReply *reply) return jsonDoc.object(); } +static rapidjson::Document parseJSONFromReply2(QNetworkReply *reply) +{ + rapidjson::Document ret(rapidjson::kNullType); + + if (reply->error() != QNetworkReply::NetworkError::NoError) { + return ret; + } + + QByteArray data = reply->readAll(); + rapidjson::ParseResult result = ret.Parse(data.data(), data.length()); + + if (result.Code() != rapidjson::kParseErrorNone) { + debug::Log("JSON parse error: {} ({})", rapidjson::GetParseError_En(result.Code()), + result.Offset()); + return ret; + } + + return ret; +} + namespace twitch { static void get(QString url, const QObject *caller, @@ -50,6 +73,19 @@ static void get(QString url, const QObject *caller, }); } +static void get2(QString url, const QObject *caller, + std::function successCallback) +{ + util::NetworkRequest req(url); + req.setCaller(caller); + req.setRawHeader("Client-ID", getDefaultClientID()); + req.setRawHeader("Accept", "application/vnd.twitchtv.v5+json"); + req.get([=](QNetworkReply *reply) { + auto document = parseJSONFromReply2(reply); + successCallback(document); + }); +} + static void getAuthorized(QString url, const QString &clientID, const QString &oauthToken, const QObject *caller, std::function successCallback) {