-
Notifications
You must be signed in to change notification settings - Fork 822
- Contents
- Sending embeds
- Permissions and Roles
- Get the time a snowflake was created
- Getting the guild from a message
- Important note about guild members
- Checking if a message is a direct message (DM)
- Getting multiple messages from a channel
- Playing audio over a voice connection
Embeds are sent through the ChannelMessageSendEmbed method. To do so, you will need to create an embed.
embed := &discordgo.MessageEmbed{
Author: &discordgo.MessageEmbedAuthor{},
Color: 0x00ff00, // Green
Description: "This is a discordgo embed",
Fields: []*discordgo.MessageEmbedField{
&discordgo.MessageEmbedField{
Name: "I am a field",
Value: "I am a value",
Inline: true,
},
&discordgo.MessageEmbedField{
Name: "I am a second field",
Value: "I am a value",
Inline: true,
},
},
Image: &discordgo.MessageEmbedImage{
URL: "https://cdn.discordapp.com/avatars/119249192806776836/cc32c5c3ee602e1fe252f9f595f9010e.jpg?size=2048",
},
Thumbnail: &discordgo.MessageEmbedThumbnail{
URL: "https://cdn.discordapp.com/avatars/119249192806776836/cc32c5c3ee602e1fe252f9f595f9010e.jpg?size=2048",
},
Timestamp: time.Now().Format(time.RFC3339), // Discord wants ISO8601; RFC3339 is an extension of ISO8601 and should be completely compatible.
Title: "I am an Embed",
}
session.ChannelMessageSendEmbed(channelid, embed)
Because creating an embed is a lot of typing, you could simplify it by creating a struct that anonymously embeds the *discordgo.MessageEmbed and use that to create helper functions.
Here is an example, which copies discord.js's helper functions for embeds. Using this, the previous method of creating an embed would become
embed := NewEmbed().
SetTitle("I am an embed").
SetDescription("This is a discordgo embed").
AddField("I am a field", "I am a value").
AddField("I am a second field", "I am a value").
SetImage("https://cdn.discordapp.com/avatars/119249192806776836/cc32c5c3ee602e1fe252f9f595f9010e.jpg?size=2048").
SetThumbnail("https://cdn.discordapp.com/avatars/119249192806776836/cc32c5c3ee602e1fe252f9f595f9010e.jpg?size=2048").
SetColor(0x00ff00).MessageEmbed
session.ChannelMessageSendEmbed(channelid, embed)
Attachments can be used to send files along with embed messages.
f, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer f.Close()
ms := &discordgo.MessageSend{
Embed: &discordgo.MessageEmbed{
Image: &discordgo.MessageEmbedImage{
URL: "attachment://" + fileName,
},
},
Files: []*discordgo.File{
&discordgo.File{
Name: fileName,
Reader: f,
},
},
}
s.ChannelMessageSendComplex(channelID, ms)
Discord permissions are stored as an integer. To extract the permission from the role you need to use the bitwise AND (&) operator and see if the result is not zero.
If you are checking permissions specific to channels, make sure to remember the channel PermissionOverides which can either allow or deny a permission to a role, this is done for you with UserChannelPermissions
// MemberHasPermission checks if a member has the given permission
// for example, If you would like to check if user has the administrator
// permission you would use
// --- MemberHasPermission(s, guildID, userID, discordgo.PermissionAdministrator)
// If you want to check for multiple permissions you would use the bitwise OR
// operator to pack more bits in. (e.g): PermissionAdministrator|PermissionAddReactions
// =================================================================================
// s : discordgo session
// guildID : guildID of the member you wish to check the roles of
// userID : userID of the member you wish to retrieve
// permission : the permission you wish to check for
func MemberHasPermission(s *discordgo.Session, guildID string, userID string, permission int) (bool, error) {
member, err := s.State.Member(guildID, userID)
if err != nil {
if member, err = s.GuildMember(guildID, userID); err != nil {
return false, err
}
}
// Iterate through the role IDs stored in member.Roles
// to check permissions
for _, roleID := range member.Roles {
role, err := s.State.Role(guildID, roleID)
if err != nil {
return false, err
}
if role.Permissions&permission != 0 {
return true, nil
}
}
return false, nil
}
A snowflake is what discord uses for its ID system, (e.g) user.ID
, channel.ID
, guild.ID
.
// CreationTime returns the creation time of a Snowflake ID relative to the creation of Discord.
// Taken from https://github.com/Moonlington/FloSelfbot/blob/master/commands/commandutils.go#L117
func CreationTime(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
}
To get a guild from a message you first need to obtain the guildID from the channel. then get the guild from the guildID property of the channel.
Getting the channel and guild from the state is optional.
NOTE: the old method of getting a guild from a message required first getting the channel to get the GuildID and then retrieving the guild from there. Now that the guildID is stored in the message struct, as well as many others, this is no longer needed.
// Attempt to get the guild from the state,
// If there is an error, fall back to the restapi.
guild, err := session.State.Guild(message.GuildID)
if err != nil {
guild, err = session.Guild(message.GuildID)
if err != nil {
return
}
}
I want to let you know that the Session.GuildMember()
function does not fill in the GuildID
field of the Member
struct. Session.State.Member()
does fill it. Because I know some people who did have some issues with that fact, I decided to create a little FAQ entry.
// ComesFromDM returns true if a message comes from a DM channel
func ComesFromDM(s *discordgo.Session, m *discordgo.MessageCreate) (bool, error) {
channel, err := s.State.Channel(m.ChannelID)
if err != nil {
if channel, err = s.Channel(m.ChannelID); err != nil {
return false, err
}
}
return channel.Type == discordgo.ChannelTypeDM, nil
}
Only bots have access to the ChannelMessages function. If you are using a user account, you will have to fetch the messages through the state.
example:
// This will fetch a limit of 100 messages from channelID
// The beforeID, aroundID, and afterID are optional parameters so they can
// Be left blank
messages, _ := session.ChannelMessages(channelID, 100, "", "", "")
To utilize the message caching feature of the state, you have to set State.MaxMessageLimit
to a value greater than zero.
example:
// Create a discordgo session and set the state message tracking limit
session, _ := discordgo.New("Bot token")
session.State.MaxMessageLimit = 100;
// Obtain messages from channel
channel, _ := session.State.Channel(channelID)
for i := 0; i < 100; i++ {
fmt.Println(channel.Messages[i].Content)
}
If you want to find the voice channel a user is currently in, you need to search for their voice state in the State. This example scans over every guild's voice states to find the User's.
func findUserVoiceState(session *discordgo.Session, userid string) (*discordgo.VoiceState, error) {
for _, guild := range session.State.Guilds {
for _, vs := range guild.VoiceStates {
if vs.UserID == userid {
return vs, nil
}
}
}
return nil, errors.New("Could not find user's voice state")
}
If you only want to scan a single guild, you can obtain a guild from state using State.Guild
and scan for the userID in the voice states.
func joinUserVoiceChannel(session *discordgo.Session, userID string) (*discordgo.VoiceConnection, error) {
// Find a user's current voice channel
vs, err := findUserVoiceState(session, userID)
if err != nil {
return nil, err
}
// Join the user's channel and start unmuted and deafened.
return session.ChannelVoiceJoin(vs.GuildID, vs.ChannelID, false, true)
}
// Reads an opus packet to send over the vc.OpusSend channel
func readOpus(source io.Reader) ([]byte, error) {
var opuslen int16
err := binary.Read(source, binary.LittleEndian, &opuslen)
if err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
return nil, err
}
return nil, errors.New("ERR reading opus header")
}
var opusframe = make([]byte, opuslen)
err = binary.Read(source, binary.LittleEndian, &opusframe)
if err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
return nil, err
}
return nil, errors.New("ERR reading opus frame")
}
return opusframe, nil
}