Browse Source

Add a new example that acts like airhorn.solutions

Chris Rhodes 8 years ago
parent
commit
290da20da7
4 changed files with 228 additions and 0 deletions
  1. 41 0
      examples/airhorn/README.md
  2. BIN
      examples/airhorn/airhorn.dca
  3. 186 0
      examples/airhorn/main.go
  4. 1 0
      examples/new_basic/main.go

+ 41 - 0
examples/airhorn/README.md

@@ -0,0 +1,41 @@
+<img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png">
+Airhorn Example
+====
+
+This example demonstrates how to utilize DiscordGo to listen to an !airhorn
+command in a channel and play a sound to that users current voice channel.
+
+### Build
+
+This assumes you already have a working Go environment setup and that
+DiscordGo is correctly installed on your system.
+
+```sh
+go install github.com/bwmarrin/discordgo/examples/airhorn
+cd $GOPATH/bin
+cp ../src/github.com/bwmarrin/discordgo/examples/airhorn/airhorn.dca .
+```
+
+### Usage
+
+```
+Usage of ./airhorn:
+  -t string
+        Account Token
+```
+
+The below example shows how to start the bot.
+
+```sh
+./airhorn -t <bot token>
+```
+
+### Creating sounds
+
+Airhorn bot uses DCA files that are pre-computed files that are easy to send to Discord.
+
+If you would like to create your own DCA files, please use [https://github.com/bwmarrin/dca/tree/master/cmd/dca](DCA).
+
+```sh
+./dca -i <input wav file> -raw > <output file>
+```

BIN
examples/airhorn/airhorn.dca


+ 186 - 0
examples/airhorn/main.go

@@ -0,0 +1,186 @@
+package main
+
+import (
+	"encoding/binary"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/bwmarrin/discordgo"
+)
+
+func init() {
+	flag.StringVar(&token, "t", "", "Account Token")
+	flag.Parse()
+}
+
+var token string
+var buffer = make([][]byte, 0)
+
+func main() {
+	if token == "" {
+		fmt.Println("No token provided. Please run: airhorn -t <bot token>")
+		return
+	}
+
+	// Load the sound file.
+	err := loadSound()
+	if err != nil {
+		fmt.Println("Error loading sound: ", err)
+		fmt.Println("Please copy $GOPATH/src/github.com/bwmarrin/examples/airhorn/airhorn.dca to this directory.")
+		return
+	}
+
+	// Create a new Discord session using the provided token.
+	dg, err := discordgo.New(token)
+	if err != nil {
+		fmt.Println("Error creating Discord session: ", err)
+		return
+	}
+
+	// Register ready as a callback for the ready events.
+	dg.AddHandler(ready)
+
+	// Register messageCreate as a callback for the messageCreate events.
+	dg.AddHandler(messageCreate)
+
+	// Register guildCreate as a callback for the guildCreate events.
+	dg.AddHandler(guildCreate)
+
+	// Open the websocket and begin listening.
+	err = dg.Open()
+	if err != nil {
+		fmt.Println("Error opening Discord session: ", err)
+	}
+
+	fmt.Println("Airhorn is now running.  Press CTRL-C to exit.")
+	// Simple way to keep program running until CTRL-C is pressed.
+	<-make(chan struct{})
+	return
+}
+
+func ready(s *discordgo.Session, event *discordgo.Ready) {
+	// Set the playing status.
+	s.UpdateStatus(0, "!airhorn")
+}
+
+// This function will be called (due to AddHandler above) every time a new
+// message is created on any channel that the autenticated bot has access to.
+func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
+	if strings.HasPrefix(m.Content, "!airhorn") {
+		// Find the channel that the message came from.
+		c, err := s.State.Channel(m.ChannelID)
+		if err != nil {
+			// Could not find channel.
+			return
+		}
+
+		// Find the guild for that channel.
+		g, err := s.State.Guild(c.GuildID)
+		if err != nil {
+			// Could not find guild.
+			return
+		}
+
+		// Look for the message sender in that guilds current voice states.
+		for _, vs := range g.VoiceStates {
+			if vs.UserID == m.Author.ID {
+				err = playSound(s, g.ID, vs.ChannelID)
+				if err != nil {
+					fmt.Println("Error playing sound:", err)
+				}
+
+				return
+			}
+		}
+	}
+}
+
+// This function will be called (due to AddHandler above) every time a new
+// guild is joined.
+func guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
+	if event.Guild.Unavailable != nil {
+		return
+	}
+
+	for _, channel := range event.Guild.Channels {
+		if channel.ID == event.Guild.ID {
+			s.ChannelMessageSend(channel.ID, "Airhorn is ready! Type !airhorn while in a voice channel to play a sound.")
+			return
+		}
+	}
+}
+
+// loadSound attempts to load an encoded sound file from disk.
+func loadSound() error {
+	file, err := os.Open("airhorn.dca")
+
+	if err != nil {
+		fmt.Println("Error opening dca file :", err)
+		return err
+	}
+
+	var opuslen int16
+
+	for {
+		// Read opus frame length from dca file.
+		err = binary.Read(file, binary.LittleEndian, &opuslen)
+
+		// If this is the end of the file, just return.
+		if err == io.EOF || err == io.ErrUnexpectedEOF {
+			return nil
+		}
+
+		if err != nil {
+			fmt.Println("Error reading from dca file :", err)
+			return err
+		}
+
+		// Read encoded pcm from dca file.
+		InBuf := make([]byte, opuslen)
+		err = binary.Read(file, binary.LittleEndian, &InBuf)
+
+		// Should not be any end of file errors
+		if err != nil {
+			fmt.Println("Error reading from dca file :", err)
+			return err
+		}
+
+		// Append encoded pcm data to the buffer.
+		buffer = append(buffer, InBuf)
+	}
+}
+
+// playSound plays the current buffer to the provided channel.
+func playSound(s *discordgo.Session, guildID, channelID string) (err error) {
+	// Join the provided voice channel.
+	vc, err := s.ChannelVoiceJoin(guildID, channelID, false, false)
+	if err != nil {
+		return err
+	}
+
+	// Sleep for a specified amount of time before playing the sound
+	time.Sleep(250 * time.Millisecond)
+
+	// Start speaking.
+	vc.Speaking(true)
+
+	// Send the buffer data.
+	for _, buff := range buffer {
+		vc.OpusSend <- buff
+	}
+
+	// Stop speaking
+	vc.Speaking(false)
+
+	// Sleep for a specificed amount of time before ending.
+	time.Sleep(250 * time.Millisecond)
+
+	// Disconnect from the provided voice channel.
+	vc.Disconnect()
+
+	return nil
+}

+ 1 - 0
examples/new_basic/main.go

@@ -26,6 +26,7 @@ func init() {
 func main() {
 
 	// Create a new Discord session using the provided login information.
+	// Use discordgo.New(Token) to just use a token for login.
 	dg, err := discordgo.New(Email, Password, Token)
 	if err != nil {
 		fmt.Println("error creating Discord session,", err)