diff --git a/endpoints.go b/endpoints.go index a2a05fe3e..22e391f19 100644 --- a/endpoints.go +++ b/endpoints.go @@ -49,9 +49,8 @@ var ( EndpointUser = func(uID string) string { return EndpointUsers + uID } EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" } EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" } - EndpointDefaultUserAvatar = func(uDiscriminator string) string { - uDiscriminatorInt, _ := strconv.Atoi(uDiscriminator) - return EndpointCDN + "embed/avatars/" + strconv.Itoa(uDiscriminatorInt%5) + ".png" + EndpointDefaultUserAvatar = func(idx int) string { + return EndpointCDN + "embed/avatars/" + strconv.Itoa(idx) + ".png" } EndpointUserBanner = func(uID, cID string) string { return EndpointCDNBanners + uID + "/" + cID + ".png" diff --git a/user.go b/user.go index 6c48bf25b..5a91adf70 100644 --- a/user.go +++ b/user.go @@ -1,5 +1,9 @@ package discordgo +import ( + "strconv" +) + // UserFlags is the flags of "user" (see UserFlags* consts) // https://discord.com/developers/docs/resources/user#user-object-user-flags type UserFlags int @@ -44,6 +48,10 @@ type User struct { // The discriminator of the user (4 numbers after name). Discriminator string `json:"discriminator"` + // The user's display name, if it is set. + // For bots, this is the application name. + GlobalName string `json:"global_name"` + // The token of the user. This is only present for // the user represented by the current session. Token string `json:"token"` @@ -81,7 +89,14 @@ type User struct { } // String returns a unique identifier of the form username#discriminator +// or just username, if the discriminator is set to "0". func (u *User) String() string { + // If the user has been migrated from the legacy username system, their discriminator is "0". + // See https://support-dev.discord.com/hc/en-us/articles/13667755828631 + if u.Discriminator == "0" { + return u.Username + } + return u.Username + "#" + u.Discriminator } @@ -91,17 +106,35 @@ func (u *User) Mention() string { } // AvatarURL returns a URL to the user'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. +// +// 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 (u *User) AvatarURL(size string) string { - return avatarURL(u.Avatar, EndpointDefaultUserAvatar(u.Discriminator), - EndpointUserAvatar(u.ID, u.Avatar), EndpointUserAvatarAnimated(u.ID, u.Avatar), size) + return avatarURL( + u.Avatar, + EndpointDefaultUserAvatar(u.DefaultAvatarIndex()), + EndpointUserAvatar(u.ID, u.Avatar), + EndpointUserAvatarAnimated(u.ID, u.Avatar), + size, + ) } // BannerURL returns the URL of the users's banner image. -// size: The size of the desired banner image as a power of two -// Image size can be any power of two between 16 and 4096. +// +// size: The size of the desired banner image as a power of two +// Image size can be any power of two between 16 and 4096. func (u *User) BannerURL(size string) string { return bannerURL(u.Banner, EndpointUserBanner(u.ID, u.Banner), EndpointUserBannerAnimated(u.ID, u.Banner), size) } + +// DefaultAvatarIndex returns the index of the user's default avatar. +func (u *User) DefaultAvatarIndex() int { + if u.Discriminator == "0" { + id, _ := strconv.ParseUint(u.ID, 10, 64) + return int((id >> 22) % 6) + } + + id, _ := strconv.Atoi(u.Discriminator) + return id % 5 +} diff --git a/user_test.go b/user_test.go index a36f673e3..22b1bd775 100644 --- a/user_test.go +++ b/user_test.go @@ -2,15 +2,36 @@ package discordgo import "testing" -func TestUser(t *testing.T) { +func TestUser_String(t *testing.T) { t.Parallel() - user := &User{ - Username: "bob", - Discriminator: "8192", + tests := []struct { + name string + u *User + want string + }{ + { + name: "User with a discriminator", + u: &User{ + Username: "bob", + Discriminator: "8192", + }, + want: "bob#8192", + }, + { + name: "User with discriminator set to 0", + u: &User{ + Username: "aldiwildan", + Discriminator: "0", + }, + want: "aldiwildan", + }, } - - if user.String() != "bob#8192" { - t.Errorf("user.String() == %v", user.String()) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := tc.u.String(); got != tc.want { + t.Errorf("User.String() = %v, want %v", got, tc.want) + } + }) } }