diff --git a/src/Discord.Net.Core/CDN.cs b/src/Discord.Net.Core/CDN.cs
index b170336dc..f46a0697f 100644
--- a/src/Discord.Net.Core/CDN.cs
+++ b/src/Discord.Net.Core/CDN.cs
@@ -47,6 +47,14 @@ namespace Discord
return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}";
}
+ public static string GetGuildUserAvatarUrl(ulong userId, ulong guildId, string avatarId, ushort size, ImageFormat format)
+ {
+ if (avatarId == null)
+ return null;
+ string extension = FormatToExtension(format, avatarId);
+ return $"{DiscordConfig.CDNUrl}guilds/{guildId}/users/{userId}/avatars/{avatarId}.{extension}?size={size}";
+ }
+
///
/// Returns a user banner URL.
///
diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs
index 58a797c5f..947ff8521 100644
--- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs
+++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs
@@ -25,6 +25,13 @@ namespace Discord
///
string Nickname { get; }
///
+ /// Gets the guild specific avatar for this users.
+ ///
+ ///
+ /// The users guild avatar hash if they have one; otherwise .
+ ///
+ string GuildAvatarId { get; }
+ ///
/// Gets the guild-level permissions for this user.
///
///
@@ -96,6 +103,20 @@ namespace Discord
///
ChannelPermissions GetPermissions(IGuildChannel channel);
+ ///
+ /// Gets the guild avatar URL for this user.
+ ///
+ ///
+ /// This property retrieves a URL for this guild user's guild specific avatar. In event that the user does not have a valid guild avatar
+ /// (i.e. their avatar identifier is not set), this method will return null.
+ ///
+ /// The format to return.
+ /// The size of the image to return in. This can be any power of two between 16 and 2048.
+ ///
+ ///
+ /// A string representing the user's avatar URL; null if the user does not have an avatar in place.
+ ///
+ string GetGuildAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128);
///
/// Kicks this user from this guild.
///
diff --git a/src/Discord.Net.Rest/API/Common/GuildMember.cs b/src/Discord.Net.Rest/API/Common/GuildMember.cs
index 53f4908bf..9b888e86a 100644
--- a/src/Discord.Net.Rest/API/Common/GuildMember.cs
+++ b/src/Discord.Net.Rest/API/Common/GuildMember.cs
@@ -9,6 +9,8 @@ namespace Discord.API
public User User { get; set; }
[JsonProperty("nick")]
public Optional Nick { get; set; }
+ [JsonProperty("avatar")]
+ public Optional Avatar { get; set; }
[JsonProperty("roles")]
public Optional Roles { get; set; }
[JsonProperty("joined_at")]
diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
index 556e5e124..2e184d32e 100644
--- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
+++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
@@ -21,6 +21,8 @@ namespace Discord.Rest
///
public string Nickname { get; private set; }
+ ///
+ public string GuildAvatarId { get; private set; }
internal IGuild Guild { get; private set; }
///
public bool IsDeafened { get; private set; }
@@ -80,6 +82,8 @@ namespace Discord.Rest
_joinedAtTicks = model.JoinedAt.Value.UtcTicks;
if (model.Nick.IsSpecified)
Nickname = model.Nick.Value;
+ if (model.Avatar.IsSpecified)
+ GuildAvatarId = model.Avatar.Value;
if (model.Deaf.IsSpecified)
IsDeafened = model.Deaf.Value;
if (model.Mute.IsSpecified)
@@ -156,6 +160,9 @@ namespace Discord.Rest
var guildPerms = GuildPermissions;
return new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, guildPerms.RawValue));
}
+
+ public string GetGuildAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128)
+ => CDN.GetGuildUserAvatarUrl(Id, GuildId, GuildAvatarId, size, format);
#endregion
#region IGuildUser
diff --git a/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs b/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs
index 561cd92ee..2cd19da41 100644
--- a/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs
+++ b/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs
@@ -54,6 +54,10 @@ namespace Discord.Rest
///
string IGuildUser.Nickname => null;
///
+ string IGuildUser.GuildAvatarId => null;
+ ///
+ string IGuildUser.GetGuildAvatarUrl(ImageFormat format, ushort size) => null;
+ ///
bool? IGuildUser.IsPending => null;
///
int IGuildUser.Hierarchy => 0;
diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
index 8dd48891b..314471b17 100644
--- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
+++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
@@ -30,7 +30,8 @@ namespace Discord.WebSocket
public SocketGuild Guild { get; }
///
public string Nickname { get; private set; }
-
+ ///
+ public string GuildAvatarId { get; private set; }
///
public override bool IsBot { get { return GlobalUser.IsBot; } internal set { GlobalUser.IsBot = value; } }
///
@@ -154,6 +155,8 @@ namespace Discord.WebSocket
_joinedAtTicks = model.JoinedAt.Value.UtcTicks;
if (model.Nick.IsSpecified)
Nickname = model.Nick.Value;
+ if (model.Avatar.IsSpecified)
+ GuildAvatarId = model.Avatar.Value;
if (model.Roles.IsSpecified)
UpdateRoles(model.Roles.Value);
if (model.PremiumSince.IsSpecified)
@@ -218,6 +221,8 @@ namespace Discord.WebSocket
///
public ChannelPermissions GetPermissions(IGuildChannel channel)
=> new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, GuildPermissions.RawValue));
+ public string GetGuildAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128)
+ => CDN.GetGuildUserAvatarUrl(Id, Guild.Id, GuildAvatarId, size, format);
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Guild)";
internal new SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser;
diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs
index c91921379..42fb807a1 100644
--- a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs
+++ b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs
@@ -52,6 +52,9 @@ namespace Discord.WebSocket
get => GuildUser.AvatarId;
internal set => GuildUser.AvatarId = value;
}
+ ///
+ public string GuildAvatarId
+ => GuildUser.GuildAvatarId;
///
public override string BannerId
@@ -205,6 +208,8 @@ namespace Discord.WebSocket
///
IReadOnlyCollection IGuildUser.RoleIds => GuildUser.Roles.Select(x => x.Id).ToImmutableArray();
+ string IGuildUser.GetGuildAvatarUrl(ImageFormat format, ushort size) => GuildUser.GetGuildAvatarUrl(format, size);
+
internal override SocketGlobalUser GlobalUser => GuildUser.GlobalUser;
internal override SocketPresence Presence { get => GuildUser.Presence; set => GuildUser.Presence = value; }
diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs
index d68414ebb..7cc7d5a44 100644
--- a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs
+++ b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs
@@ -81,6 +81,10 @@ namespace Discord.WebSocket
///
string IGuildUser.Nickname => null;
///
+ string IGuildUser.GuildAvatarId => null;
+ ///
+ string IGuildUser.GetGuildAvatarUrl(ImageFormat format, ushort size) => null;
+ ///
DateTimeOffset? IGuildUser.PremiumSince => null;
///
bool? IGuildUser.IsPending => null;