From a47f6b2df18996a63ea8453e96dd7ff2b0916e32 Mon Sep 17 00:00:00 2001 From: adminoo Date: Sun, 13 Dec 2020 16:14:23 +0100 Subject: [PATCH] talk in audio channel (not working yet) --- core/audio.go | 53 ++++++++++++++++++++++++++++++++++++++ core/commands.go | 6 +++++ core/messages.go | 67 ++++++++++++++++++++++++++++++++++++++---------- main.go | 6 +++++ 4 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 core/audio.go diff --git a/core/audio.go b/core/audio.go new file mode 100644 index 0000000..5a08bd0 --- /dev/null +++ b/core/audio.go @@ -0,0 +1,53 @@ +package core + +import ( + "fmt" + "log" + "os/exec" + "time" + + "github.com/bwmarrin/discordgo" +) + +// playSound plays the current buffer to the provided channel. +func playSound(s *discordgo.Session, guildID, channelID string, buffer []byte) (err error) { + + // Join the provided voice channel. + vc, err := s.ChannelVoiceJoin(guildID, channelID, false, true) + if err != nil { + log.Println("Could not find channel.") + return err + } + + // Sleep for a specified amount of time before playing the sound + time.Sleep(250 * time.Millisecond) + + // Start speaking. + vc.Speaking(true) + + vc.OpusSend <- buffer + + // 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 +} + +func getAudioMessage(msg string) (filename string, out []byte) { + curr_time := time.Now().Unix() + filename = fmt.Sprintf("%d.ogg", curr_time) + var cmd_args string = fmt.Sprintf("espeak-ng -s 120 -v mb-fr2 -p 30 '%s' --stdout | ffmpeg -i - -c:a libopus -f ogg pipe:1 2>/dev/null", + maxString(msg, 300)) + cmd := exec.Command("sh", "-c", cmd_args) + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Println(fmt.Sprint(err)) + } + return +} diff --git a/core/commands.go b/core/commands.go index b33d45c..df08a9b 100644 --- a/core/commands.go +++ b/core/commands.go @@ -41,6 +41,12 @@ func CommandInit() { "`/ggd [audio|tts] hello everyone`", MessageAudio) + SetCommand( + []string{"/ggd voca"}, + "Play audio message in vocal channel", + "`/ggd voca let's go shopping`", + MessageVocal) + SetCommand( []string{"ping", "pong"}, "*Check if the bot is alive*", diff --git a/core/messages.go b/core/messages.go index fb98937..35e8d26 100644 --- a/core/messages.go +++ b/core/messages.go @@ -3,7 +3,7 @@ package core import ( "bytes" "fmt" - "os/exec" + "log" "math/rand" "sort" "strings" @@ -12,18 +12,20 @@ import ( "github.com/bwmarrin/discordgo" ) -func getAudioMessage(msg string) (filename string, file *bytes.Reader) { - curr_time := time.Now().Unix() - filename = fmt.Sprintf("/tmp/%d.mp3", curr_time) - var cmd_args string = fmt.Sprintf("espeak-ng -s 120 -v mb-fr2 -p 30 '%s' --stdout", - maxString(msg, 300)) - cmd := exec.Command("sh", "-c", cmd_args) - out, err := cmd.CombinedOutput() - if err != nil { - fmt.Println(fmt.Sprint(err)) +// 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 { + 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 + } } - file = bytes.NewReader(out) - return } func getHelpMessage() string { @@ -113,6 +115,45 @@ func MessagePing(s *discordgo.Session, m *discordgo.MessageCreate, message strin func MessageAudio(s *discordgo.Session, m *discordgo.MessageCreate, message string) { var cleanMessage string = prepareTTSMessage(message) - filename, file := getAudioMessage(cleanMessage) + filename, out := getAudioMessage(cleanMessage) + file := bytes.NewReader(out) s.ChannelFileSend(m.ChannelID, filename, file) } + +func MessageVocal(s *discordgo.Session, m *discordgo.MessageCreate, message string) { + log.Println("We get there (MessageVocal)") + // Ignore all messages created by the bot itself + // This isn't required in this specific example but it's a good practice. + if m.Author.ID == s.State.User.ID { + return + } + + // 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 + } + + var cleanMessage string = prepareTTSMessage(message) + _, out := getAudioMessage(cleanMessage) + + // Look for the message sender in that guild's current voice states. + for _, vs := range g.VoiceStates { + if vs.UserID == m.Author.ID { + log.Println("We get there (MessageVocal) voice state for loop") + err = playSound(s, g.ID, vs.ChannelID, out) + if err != nil { + fmt.Println("Error playing sound:", err) + } + return + } + } +} diff --git a/main.go b/main.go index 23b7397..7e4fd5b 100644 --- a/main.go +++ b/main.go @@ -20,8 +20,14 @@ func main() { return } + discord.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsGuilds | + discordgo.IntentsGuildMessages | + discordgo.IntentsGuildVoiceStates) + + discord.AddHandler(core.MessageHandler) discord.AddHandler(core.MessageTalkback) + discord.AddHandler(core.GuildCreate) err = discord.Open() if err != nil {