diff --git a/CHANGELOG.md b/CHANGELOG.md index ee104f69..325ba5ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unversioned +- Minor: Added followage and subage information to usercard. (#2023) - Minor: Added an option to only open channels specified in command line with `-c` parameter. You can also use `--help` to display short help message (#1940) - Minor: Added customizable timeout buttons to the user info popup - Minor: Deprecate loading of "v1" window layouts. If you haven't updated Chatterino in more than 2 years, there's a chance you will lose your window layout. diff --git a/chatterino.pro b/chatterino.pro index 4a1d7f10..cbd5c987 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -175,6 +175,7 @@ SOURCES += \ src/providers/irc/IrcConnection2.cpp \ src/providers/irc/IrcMessageBuilder.cpp \ src/providers/irc/IrcServer.cpp \ + src/providers/IvrApi.cpp \ src/providers/LinkResolver.cpp \ src/providers/twitch/ChannelPointReward.cpp \ src/providers/twitch/api/Helix.cpp \ @@ -389,6 +390,7 @@ HEADERS += \ src/providers/irc/IrcConnection2.hpp \ src/providers/irc/IrcMessageBuilder.hpp \ src/providers/irc/IrcServer.hpp \ + src/providers/IvrApi.hpp \ src/providers/LinkResolver.hpp \ src/providers/twitch/ChannelPointReward.hpp \ src/providers/twitch/api/Helix.hpp \ diff --git a/src/main.cpp b/src/main.cpp index 4202654d..72c577e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ #include "common/Args.hpp" #include "common/Modes.hpp" #include "common/Version.hpp" +#include "providers/IvrApi.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/api/Kraken.hpp" #include "singletons/Paths.hpp" @@ -45,6 +46,7 @@ int main(int argc, char **argv) } else { + IvrApi::initialize(); Helix::initialize(); Kraken::initialize(); diff --git a/src/providers/IvrApi.cpp b/src/providers/IvrApi.cpp new file mode 100644 index 00000000..e2163ecf --- /dev/null +++ b/src/providers/IvrApi.cpp @@ -0,0 +1,59 @@ +#include "IvrApi.hpp" + +#include "common/Outcome.hpp" + +#include + +namespace chatterino { + +static IvrApi *instance = nullptr; + +void IvrApi::getSubage(QString userName, QString channelName, + ResultCallback successCallback, + IvrFailureCallback failureCallback) +{ + assert(!userName.isEmpty() && !channelName.isEmpty()); + + this->makeRequest("twitch/subage/" + userName + "/" + channelName, {}) + .onSuccess([successCallback, failureCallback](auto result) -> Outcome { + auto root = result.parseJson(); + + successCallback(root); + + return Success; + }) + .onError([failureCallback](NetworkResult result) { + qDebug() << "Failed IVR API Call!" << result.status() + << QString(result.getData()); + failureCallback(); + }) + .execute(); +} + +NetworkRequest IvrApi::makeRequest(QString url, QUrlQuery urlQuery) +{ + assert(!url.startsWith("/")); + + const QString baseUrl("https://api.ivr.fi/"); + QUrl fullUrl(baseUrl + url); + fullUrl.setQuery(urlQuery); + + return NetworkRequest(fullUrl).timeout(5 * 1000).header("Accept", + "application/json"); +} + +void IvrApi::initialize() +{ + assert(instance == nullptr); + + instance = new IvrApi(); +} + +IvrApi *getIvr() +{ + assert(instance != nullptr); + + return instance; +} + +} // namespace chatterino diff --git a/src/providers/IvrApi.hpp b/src/providers/IvrApi.hpp new file mode 100644 index 00000000..7cf73e2c --- /dev/null +++ b/src/providers/IvrApi.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "common/NetworkRequest.hpp" +#include "messages/Link.hpp" + +#include + +namespace chatterino { + +using IvrFailureCallback = std::function; +template +using ResultCallback = std::function; + +struct IvrSubage { + const bool isSubHidden; + const bool isSubbed; + const QString subTier; + const int totalSubMonths; + const QString followingSince; + + IvrSubage(QJsonObject root) + : isSubHidden(root.value("hidden").toBool()) + , isSubbed(root.value("subscribed").toBool()) + , subTier(root.value("meta").toObject().value("tier").toString()) + , totalSubMonths( + root.value("cumulative").toObject().value("months").toInt()) + , followingSince(root.value("followedAt").toString()) + { + } +}; + +class IvrApi final : boost::noncopyable +{ +public: + // https://api.ivr.fi/docs#tag/Twitch/paths/~1twitch~1subage~1{username}~1{channel}/get + void getSubage(QString userName, QString channelName, + ResultCallback resultCallback, + IvrFailureCallback failureCallback); + + static void initialize(); + +private: + NetworkRequest makeRequest(QString url, QUrlQuery urlQuery); +}; + +IvrApi *getIvr(); + +} // namespace chatterino diff --git a/src/providers/twitch/api/Helix.cpp b/src/providers/twitch/api/Helix.cpp index 974b6212..73c2923c 100644 --- a/src/providers/twitch/api/Helix.cpp +++ b/src/providers/twitch/api/Helix.cpp @@ -52,12 +52,12 @@ void Helix::fetchUsers(QStringList userIds, QStringList userLogins, .execute(); } -void Helix::getUserByName(QString userId, +void Helix::getUserByName(QString userName, ResultCallback successCallback, HelixFailureCallback failureCallback) { QStringList userIds; - QStringList userLogins{userId}; + QStringList userLogins{userName}; this->fetchUsers( userIds, userLogins, diff --git a/src/providers/twitch/api/Kraken.hpp b/src/providers/twitch/api/Kraken.hpp index 047173d6..1a5f4013 100644 --- a/src/providers/twitch/api/Kraken.hpp +++ b/src/providers/twitch/api/Kraken.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index e810f458..3b45891f 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -6,6 +6,7 @@ #include "controllers/accounts/AccountController.hpp" #include "controllers/highlights/HighlightBlacklistUser.hpp" #include "messages/Message.hpp" +#include "providers/IvrApi.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/api/Kraken.hpp" @@ -140,9 +141,9 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically) QUrl("https://twitch.tv/" + this->userName_.toLower())); }); - // items on the right auto vbox = head.emplace(); { + // items on the right { auto box = vbox.emplace() .withoutMargin() @@ -150,18 +151,23 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically) this->ui_.nameLabel = addCopyableLabel(box); this->ui_.nameLabel->setFontStyle(FontStyle::UiMediumBold); box->addStretch(1); - this->ui_.userIDLabel = addCopyableLabel(box); auto palette = QPalette(); palette.setColor(QPalette::WindowText, QColor("#aaa")); + this->ui_.userIDLabel = addCopyableLabel(box); this->ui_.userIDLabel->setPalette(palette); } + // items on the left vbox.emplace