-
Notifications
You must be signed in to change notification settings - Fork 822
- Contents
- HTTP 401 Errors
- Sending embeds
- Get the time a snowflake was created
- Getting the guild from a message
- Checking if a message is from a private channel
- Getting multiple messages from a channel
- Playing audio over a voice connection
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`)
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().String(),
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)
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.
// 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
}
}
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")
}
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
}
// Connect to a user's voice channel
vc, err := joinUserVoiceChannel(sesssion, userid)
if err != nil {
return
}
// Get youtube stream
yt, err := youtubePy("https://www.youtube.com/watch?v=0Z8weY8MJxc")
if err != nil {
return
}
// Create opus stream
stream, err := convertToOpus(yt)
if err != nil {
return
}
// Loop until the audio is done playing.
for {
opus, err := readOpus(stream)
if err != nil {
if err == io.ErrUnexpectedEOF || err == io.EOF {
break
}
fmt.Println("Audio error: ", err)
}
vc.OpusSend <- opus
}