From 4cc57c507061d5f563c2a3571b9c3a5248a9a017 Mon Sep 17 00:00:00 2001 From: Rens Rikkerink Date: Wed, 9 May 2018 14:18:30 +0200 Subject: [PATCH 01/35] Added copy of previous Message state to MessageUpdate --- events.go | 2 ++ state.go | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/events.go b/events.go index e784cac..8c560db 100644 --- a/events.go +++ b/events.go @@ -162,6 +162,8 @@ type MessageCreate struct { // MessageUpdate is the data for a MessageUpdate event. type MessageUpdate struct { *Message + // BeforeUpdate will be nil if the Message was not previously cached in the state cache. + BeforeUpdate *Message `json:"-"` } // MessageDelete is the data for a MessageDelete event. diff --git a/state.go b/state.go index 695f47c..df1b47a 100644 --- a/state.go +++ b/state.go @@ -863,6 +863,12 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) { } case *MessageUpdate: if s.MaxMessageCount != 0 { + old, err := s.Message(t.ChannelID, t.ID) + if err == nil { + oldCopy := *old + t.BeforeUpdate = &oldCopy + } + err = s.MessageAdd(t.Message) } case *MessageDelete: From ee1699649048e67171ccb0a6ffd9b6be91541eaa Mon Sep 17 00:00:00 2001 From: Rens Rikkerink Date: Wed, 9 May 2018 14:35:06 +0200 Subject: [PATCH 02/35] Fixed err shadowing --- state.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/state.go b/state.go index df1b47a..77fb2c4 100644 --- a/state.go +++ b/state.go @@ -863,7 +863,8 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) { } case *MessageUpdate: if s.MaxMessageCount != 0 { - old, err := s.Message(t.ChannelID, t.ID) + var old *Message + old, err = s.Message(t.ChannelID, t.ID) if err == nil { oldCopy := *old t.BeforeUpdate = &oldCopy From e184c57068de4d38922aec306e4d2ff71c609583 Mon Sep 17 00:00:00 2001 From: Chris Rhodes Date: Fri, 2 Nov 2018 11:22:31 -0700 Subject: [PATCH 03/35] Discord v0.20.0-alpha --- discord.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord.go b/discord.go index cdac67f..77d1341 100644 --- a/discord.go +++ b/discord.go @@ -21,7 +21,7 @@ import ( ) // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) -const VERSION = "0.19.0" +const VERSION = "0.20.0-alpha" // ErrMFA will be risen by New when the user has 2FA. var ErrMFA = errors.New("account has 2FA enabled") From aca3f3898c3c1efb06da32d95aabb449ddcbf4e6 Mon Sep 17 00:00:00 2001 From: robbix1206 Date: Tue, 6 Nov 2018 02:37:18 +0100 Subject: [PATCH 04/35] Remove code duplication in ChannelVoiceJoin (#611) --- wsapi.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/wsapi.go b/wsapi.go index 8ecaaa7..d0a89e9 100644 --- a/wsapi.go +++ b/wsapi.go @@ -615,11 +615,7 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi voice.session = s voice.Unlock() - // Send the request to Discord that we want to join the voice channel - data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}} - s.wsMutex.Lock() - err = s.wsConn.WriteJSON(data) - s.wsMutex.Unlock() + err = s.ChannelVoiceJoinManual(gID, cID, mute, deaf) if err != nil { return } @@ -652,10 +648,6 @@ func (s *Session) ChannelVoiceJoinManual(gID, cID string, mute, deaf bool) (err s.wsMutex.Lock() err = s.wsConn.WriteJSON(data) s.wsMutex.Unlock() - if err != nil { - return - } - return } From d6d46b0b1b1cb54da094161b5c910d70eca538b3 Mon Sep 17 00:00:00 2001 From: Krognol <10560012+Krognol@users.noreply.github.com> Date: Thu, 8 Nov 2018 19:04:07 +0100 Subject: [PATCH 05/35] Fix spelling of `synthetic` (#613) --- events.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/events.go b/events.go index c4fb520..7c2195d 100644 --- a/events.go +++ b/events.go @@ -10,15 +10,15 @@ import ( //go:generate go run tools/cmd/eventhandlers/main.go // Connect is the data for a Connect event. -// This is a sythetic event and is not dispatched by Discord. +// This is a synthetic event and is not dispatched by Discord. type Connect struct{} // Disconnect is the data for a Disconnect event. -// This is a sythetic event and is not dispatched by Discord. +// This is a synthetic event and is not dispatched by Discord. type Disconnect struct{} // RateLimit is the data for a RateLimit event. -// This is a sythetic event and is not dispatched by Discord. +// This is a synthetic event and is not dispatched by Discord. type RateLimit struct { *TooManyRequests URL string From 62b450ec91dee6f643d484ac497ea32f9c1514a3 Mon Sep 17 00:00:00 2001 From: bitspill Date: Sun, 2 Dec 2018 18:35:46 -0800 Subject: [PATCH 06/35] Update expired Discord API invite link --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 9b433da..1dfdd90 100644 --- a/docs/index.md +++ b/docs/index.md @@ -30,4 +30,4 @@ information and support for DiscordGo. There's also a chance to make some friends :) * Join the [Discord Gophers](https://discord.gg/0f1SbxBZjYoCtNPP) chat server dedicated to Go programming. -* Join the [Discord API](https://discord.gg/0SBTUU1wZTWT6sqd) chat server dedicated to the Discord API. +* Join the [Discord API](https://discordapp.com/invite/discord-API) chat server dedicated to the Discord API. From c5ae3211870ad46aabd8c157c2bcf44929c40f3e Mon Sep 17 00:00:00 2001 From: JurrijnP Date: Tue, 5 Feb 2019 21:41:52 +0100 Subject: [PATCH 07/35] Add "Priority Speaker" permission as constant (#628) * Bump to v0.17.0 * Add members from GuildMembersChunk to state (#454) * Revert "Add members from GuildMembersChunk to state (#454)" (#455) This reverts commit e4487b30d4d846b1fdc08fd3982bd5b9965a8cc9. * added clarification when initializing discordgo from the code I ran on my system with the latest changes this seems to be the syntax for the authentication tokens. I'm guessing it was just never updated. Let me know if this is incorrect. Thanks! * travis: update go versions * Add "Priority Speaker" permission constant The permission "Priority Speaker" was missing as constant. Permission has been added as constant and to the "PermissionAllVoice" constant as well. --- README.md | 2 +- structs.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d526d35..cb5a665 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Construct a new Discord client which can be used to access the variety of Discord API functions and to set callback functions for Discord events. ```go -discord, err := discordgo.New("authentication token") +discord, err := discordgo.New("Bot " + "authentication token") ``` See Documentation and Examples below for more detailed information. diff --git a/structs.go b/structs.go index 4465ec5..c643bd5 100644 --- a/structs.go +++ b/structs.go @@ -872,6 +872,7 @@ const ( PermissionVoiceDeafenMembers PermissionVoiceMoveMembers PermissionVoiceUseVAD + PermissionVoicePrioritySpeaker = 1 << (iota + 2) ) // Constants for general management. @@ -907,7 +908,8 @@ const ( PermissionVoiceMuteMembers | PermissionVoiceDeafenMembers | PermissionVoiceMoveMembers | - PermissionVoiceUseVAD + PermissionVoiceUseVAD | + PermissionVoicePrioritySpeaker PermissionAllChannel = PermissionAllText | PermissionAllVoice | PermissionCreateInstantInvite | From e3acfe56f06abc4eff33d61b2fd8c1696a1b0126 Mon Sep 17 00:00:00 2001 From: necro Date: Fri, 12 Apr 2019 11:19:31 -0400 Subject: [PATCH 08/35] added SnowflakeTimestamp utility function to obtain the creation date of a discord snowflake ID --- util.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 util.go diff --git a/util.go b/util.go new file mode 100644 index 0000000..02443ca --- /dev/null +++ b/util.go @@ -0,0 +1,17 @@ +package discordgo + +import ( + "strconv" + "time" +) + +// SnowflakeTimestamp returns the creation time of a Snowflake ID relative to the creation of Discord. +func SnowflakeTimestamp(ID string) (t time.Time, err error) { + i, err := strconv.ParseInt(ID, 10, 64) + if err != nil { + return + } + timestamp := (i >> 22) + 1420070400000 + t = time.Unix(timestamp/1000, 0) + return +} From 544e4b9a8c70a0f820e37a09558f5f5795f3b8e4 Mon Sep 17 00:00:00 2001 From: Jesse <34263365+NewWinter@users.noreply.github.com> Date: Sun, 12 May 2019 19:14:27 -0600 Subject: [PATCH 09/35] Add proper response type for GuildBans docs The previous documentation stated that the response type was an array of User structures, when the function return an array of GuildBan structures. --- restapi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/restapi.go b/restapi.go index 84a2a31..6023cc3 100644 --- a/restapi.go +++ b/restapi.go @@ -675,7 +675,7 @@ func (s *Session) GuildLeave(guildID string) (err error) { return } -// GuildBans returns an array of User structures for all bans of a +// GuildBans returns an array of GuildBan structures for all bans of a // given guild. // guildID : The ID of a Guild. func (s *Session) GuildBans(guildID string) (st []*GuildBan, err error) { From 7896167153322db37606092a95a9b90b53452eef Mon Sep 17 00:00:00 2001 From: diamond's alt <51140562+datutbrus@users.noreply.github.com> Date: Tue, 28 May 2019 16:52:23 -0700 Subject: [PATCH 10/35] added useragent (#653) --- discord.go | 1 + restapi.go | 2 +- structs.go | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/discord.go b/discord.go index 77d1341..cb43e7e 100644 --- a/discord.go +++ b/discord.go @@ -58,6 +58,7 @@ func New(args ...interface{}) (s *Session, err error) { ShardCount: 1, MaxRestRetries: 3, Client: &http.Client{Timeout: (20 * time.Second)}, + UserAgent: "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")", sequence: new(int64), LastHeartbeatAck: time.Now().UTC(), } diff --git a/restapi.go b/restapi.go index 84a2a31..ce1e823 100644 --- a/restapi.go +++ b/restapi.go @@ -90,7 +90,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b req.Header.Set("Content-Type", contentType) // TODO: Make a configurable static variable. - req.Header.Set("User-Agent", "DiscordBot (https://github.com/bwmarrin/discordgo, v"+VERSION+")") + req.Header.Set("User-Agent", s.UserAgent) if s.Debug { for k, v := range req.Header { diff --git a/structs.go b/structs.go index c643bd5..01a6f00 100644 --- a/structs.go +++ b/structs.go @@ -82,6 +82,9 @@ type Session struct { // The http client used for REST requests Client *http.Client + // The user agent used for REST APIs + UserAgent string + // Stores the last HeartbeatAck that was recieved (in UTC) LastHeartbeatAck time.Time From 60dbc5557c7edb8c5e0f4bef22595a1d15fb8e0f Mon Sep 17 00:00:00 2001 From: Christopher Felegy Date: Wed, 29 May 2019 13:54:56 -0400 Subject: [PATCH 11/35] fix: remove _trace from helloOp As per discordapp/discord-api-docs#967, _trace in OP10 HELLO is no longer an array of strings, but rather an undefined glob of data that presently contains a mixed bag of strings and objects. type helloOp does not seem to be exposed outside of the library, so this is not a breaking change; furthermore, the Trace field of helloOp was not used anywhere within the library. It seems like it would be safer to just remove the field outright, rather than accept it as an interface{} and waste cycles unmarshaling data that is never used. This is a critically breaking bug, as if the upstream change is merged, bots using DiscordGo prior to this patch will be unable to connect; an error would occur when trying to unmarshal the new data glob into a []string, causing (*Session).Open() to prematurely return. --- wsapi.go | 1 - 1 file changed, 1 deletion(-) diff --git a/wsapi.go b/wsapi.go index d0a89e9..9dff232 100644 --- a/wsapi.go +++ b/wsapi.go @@ -261,7 +261,6 @@ type heartbeatOp struct { type helloOp struct { HeartbeatInterval time.Duration `json:"heartbeat_interval"` - Trace []string `json:"_trace"` } // FailedHeartbeatAcks is the Number of heartbeat intervals to wait until forcing a connection restart. From 347a4f69b0b55ba2a2fa1e9611189d25db5f4432 Mon Sep 17 00:00:00 2001 From: Sebastian Winkler Date: Sat, 8 Jun 2019 22:54:39 +0200 Subject: [PATCH 12/35] Add premium fields to Guild and Member (#656) * adds premium fields to Guild and Member * fixes formatting --- endpoints.go | 2 ++ structs.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/endpoints.go b/endpoints.go index b961908..a5c59ed 100644 --- a/endpoints.go +++ b/endpoints.go @@ -38,6 +38,7 @@ var ( EndpointCDNIcons = EndpointCDN + "icons/" EndpointCDNSplashes = EndpointCDN + "splashes/" EndpointCDNChannelIcons = EndpointCDN + "channel-icons/" + EndpointCDNBanners = EndpointCDN + "banners/" EndpointAuth = EndpointAPI + "auth/" EndpointLogin = EndpointAuth + "login" @@ -97,6 +98,7 @@ var ( EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" } EndpointGuildEmojis = func(gID string) string { return EndpointGuilds + gID + "/emojis" } EndpointGuildEmoji = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID } + EndpointGuildBanner = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" } EndpointChannel = func(cID string) string { return EndpointChannels + cID } EndpointChannelPermissions = func(cID string) string { return EndpointChannels + cID + "/permissions" } diff --git a/structs.go b/structs.go index 01a6f00..19d94ef 100644 --- a/structs.go +++ b/structs.go @@ -342,6 +342,17 @@ const ( MfaLevelElevated ) +// PremiumTier type definition +type PremiumTier int + +// Constants for PremiumTier levels from 0 to 3 inclusive +const ( + PremiumTierNone PremiumTier = iota + PremiumTier1 + PremiumTier2 + PremiumTier3 +) + // A Guild holds all data related to a specific Discord Guild. Guilds are also // sometimes referred to as Servers in the Discord client. type Guild struct { @@ -446,6 +457,21 @@ type Guild struct { // The Channel ID to which system messages are sent (eg join and leave messages) SystemChannelID string `json:"system_channel_id"` + + // the vanity url code for the guild + VanityURLCode string `json:"vanity_url_code"` + + // the description for the guild + Description string `json:"description"` + + // The hash of the guild's banner + Banner string `json:"banner"` + + // The premium tier of the guild + PremiumTier PremiumTier `json:"premium_tier"` + + // The total number of users currently boosting this server + PremiumSubscriptionCount int `json:"premium_subscription_count"` } // A UserGuild holds a brief version of a Guild @@ -620,6 +646,9 @@ type Member struct { // A list of IDs of the roles which are possessed by the member. Roles []string `json:"roles"` + + // When the user used their Nitro boost on the server + PremiumSince Timestamp `json:"premium_since"` } // Mention creates a member mention From d19be02e423c265df43927e8a91eaf53a3da023a Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Mon, 22 Jul 2019 11:02:28 +0700 Subject: [PATCH 13/35] Add `Available` field to Emoji struct (#676) --- structs.go | 1 + 1 file changed, 1 insertion(+) diff --git a/structs.go b/structs.go index 19d94ef..948682f 100644 --- a/structs.go +++ b/structs.go @@ -286,6 +286,7 @@ type Emoji struct { Managed bool `json:"managed"` RequireColons bool `json:"require_colons"` Animated bool `json:"animated"` + Available bool `json:"available"` } // MessageFormat returns a correctly formatted Emoji for use in Message content and embeds From e405cbd54c25c2cc99cac4ec273127a7561e96de Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 22 Jul 2019 06:02:54 +0200 Subject: [PATCH 14/35] handle empty channel id in ChannelVoiceJoinManual (#672) --- wsapi.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/wsapi.go b/wsapi.go index 9dff232..eccbb9f 100644 --- a/wsapi.go +++ b/wsapi.go @@ -635,15 +635,22 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi // This should only be used when the VoiceServerUpdate will be intercepted and used elsewhere. // // gID : Guild ID of the channel to join. -// cID : Channel ID of the channel to join. +// cID : Channel ID of the channel to join, leave empty to disconnect. // mute : If true, you will be set to muted upon joining. // deaf : If true, you will be set to deafened upon joining. func (s *Session) ChannelVoiceJoinManual(gID, cID string, mute, deaf bool) (err error) { s.log(LogInformational, "called") + var channelID *string + if cID == "" { + channelID = nil + } else { + channelID = &cID + } + // Send the request to Discord that we want to join the voice channel - data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}} + data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, channelID, mute, deaf}} s.wsMutex.Lock() err = s.wsConn.WriteJSON(data) s.wsMutex.Unlock() From a6d2557a8e837e794f3664d3a4036d4bf3a01b3c Mon Sep 17 00:00:00 2001 From: diamond's alt <51140562+datutbrus@users.noreply.github.com> Date: Sun, 21 Jul 2019 21:06:20 -0700 Subject: [PATCH 15/35] Added Asset and ApplicationAssets (#666) Fixed ApplicationAssets returning the wrong type Added Asset and ApplicationAssets --- endpoints.go | 9 +++++---- oauth2.go | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/endpoints.go b/endpoints.go index a5c59ed..d3fe034 100644 --- a/endpoints.go +++ b/endpoints.go @@ -141,8 +141,9 @@ var ( EndpointEmoji = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".png" } EndpointEmojiAnimated = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".gif" } - EndpointOauth2 = EndpointAPI + "oauth2/" - EndpointApplications = EndpointOauth2 + "applications" - EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID } - EndpointApplicationsBot = func(aID string) string { return EndpointApplications + "/" + aID + "/bot" } + EndpointOauth2 = EndpointAPI + "oauth2/" + EndpointApplications = EndpointOauth2 + "applications" + EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID } + EndpointApplicationsBot = func(aID string) string { return EndpointApplications + "/" + aID + "/bot" } + EndpointApplicationAssets = func(aID string) string { return EndpointApplications + "/" + aID + "/assets" } ) diff --git a/oauth2.go b/oauth2.go index 108b32f..4a52120 100644 --- a/oauth2.go +++ b/oauth2.go @@ -105,6 +105,25 @@ func (s *Session) ApplicationDelete(appID string) (err error) { return } +// Asset struct stores values for an asset of an application +type Asset struct { + Type int `json:"type"` + ID string `json:"id"` + Name string `json:"name"` +} + +// ApplicationAssets returns an application's assets +func (s *Session) ApplicationAssets(appID string) (ass []*Asset, err error) { + + body, err := s.RequestWithBucketID("GET", EndpointApplicationAssets(appID), nil, EndpointApplicationAssets("")) + if err != nil { + return + } + + err = unmarshal(body, &ass) + return +} + // ------------------------------------------------------------------------------------------------ // Code specific to Discord OAuth2 Application Bots // ------------------------------------------------------------------------------------------------ From d3c96d18be9c3c835f5a14473ca99f91b30621b3 Mon Sep 17 00:00:00 2001 From: Qais Patankar Date: Mon, 22 Jul 2019 13:07:28 +0900 Subject: [PATCH 16/35] Fix #622: support for WebhookExecute msg response (#663) --- restapi.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/restapi.go b/restapi.go index ce1e823..f1a1ed4 100644 --- a/restapi.go +++ b/restapi.go @@ -2067,14 +2067,20 @@ func (s *Session) WebhookDeleteWithToken(webhookID, token string) (st *Webhook, // WebhookExecute executes a webhook. // webhookID: The ID of a webhook. // token : The auth token for the webhook -func (s *Session) WebhookExecute(webhookID, token string, wait bool, data *WebhookParams) (err error) { +// wait : Waits for server confirmation of message send and ensures that the return struct is populated (it is nil otherwise) +func (s *Session) WebhookExecute(webhookID, token string, wait bool, data *WebhookParams) (st *Message, err error) { uri := EndpointWebhookToken(webhookID, token) if wait { uri += "?wait=true" } - _, err = s.RequestWithBucketID("POST", uri, data, EndpointWebhookToken("", "")) + response, err := s.RequestWithBucketID("POST", uri, data, EndpointWebhookToken("", "")) + if !wait || err != nil { + return + } + + err = unmarshal(response, &st) return } From d7c22e2791738b0ce5252778690c3978b9e4c385 Mon Sep 17 00:00:00 2001 From: yuko1225 Date: Mon, 22 Jul 2019 12:08:31 +0800 Subject: [PATCH 17/35] Fix broken IP Discovery in voice connection. (#669) https://github.com/bwmarrin/discordgo/issues/598 https://github.com/bwmarrin/discordgo/issues/668 --- voice.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voice.go b/voice.go index aa630b1..42fa932 100644 --- a/voice.go +++ b/voice.go @@ -593,7 +593,7 @@ func (v *VoiceConnection) udpOpen() (err error) { } // Grab port from position 68 and 69 - port := binary.LittleEndian.Uint16(rb[68:70]) + port := binary.BigEndian.Uint16(rb[68:70]) // Take the data from above and send it back to Discord to finalize // the UDP connection handshake. From 579121fe1a9e6c1b428daac0e06a06104fcb402b Mon Sep 17 00:00:00 2001 From: Sebastian Winkler Date: Mon, 22 Jul 2019 06:09:39 +0200 Subject: [PATCH 18/35] adds EndpointGuildIconAnimated; adds guild.IconURL() helper (#658) --- endpoints.go | 1 + structs.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/endpoints.go b/endpoints.go index d3fe034..6f86b67 100644 --- a/endpoints.go +++ b/endpoints.go @@ -93,6 +93,7 @@ var ( EndpointGuildEmbed = func(gID string) string { return EndpointGuilds + gID + "/embed" } EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" } EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" } + EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" } EndpointGuildSplash = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" } EndpointGuildWebhooks = func(gID string) string { return EndpointGuilds + gID + "/webhooks" } EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" } diff --git a/structs.go b/structs.go index 948682f..bb00368 100644 --- a/structs.go +++ b/structs.go @@ -15,6 +15,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "sync" "time" @@ -475,6 +476,19 @@ type Guild struct { PremiumSubscriptionCount int `json:"premium_subscription_count"` } +// IconURL returns a URL to the guild's icon. +func (g *Guild) IconURL() string { + if g.Icon == "" { + return "" + } + + if strings.HasPrefix(g.Icon, "a_") { + return EndpointGuildIconAnimated(g.ID, g.Icon) + } + + return EndpointGuildIcon(g.ID, g.Icon) +} + // A UserGuild holds a brief version of a Guild type UserGuild struct { ID string `json:"id"` From 5fb15f58237d6cfa332bf3eb45b52193ea6a089f Mon Sep 17 00:00:00 2001 From: JurrijnP Date: Mon, 22 Jul 2019 06:10:35 +0200 Subject: [PATCH 19/35] Add Pinned to Message struct (#633) * Bump to v0.17.0 * Add members from GuildMembersChunk to state (#454) * Revert "Add members from GuildMembersChunk to state (#454)" (#455) This reverts commit e4487b30d4d846b1fdc08fd3982bd5b9965a8cc9. * added clarification when initializing discordgo from the code I ran on my system with the latest changes this seems to be the syntax for the authentication tokens. I'm guessing it was just never updated. Let me know if this is incorrect. Thanks! * travis: update go versions * Add Pinned member to message struct Pinned member was missing. * Missed an : * Update README.md * Removed space --- message.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/message.go b/message.go index 2b60992..f22def5 100644 --- a/message.go +++ b/message.go @@ -80,6 +80,9 @@ type Message struct { // A list of reactions to the message. Reactions []*MessageReactions `json:"reactions"` + // Whether the message is pinned or not. + Pinned bool `json:"pinned"` + // The type of the message. Type MessageType `json:"type"` From 191dea097deab93d284e1383e7c7db6c3590b1d4 Mon Sep 17 00:00:00 2001 From: tsudoko Date: Mon, 22 Jul 2019 06:11:44 +0200 Subject: [PATCH 20/35] Escape # in emoji IDs passed to reaction endpoints (#615) --- restapi.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/restapi.go b/restapi.go index f1a1ed4..02909d0 100644 --- a/restapi.go +++ b/restapi.go @@ -2091,6 +2091,8 @@ func (s *Session) WebhookExecute(webhookID, token string, wait bool, data *Webho // emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier. func (s *Session) MessageReactionAdd(channelID, messageID, emojiID string) error { + // emoji such as #⃣ need to have # escaped + emojiID = strings.Replace(emojiID, "#", "%23", -1) _, err := s.RequestWithBucketID("PUT", EndpointMessageReaction(channelID, messageID, emojiID, "@me"), nil, EndpointMessageReaction(channelID, "", "", "")) return err @@ -2103,6 +2105,8 @@ func (s *Session) MessageReactionAdd(channelID, messageID, emojiID string) error // userID : @me or ID of the user to delete the reaction for. func (s *Session) MessageReactionRemove(channelID, messageID, emojiID, userID string) error { + // emoji such as #⃣ need to have # escaped + emojiID = strings.Replace(emojiID, "#", "%23", -1) _, err := s.RequestWithBucketID("DELETE", EndpointMessageReaction(channelID, messageID, emojiID, userID), nil, EndpointMessageReaction(channelID, "", "", "")) return err @@ -2124,6 +2128,8 @@ func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error { // emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier. // limit : max number of users to return (max 100) func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit int) (st []*User, err error) { + // emoji such as #⃣ need to have # escaped + emojiID = strings.Replace(emojiID, "#", "%23", -1) uri := EndpointMessageReactions(channelID, messageID, emojiID) v := url.Values{} From 66f4df19c8043d3caaccf5507fa0cc19fc6ad975 Mon Sep 17 00:00:00 2001 From: Christopher F Date: Mon, 22 Jul 2019 00:12:21 -0400 Subject: [PATCH 21/35] faeture: add last_pin_timestamp to Channel struct (#596) This resolves #547. Adds a "LastPinTimestamp" field to the Channel structure, which reflects the `last_pin_timestamp` field on the Discord API. This field is indicative of whether or not the channel has any pinned messages, and can save an API request from being sent if there are none. FWIW, The API doesn't seem to return a 404 anymore when there are no pinned messages; it returns a 200 with `[]`. --- structs.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/structs.go b/structs.go index bb00368..fd0050a 100644 --- a/structs.go +++ b/structs.go @@ -224,6 +224,10 @@ type Channel struct { // guaranteed to be an ID of a valid message. LastMessageID string `json:"last_message_id"` + // The timestamp of the last pinned message in the channel. + // Empty if the channel has no pinned messages. + LastPinTimestamp Timestamp `json:"last_pin_timestamp"` + // Whether the channel is marked as NSFW. NSFW bool `json:"nsfw"` From dbe490a54ae458df500f4569a08e615cf082721c Mon Sep 17 00:00:00 2001 From: Jon Chen Date: Sun, 21 Jul 2019 21:14:33 -0700 Subject: [PATCH 22/35] updates discord api invite link (#595) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb5a665..7a83b9e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # DiscordGo -[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.gg/0SBTUU1wZTWT6sqd) +[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discordapp.com/invite/discord-api) From f4f8cc09bcdc1b65d36a604c274360f3828eeb8c Mon Sep 17 00:00:00 2001 From: JurrijnP Date: Fri, 2 Aug 2019 20:06:45 +0200 Subject: [PATCH 23/35] Added more message types Added Premium Guild Sub message types. --- message.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/message.go b/message.go index f22def5..7ef1e1c 100644 --- a/message.go +++ b/message.go @@ -28,6 +28,10 @@ const ( MessageTypeChannelIconChange MessageTypeChannelPinnedMessage MessageTypeGuildMemberJoin + MessageTypeUserPremiumGuildSubscription + MessageTypeUserPremiumGuildSubscriptionTierOne + MessageTypeUserPremiumGuildSubscriptionTierTwo + MessageTypeUserPremiumGuildSubscriptionTierThree ) // A Message stores all data related to a specific Discord message. From 8713b45ae71f9ab061385c60e7ffae8f9e65a85c Mon Sep 17 00:00:00 2001 From: Julian Y Date: Sat, 3 Aug 2019 23:48:24 -0700 Subject: [PATCH 24/35] Create new VerificationLevel VerificationLevelVeryHigh Closes #677 --- structs.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/structs.go b/structs.go index 4465ec5..9db3a96 100644 --- a/structs.go +++ b/structs.go @@ -312,12 +312,13 @@ func (e *Emoji) APIName() string { // VerificationLevel type definition type VerificationLevel int -// Constants for VerificationLevel levels from 0 to 3 inclusive +// Constants for VerificationLevel levels from 0 to 4 inclusive const ( VerificationLevelNone VerificationLevel = iota VerificationLevelLow VerificationLevelMedium VerificationLevelHigh + VerificationLevelVeryHigh ) // ExplicitContentFilterLevel type definition From 792b209680468e54d4fc96d1c4725f1af0d5385d Mon Sep 17 00:00:00 2001 From: Julian Y Date: Sun, 4 Aug 2019 01:28:49 -0700 Subject: [PATCH 25/35] Modify GuildEdit bounds check --- restapi.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/restapi.go b/restapi.go index 6023cc3..503ac14 100644 --- a/restapi.go +++ b/restapi.go @@ -617,10 +617,10 @@ func (s *Session) GuildCreate(name string) (st *Guild, err error) { // g : A GuildParams struct with the values Name, Region and VerificationLevel defined. func (s *Session) GuildEdit(guildID string, g GuildParams) (st *Guild, err error) { - // Bounds checking for VerificationLevel, interval: [0, 3] + // Bounds checking for VerificationLevel, interval: [0, 4] if g.VerificationLevel != nil { val := *g.VerificationLevel - if val < 0 || val > 3 { + if val < 0 || val > 4 { err = ErrVerificationLevelBounds return } From b8638c036388b184e211ebede4e8a3277ca4e70c Mon Sep 17 00:00:00 2001 From: JurrijnP Date: Sun, 4 Aug 2019 10:44:25 +0200 Subject: [PATCH 26/35] Add Channel Types --- structs.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/structs.go b/structs.go index fd0050a..e7192d9 100644 --- a/structs.go +++ b/structs.go @@ -200,6 +200,8 @@ const ( ChannelTypeGuildVoice ChannelTypeGroupDM ChannelTypeGuildCategory + ChannelTypeGuildNews + ChannelTypeGuildStore ) // A Channel holds all data related to an individual Discord channel. From e36ed7520eee63967cc1b9c22c4c96e217b18de1 Mon Sep 17 00:00:00 2001 From: Patrik Lundin Date: Wed, 7 Aug 2019 08:15:07 +0200 Subject: [PATCH 27/35] Typo: sythetic -> synthetic --- events.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/events.go b/events.go index c4fb520..7c2195d 100644 --- a/events.go +++ b/events.go @@ -10,15 +10,15 @@ import ( //go:generate go run tools/cmd/eventhandlers/main.go // Connect is the data for a Connect event. -// This is a sythetic event and is not dispatched by Discord. +// This is a synthetic event and is not dispatched by Discord. type Connect struct{} // Disconnect is the data for a Disconnect event. -// This is a sythetic event and is not dispatched by Discord. +// This is a synthetic event and is not dispatched by Discord. type Disconnect struct{} // RateLimit is the data for a RateLimit event. -// This is a sythetic event and is not dispatched by Discord. +// This is a synthetic event and is not dispatched by Discord. type RateLimit struct { *TooManyRequests URL string From 05bae35ddb3ac1ab42cc40d6df9f0ef5f81aec24 Mon Sep 17 00:00:00 2001 From: JurrijnP Date: Mon, 19 Aug 2019 10:55:59 +0200 Subject: [PATCH 28/35] Add 1 more message type --- message.go | 1 + 1 file changed, 1 insertion(+) diff --git a/message.go b/message.go index 7ef1e1c..5aab7e5 100644 --- a/message.go +++ b/message.go @@ -32,6 +32,7 @@ const ( MessageTypeUserPremiumGuildSubscriptionTierOne MessageTypeUserPremiumGuildSubscriptionTierTwo MessageTypeUserPremiumGuildSubscriptionTierThree + MessageTypeChannelFollowAdd ) // A Message stores all data related to a specific Discord message. From 97726fe5b6c2493ef66ae0bf4dfcb2dc349c08a9 Mon Sep 17 00:00:00 2001 From: Haze Booth Date: Sat, 28 Sep 2019 03:34:22 -0400 Subject: [PATCH 29/35] Fix typo in ErrorEmbedDisabled --- structs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structs.go b/structs.go index 9db3a96..44ffd13 100644 --- a/structs.go +++ b/structs.go @@ -957,7 +957,7 @@ const ( ErrCodeMissingAccess = 50001 ErrCodeInvalidAccountType = 50002 ErrCodeCannotExecuteActionOnDMChannel = 50003 - ErrCodeEmbedCisabled = 50004 + ErrCodeEmbedDisabled = 50004 ErrCodeCannotEditFromAnotherUser = 50005 ErrCodeCannotSendEmptyMessage = 50006 ErrCodeCannotSendMessagesToThisUser = 50007 From 4ffe741f3ebd92fd252117e0a87a7c855337cd7e Mon Sep 17 00:00:00 2001 From: Sebastian Winkler Date: Tue, 1 Oct 2019 20:32:18 +0200 Subject: [PATCH 30/35] adds RateLimitPerUser to Channel struct --- structs.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/structs.go b/structs.go index e7192d9..9dc1176 100644 --- a/structs.go +++ b/structs.go @@ -257,6 +257,10 @@ type Channel struct { // The ID of the parent channel, if the channel is under a category ParentID string `json:"parent_id"` + + // Amount of seconds a user has to wait before sending another message (0-21600) + // bots, as well as users with the permission manage_messages or manage_channel, are unaffected + RateLimitPerUser int `json:"rate_limit_per_user"` } // Mention returns a string which mentions the channel From cb8dd746bc92c29f5e59bf11a1c3b175dd228546 Mon Sep 17 00:00:00 2001 From: Sebastian Winkler Date: Thu, 3 Oct 2019 14:14:32 +0200 Subject: [PATCH 31/35] adds message fields --- message.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/message.go b/message.go index 5aab7e5..d7178f6 100644 --- a/message.go +++ b/message.go @@ -93,6 +93,31 @@ type Message struct { // The webhook ID of the message, if it was generated by a webhook WebhookID string `json:"webhook_id"` + + // Member properties for this message's author, + // contains only partial information + Member *Member `json:"member"` + + // Channels specifically mentioned in this message + // Not all channel mentions in a message will appear in mention_channels. + // Only textual channels that are visible to everyone in a lurkable guild will ever be included. + // Only crossposted messages (via Channel Following) currently include mention_channels at all. + // If no mentions in the message meet these requirements, this field will not be sent. + MentionChannels []*Channel `json:"mention_channels"` + + // Is sent with Rich Presence-related chat embeds + Activity *MessageActivity `json:"activity"` + + // Is sent with Rich Presence-related chat embeds + Application *MessageApplication `json:"application"` + + // MessageReference contains reference data sent with crossposted messages + MessageReference *MessageReference `json:"message_reference"` + + // The flags of the message, which describe extra features of a message. + // This is a combination of bit masks; the presence of a certain permission can + // be checked by performing a bitwise AND between this int and the flag. + Flags int `json:"flags"` } // File stores info about files you e.g. send in messages. @@ -233,6 +258,51 @@ type MessageReactions struct { Emoji *Emoji `json:"emoji"` } +// MessageActivity is sent with Rich Presence-related chat embeds +type MessageActivity struct { + Type MessageActivityType `json:"type"` + PartyID string `json:"party_id"` +} + +// MessageActivityType is the type of message activity +type MessageActivityType int + +const ( + MessageActivityTypeJoin = iota + 1 + MessageActivityTypeSpectate + MessageActivityTypeListen + MessageActivityTypeJoinRequest +) + +// MessageFlag describes an extra feature of the message +type MessageFlag int + +// Constants for the different bit offsets of Message Flags +const ( + // This message has been published to subscribed channels (via Channel Following) + MessageFlagCrossposted = 1 << iota + // This message originated from a message in another channel (via Channel Following) + MessageFlagIsCrosspost + // Do not include any embeds when serializing this message + MessageFlagSuppressEmbeds +) + +// MessageApplication is sent with Rich Presence-related chat embeds +type MessageApplication struct { + ID string `json:"id"` + CoverImage string `json:"cover_image"` + Description string `json:"description"` + Icon string `json:"icon"` + Name string `json:"name"` +} + +// MessageReference contains reference data sent with crossposted messages +type MessageReference struct { + MessageID string `json:"message_id"` + ChannelID string `json:"channel_id"` + GuildID string `json:"guild_id"` +} + // ContentWithMentionsReplaced will replace all @ mentions with the // username of the mention. func (m *Message) ContentWithMentionsReplaced() (content string) { From dce574199f811ed28b5a741e07e2d68c74a5deb7 Mon Sep 17 00:00:00 2001 From: Sebastian Winkler Date: Thu, 3 Oct 2019 14:52:55 +0200 Subject: [PATCH 32/35] fixes lint --- message.go | 1 + 1 file changed, 1 insertion(+) diff --git a/message.go b/message.go index d7178f6..cc87429 100644 --- a/message.go +++ b/message.go @@ -267,6 +267,7 @@ type MessageActivity struct { // MessageActivityType is the type of message activity type MessageActivityType int +// Constants for the different types of Message Activity const ( MessageActivityTypeJoin = iota + 1 MessageActivityTypeSpectate From ac0011a12f3faa34a813972f2b0cd2e53ffdfd21 Mon Sep 17 00:00:00 2001 From: dondish Date: Fri, 18 Oct 2019 14:38:12 +0300 Subject: [PATCH 33/35] updated the develop branch to fix the voice holdup issue --- go.mod | 2 ++ voice.go | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2ff8868..8cd2cf6 100644 --- a/go.mod +++ b/go.mod @@ -4,3 +4,5 @@ require ( github.com/gorilla/websocket v1.4.0 golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 ) + +go 1.13 diff --git a/voice.go b/voice.go index 42fa932..51ac16c 100644 --- a/voice.go +++ b/voice.go @@ -243,6 +243,7 @@ type voiceOP2 struct { Port int `json:"port"` Modes []string `json:"modes"` HeartbeatInterval time.Duration `json:"heartbeat_interval"` + IP string `json:"ip"` } // WaitUntilConnected waits for the Voice Connection to @@ -542,7 +543,7 @@ func (v *VoiceConnection) udpOpen() (err error) { return fmt.Errorf("empty endpoint") } - host := strings.TrimSuffix(v.endpoint, ":80") + ":" + strconv.Itoa(v.op2.Port) + host := v.op2.IP + ":" + strconv.Itoa(v.op2.Port) addr, err := net.ResolveUDPAddr("udp", host) if err != nil { v.log(LogWarning, "error resolving udp host %s, %s", host, err) From 8e3862b14be0a3646949474025e5d28e21eb2a39 Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Fri, 18 Oct 2019 10:45:07 -0500 Subject: [PATCH 34/35] Bump version to v0.20.0 --- discord.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord.go b/discord.go index cb43e7e..f1ba0ee 100644 --- a/discord.go +++ b/discord.go @@ -21,7 +21,7 @@ import ( ) // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) -const VERSION = "0.20.0-alpha" +const VERSION = "0.20.0" // ErrMFA will be risen by New when the user has 2FA. var ErrMFA = errors.New("account has 2FA enabled") From dd99dea7adba674baa401e52362d6e330b50acf8 Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Fri, 18 Oct 2019 11:23:41 -0500 Subject: [PATCH 35/35] Remove go1.13 from go.mod, bump version to v0.20.1 Go 1.13 was accidently added, this backs it back out. I don't think there's really much impact from this but I would prefer it not be in there for this release. --- discord.go | 2 +- go.mod | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/discord.go b/discord.go index f1ba0ee..76f1ad9 100644 --- a/discord.go +++ b/discord.go @@ -21,7 +21,7 @@ import ( ) // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) -const VERSION = "0.20.0" +const VERSION = "0.20.1" // ErrMFA will be risen by New when the user has 2FA. var ErrMFA = errors.New("account has 2FA enabled") diff --git a/go.mod b/go.mod index 8cd2cf6..2ff8868 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,3 @@ require ( github.com/gorilla/websocket v1.4.0 golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 ) - -go 1.13