Migrate to the new Get Channel Followers Helix endpoint, fixing follower count not showing up in usercards (#4809)

This commit is contained in:
pajlada 2023-09-09 14:51:45 +02:00 committed by Rasmus Karlsson
parent 896f12c814
commit 116af46004
5 changed files with 60 additions and 98 deletions

View file

@ -2,6 +2,7 @@
## Unversioned
- Minor: Migrate to the new Get Channel Followers Helix endpoint, fixing follower count not showing up in usercards. (#4809)
- Dev: Temporarily disable High DPI scaling on Qt6 builds on Windows. (#4767)
## 2.4.5

View file

@ -31,17 +31,12 @@ public:
HelixFailureCallback failureCallback),
(override));
MOCK_METHOD(void, fetchUsersFollows,
(QString fromId, QString toId,
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback),
(override));
MOCK_METHOD(void, getUserFollowers,
(QString userId,
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback),
(override));
MOCK_METHOD(
void, getChannelFollowers,
(QString broadcasterID,
ResultCallback<HelixGetChannelFollowersResponse> successCallback,
std::function<void(QString)> failureCallback),
(override));
MOCK_METHOD(void, fetchStreams,
(QStringList userIds, QStringList userLogins,

View file

@ -126,52 +126,43 @@ void Helix::getUserById(QString userId,
failureCallback);
}
void Helix::fetchUsersFollows(
QString fromId, QString toId,
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback)
void Helix::getChannelFollowers(
QString broadcasterID,
ResultCallback<HelixGetChannelFollowersResponse> successCallback,
std::function<void(QString)> failureCallback)
{
assert(!fromId.isEmpty() || !toId.isEmpty());
assert(!broadcasterID.isEmpty());
QUrlQuery urlQuery;
if (!fromId.isEmpty())
{
urlQuery.addQueryItem("from_id", fromId);
}
if (!toId.isEmpty())
{
urlQuery.addQueryItem("to_id", toId);
}
urlQuery.addQueryItem("broadcaster_id", broadcasterID);
// TODO: set on success and on error
this->makeGet("users/follows", urlQuery)
this->makeGet("channels/followers", urlQuery)
.onSuccess([successCallback, failureCallback](auto result) -> Outcome {
auto root = result.parseJson();
if (root.empty())
{
failureCallback();
failureCallback("Bad JSON response");
return Failure;
}
successCallback(HelixUsersFollowsResponse(root));
successCallback(HelixGetChannelFollowersResponse(root));
return Success;
})
.onError([failureCallback](auto /*result*/) {
// TODO: make better xd
failureCallback();
.onError([failureCallback](auto result) {
auto root = result.parseJson();
if (root.empty())
{
failureCallback("Unknown error");
return;
}
// Forward "message" from Twitch
HelixError error(root);
failureCallback(error.message);
})
.execute();
}
void Helix::getUserFollowers(
QString userId, ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback)
{
this->fetchUsersFollows("", std::move(userId), std::move(successCallback),
std::move(failureCallback));
}
void Helix::fetchStreams(
QStringList userIds, QStringList userLogins,
ResultCallback<std::vector<HelixStream>> successCallback,

View file

@ -45,44 +45,12 @@ struct HelixUser {
}
};
struct HelixUsersFollowsRecord {
QString fromId;
QString fromName;
QString toId;
QString toName;
QString followedAt; // date time object
HelixUsersFollowsRecord()
: fromId("")
, fromName("")
, toId("")
, toName("")
, followedAt("")
{
}
explicit HelixUsersFollowsRecord(QJsonObject jsonObject)
: fromId(jsonObject.value("from_id").toString())
, fromName(jsonObject.value("from_name").toString())
, toId(jsonObject.value("to_id").toString())
, toName(jsonObject.value("to_name").toString())
, followedAt(jsonObject.value("followed_at").toString())
{
}
};
struct HelixUsersFollowsResponse {
struct HelixGetChannelFollowersResponse {
int total;
std::vector<HelixUsersFollowsRecord> data;
explicit HelixUsersFollowsResponse(QJsonObject jsonObject)
explicit HelixGetChannelFollowersResponse(const QJsonObject &jsonObject)
: total(jsonObject.value("total").toInt())
{
const auto &jsonData = jsonObject.value("data").toArray();
std::transform(jsonData.begin(), jsonData.end(),
std::back_inserter(this->data),
[](const QJsonValue &record) {
return HelixUsersFollowsRecord(record.toObject());
});
}
};
@ -720,6 +688,22 @@ enum class HelixGetGlobalBadgesError {
Forwarded,
};
struct HelixError {
/// Text version of the HTTP error that happened (e.g. Bad Request)
QString error;
/// Number version of the HTTP error that happened (e.g. 400)
int status;
/// The error message string
QString message;
explicit HelixError(const QJsonObject &json)
: error(json["error"].toString())
, status(json["status"].toInt())
, message(json["message"].toString())
{
}
};
using HelixGetChannelBadgesError = HelixGetGlobalBadgesError;
class IHelix
@ -740,16 +724,11 @@ public:
ResultCallback<HelixUser> successCallback,
HelixFailureCallback failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference#get-users-follows
virtual void fetchUsersFollows(
QString fromId, QString toId,
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback) = 0;
virtual void getUserFollowers(
QString userId,
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference/#get-channel-followers
virtual void getChannelFollowers(
QString broadcasterID,
ResultCallback<HelixGetChannelFollowersResponse> successCallback,
std::function<void(QString)> failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference#get-streams
virtual void fetchStreams(
@ -1064,16 +1043,11 @@ public:
void getUserById(QString userId, ResultCallback<HelixUser> successCallback,
HelixFailureCallback failureCallback) final;
// https://dev.twitch.tv/docs/api/reference#get-users-follows
void fetchUsersFollows(
QString fromId, QString toId,
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback) final;
void getUserFollowers(
QString userId,
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback) final;
// https://dev.twitch.tv/docs/api/reference/#get-channel-followers
void getChannelFollowers(
QString broadcasterID,
ResultCallback<HelixGetChannelFollowersResponse> successCallback,
std::function<void(QString)> failureCallback) final;
// https://dev.twitch.tv/docs/api/reference#get-streams
void fetchStreams(QStringList userIds, QStringList userLogins,

View file

@ -817,7 +817,7 @@ void UserInfoPopup::updateUserData()
this->loadAvatar(user.profileImageUrl);
}
getHelix()->getUserFollowers(
getHelix()->getChannelFollowers(
user.id,
[this, hack](const auto &followers) {
if (!hack.lock())
@ -827,8 +827,9 @@ void UserInfoPopup::updateUserData()
this->ui_.followerCountLabel->setText(
TEXT_FOLLOWERS.arg(localizeNumbers(followers.total)));
},
[] {
// on failure
[](const auto &errorMessage) {
qCWarning(chatterinoTwitch)
<< "Error getting followers:" << errorMessage;
});
// get ignore state