diff --git a/CHANGELOG.md b/CHANGELOG.md index 907bb1356..9fe6aa1c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Bugfix: Fixed pasting text with URLs included (#1688, #2855) - Bugfix: Fix reconnecting when IRC write connection is lost (#1831, #2356, #2850, #2892) - Bugfix: Fixed bit and new subscriber emotes not (re)loading in some rare cases. (#2856, #2857) +- Bugfix: Fixed subscription emotes showing up incorrectly in the emote menu. (#2905) ## 2.3.2 diff --git a/src/providers/twitch/TwitchAccount.cpp b/src/providers/twitch/TwitchAccount.cpp index 6f70386f3..580ee89ba 100644 --- a/src/providers/twitch/TwitchAccount.cpp +++ b/src/providers/twitch/TwitchAccount.cpp @@ -358,7 +358,6 @@ void TwitchAccount::loadUserstateEmotes() name[0] = name[0].toUpper(); newUserEmoteSet->text = name; - newUserEmoteSet->type = QString(); newUserEmoteSet->channelName = ivrEmoteSet.login; for (const auto &emote : ivrEmoteSet.emotes) @@ -508,38 +507,48 @@ void TwitchAccount::loadEmoteSetData(std::shared_ptr emoteSet) return; } - NetworkRequest(Env::get().twitchEmoteSetResolverUrl.arg(emoteSet->key)) - .cache() - .onSuccess([emoteSet](NetworkResult result) -> Outcome { - auto root = result.parseJson(); - if (root.isEmpty()) + getHelix()->getEmoteSetData( + emoteSet->key, + [emoteSet](HelixEmoteSetData emoteSetData) { + if (emoteSetData.ownerId.isEmpty() || + emoteSetData.setId != emoteSet->key) { - return Failure; + qCWarning(chatterinoTwitch) + << QString("Failed to fetch emoteSetData for %1, assuming " + "Twitch is the owner") + .arg(emoteSet->key); + + // most (if not all) emotes that fail to load are time limited event emotes owned by Twitch + emoteSet->channelName = "twitch"; + emoteSet->text = "Twitch"; + + return; } - TwitchEmoteSetResolverResponse response(root); + // emote set 0 = global emotes + if (emoteSetData.ownerId == "0") + { + // emoteSet->channelName = QString(); + emoteSet->text = "Twitch Global"; + return; + } - auto name = response.channelName; - name.detach(); - name[0] = name[0].toUpper(); - - emoteSet->text = name; - emoteSet->type = response.type; - emoteSet->channelName = response.channelName; - - qCDebug(chatterinoTwitch) - << QString("Loaded twitch emote set data for %1") - .arg(emoteSet->key); - - return Success; - }) - .onError([emoteSet](NetworkResult result) { - qCWarning(chatterinoTwitch) - << QString("Error code %1 while loading emote set data for %2") - .arg(result.status()) - .arg(emoteSet->key); - }) - .execute(); + getHelix()->getUserById( + emoteSetData.ownerId, + [emoteSet](HelixUser user) { + emoteSet->channelName = user.login; + emoteSet->text = user.displayName; + }, + [emoteSetData] { + qCWarning(chatterinoTwitch) + << "Failed to query user by id:" << emoteSetData.ownerId + << emoteSetData.setId; + }); + }, + [emoteSet] { + // fetching emoteset data failed + return; + }); } } // namespace chatterino diff --git a/src/providers/twitch/TwitchAccount.hpp b/src/providers/twitch/TwitchAccount.hpp index 761a583ed..fc1918b1e 100644 --- a/src/providers/twitch/TwitchAccount.hpp +++ b/src/providers/twitch/TwitchAccount.hpp @@ -62,7 +62,6 @@ public: QString key; QString channelName; QString text; - QString type; std::vector emotes; }; diff --git a/src/providers/twitch/api/Helix.cpp b/src/providers/twitch/api/Helix.cpp index a105914a3..c430b59cf 100644 --- a/src/providers/twitch/api/Helix.cpp +++ b/src/providers/twitch/api/Helix.cpp @@ -761,6 +761,38 @@ void Helix::getCheermotes( .execute(); } +void Helix::getEmoteSetData(QString emoteSetId, + ResultCallback successCallback, + HelixFailureCallback failureCallback) +{ + QUrlQuery urlQuery; + + urlQuery.addQueryItem("emote_set_id", emoteSetId); + + this->makeRequest("chat/emotes/set", urlQuery) + .onSuccess([successCallback, failureCallback, + emoteSetId](auto result) -> Outcome { + QJsonObject root = result.parseJson(); + auto data = root.value("data"); + + if (!data.isArray()) + { + failureCallback(); + return Failure; + } + + HelixEmoteSetData emoteSetData(data.toArray()[0].toObject()); + + successCallback(emoteSetData); + return Success; + }) + .onError([failureCallback](NetworkResult result) { + // TODO: make better xd + failureCallback(); + }) + .execute(); +} + NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery) { assert(!url.startsWith("/")); diff --git a/src/providers/twitch/api/Helix.hpp b/src/providers/twitch/api/Helix.hpp index 6e0273918..a4f745a75 100644 --- a/src/providers/twitch/api/Helix.hpp +++ b/src/providers/twitch/api/Helix.hpp @@ -264,6 +264,17 @@ struct HelixCheermoteSet { } }; +struct HelixEmoteSetData { + QString setId; + QString ownerId; + + explicit HelixEmoteSetData(QJsonObject jsonObject) + : setId(jsonObject.value("emote_set_id").toString()) + , ownerId(jsonObject.value("owner_id").toString()) + { + } +}; + enum class HelixClipError { Unknown, ClipsDisabled, @@ -398,6 +409,11 @@ public: ResultCallback> successCallback, HelixFailureCallback failureCallback); + // https://dev.twitch.tv/docs/api/reference#get-emote-sets + void getEmoteSetData(QString emoteSetId, + ResultCallback successCallback, + HelixFailureCallback failureCallback); + void update(QString clientId, QString oauthToken); static void initialize(); diff --git a/src/providers/twitch/api/README.md b/src/providers/twitch/api/README.md index 9b24e8f7e..2a4a2dede 100644 --- a/src/providers/twitch/api/README.md +++ b/src/providers/twitch/api/README.md @@ -157,6 +157,14 @@ URL: https://dev.twitch.tv/docs/api/reference/#get-cheermotes Used in: - `providers/twitch/TwitchChannel.cpp` to resolve a chats available cheer emotes. This helps us parse incoming messages like `pajaCheer1000` +### Get Emote Sets + +URL: https://dev.twitch.tv/docs/api/reference#get-emote-sets + +- We implement this in `providers/twitch/api/Helix.cpp getEmoteSetData` + Used in: + - `providers/twitch/TwitchAccount.cpp` to set emoteset owner data upon loading subscriber emotes from Kraken + ## TMI The TMI api is undocumented. diff --git a/src/widgets/dialogs/EmotePopup.cpp b/src/widgets/dialogs/EmotePopup.cpp index 90bb80c60..ce839b4b7 100644 --- a/src/widgets/dialogs/EmotePopup.cpp +++ b/src/widgets/dialogs/EmotePopup.cpp @@ -71,8 +71,7 @@ namespace { { // TITLE auto channelName = set->channelName; - auto text = - set->key == "0" || set->text.isEmpty() ? "Twitch" : set->text; + auto text = set->text.isEmpty() ? "Twitch" : set->text; // EMOTES MessageBuilder builder;