736 lines
17 KiB
Go
736 lines
17 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"math/rand"
|
|
"os"
|
|
"os/signal"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"text/tabwriter"
|
|
"time"
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
"github.com/bwmarrin/discordgo"
|
|
"github.com/dustin/go-humanize"
|
|
)
|
|
|
|
var (
|
|
// discordgo session
|
|
discord *discordgo.Session
|
|
|
|
// Map of Guild id's to *Play channels, used for queuing and rate-limiting guilds
|
|
queues = make(map[string]chan *Play)
|
|
|
|
// bitrate Sound encoding settings
|
|
bitrate = 128
|
|
// maxQueueSize Sound encoding settings
|
|
maxQueueSize = 6
|
|
|
|
// OWNER variable
|
|
OWNER string
|
|
)
|
|
|
|
// Play represents an individual use of the !airhorn command
|
|
type Play struct {
|
|
GuildID string
|
|
ChannelID string
|
|
UserID string
|
|
Sound *Sound
|
|
|
|
// The next play to occur after this, only used for chaining sounds like anotha
|
|
Next *Play
|
|
|
|
// If true, this was a forced play using a specific airhorn sound name
|
|
Forced bool
|
|
}
|
|
|
|
// SoundCollection of Sounds
|
|
type SoundCollection struct {
|
|
Prefix string
|
|
Commands []string
|
|
Sounds []*Sound
|
|
ChainWith *SoundCollection
|
|
|
|
soundRange int
|
|
}
|
|
|
|
// Sound represents a sound clip
|
|
type Sound struct {
|
|
Name string
|
|
|
|
// Weight adjust how likely it is this song will play, higher = more likely
|
|
Weight int
|
|
|
|
// Delay (in milliseconds) for the bot to wait before sending the disconnect request
|
|
PartDelay int
|
|
|
|
// Buffer to store encoded PCM packets
|
|
buffer [][]byte
|
|
}
|
|
|
|
// AIRHORN Array of all the sounds we have
|
|
var AIRHORN = &SoundCollection{
|
|
Prefix: "airhorn",
|
|
Commands: []string{
|
|
"!airhorn",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("default", 1000, 250),
|
|
createSound("reverb", 800, 250),
|
|
createSound("spam", 800, 0),
|
|
createSound("tripletap", 800, 250),
|
|
createSound("fourtap", 800, 250),
|
|
createSound("distant", 500, 250),
|
|
createSound("echo", 500, 250),
|
|
createSound("clownfull", 250, 250),
|
|
createSound("clownshort", 250, 250),
|
|
createSound("clownspam", 250, 0),
|
|
createSound("highfartlong", 200, 250),
|
|
createSound("highfartshort", 200, 250),
|
|
createSound("midshort", 100, 250),
|
|
createSound("truck", 10, 250),
|
|
},
|
|
}
|
|
|
|
// BSTH collection
|
|
var BSTH = &SoundCollection{
|
|
Prefix: "bsth",
|
|
Commands: []string{
|
|
"!bsth",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("achso", 1, 250),
|
|
createSound("angeben", 1, 250),
|
|
createSound("aufwiedersehen", 1, 250),
|
|
createSound("bluemchen", 1, 250),
|
|
createSound("blutsprobe", 1, 250),
|
|
createSound("chefkoch", 1, 250),
|
|
createSound("danke", 1, 250),
|
|
createSound("eindummer", 1, 250),
|
|
createSound("eleganz", 1, 250),
|
|
createSound("fettesau", 1, 250),
|
|
createSound("fett", 1, 250),
|
|
createSound("fressen", 1, 250),
|
|
createSound("geraeusch", 1, 250),
|
|
createSound("gottseimitdir", 1, 250),
|
|
createSound("gruss", 1, 250),
|
|
createSound("gulli", 1, 250),
|
|
createSound("harfenkonzert", 1, 250),
|
|
createSound("hosen", 1, 250),
|
|
createSound("indiehose", 1, 250),
|
|
createSound("kai", 1, 250),
|
|
createSound("kalkleiste", 1, 250),
|
|
createSound("keinegrauenzellen", 1, 250),
|
|
createSound("kohlen", 1, 250),
|
|
createSound("meinspruch", 1, 250),
|
|
createSound("miete", 1, 250),
|
|
createSound("nuesse", 1, 250),
|
|
createSound("ohneheu", 1, 250),
|
|
createSound("riecher", 1, 250),
|
|
createSound("sauer", 1, 250),
|
|
createSound("schatten", 1, 250),
|
|
createSound("scheitel", 1, 250),
|
|
createSound("solingen", 1, 250),
|
|
createSound("unglaublich", 1, 250),
|
|
createSound("unmoeglich", 1, 250),
|
|
createSound("vortreten", 1, 250),
|
|
createSound("zufaellig", 1, 250),
|
|
createSound("arschloch", 1, 250),
|
|
createSound("aufstossen", 1, 250),
|
|
createSound("ausholen", 1, 250),
|
|
createSound("blaehungen", 1, 250),
|
|
createSound("haesslich", 1, 250),
|
|
createSound("horchlappen", 1, 250),
|
|
createSound("interesseng", 1, 250),
|
|
createSound("keingrips", 1, 250),
|
|
createSound("kriegicheineis", 1, 250),
|
|
createSound("lachespaeter", 1, 250),
|
|
createSound("machtjanix", 1, 250),
|
|
createSound("nichtsofett", 1, 250),
|
|
createSound("schweine", 1, 250),
|
|
createSound("unfreundlich", 1, 250),
|
|
createSound("verheiratet", 1, 250),
|
|
createSound("zulaut", 1, 250),
|
|
},
|
|
}
|
|
|
|
// BSTH2 collection
|
|
var BSTH2 = &SoundCollection{
|
|
Prefix: "bsth2",
|
|
Commands: []string{
|
|
"!bsth2",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("abendplanung", 1, 250),
|
|
createSound("alleine", 1, 250),
|
|
createSound("chefkoch", 1, 250),
|
|
createSound("fett", 1, 250),
|
|
createSound("hubschrauber", 1, 250),
|
|
createSound("perspektive", 1, 250),
|
|
createSound("platonisch", 1, 250),
|
|
createSound("qualle", 1, 250),
|
|
},
|
|
}
|
|
|
|
// KHALED collection
|
|
var KHALED = &SoundCollection{
|
|
Prefix: "another",
|
|
ChainWith: AIRHORN,
|
|
Commands: []string{
|
|
"!anotha",
|
|
"!anothaone",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("one", 1, 250),
|
|
createSound("one_classic", 1, 250),
|
|
createSound("one_echo", 1, 250),
|
|
},
|
|
}
|
|
|
|
// CENA collection
|
|
var CENA = &SoundCollection{
|
|
Prefix: "jc",
|
|
Commands: []string{
|
|
"!johncena",
|
|
"!cena",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("airhorn", 1, 250),
|
|
createSound("echo", 1, 250),
|
|
createSound("full", 1, 250),
|
|
createSound("jc", 1, 250),
|
|
createSound("nameis", 1, 250),
|
|
createSound("spam", 1, 250),
|
|
},
|
|
}
|
|
|
|
// ETHAN collection
|
|
var ETHAN = &SoundCollection{
|
|
Prefix: "ethan",
|
|
Commands: []string{
|
|
"!ethan",
|
|
"!eb",
|
|
"!ethanbradberry",
|
|
"!h3h3",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("areyou_classic", 100, 250),
|
|
createSound("areyou_condensed", 100, 250),
|
|
createSound("areyou_crazy", 100, 250),
|
|
createSound("areyou_ethan", 100, 250),
|
|
createSound("classic", 100, 250),
|
|
createSound("echo", 100, 250),
|
|
createSound("high", 100, 250),
|
|
createSound("slowandlow", 100, 250),
|
|
createSound("cuts", 30, 250),
|
|
createSound("beat", 30, 250),
|
|
createSound("sodiepop", 1, 250),
|
|
},
|
|
}
|
|
|
|
// COW collection
|
|
var COW = &SoundCollection{
|
|
Prefix: "cow",
|
|
Commands: []string{
|
|
"!stan",
|
|
"!stanislav",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("herd", 10, 250),
|
|
createSound("moo", 10, 250),
|
|
createSound("x3", 1, 250),
|
|
},
|
|
}
|
|
|
|
// BIRTHDAY collection
|
|
var BIRTHDAY = &SoundCollection{
|
|
Prefix: "birthday",
|
|
Commands: []string{
|
|
"!birthday",
|
|
"!bday",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("horn", 50, 250),
|
|
createSound("horn3", 30, 250),
|
|
createSound("sadhorn", 25, 250),
|
|
createSound("weakhorn", 25, 250),
|
|
},
|
|
}
|
|
|
|
// WOW collection
|
|
var WOW = &SoundCollection{
|
|
Prefix: "wow",
|
|
Commands: []string{
|
|
"!wowthatscool",
|
|
"!wtc",
|
|
},
|
|
Sounds: []*Sound{
|
|
createSound("thatscool", 50, 250),
|
|
},
|
|
}
|
|
|
|
// COLLECTIONS all collections
|
|
var COLLECTIONS = []*SoundCollection{
|
|
AIRHORN,
|
|
KHALED,
|
|
CENA,
|
|
ETHAN,
|
|
COW,
|
|
BIRTHDAY,
|
|
WOW,
|
|
BSTH,
|
|
BSTH2,
|
|
}
|
|
|
|
// Create a Sound struct
|
|
func createSound(Name string, Weight int, PartDelay int) *Sound {
|
|
return &Sound{
|
|
Name: Name,
|
|
Weight: Weight,
|
|
PartDelay: PartDelay,
|
|
buffer: make([][]byte, 0),
|
|
}
|
|
}
|
|
|
|
// Load soundcollection
|
|
func (sc *SoundCollection) Load() {
|
|
for _, sound := range sc.Sounds {
|
|
sc.soundRange += sound.Weight
|
|
sound.Load(sc)
|
|
}
|
|
}
|
|
|
|
// Random select sound
|
|
func (sc *SoundCollection) Random() *Sound {
|
|
var (
|
|
i int
|
|
number = randomRange(0, sc.soundRange)
|
|
)
|
|
|
|
for _, sound := range sc.Sounds {
|
|
i += sound.Weight
|
|
|
|
if number < i {
|
|
return sound
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Load attempts to load an encoded sound file from disk
|
|
// DCA files are pre-computed sound files that are easy to send to Discord.
|
|
// If you would like to create your own DCA files, please use:
|
|
// https://github.com/nstafie/dca-rs
|
|
// eg: dca-rs --raw -i <input wav file> > <output file>
|
|
func (s *Sound) Load(c *SoundCollection) error {
|
|
path := fmt.Sprintf("audio/%v_%v.dca", c.Prefix, s.Name)
|
|
|
|
file, err := os.Open(path)
|
|
|
|
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
|
|
s.buffer = append(s.buffer, InBuf)
|
|
}
|
|
}
|
|
|
|
// Play plays this sound over the specified VoiceConnection
|
|
func (s *Sound) Play(vc *discordgo.VoiceConnection) {
|
|
vc.Speaking(true)
|
|
defer vc.Speaking(false)
|
|
|
|
for _, buff := range s.buffer {
|
|
vc.OpusSend <- buff
|
|
}
|
|
}
|
|
|
|
// Attempts to find the current users voice channel inside a given guild
|
|
func getCurrentVoiceChannel(user *discordgo.User, guild *discordgo.Guild) *discordgo.Channel {
|
|
for _, vs := range guild.VoiceStates {
|
|
if vs.UserID == user.ID {
|
|
channel, _ := discord.State.Channel(vs.ChannelID)
|
|
return channel
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Returns a random integer between min and max
|
|
func randomRange(min, max int) int {
|
|
rand.Seed(time.Now().UTC().UnixNano())
|
|
return rand.Intn(max-min) + min
|
|
}
|
|
|
|
// Prepares a play
|
|
func createPlay(user *discordgo.User, guild *discordgo.Guild, coll *SoundCollection, sound *Sound) *Play {
|
|
// Grab the users voice channel
|
|
channel := getCurrentVoiceChannel(user, guild)
|
|
if channel == nil {
|
|
log.WithFields(log.Fields{
|
|
"user": user.ID,
|
|
"guild": guild.ID,
|
|
}).Warning("Failed to find channel to play sound in")
|
|
return nil
|
|
}
|
|
|
|
// Create the play
|
|
play := &Play{
|
|
GuildID: guild.ID,
|
|
ChannelID: channel.ID,
|
|
UserID: user.ID,
|
|
Sound: sound,
|
|
Forced: true,
|
|
}
|
|
|
|
// If we didn't get passed a manual sound, generate a random one
|
|
if play.Sound == nil {
|
|
play.Sound = coll.Random()
|
|
play.Forced = false
|
|
}
|
|
|
|
// If the collection is a chained one, set the next sound
|
|
if coll.ChainWith != nil {
|
|
play.Next = &Play{
|
|
GuildID: play.GuildID,
|
|
ChannelID: play.ChannelID,
|
|
UserID: play.UserID,
|
|
Sound: coll.ChainWith.Random(),
|
|
Forced: play.Forced,
|
|
}
|
|
}
|
|
|
|
return play
|
|
}
|
|
|
|
// Prepares and enqueues a play into the ratelimit/buffer guild queue
|
|
func enqueuePlay(user *discordgo.User, guild *discordgo.Guild, coll *SoundCollection, sound *Sound) {
|
|
play := createPlay(user, guild, coll, sound)
|
|
if play == nil {
|
|
return
|
|
}
|
|
|
|
// Check if we already have a connection to this guild
|
|
// yes, this isn't threadsafe, but its "OK" 99% of the time
|
|
_, exists := queues[guild.ID]
|
|
|
|
if exists {
|
|
if len(queues[guild.ID]) < maxQueueSize {
|
|
queues[guild.ID] <- play
|
|
}
|
|
} else {
|
|
queues[guild.ID] = make(chan *Play, maxQueueSize)
|
|
playSound(play, nil)
|
|
}
|
|
}
|
|
|
|
// Play a sound
|
|
func playSound(play *Play, vc *discordgo.VoiceConnection) (err error) {
|
|
log.WithFields(log.Fields{
|
|
"play": play,
|
|
}).Info("Playing sound")
|
|
|
|
if vc == nil {
|
|
vc, err = discord.ChannelVoiceJoin(play.GuildID, play.ChannelID, false, false)
|
|
// vc.Receive = false
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"error": err,
|
|
}).Error("Failed to play sound")
|
|
delete(queues, play.GuildID)
|
|
return err
|
|
}
|
|
}
|
|
|
|
// If we need to change channels, do that now
|
|
if vc.ChannelID != play.ChannelID {
|
|
vc.ChangeChannel(play.ChannelID, false, false)
|
|
time.Sleep(time.Millisecond * 125)
|
|
}
|
|
|
|
// Sleep for a specified amount of time before playing the sound
|
|
time.Sleep(time.Millisecond * 32)
|
|
|
|
// Play the sound
|
|
play.Sound.Play(vc)
|
|
|
|
// If this is chained, play the chained sound
|
|
if play.Next != nil {
|
|
playSound(play.Next, vc)
|
|
}
|
|
|
|
// If there is another song in the queue, recurse and play that
|
|
if len(queues[play.GuildID]) > 0 {
|
|
play = <-queues[play.GuildID]
|
|
playSound(play, vc)
|
|
return nil
|
|
}
|
|
|
|
// If the queue is empty, delete it
|
|
time.Sleep(time.Millisecond * time.Duration(play.Sound.PartDelay))
|
|
delete(queues, play.GuildID)
|
|
vc.Disconnect()
|
|
return nil
|
|
}
|
|
|
|
func onReady(s *discordgo.Session, event *discordgo.Ready) {
|
|
log.Info("Received READY payload.")
|
|
}
|
|
|
|
func scontains(key string, options ...string) bool {
|
|
for _, item := range options {
|
|
if item == key {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func displayBotStats(cid string) {
|
|
stats := runtime.MemStats{}
|
|
runtime.ReadMemStats(&stats)
|
|
|
|
users := 0
|
|
for _, guild := range discord.State.Ready.Guilds {
|
|
users += len(guild.Members)
|
|
}
|
|
|
|
w := &tabwriter.Writer{}
|
|
buf := &bytes.Buffer{}
|
|
|
|
w.Init(buf, 0, 4, 0, ' ', 0)
|
|
fmt.Fprintf(w, "```\n")
|
|
fmt.Fprintf(w, "Discordgo: \t%s\n", discordgo.VERSION)
|
|
fmt.Fprintf(w, "Go: \t%s\n", runtime.Version())
|
|
fmt.Fprintf(w, "Memory: \t%s / %s (%s total allocated)\n", humanize.Bytes(stats.Alloc), humanize.Bytes(stats.Sys), humanize.Bytes(stats.TotalAlloc))
|
|
fmt.Fprintf(w, "Tasks: \t%d\n", runtime.NumGoroutine())
|
|
fmt.Fprintf(w, "Servers: \t%d\n", len(discord.State.Ready.Guilds))
|
|
fmt.Fprintf(w, "Users: \t%d\n", users)
|
|
fmt.Fprintf(w, "```\n")
|
|
w.Flush()
|
|
discord.ChannelMessageSend(cid, buf.String())
|
|
}
|
|
|
|
func utilGetMentioned(s *discordgo.Session, m *discordgo.MessageCreate) *discordgo.User {
|
|
for _, mention := range m.Mentions {
|
|
if mention.ID != s.State.Ready.User.ID {
|
|
return mention
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func airhornBomb(cid string, guild *discordgo.Guild, user *discordgo.User, cs string) {
|
|
count, _ := strconv.Atoi(cs)
|
|
discord.ChannelMessageSend(cid, ":ok_hand:"+strings.Repeat(":trumpet:", count))
|
|
|
|
// Cap it at something
|
|
if count > 100 {
|
|
return
|
|
}
|
|
|
|
play := createPlay(user, guild, AIRHORN, nil)
|
|
vc, err := discord.ChannelVoiceJoin(play.GuildID, play.ChannelID, true, true)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for i := 0; i < count; i++ {
|
|
AIRHORN.Random().Play(vc)
|
|
}
|
|
|
|
vc.Disconnect()
|
|
}
|
|
|
|
// Handles bot operator messages, should be refactored (lmao)
|
|
func handleBotControlMessages(s *discordgo.Session, m *discordgo.MessageCreate, parts []string, g *discordgo.Guild) {
|
|
if scontains(parts[1], "status") {
|
|
displayBotStats(m.ChannelID)
|
|
} else if scontains(parts[1], "bomb") && len(parts) >= 4 {
|
|
airhornBomb(m.ChannelID, g, utilGetMentioned(s, m), parts[3])
|
|
}
|
|
}
|
|
|
|
func setIdleStatus(s *discordgo.Session) {
|
|
games := []string{"Terranigma", "Secret of Mana", "Quake III Arena", "Duke Nukem 3D", "Monkey Island 2: LeChuck's Revenge", "Turtles in Time", "Unreal Tournament", "Half-Life", "Half-Life 2", "Warcraft II", "Starcraft", "Diablo", "Diablo II", "A Link to the Past", "Ocarina of Time", "Star Fox", "Tetris", "Pokémon Red", "Pokémon Blue", "Die Siedler II", "Day of the Tentacle", "Maniac Mansion", "Prince of Persia", "Super Mario Kart"}
|
|
for {
|
|
s.UpdateStreamingStatus(1, "", "")
|
|
s.UpdateStatus(0, games[randomRange(0, len(games))])
|
|
time.Sleep(time.Duration(randomRange(5, 15)) * time.Minute)
|
|
}
|
|
}
|
|
|
|
func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|
if m.Content == "ping" || m.Content == "pong" {
|
|
// If the message is "ping" reply with "Pong!"
|
|
if m.Content == "ping" {
|
|
s.ChannelMessageSend(m.ChannelID, "Pong!")
|
|
}
|
|
|
|
// If the message is "pong" reply with "Ping!"
|
|
if m.Content == "pong" {
|
|
s.ChannelMessageSend(m.ChannelID, "Ping!")
|
|
}
|
|
|
|
// Updating bot status
|
|
s.UpdateStatus(0, "Ping Pong with "+m.Author.Username)
|
|
}
|
|
if len(m.Content) <= 0 || (m.Content[0] != '!' && len(m.Mentions) < 1) {
|
|
return
|
|
}
|
|
|
|
msg := strings.Replace(m.ContentWithMentionsReplaced(), s.State.Ready.User.Username, "username", 1)
|
|
parts := strings.Split(strings.ToLower(msg), " ")
|
|
|
|
channel, _ := discord.State.Channel(m.ChannelID)
|
|
if channel == nil {
|
|
log.WithFields(log.Fields{
|
|
"channel": m.ChannelID,
|
|
"message": m.ID,
|
|
}).Warning("Failed to grab channel")
|
|
return
|
|
}
|
|
|
|
guild, _ := discord.State.Guild(channel.GuildID)
|
|
if guild == nil {
|
|
log.WithFields(log.Fields{
|
|
"guild": channel.GuildID,
|
|
"channel": channel,
|
|
"message": m.ID,
|
|
}).Warning("Failed to grab guild")
|
|
return
|
|
}
|
|
|
|
// If this is a mention, it should come from the owner (otherwise we don't care)
|
|
if len(m.Mentions) > 0 && m.Author.ID == OWNER && len(parts) > 0 {
|
|
mentioned := false
|
|
for _, mention := range m.Mentions {
|
|
mentioned = (mention.ID == s.State.Ready.User.ID)
|
|
if mentioned {
|
|
break
|
|
}
|
|
}
|
|
|
|
if mentioned {
|
|
handleBotControlMessages(s, m, parts, guild)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Find the collection for the command we got
|
|
for _, coll := range COLLECTIONS {
|
|
if scontains(parts[0], coll.Commands...) {
|
|
|
|
// If they passed a specific sound effect, find and select that (otherwise play nothing)
|
|
var sound *Sound
|
|
if len(parts) > 1 {
|
|
for _, s := range coll.Sounds {
|
|
if parts[1] == s.Name {
|
|
sound = s
|
|
}
|
|
}
|
|
|
|
if sound == nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
go enqueuePlay(m.Author, guild, coll, sound)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
var (
|
|
Token = flag.String("t", "", "Discord Authentication Token")
|
|
Shard = flag.String("s", "", "Shard ID")
|
|
ShardCount = flag.String("c", "", "Number of shards")
|
|
Owner = flag.String("o", "", "Owner ID")
|
|
err error
|
|
)
|
|
flag.Parse()
|
|
|
|
if *Owner != "" {
|
|
OWNER = *Owner
|
|
}
|
|
|
|
// Preload all the sounds
|
|
log.Info("Preloading sounds...")
|
|
for _, coll := range COLLECTIONS {
|
|
coll.Load()
|
|
}
|
|
|
|
// Create a discord session
|
|
log.Info("Starting discord session...")
|
|
discord, err = discordgo.New("Bot " + *Token)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"error": err,
|
|
}).Fatal("Failed to create discord session")
|
|
return
|
|
}
|
|
|
|
// Set sharding info
|
|
discord.ShardID, _ = strconv.Atoi(*Shard)
|
|
discord.ShardCount, _ = strconv.Atoi(*ShardCount)
|
|
|
|
if discord.ShardCount <= 0 {
|
|
discord.ShardCount = 1
|
|
}
|
|
|
|
discord.AddHandler(onReady)
|
|
discord.AddHandler(onMessageCreate)
|
|
|
|
err = discord.Open()
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"error": err,
|
|
}).Fatal("Failed to create discord websocket connection")
|
|
return
|
|
}
|
|
|
|
go setIdleStatus(discord)
|
|
// We're running!
|
|
log.Info("Gidbig is ready. Quit with CTRL-C.")
|
|
|
|
// Wait for a signal to quit
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt, os.Kill)
|
|
<-c
|
|
}
|