// Discordgo - Discord bindings for Go // Available at https://github.com/bwmarrin/discordgo // Copyright 2015-2016 Bruce Marriner . All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file contains code related to the Message struct package discordgo import ( "encoding/json" "io" "regexp" "strings" "time" ) // MessageType is the type of Message // https://discord.com/developers/docs/resources/channel#message-object-message-types type MessageType int // Block contains the valid known MessageType values const ( MessageTypeDefault MessageType = 0 MessageTypeRecipientAdd MessageType = 1 MessageTypeRecipientRemove MessageType = 2 MessageTypeCall MessageType = 3 MessageTypeChannelNameChange MessageType = 4 MessageTypeChannelIconChange MessageType = 5 MessageTypeChannelPinnedMessage MessageType = 6 MessageTypeGuildMemberJoin MessageType = 7 MessageTypeUserPremiumGuildSubscription MessageType = 8 MessageTypeUserPremiumGuildSubscriptionTierOne MessageType = 9 MessageTypeUserPremiumGuildSubscriptionTierTwo MessageType = 10 MessageTypeUserPremiumGuildSubscriptionTierThree MessageType = 11 MessageTypeChannelFollowAdd MessageType = 12 MessageTypeGuildDiscoveryDisqualified MessageType = 14 MessageTypeGuildDiscoveryRequalified MessageType = 15 MessageTypeThreadCreated MessageType = 18 MessageTypeReply MessageType = 19 MessageTypeChatInputCommand MessageType = 20 MessageTypeThreadStarterMessage MessageType = 21 MessageTypeContextMenuCommand MessageType = 23 ) // A Message stores all data related to a specific Discord message. type Message struct { // The ID of the message. ID string `json:"id"` // The ID of the channel in which the message was sent. ChannelID string `json:"channel_id"` // The ID of the guild in which the message was sent. GuildID string `json:"guild_id,omitempty"` // The content of the message. Content string `json:"content"` // The time at which the messsage was sent. // CAUTION: this field may be removed in a // future API version; it is safer to calculate // the creation time via the ID. Timestamp time.Time `json:"timestamp"` // The time at which the last edit of the message // occurred, if it has been edited. EditedTimestamp *time.Time `json:"edited_timestamp"` // The roles mentioned in the message. MentionRoles []string `json:"mention_roles"` // Whether the message is text-to-speech. TTS bool `json:"tts"` // Whether the message mentions everyone. MentionEveryone bool `json:"mention_everyone"` // The author of the message. This is not guaranteed to be a // valid user (webhook-sent messages do not possess a full author). Author *User `json:"author"` // A list of attachments present in the message. Attachments []*MessageAttachment `json:"attachments"` // A list of components attached to the message. Components []MessageComponent `json:"-"` // A list of embeds present in the message. Embeds []*MessageEmbed `json:"embeds"` // A list of users mentioned in the message. Mentions []*User `json:"mentions"` // 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"` // 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 or reply messages. // This does not contain the reference *to* this message; this is for when *this* message references another. // To generate a reference to this message, use (*Message).Reference(). MessageReference *MessageReference `json:"message_reference"` // The message associated with the message_reference // NOTE: This field is only returned for messages with a type of 19 (REPLY) or 21 (THREAD_STARTER_MESSAGE). // If the message is a reply but the referenced_message field is not present, // the backend did not attempt to fetch the message that was being replied to, so its state is unknown. // If the field exists but is null, the referenced message was deleted. ReferencedMessage *Message `json:"referenced_message"` // Is sent when the message is a response to an Interaction, without an existing message. // This means responses to message component interactions do not include this property, // instead including a MessageReference, as components exist on preexisting messages. Interaction *MessageInteraction `json:"interaction"` // 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 MessageFlags `json:"flags"` // The thread that was started from this message, includes thread member object Thread *Channel `json:"thread,omitempty"` // An array of Sticker objects, if any were sent. StickerItems []*Sticker `json:"sticker_items"` } // UnmarshalJSON is a helper function to unmarshal the Message. func (m *Message) UnmarshalJSON(data []byte) error { type message Message var v struct { message RawComponents []unmarshalableMessageComponent `json:"components"` } err := json.Unmarshal(data, &v) if err != nil { return err } *m = Message(v.message) m.Components = make([]MessageComponent, len(v.RawComponents)) for i, v := range v.RawComponents { m.Components[i] = v.MessageComponent } return err } // GetCustomEmojis pulls out all the custom (Non-unicode) emojis from a message and returns a Slice of the Emoji struct. func (m *Message) GetCustomEmojis() []*Emoji { var toReturn []*Emoji emojis := EmojiRegex.FindAllString(m.Content, -1) if len(emojis) < 1 { return toReturn } for _, em := range emojis { parts := strings.Split(em, ":") toReturn = append(toReturn, &Emoji{ ID: parts[2][:len(parts[2])-1], Name: parts[1], Animated: strings.HasPrefix(em, " mentions with the // username of the mention. func (m *Message) ContentWithMentionsReplaced() (content string) { content = m.Content for _, user := range m.Mentions { content = strings.NewReplacer( "<@"+user.ID+">", "@"+user.Username, "<@!"+user.ID+">", "@"+user.Username, ).Replace(content) } return } var patternChannels = regexp.MustCompile("<#[^>]*>") // ContentWithMoreMentionsReplaced will replace all @ mentions with the // username of the mention, but also role IDs and more. func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) { content = m.Content if !s.StateEnabled { content = m.ContentWithMentionsReplaced() return } channel, err := s.State.Channel(m.ChannelID) if err != nil { content = m.ContentWithMentionsReplaced() return } for _, user := range m.Mentions { nick := user.Username member, err := s.State.Member(channel.GuildID, user.ID) if err == nil && member.Nick != "" { nick = member.Nick } content = strings.NewReplacer( "<@"+user.ID+">", "@"+user.Username, "<@!"+user.ID+">", "@"+nick, ).Replace(content) } for _, roleID := range m.MentionRoles { role, err := s.State.Role(channel.GuildID, roleID) if err != nil || !role.Mentionable { continue } content = strings.Replace(content, "<@&"+role.ID+">", "@"+role.Name, -1) } content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string { channel, err := s.State.Channel(mention[2 : len(mention)-1]) if err != nil || channel.Type == ChannelTypeGuildVoice { return mention } return "#" + channel.Name }) return } // MessageInteraction contains information about the application command interaction which generated the message. type MessageInteraction struct { ID string `json:"id"` Type InteractionType `json:"type"` Name string `json:"name"` User *User `json:"user"` // Member is only present when the interaction is from a guild. Member *Member `json:"member"` }