Skip to content
Chris Rhodes edited this page Apr 13, 2018 · 49 revisions

Contents

HTTP 401 Errors

HTTP 401 Unauthorized, {"code": 0, "message": "401: Unauthorized"}

You may be getting a 401 error if you forgot to prefix your token with Bot . Discord requires that you do so to authenticate with a bot user.

example:

discordgo.New(`Bot 123456789012345627`)

Sending embeds

Embeds are sent through the ChannelMessageSendEmbed method. To do so, you will need to create an embed.

Creating 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().String(),
    Title:     "I am an Embed",
}

session.ChannelMessageSendEmbed(channelid, embed)

Simplifying Embeds

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)

Embeds using attachments

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)

Get the time a snowflake was created

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
}

Getting the guild from a message

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.

// Attempt to get the channel from the state.
// If there is an error, fall back to the restapi
channel, err := session.State.Channel(msg.ChannelID)
if err != nil {
    channel, err = session.Channel(msg.ChannelID)
    if err != nil {
        return
    }
}

// Attempt to get the guild from the state, 
// If there is an error, fall back to the restapi.
guild, err := session.State.Guild(channel.GuildID)
if err != nil {
    guild, err = session.Guild(channel.GuildID)
    if err != nil {
        return
    }
}

Checking if a message is from a private channel

Cléo - Today at 1:02 PM
Hoo, okay
Finally managed to do it
func isTheChannelTheMessageWasSentInPrivate(s *discordgo.Session, m *discordgo.MessageCreate) {
    channel, err := s.State.Channel(m.ChannelID)
    if err != nil {
        astilog.Fatal(err)
        return
    } else if m.Author.ID == s.State.User.ID {
        return
    }
    channelIsPrivate := strconv.FormatBool(channel.IsPrivate)
    print("Channel ID: " + m.ChannelID + ". Is it private? " + channelIsPrivate + "\n")
}

Getting multiple messages from a channel

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.

Bot account

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, "", "", "")

User account

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)
}

Playing audio over a voice connection

Finding a user's voice channel

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.

Connecting to voice a channel

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)
}

Reading opus

// 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
}

Sending opus

Follow the instructions here.

Clone this wiki locally