diff --git a/chatterino.pro b/chatterino.pro index bb033aba8..18d67f250 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -162,7 +162,8 @@ SOURCES += \ src/widgets/settingspages/logspage.cpp \ src/widgets/basewindow.cpp \ src/singletons/helper/moderationaction.cpp \ - src/widgets/streamview.cpp + src/widgets/streamview.cpp \ + src/util/networkrequest.cpp HEADERS += \ src/precompiled_header.hpp \ @@ -262,7 +263,10 @@ HEADERS += \ src/widgets/settingspages/logspage.hpp \ src/widgets/basewindow.hpp \ src/singletons/helper/moderationaction.hpp \ - src/widgets/streamview.hpp + src/widgets/streamview.hpp \ + src/util/networkrequest.hpp \ + src/util/networkworker.hpp \ + src/util/networkrequester.hpp RESOURCES += \ resources/resources.qrc diff --git a/src/messages/image.cpp b/src/messages/image.cpp index 3ea575b0c..a29a47ce5 100644 --- a/src/messages/image.cpp +++ b/src/messages/image.cpp @@ -47,9 +47,10 @@ void Image::loadImage() { util::NetworkRequest req(this->getUrl()); req.setCaller(this); - req.get([lli = this](QNetworkReply * reply) { - QByteArray array = reply->readAll(); - QBuffer buffer(&array); + req.setUseQuickLoadCache(true); + req.get([lli = this](QByteArray bytes) { + QByteArray copy = QByteArray::fromRawData(bytes.constData(), bytes.length()); + QBuffer buffer(©); buffer.open(QIODevice::ReadOnly); QImage image; @@ -63,7 +64,7 @@ void Image::loadImage() if (first) { first = false; - lli->currentPixmap = pixmap; + lli->loadedPixmap = pixmap; } chatterino::messages::Image::FrameData data; @@ -78,6 +79,10 @@ void Image::loadImage() lli->animated = true; } + lli->currentPixmap = lli->loadedPixmap; + + lli->isLoaded = true; + singletons::EmoteManager::getInstance().incGeneration(); singletons::WindowManager::getInstance().layoutVisibleChatWidgets(); @@ -91,7 +96,7 @@ void Image::loadImage() void Image::gifUpdateTimout() { - if (animated) { + if (this->animated) { this->currentFrameOffset += GIF_FRAME_LENGTH; while (true) { @@ -112,9 +117,16 @@ const QPixmap *Image::getPixmap() if (!this->isLoading) { this->isLoading = true; - loadImage(); + this->loadImage(); + + return nullptr; + } + + if (this->isLoaded) { + return this->currentPixmap; + } else { + return nullptr; } - return this->currentPixmap; } qreal Image::getScale() const @@ -157,6 +169,7 @@ int Image::getWidth() const if (this->currentPixmap == nullptr) { return 16; } + return this->currentPixmap->width(); } diff --git a/src/messages/image.hpp b/src/messages/image.hpp index 48c649c19..a32446d8b 100644 --- a/src/messages/image.hpp +++ b/src/messages/image.hpp @@ -2,9 +2,11 @@ #include #include - #include +#include +#include + namespace chatterino { namespace messages { @@ -41,6 +43,7 @@ private: }; QPixmap *currentPixmap; + QPixmap *loadedPixmap; std::vector allFrames; int currentFrame = 0; int currentFrameOffset = 0; @@ -53,7 +56,8 @@ private: bool ishat; qreal scale; - bool isLoading; + bool isLoading = false; + std::atomic isLoaded{false}; void loadImage(); void gifUpdateTimout(); diff --git a/src/messages/layouts/messagelayoutelement.cpp b/src/messages/layouts/messagelayoutelement.cpp index b168a4637..994016b57 100644 --- a/src/messages/layouts/messagelayoutelement.cpp +++ b/src/messages/layouts/messagelayoutelement.cpp @@ -79,6 +79,10 @@ int ImageLayoutElement::getSelectionIndexCount() void ImageLayoutElement::paint(QPainter &painter) { + if (this->image == nullptr) { + return; + } + const QPixmap *pixmap = this->image->getPixmap(); if (pixmap != nullptr && !this->image->isAnimated()) { @@ -89,12 +93,18 @@ void ImageLayoutElement::paint(QPainter &painter) void ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) { + if (this->image == nullptr) { + return; + } + if (this->image->isAnimated()) { - if (this->image->getPixmap() != nullptr) { + auto pixmap = this->image->getPixmap(); + + if (pixmap != nullptr) { // fourtf: make it use qreal values QRect rect = this->getRect(); rect.moveTop(rect.y() + yOffset); - painter.drawPixmap(QRectF(rect), *this->image->getPixmap(), QRectF()); + painter.drawPixmap(QRectF(rect), *pixmap, QRectF()); } } } diff --git a/src/messages/limitedqueue.hpp b/src/messages/limitedqueue.hpp index 07f6b3b35..23618fe0a 100644 --- a/src/messages/limitedqueue.hpp +++ b/src/messages/limitedqueue.hpp @@ -121,8 +121,8 @@ public: newChunks->at(0) = newFirstChunk; this->chunks = newChunks; - qDebug() << acceptedItems.size(); - qDebug() << this->chunks->at(0)->size(); + // qDebug() << acceptedItems.size(); + // qDebug() << this->chunks->at(0)->size(); if (this->chunks->size() == 1) { this->lastChunkEnd += offset; diff --git a/src/messages/messageelement.cpp b/src/messages/messageelement.cpp index ca779a533..50df13fe6 100644 --- a/src/messages/messageelement.cpp +++ b/src/messages/messageelement.cpp @@ -237,7 +237,7 @@ TwitchModerationElement::TwitchModerationElement() void TwitchModerationElement::addToContainer(MessageLayoutContainer &container, MessageElement::Flags _flags) { - qDebug() << _flags; + // qDebug() << _flags; if (_flags & MessageElement::ModeratorTools) { QSize size((int)(container.scale * 16), (int)(container.scale * 16)); diff --git a/src/singletons/emotemanager.cpp b/src/singletons/emotemanager.cpp index 3f6371d6a..b1cadf44b 100644 --- a/src/singletons/emotemanager.cpp +++ b/src/singletons/emotemanager.cpp @@ -142,8 +142,7 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName, link = link.replace("{{id}}", id).replace("{{image}}", "1x"); auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [this, &code, &link] { - return util::EmoteData( - new Image(link, 1, code, code + "
Channel BTTV Emote")); + return util::EmoteData(new Image(link, 1, code, code + "
Channel BTTV Emote")); }); this->bttvChannelEmotes.insert(code, emote); @@ -293,9 +292,8 @@ void EmoteManager::loadEmojis() "emojione/2.2.6/assets/png/" + code + ".png"; - this->emojis.insert(code, - util::EmoteData(new Image(url, 0.35, ":" + shortCode + ":", - ":" + shortCode + ":
Emoji"))); + this->emojis.insert(code, util::EmoteData(new Image(url, 0.35, ":" + shortCode + ":", + ":" + shortCode + ":
Emoji"))); // TODO(pajlada): The vectors in emojiFirstByte need to be sorted by // emojiData.code.length() @@ -374,8 +372,7 @@ void EmoteManager::parseEmojis(std::vector> // Create or fetch cached emoji image auto emojiImage = this->emojis.getOrAdd(matchedEmoji.code, [this, &url] { - return util::EmoteData( - new Image(url, 0.35, "?????????", "???????????????")); // + return util::EmoteData(new Image(url, 0.35, "?????????", "???????????????")); // }); // Push the emoji as a word to parsedWords @@ -447,7 +444,7 @@ void EmoteManager::refreshTwitchEmotes(const std::shared_ptr util::twitch::getAuthorized( url, clientID, oauthToken, QThread::currentThread(), - [=, &emoteData](QJsonObject &root) { + [=, &emoteData](const QJsonObject &root) { emoteData.emoteSets.clear(); emoteData.emoteCodes.clear(); auto emoticonSets = root.value("emoticon_sets").toObject(); @@ -477,6 +474,7 @@ void EmoteManager::loadBTTVEmotes() util::NetworkRequest req(url); req.setCaller(QThread::currentThread()); req.setTimeout(30000); + req.setUseQuickLoadCache(true); req.getJSON([this](QJsonObject &root) { debug::Log("Got global bttv emotes"); auto emotes = root.value("emotes").toArray(); @@ -489,12 +487,12 @@ void EmoteManager::loadBTTVEmotes() QString code = emote.toObject().value("code").toString(); util::EmoteData emoteData; - emoteData.image1x = new Image(GetBTTVEmoteLink(urlTemplate, id, "1x"), 1, - code, code + "
Global BTTV Emote"); - emoteData.image2x = new Image(GetBTTVEmoteLink(urlTemplate, id, "2x"), 0.5, - code, code + "
Global BTTV Emote"); - emoteData.image3x = new Image(GetBTTVEmoteLink(urlTemplate, id, "3x"), 0.25, - code, code + "
Global BTTV Emote"); + emoteData.image1x = new Image(GetBTTVEmoteLink(urlTemplate, id, "1x"), 1, code, + code + "
Global BTTV Emote"); + emoteData.image2x = new Image(GetBTTVEmoteLink(urlTemplate, id, "2x"), 0.5, code, + code + "
Global BTTV Emote"); + emoteData.image3x = new Image(GetBTTVEmoteLink(urlTemplate, id, "3x"), 0.25, code, + code + "
Global BTTV Emote"); this->bttvGlobalEmotes.insert(code, emoteData); codes.push_back(code.toStdString()); @@ -548,11 +546,11 @@ util::EmoteData EmoteManager::getTwitchEmoteById(long id, const QString &emoteNa return _twitchEmoteFromCache.getOrAdd(id, [this, &emoteName, &_emoteName, &id] { util::EmoteData newEmoteData; newEmoteData.image1x = new Image(GetTwitchEmoteLink(id, "1.0"), 1, emoteName, - _emoteName + "
Twitch Emote 1x"); + _emoteName + "
Twitch Emote 1x"); newEmoteData.image2x = new Image(GetTwitchEmoteLink(id, "2.0"), .5, emoteName, - _emoteName + "
Twitch Emote 2x"); + _emoteName + "
Twitch Emote 2x"); newEmoteData.image3x = new Image(GetTwitchEmoteLink(id, "3.0"), .25, emoteName, - _emoteName + "
Twitch Emote 3x"); + _emoteName + "
Twitch Emote 3x"); return newEmoteData; }); diff --git a/src/singletons/ircmanager.cpp b/src/singletons/ircmanager.cpp index b01996e11..5ed5d2fdc 100644 --- a/src/singletons/ircmanager.cpp +++ b/src/singletons/ircmanager.cpp @@ -253,6 +253,11 @@ void IrcManager::privateMessageReceived(Communi::IrcPrivateMessage *message) return; } + auto xd = message->content(); + auto xd2 = message->toData(); + + debug::Log("HEHE: {}", xd2.toStdString()); + messages::MessageParseArgs args; twitch::TwitchMessageBuilder builder(c.get(), message, args); diff --git a/src/singletons/pathmanager.cpp b/src/singletons/pathmanager.cpp index 8d31c9de1..0047b11e6 100644 --- a/src/singletons/pathmanager.cpp +++ b/src/singletons/pathmanager.cpp @@ -50,6 +50,13 @@ bool PathManager::init(int argc, char **argv) return false; } + this->cacheFolderPath = rootPath + "/Cache"; + + if (!QDir().mkpath(this->cacheFolderPath)) { + printf("Error creating cache directory: %s\n", qPrintable(this->cacheFolderPath)); + return false; + } + return true; } diff --git a/src/singletons/pathmanager.hpp b/src/singletons/pathmanager.hpp index 6855eab61..7d89af9bc 100644 --- a/src/singletons/pathmanager.hpp +++ b/src/singletons/pathmanager.hpp @@ -16,6 +16,7 @@ public: QString settingsFolderPath; QString customFolderPath; + QString cacheFolderPath; }; } // namespace singletons diff --git a/src/twitch/twitchchannel.cpp b/src/twitch/twitchchannel.cpp index 038978594..d78537665 100644 --- a/src/twitch/twitchchannel.cpp +++ b/src/twitch/twitchchannel.cpp @@ -106,11 +106,6 @@ void TwitchChannel::setMod(bool value) bool TwitchChannel::isBroadcaster() { - QString xD = this->name; - QString xD2 = singletons::AccountManager::getInstance().Twitch.getCurrent()->getUserName(); - - qDebug() << xD << xD2; - return this->name == singletons::AccountManager::getInstance().Twitch.getCurrent()->getUserName(); } @@ -144,7 +139,7 @@ void TwitchChannel::refreshLiveStatus() std::weak_ptr weak = this->shared_from_this(); - util::twitch::get2(url, QThread::currentThread(), [weak](rapidjson::Document &d) { + util::twitch::get2(url, QThread::currentThread(), [weak](const rapidjson::Document &d) { SharedChannel shared = weak.lock(); if (!shared) { diff --git a/src/util/networkmanager.hpp b/src/util/networkmanager.hpp index dc43c44ff..309c0ec63 100644 --- a/src/util/networkmanager.hpp +++ b/src/util/networkmanager.hpp @@ -1,6 +1,8 @@ #pragma once #include "debug/log.hpp" +#include "util/networkrequester.hpp" +#include "util/networkworker.hpp" #include #include @@ -29,22 +31,6 @@ static QJsonObject parseJSONFromReplyxD(QNetworkReply *reply) return jsonDoc.object(); } -class NetworkWorker : public QObject -{ - Q_OBJECT - -signals: - void doneUrl(QNetworkReply *); -}; - -class NetworkRequester : public QObject -{ - Q_OBJECT - -signals: - void requestUrl(); -}; - class NetworkManager : public QObject { Q_OBJECT @@ -183,122 +169,5 @@ public: } }; -class NetworkRequest -{ - struct Data { - QNetworkRequest request; - const QObject *caller = nullptr; - std::function onReplyCreated; - int timeoutMS = -1; - } data; - -public: - NetworkRequest() = delete; - - explicit NetworkRequest(const char *url) - { - this->data.request.setUrl(QUrl(url)); - } - - explicit NetworkRequest(const std::string &url) - { - this->data.request.setUrl(QUrl(QString::fromStdString(url))); - } - - explicit NetworkRequest(const QString &url) - { - this->data.request.setUrl(QUrl(url)); - } - - void setCaller(const QObject *_caller) - { - this->data.caller = _caller; - } - - void setOnReplyCreated(std::function f) - { - this->data.onReplyCreated = f; - } - - void setRawHeader(const QByteArray &headerName, const QByteArray &value) - { - this->data.request.setRawHeader(headerName, value); - } - - void setTimeout(int ms) - { - this->data.timeoutMS = ms; - } - - template - void get(FinishedCallback onFinished) - { - QTimer *timer = nullptr; - if (this->data.timeoutMS > 0) { - timer = new QTimer; - } - - NetworkRequester requester; - NetworkWorker *worker = new NetworkWorker; - - worker->moveToThread(&NetworkManager::workerThread); - - if (this->data.caller != nullptr) { - QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller, - [onFinished](auto reply) { - onFinished(reply); - reply->deleteLater(); - }); - } - - if (timer != nullptr) { - timer->start(this->data.timeoutMS); - } - - QObject::connect( - &requester, &NetworkRequester::requestUrl, worker, - [ timer, data = std::move(this->data), worker, onFinished{std::move(onFinished)} ]() { - QNetworkReply *reply = NetworkManager::NaM.get(data.request); - - if (timer != nullptr) { - QObject::connect(timer, &QTimer::timeout, worker, [reply, timer]() { - debug::Log("Aborted!"); - reply->abort(); - timer->deleteLater(); - }); - } - - if (data.onReplyCreated) { - data.onReplyCreated(reply); - } - - QObject::connect(reply, &QNetworkReply::finished, worker, [ - data = std::move(data), worker, reply, onFinished = std::move(onFinished) - ]() { - if (data.caller == nullptr) { - onFinished(reply); - - reply->deleteLater(); - } else { - emit worker->doneUrl(reply); - } - - delete worker; - }); - }); - - emit requester.requestUrl(); - } - - template - void getJSON(FinishedCallback onFinished) - { - this->get([onFinished{std::move(onFinished)}](auto reply) { - auto object = parseJSONFromReplyxD(reply); - onFinished(object); - }); - } -}; - } // namespace util } // namespace chatterino diff --git a/src/util/networkrequest.cpp b/src/util/networkrequest.cpp new file mode 100644 index 000000000..7bdc040e5 --- /dev/null +++ b/src/util/networkrequest.cpp @@ -0,0 +1,42 @@ +#include "util/networkrequest.hpp" + +namespace chatterino { +namespace util { + +NetworkRequest::NetworkRequest(const char *url) +{ + this->data.request.setUrl(QUrl(url)); +} + +NetworkRequest::NetworkRequest(const std::string &url) +{ + this->data.request.setUrl(QUrl(QString::fromStdString(url))); +} + +NetworkRequest::NetworkRequest(const QString &url) +{ + this->data.request.setUrl(QUrl(url)); +} + +void NetworkRequest::setUseQuickLoadCache(bool value) +{ + this->data.useQuickLoadCache = value; +} + +void NetworkRequest::Data::writeToCache(const QByteArray &bytes) +{ + if (this->useQuickLoadCache) { + auto &pathManager = singletons::PathManager::getInstance(); + + QFile cachedFile(pathManager.cacheFolderPath + "/" + this->getHash()); + + if (cachedFile.open(QIODevice::WriteOnly)) { + cachedFile.write(bytes); + + cachedFile.close(); + } + } +} + +} // namespace util +} // namespace chatterino diff --git a/src/util/networkrequest.hpp b/src/util/networkrequest.hpp new file mode 100644 index 000000000..06c7292f2 --- /dev/null +++ b/src/util/networkrequest.hpp @@ -0,0 +1,228 @@ +#pragma once + +#include "singletons/pathmanager.hpp" +#include "util/networkmanager.hpp" +#include "util/networkrequester.hpp" +#include "util/networkworker.hpp" + +#include +#include + +namespace chatterino { +namespace util { + +static QJsonObject parseJSONFromData(const QByteArray &data) +{ + QJsonDocument jsonDoc(QJsonDocument::fromJson(data)); + + if (jsonDoc.isNull()) { + return QJsonObject(); + } + + return jsonDoc.object(); +} + +static rapidjson::Document parseJSONFromData2(const QByteArray &data) +{ + rapidjson::Document ret(rapidjson::kNullType); + + 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; +} + +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; +} + +class NetworkRequest +{ + struct Data { + QNetworkRequest request; + const QObject *caller = nullptr; + std::function onReplyCreated; + int timeoutMS = -1; + bool useQuickLoadCache = false; + + QString getHash() + { + if (this->hash.isEmpty()) { + QByteArray bytes; + + bytes.append(this->request.url().toString()); + + for (const auto &header : this->request.rawHeaderList()) { + bytes.append(header); + } + + QByteArray hashBytes(QCryptographicHash::hash(bytes, QCryptographicHash::Sha256)); + + this->hash = hashBytes.toHex(); + } + + return this->hash; + } + + void writeToCache(const QByteArray &bytes); + + private: + QString hash; + } data; + +public: + NetworkRequest() = delete; + explicit NetworkRequest(const char *url); + explicit NetworkRequest(const std::string &url); + explicit NetworkRequest(const QString &url); + + void setUseQuickLoadCache(bool value); + + void setCaller(const QObject *_caller) + { + this->data.caller = _caller; + } + + void setOnReplyCreated(std::function f) + { + this->data.onReplyCreated = f; + } + + void setRawHeader(const QByteArray &headerName, const QByteArray &value) + { + this->data.request.setRawHeader(headerName, value); + } + + void setTimeout(int ms) + { + this->data.timeoutMS = ms; + } + + template + void get(FinishedCallback onFinished) + { + if (this->data.useQuickLoadCache) { + auto &pathManager = singletons::PathManager::getInstance(); + + QFile cachedFile(pathManager.cacheFolderPath + "/" + this->data.getHash()); + + if (cachedFile.exists()) { + if (cachedFile.open(QIODevice::ReadOnly)) { + QByteArray bytes = cachedFile.readAll(); + + onFinished(bytes); + + cachedFile.close(); + } + } + } + + QTimer *timer = nullptr; + if (this->data.timeoutMS > 0) { + timer = new QTimer; + } + + NetworkRequester requester; + NetworkWorker *worker = new NetworkWorker; + + worker->moveToThread(&NetworkManager::workerThread); + + if (this->data.caller != nullptr) { + QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller, + [ onFinished, data = this->data ](auto reply) mutable { + if (reply->error() != QNetworkReply::NetworkError::NoError) { + // TODO: We might want to call an onError callback here + return; + } + + QByteArray bytes = reply->readAll(); + data.writeToCache(bytes); + // onFinished(bytes); + + reply->deleteLater(); + }); + } + + if (timer != nullptr) { + timer->start(this->data.timeoutMS); + } + + QObject::connect( + &requester, &NetworkRequester::requestUrl, worker, + [ timer, data = std::move(this->data), worker, onFinished{std::move(onFinished)} ]() { + QNetworkReply *reply = NetworkManager::NaM.get(data.request); + + if (timer != nullptr) { + QObject::connect(timer, &QTimer::timeout, worker, [reply, timer]() { + debug::Log("Aborted!"); + reply->abort(); + timer->deleteLater(); + }); + } + + if (data.onReplyCreated) { + data.onReplyCreated(reply); + } + + QObject::connect(reply, &QNetworkReply::finished, worker, [ + data = std::move(data), worker, reply, onFinished = std::move(onFinished) + ]() mutable { + if (data.caller == nullptr) { + QByteArray bytes = reply->readAll(); + data.writeToCache(bytes); + // onFinished(bytes); + + reply->deleteLater(); + } else { + emit worker->doneUrl(reply); + } + + delete worker; + }); + }); + + emit requester.requestUrl(); + } + + template + void getJSON(FinishedCallback onFinished) + { + this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes) { + auto object = parseJSONFromData(bytes); + onFinished(object); + }); + } + + template + void getJSON2(FinishedCallback onFinished) + { + this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes) { + auto object = parseJSONFromData2(bytes); + onFinished(object); + }); + } +}; + +} // namespace util +} // namespace chatterino diff --git a/src/util/networkrequester.hpp b/src/util/networkrequester.hpp new file mode 100644 index 000000000..872fd9a44 --- /dev/null +++ b/src/util/networkrequester.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace chatterino { +namespace util { + +class NetworkRequester : public QObject +{ + Q_OBJECT + +signals: + void requestUrl(); +}; + +} // namespace util +} // namespace chatterino diff --git a/src/util/networkworker.hpp b/src/util/networkworker.hpp new file mode 100644 index 000000000..7da13fe19 --- /dev/null +++ b/src/util/networkworker.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace chatterino { +namespace util { + +class NetworkWorker : public QObject +{ + Q_OBJECT + +signals: + void doneUrl(QNetworkReply *); +}; + +} // namespace util +} // namespace chatterino diff --git a/src/util/urlfetch.hpp b/src/util/urlfetch.hpp index a9b180e85..b590df3f6 100644 --- a/src/util/urlfetch.hpp +++ b/src/util/urlfetch.hpp @@ -4,6 +4,7 @@ #include "debug/log.hpp" #include "singletons/accountmanager.hpp" #include "util/networkmanager.hpp" +#include "util/networkrequest.hpp" #include #include @@ -21,82 +22,47 @@ namespace chatterino { namespace util { - -static QJsonObject parseJSONFromReply(QNetworkReply *reply) -{ - if (reply->error() != QNetworkReply::NetworkError::NoError) { - return QJsonObject(); - } - - QByteArray data = reply->readAll(); - QJsonDocument jsonDoc(QJsonDocument::fromJson(data)); - - if (jsonDoc.isNull()) { - return QJsonObject(); - } - - 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, - std::function successCallback) + 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 node = parseJSONFromReply(reply); - successCallback(node); + + req.getJSON([=](const QJsonObject &node) { + successCallback(node); // }); } static void get2(QString url, const QObject *caller, - std::function successCallback) + 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); + req.setUseQuickLoadCache(true); + + req.getJSON2([=](const rapidjson::Document &document) { + successCallback(document); // }); } static void getAuthorized(QString url, const QString &clientID, const QString &oauthToken, - const QObject *caller, std::function successCallback) + const QObject *caller, + std::function successCallback) { util::NetworkRequest req(url); req.setCaller(caller); req.setRawHeader("Client-ID", clientID.toUtf8()); req.setRawHeader("Authorization", "OAuth " + oauthToken.toUtf8()); req.setRawHeader("Accept", "application/vnd.twitchtv.v5+json"); - req.get([=](QNetworkReply *reply) { - auto node = parseJSONFromReply(reply); - successCallback(node); + + req.getJSON([=](const QJsonObject &node) { + successCallback(node); // }); }