Browse Source

Add Guild Member avatar (#1077)

* Add guild member avatar

* add avatar field on Member struct

* add endpoints for guild avatars

* add avatarURL util function for *User.AvatarURL and *Member.AvatarURL

* set GuildID on after GuildMember request

* fix Member.Avatar comment

* fix: gofmt

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>
Andres Perez 3 years ago
parent
commit
dd5b9c6c05
5 changed files with 45 additions and 15 deletions
  1. 7 0
      endpoints.go
  2. 2 0
      restapi.go
  3. 17 0
      structs.go
  4. 2 15
      user.go
  5. 17 0
      util.go

+ 7 - 0
endpoints.go

@@ -40,6 +40,7 @@ var (
 	EndpointCDNSplashes     = EndpointCDN + "splashes/"
 	EndpointCDNChannelIcons = EndpointCDN + "channel-icons/"
 	EndpointCDNBanners      = EndpointCDN + "banners/"
+	EndpointCDNGuilds       = EndpointCDN + "guilds/"
 
 	EndpointVoice        = EndpointAPI + "/voice/"
 	EndpointVoiceRegions = EndpointVoice + "regions"
@@ -90,6 +91,12 @@ var (
 	EndpointGuildTemplate      = func(tID string) string { return EndpointGuilds + "/templates/" + tID }
 	EndpointGuildTemplates     = func(gID string) string { return EndpointGuilds + gID + "/templates" }
 	EndpointGuildTemplateSync  = func(gID, tID string) string { return EndpointGuilds + gID + "/templates/" + tID }
+	EndpointGuildMemberAvatar  = func(gId, uID, aID string) string {
+		return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".png"
+	}
+	EndpointGuildMemberAvatarAnimated = func(gId, uID, aID string) string {
+		return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".gif"
+	}
 
 	EndpointChannel                             = func(cID string) string { return EndpointChannels + cID }
 	EndpointChannelThreads                      = func(cID string) string { return EndpointChannel(cID) + "/threads" }

+ 2 - 0
restapi.go

@@ -642,6 +642,8 @@ func (s *Session) GuildMember(guildID, userID string) (st *Member, err error) {
 	}
 
 	err = unmarshal(body, &st)
+	// The returned object doesn't have the GuildID attribute so we will set it here.
+	st.GuildID = guildID
 	return
 }
 

+ 17 - 0
structs.go

@@ -985,6 +985,9 @@ type Member struct {
 	// Whether the member is muted at a guild level.
 	Mute bool `json:"mute"`
 
+	// The hash of the avatar for the guild member, if any.
+	Avatar string `json:"avatar"`
+
 	// The underlying user on which the member is based.
 	User *User `json:"user"`
 
@@ -1010,6 +1013,20 @@ func (m *Member) Mention() string {
 	return "<@!" + m.User.ID + ">"
 }
 
+// AvatarURL returns the URL of the member's avatar
+//    size:    The size of the user's avatar as a power of two
+//             if size is an empty string, no size parameter will
+//             be added to the URL.
+func (m *Member) AvatarURL(size string) string {
+	if m.Avatar == "" {
+		return m.User.AvatarURL(size)
+	}
+	// The default/empty avatar case should be handled by the above condition
+	return avatarURL(m.Avatar, "", EndpointGuildMemberAvatar(m.GuildID, m.User.ID, m.Avatar),
+		EndpointGuildMemberAvatarAnimated(m.GuildID, m.User.ID, m.Avatar), size)
+
+}
+
 // A Settings stores data for a specific users Discord client settings.
 type Settings struct {
 	RenderEmbeds           bool               `json:"render_embeds"`

+ 2 - 15
user.go

@@ -1,7 +1,5 @@
 package discordgo
 
-import "strings"
-
 // UserFlags is the flags of "user" (see UserFlags* consts)
 // https://discord.com/developers/docs/resources/user#user-object-user-flags
 type UserFlags int
@@ -91,17 +89,6 @@ func (u *User) Mention() string {
 //             if size is an empty string, no size parameter will
 //             be added to the URL.
 func (u *User) AvatarURL(size string) string {
-	var URL string
-	if u.Avatar == "" {
-		URL = EndpointDefaultUserAvatar(u.Discriminator)
-	} else if strings.HasPrefix(u.Avatar, "a_") {
-		URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
-	} else {
-		URL = EndpointUserAvatar(u.ID, u.Avatar)
-	}
-
-	if size != "" {
-		return URL + "?size=" + size
-	}
-	return URL
+	return avatarURL(u.Avatar, EndpointDefaultUserAvatar(u.Discriminator),
+		EndpointUserAvatar(u.ID, u.Avatar), EndpointUserAvatarAnimated(u.ID, u.Avatar), size)
 }

+ 17 - 0
util.go

@@ -8,6 +8,7 @@ import (
 	"mime/multipart"
 	"net/textproto"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -75,3 +76,19 @@ func MultipartBodyWithJSON(data interface{}, files []*File) (requestContentType
 
 	return bodywriter.FormDataContentType(), body.Bytes(), nil
 }
+
+func avatarURL(avatarHash, defaultAvatarURL, staticAvatarURL, animatedAvatarURL, size string) string {
+	var URL string
+	if avatarHash == "" {
+		URL = defaultAvatarURL
+	} else if strings.HasPrefix(avatarHash, "a_") {
+		URL = animatedAvatarURL
+	} else {
+		URL = staticAvatarURL
+	}
+
+	if size != "" {
+		return URL + "?size=" + size
+	}
+	return URL
+}