From 39120a65fad8686c0b69fb8302f21790636aeb41 Mon Sep 17 00:00:00 2001 From: Rafael Bradley Date: Sun, 24 Aug 2025 15:45:54 -0300 Subject: [PATCH] Add links to reply embeds and fix nitro custom server avatars not displaying --- src/discord/images.rs | 12 ++++++++--- src/groups/about/embeds.rs | 6 ++++++ src/groups/calls/embeds.rs | 8 ++++++++ src/groups/calls/events.rs | 31 +++++++++++++++++++++++++++-- src/groups/leveling/commands.rs | 3 +++ src/groups/moderation/components.rs | 2 +- 6 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/discord/images.rs b/src/discord/images.rs index c6012f0..11307dc 100644 --- a/src/discord/images.rs +++ b/src/discord/images.rs @@ -8,15 +8,21 @@ use twilight_model::util::ImageHash; /// * `hash` - The user's avatar hash (if available). /// * `user_id` - The user's ID. /// * `discriminator` - The user's discriminator. +/// * `guild_id` - The guild ID, **only set if the user has Nitro and a custom avatar for the +/// server. Otherwise, even in a server, this is NOT SET**. /// /// Returns: /// [`String`] - The URL of the user's avatar. -pub fn get_avatar_url(hash: Option, user_id: u64, discriminator: u64) -> String { +pub fn get_avatar_url(hash: Option, user_id: u64, discriminator: u64, guild_id: Option) -> String { if let Some(hash) = hash { - format!("https://cdn.discordapp.com/avatars/{user_id}/{hash}.png?size=256") + if let Some(guild_id) = guild_id { + return format!("https://cdn.discordapp.com/guilds/{guild_id}/users/{user_id}/avatars/{hash}.webp?size=256"); + } + + format!("https://cdn.discordapp.com/avatars/{user_id}/{hash}.webp?size=256") } else { format!( - "https://cdn.discordapp.com/embed/avatars/{}.png?size=256", + "https://cdn.discordapp.com/embed/avatars/{}.webp?size=256", match discriminator.to_string().as_str() { "0" => (user_id >> 22) % 6, _ => discriminator % 6, diff --git a/src/groups/about/embeds.rs b/src/groups/about/embeds.rs index 56d8c6c..ea8cc3c 100644 --- a/src/groups/about/embeds.rs +++ b/src/groups/about/embeds.rs @@ -43,6 +43,7 @@ pub(super) fn get_command_help_embed( ctx.rt.app.bot.as_ref().unwrap().avatar, ctx.rt.app.bot.as_ref().unwrap().id.get(), ctx.rt.app.bot.as_ref().unwrap().discriminator as u64, + None, )) .unwrap(), ) @@ -53,6 +54,7 @@ pub(super) fn get_command_help_embed( ctx.rt.app.bot.as_ref().unwrap().avatar, ctx.rt.app.bot.as_ref().unwrap().id.get(), ctx.rt.app.bot.as_ref().unwrap().discriminator as u64, + None, )) .unwrap(), ) @@ -90,6 +92,7 @@ pub(super) fn get_all_command_help_embed( rt.app.bot.as_ref().unwrap().avatar, rt.app.bot.as_ref().unwrap().id.get(), rt.app.bot.as_ref().unwrap().discriminator as u64, + None )) .unwrap())) .title("Pick up the phone and start making friends!") @@ -98,6 +101,7 @@ pub(super) fn get_all_command_help_embed( rt.app.bot.as_ref().unwrap().avatar, rt.app.bot.as_ref().unwrap().id.get(), rt.app.bot.as_ref().unwrap().discriminator as u64, + None )) .unwrap()) .color(COLOR_WHITE) @@ -125,6 +129,7 @@ pub(super) fn get_command_not_found_embed(rt: &Runtime, name: Stri rt.app.bot.as_ref().unwrap().avatar, rt.app.bot.as_ref().unwrap().id.get(), rt.app.bot.as_ref().unwrap().discriminator as u64, + None )) .unwrap())) .title("That's not a command") @@ -133,6 +138,7 @@ pub(super) fn get_command_not_found_embed(rt: &Runtime, name: Stri rt.app.bot.as_ref().unwrap().avatar, rt.app.bot.as_ref().unwrap().id.get(), rt.app.bot.as_ref().unwrap().discriminator as u64, + None )) .unwrap()) .build() diff --git a/src/groups/calls/embeds.rs b/src/groups/calls/embeds.rs index f51505e..b709fc4 100644 --- a/src/groups/calls/embeds.rs +++ b/src/groups/calls/embeds.rs @@ -27,6 +27,7 @@ pub fn first_warning_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None ) ).unwrap() ) @@ -49,6 +50,7 @@ pub fn first_warning_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None )) .unwrap() ) @@ -70,6 +72,7 @@ pub fn repeat_warning_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None ) ).unwrap() ) @@ -92,6 +95,7 @@ pub fn repeat_warning_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None )) .unwrap() ) @@ -113,6 +117,7 @@ pub fn first_ban_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None ) ).unwrap() ) @@ -135,6 +140,7 @@ pub fn first_ban_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None )) .unwrap() ) @@ -156,6 +162,7 @@ pub fn final_ban_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None ) ).unwrap() ) @@ -178,6 +185,7 @@ pub fn final_ban_embed( app.icon, app.bot.as_ref().unwrap().id.get(), app.bot.as_ref().unwrap().discriminator as u64, + None ) ).unwrap() ) diff --git a/src/groups/calls/events.rs b/src/groups/calls/events.rs index 4ab4225..62c0734 100644 --- a/src/groups/calls/events.rs +++ b/src/groups/calls/events.rs @@ -6,6 +6,7 @@ use time::{Duration, UtcDateTime}; use twilight_http::{api_error::ApiError, error::ErrorType}; use twilight_model::{ gateway::payload::incoming::{MessageCreate, MessageDelete, MessageUpdate}, + guild, id::Id, }; use twilight_util::{ @@ -110,6 +111,10 @@ impl OnMessageHandler for CallMessageHandler { return Ok(()); } + let Some(guild_id) = event.guild_id else { + return Ok(()); + }; + let prefixes = rt .get_prefixes(event.guild_id.map(|i| i.get()), Some(event.author.id.get())) .await; @@ -252,6 +257,11 @@ impl OnMessageHandler for CallMessageHandler { .or(event.author.avatar), event.author.id.get(), event.author.discriminator as u64, + event + .member + .as_ref() + .and_then(|member| member.avatar) + .map(|_| guild_id.get()), ), user.is_masked, &rt.state.db, @@ -291,7 +301,11 @@ impl OnMessageHandler for CallMessageHandler { let mut embeds = vec![]; if let Some(replying_to) = replying_to { - if let Some(propagation_channel_id) = replying_to.data.propagation_channel_id { + if let Some((propagation_channel_id, propagation_message_id)) = replying_to + .data + .propagation_channel_id + .zip(replying_to.data.propagation_message_id) + { let (display_name, avatar_url) = if let Some(mask) = replying_to.data.author_mask { ( @@ -313,11 +327,24 @@ impl OnMessageHandler for CallMessageHandler { ) }; + let message_link = if i64_to_u64(propagation_channel_id) == channel.id { + format!( + "https://discord.com/channels/{}/{}/{}", + opposite_channel.server_id, opposite_channel.id, replying_to.message_id + ) + } else { + format!( + "https://discord.com/channels/{}/{}/{}", + channel.server_id, propagation_channel_id, propagation_message_id + ) + }; + embeds.push( EmbedBuilder::new() .author( EmbedAuthorBuilder::new(format!("Replying to {display_name}",)) - .icon_url(ImageSource::url(avatar_url).unwrap()), + .icon_url(ImageSource::url(avatar_url).unwrap()) + .url(message_link), ) .color(COLOR_WHITE) .description(ellipse(replying_to.data.content, 100)) diff --git a/src/groups/leveling/commands.rs b/src/groups/leveling/commands.rs index 5803009..eb1ec35 100644 --- a/src/groups/leveling/commands.rs +++ b/src/groups/leveling/commands.rs @@ -99,6 +99,7 @@ impl Command for LeaderboardCommand { ctx.rt.app.bot.as_ref().unwrap().avatar, ctx.rt.app.bot.as_ref().unwrap().id.get(), ctx.rt.app.bot.as_ref().unwrap().discriminator as u64, + None, )) .unwrap(), ), @@ -108,6 +109,7 @@ impl Command for LeaderboardCommand { ctx.rt.app.bot.as_ref().unwrap().avatar, ctx.rt.app.bot.as_ref().unwrap().id.get(), ctx.rt.app.bot.as_ref().unwrap().discriminator as u64, + None, )) .unwrap(), ) @@ -117,6 +119,7 @@ impl Command for LeaderboardCommand { ctx.event.author.avatar, ctx.event.author.id.get(), ctx.event.author.discriminator as u64, + None, )) .unwrap(), ), diff --git a/src/groups/moderation/components.rs b/src/groups/moderation/components.rs index 558bb2b..f4a72c4 100644 --- a/src/groups/moderation/components.rs +++ b/src/groups/moderation/components.rs @@ -24,7 +24,7 @@ impl Button for ArrowIncidentButton { } fn label(&self) -> Option { - Some(format!("{}", self.arrow)) + Some(self.arrow.to_string()) } fn disabled(&self) -> bool {