From 9d0de1c373b166c2b7f6111e50b0fcb430557ea0 Mon Sep 17 00:00:00 2001 From: treuks Date: Sat, 22 Mar 2025 13:45:47 +0200 Subject: [PATCH] feat: Use streamer profile picture for shared chat badge (#5760) Co-authored-by: Rasmus Karlsson Co-authored-by: Nerixyz --- CHANGELOG.md | 1 + src/messages/MessageBuilder.cpp | 57 +++++++++++++++++++++++----- src/providers/twitch/TwitchUser.cpp | 1 + src/providers/twitch/TwitchUser.hpp | 2 + src/providers/twitch/TwitchUsers.cpp | 1 + 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e11763de..3b1e5487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unversioned +- Minor: Shared chat messages now use the source channel's profile picture to denote it's a shared chat message. (#5760) - Minor: Moved the "Delete message" menu option into a "Moderate" sub-menu. (#6100) - Bugfix: Fixed the channel name input not being focused when opening the select-channel dialog. (#6096) - Bugfix: Fixed inputs in dialogs not having a border around and padding in them. (#6098) diff --git a/src/messages/MessageBuilder.cpp b/src/messages/MessageBuilder.cpp index 3c2d0b3c..920d8a43 100644 --- a/src/messages/MessageBuilder.cpp +++ b/src/messages/MessageBuilder.cpp @@ -385,8 +385,36 @@ EmotePtr makeAutoModBadge() Url{"https://dashboard.twitch.tv/settings/moderation/automod"}}); } -EmotePtr makeSharedChatBadge(const QString &sourceName) +EmotePtr makeSharedChatBadge(const QString &sourceName, + const QString &sourceProfileURL, + const QString &sourceLogin) { + if (!sourceProfileURL.isEmpty()) + { + QString modifiedUrl = sourceProfileURL; + modifiedUrl.replace("300x300", "28x28"); + + auto badgeLink = [&] { + if (sourceLogin.isEmpty()) + { + return Url{"https://link.twitch.tv/SharedChatViewer"}; + } + + return Url{u"https://twitch.tv/%1"_s.arg(sourceLogin)}; + }(); + + return std::make_shared(Emote{ + .name = EmoteName{}, + .images = ImageSet{Image::fromUrl( + Url{modifiedUrl}, + 18.F / 28.F)}, // get as close to 18x18 as possible + .tooltip = + Tooltip{"Shared Message" + + (sourceName.isEmpty() ? "" : " from " + sourceName)}, + .homePage = badgeLink, + }); + } + return std::make_shared(Emote{ .name = EmoteName{}, .images = ImageSet{Image::fromResourcePixmap( @@ -2985,22 +3013,33 @@ void MessageBuilder::appendTwitchBadges(const QVariantMap &tags, { const QString sourceId = tags["source-room-id"].toString(); QString sourceName; + QString sourceProfilePicture; + QString sourceLogin; + if (sourceId.isEmpty()) { sourceName = ""; } - else if (twitchChannel->roomId() == sourceId) - { - sourceName = twitchChannel->getName(); - } else { - sourceName = - getApp()->getTwitchUsers()->resolveID({sourceId})->displayName; + auto twitchUser = getApp()->getTwitchUsers()->resolveID({sourceId}); + sourceProfilePicture = twitchUser->profilePictureUrl; + sourceLogin = twitchUser->name; + + if (twitchChannel->roomId() == sourceId) + { + // We have the source channel open, but we still need to load the profile picture URL + sourceName = twitchChannel->getName(); + } + else + { + sourceName = twitchUser->displayName; + } } - this->emplace(makeSharedChatBadge(sourceName), - MessageElementFlag::BadgeSharedChannel); + this->emplace( + makeSharedChatBadge(sourceName, sourceProfilePicture, sourceLogin), + MessageElementFlag::BadgeSharedChannel); } auto badgeInfos = parseBadgeInfoTag(tags); diff --git a/src/providers/twitch/TwitchUser.cpp b/src/providers/twitch/TwitchUser.cpp index 655e2061..edc39c18 100644 --- a/src/providers/twitch/TwitchUser.cpp +++ b/src/providers/twitch/TwitchUser.cpp @@ -18,6 +18,7 @@ void TwitchUser::update(const HelixUser &user) const assert(this->id == user.id); this->name = user.login; this->displayName = user.displayName; + this->profilePictureUrl = user.profileImageUrl; } } // namespace chatterino diff --git a/src/providers/twitch/TwitchUser.hpp b/src/providers/twitch/TwitchUser.hpp index bc1b0837..932e8829 100644 --- a/src/providers/twitch/TwitchUser.hpp +++ b/src/providers/twitch/TwitchUser.hpp @@ -18,6 +18,7 @@ struct TwitchUser { QString id; mutable QString name; mutable QString displayName; + mutable QString profilePictureUrl; void update(const TwitchUser &other) const { @@ -25,6 +26,7 @@ struct TwitchUser { this->name = other.name; this->displayName = other.displayName; + this->profilePictureUrl = other.profilePictureUrl; } void update(const HelixUser &user) const; diff --git a/src/providers/twitch/TwitchUsers.cpp b/src/providers/twitch/TwitchUsers.cpp index 583d662c..eb17965c 100644 --- a/src/providers/twitch/TwitchUsers.cpp +++ b/src/providers/twitch/TwitchUsers.cpp @@ -82,6 +82,7 @@ std::shared_ptr TwitchUsersPrivate::makeUnresolved(const UserId &id) .id = id.string, .name = {}, .displayName = {}, + .profilePictureUrl = {}, })) .first->second; if (id.string.isEmpty())