/
main.go
186 lines (163 loc) · 4.76 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package main
import (
"log"
"os"
"os/signal"
"strings"
"syscall"
"github.com/Gaoyagi/dgvoice"
"github.com/bwmarrin/discordgo"
"github.com/spf13/viper"
"time"
)
var bound bool = false
var chlBound string
var guildID string
var queue = make(chan string, 20)
var voiceCall *discordgo.VoiceConnection
var killch = make(chan bool, 2)
// load the .env file
func loadDotEnv() {
viper.SetConfigFile(".env")
viper.ReadInConfig()
}
func main() {
loadDotEnv()
//create discord session
session, err := discordgo.New("Bot " + viper.GetString("BOT_TOKEN"))
if err!=nil {
log.Println("Unable to create Discord session", err)
return
}
//this add handler handles whenever a message is created
//the message created is a callback
session.AddHandler(msgCreate)
// Open a websocket connection to Discord and begin listening.
err = session.Open()
if err != nil {
log.Println("error opening connection,", err)
return
}
// Wait here until CTRL-C or other term signal is received.
log.Println("Bot is now running. Press CTRL-C to exit.")
go playSong()
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-sc
// Cleanly close down the Discord session.
session.Close()
}
//checks everytime a message is created
//should look for channel origin, an @, commands
func msgCreate(session *discordgo.Session, msg *discordgo.MessageCreate) {
split := strings.Split(msg.Content, " ") //split message up by word
// if unbound
if !bound{
// checks to see if this message will bind it (command: @Doot-Doot bind)
if msg.Mentions[0].ID==session.State.User.ID{
if len(split)==2 && split[1]=="bind"{
bound = true
chlBound = msg.ChannelID
log.Println("doot-doot is now bound")
}
}
// if bound
} else {
// only consider messages if not from itself and if in bounded channel
if msg.ChannelID == chlBound && msg.Author.ID != session.State.User.ID {
switch split[0] {
// joins vc and then plays specified song (!play songFile)
case "!play":
log.Println("this is the play command")
// check if bot is already in call
if voiceCall == nil {
vc, err := joinCall(session, msg.Author.ID) // joins vc
if err!=nil {
log.Println("Unable to join VC")
} else {
voiceCall = vc
}
}
if voiceCall!=nil {
// if the play command doesnt include a url/file name
if len(split)!=2{
session.ChannelMessageSend(chlBound, "no file name or url detected")
} else {
queue <- split[1]
}
}
// skips to the next song in queue
case "!skip":
log.Println("this is skip the command")
killch <- true
// stops playing music and leaves the call,
case "!stop":
log.Println("this is the stop command")
//clears the queue
for len(queue) > 0 {
temp:=<-queue
log.Println("cleared "+ temp)
}
killch <- true // sends a value to killch, should kill ffmpeg in playaudiofile
time.Sleep(1*time.Second) // need to wait for the audio stream to close compeltly before exiting the vc
voiceCall.Disconnect() // leaves the vc
voiceCall = nil
// case "!leave":
// voiceCall.Disconnect() // leaves the vc
// voiceCall = nil
default:
log.Println("invalid command")
session.ChannelMessageSend(chlBound, "invalid command")
}
} else {
return
}
}
}
// joins the same voice channel as the user who requested the song
func joinCall(session *discordgo.Session, userID string) (*discordgo.VoiceConnection, error){
// gets the guild that they belong to
chnl, err := session.Channel(chlBound)
if err!=nil {
log.Println("Unable to obtain bound Discord channel")
return nil, err
}
guildID = chnl.GuildID
// use state.voicestate to get the voice state of the user who called it
vs, err := session.State.VoiceState(guildID, userID)
if err!=nil {
log.Println("User is not part of a Voice Call (unable to create VoiceState)")
return nil, err
}
// use the voice state to get the voice channel the user is in
// join that voice channel
return session.ChannelVoiceJoin(guildID, vs.ChannelID, false, false)
}
func playSong() {
for {
song:= <-queue
log.Println("now playing " + song)
dgvoice.PlayAudioFile(voiceCall, "music/"+song, killch)
}
}
func downloadSong(session *discordgo.Session, file string, voiceCall*discordgo.VoiceConnection) {
/* illegal to use due to dmca and youtube terms of service
client := youtube.Client{}
video, err := client.GetVideo(videoID)
if err != nil {
panic(err)
}
stream, _, err := client.GetStream(video, &video.Formats[0])
if err != nil {
panic(err)
}
file, err := os.Create("video.mp4")
if err != nil {
panic(err)
}
defer file.Close()
_, err = io.Copy(file, stream)
if err != nil {
panic(err)
}*/
}