Starting this bad boy again. No api keys on the repo
This commit is contained in:
commit
f223c87353
3
.env.example
Normal file
3
.env.example
Normal file
@ -0,0 +1,3 @@
|
||||
DISCORD_APP_ID=
|
||||
DISCORD_PUBLIC_KEY=
|
||||
DISCORD_BOT_TOKEN=
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
testfile.wav
|
||||
play.opus
|
||||
output.opus
|
||||
.env
|
||||
*.wav
|
||||
*.opus
|
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Papi Bot
|
||||
|
||||
Currently in development.
|
||||
|
||||
## Current testing steps
|
||||
|
||||
Copy .env.example to .env
|
||||
|
||||
Populate the discord bot keys
|
||||
|
||||
`go run .`
|
||||
|
||||
type `!` in any channel in the discord while you're in a voice channel.
|
14
convert.sh
Executable file
14
convert.sh
Executable file
@ -0,0 +1,14 @@
|
||||
# ffmpeg -i testfile.wav -c:a libopus -ar 48000 -ac 2 -f opus -map_metadata -1 -vn -y play.opus
|
||||
# ffmpeg -i testfile.wav \
|
||||
# -ac 2 -ar 48000 \
|
||||
# -b:a 96k \
|
||||
# -f opus \
|
||||
# -y \
|
||||
# -vbr off \
|
||||
# -frame_duration 20 \
|
||||
# pipe:1 > output.opus
|
||||
|
||||
# Version used by the code sample i found
|
||||
ffmpeg -i testfile.wav -hide_banner -loglevel quiet -f data -map 0:a -ar 48k -ac 2 -acodec libopus -b:a 128k pipe:1 > testfile.raw
|
||||
|
||||
opusinfo output.opus
|
16
go.mod
Normal file
16
go.mod
Normal file
@ -0,0 +1,16 @@
|
||||
module git.thegrind.dev/thegrind/papibot
|
||||
|
||||
go 1.22.2
|
||||
|
||||
require (
|
||||
github.com/bwmarrin/discordgo v0.28.1
|
||||
github.com/javif89/dotenv v0.0.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/jogramming/dca v0.0.0-20210930103944-155f5e5f0cc7 // indirect
|
||||
github.com/jonas747/ogg v0.0.0-20161220051205-b4f6f4cf3757 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
||||
)
|
18
go.sum
Normal file
18
go.sum
Normal file
@ -0,0 +1,18 @@
|
||||
github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4=
|
||||
github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/javif89/dotenv v0.0.6 h1:xSXuDwEREMZi29iU5eUcbw8B+cWA3zafGBn1WfnZ06k=
|
||||
github.com/javif89/dotenv v0.0.6/go.mod h1:4HS1Vewf6uMVysiBuaKRwEwFBuKUG0L2c+VH8jxQn18=
|
||||
github.com/jogramming/dca v0.0.0-20210930103944-155f5e5f0cc7 h1:3nT2dRfYYlVBofXRG2WECKHDN5nwL22oyeBTClAONzU=
|
||||
github.com/jogramming/dca v0.0.0-20210930103944-155f5e5f0cc7/go.mod h1:dxkp/IJD9cJBPedO7O+wWDidThTNKcl5/AkIbvLV5mE=
|
||||
github.com/jonas747/ogg v0.0.0-20161220051205-b4f6f4cf3757 h1:Kyv+zTfWIGRNaz/4+lS+CxvuKVZSKFz/6G8E3BKKBRs=
|
||||
github.com/jonas747/ogg v0.0.0-20161220051205-b4f6f4cf3757/go.mod h1:cZnNmdLiLpihzgIVqiaQppi9Ts3D4qF/M45//yW35nI=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
166
main.go
Normal file
166
main.go
Normal file
@ -0,0 +1,166 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
dg "github.com/bwmarrin/discordgo"
|
||||
"github.com/javif89/dotenv"
|
||||
)
|
||||
|
||||
var commandPrefix string = "!"
|
||||
|
||||
func main() {
|
||||
env := dotenv.Load(".env")
|
||||
botToken := env.Get("DISCORD_BOT_TOKEN")
|
||||
log.Println("Starting bot")
|
||||
discord, err := dg.New(fmt.Sprintf("Bot %s", botToken))
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error starting the bot", err)
|
||||
return
|
||||
}
|
||||
|
||||
discord.AddHandler(ready)
|
||||
discord.AddHandler(handleCommand) // This will receive an event when a message is sent
|
||||
|
||||
discord.Identify.Intents = dg.IntentsGuilds | dg.IntentsGuildMessages | dg.IntentsGuildVoiceStates
|
||||
|
||||
err = discord.Open()
|
||||
if err != nil {
|
||||
log.Println("Error opening Discord session: ", err)
|
||||
}
|
||||
|
||||
log.Println("Bot is running. Press CTRL+C to exit.")
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
||||
<-sc
|
||||
|
||||
log.Println("Bot is exiting...")
|
||||
discord.Close()
|
||||
log.Println("Goodbye!")
|
||||
}
|
||||
|
||||
func ready(s *dg.Session, event *dg.Ready) {
|
||||
log.Println("Bot is ready")
|
||||
}
|
||||
|
||||
func handleCommand(s *dg.Session, msg *dg.MessageCreate) {
|
||||
// Ignore any message sent by the bot itself
|
||||
if msg.Author.ID == s.State.User.ID {
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(msg.Content, commandPrefix) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get the channel
|
||||
msgChannel, err := s.State.Channel(msg.ChannelID)
|
||||
if err != nil {
|
||||
log.Println("Could not find the channel the message came from")
|
||||
return
|
||||
}
|
||||
|
||||
msgServer, err := s.State.Guild(msgChannel.GuildID)
|
||||
if err != nil {
|
||||
log.Println("Failed to get server for message")
|
||||
}
|
||||
|
||||
var voiceChannelId string
|
||||
for _, vs := range msgServer.VoiceStates {
|
||||
if vs.UserID == msg.Author.ID {
|
||||
voiceChannelId = vs.ChannelID
|
||||
}
|
||||
}
|
||||
|
||||
voiceChannel, err := s.ChannelVoiceJoin(msgServer.ID, voiceChannelId, false, true)
|
||||
if err != nil {
|
||||
log.Println("Failed to join voice channel")
|
||||
}
|
||||
|
||||
log.Println("Joined channel. Playing sound")
|
||||
voiceChannel.Speaking(true)
|
||||
time.Sleep(time.Second * 1)
|
||||
|
||||
log.Println("Starting ffmpeg stream")
|
||||
// I got this implementation from:
|
||||
// https://github.com/nhooyr/botatouille/blob/7e1cd9d5a8d517fd43fd11599b2a62bf832a5c96/cmd/botatouille/music/music.go#L62-L104
|
||||
// after hours of searching.
|
||||
ffmpeg := exec.Command(
|
||||
"ffmpeg",
|
||||
"-i", "testfile.wav",
|
||||
"-hide_banner",
|
||||
"-loglevel", "quiet",
|
||||
"-i", "testfile.wav",
|
||||
"-f", "data",
|
||||
"-map", "0:a",
|
||||
"-ar", "48k",
|
||||
"-ac", "2",
|
||||
"-acodec", "libopus",
|
||||
"-b:a", "128k",
|
||||
"pipe:1")
|
||||
|
||||
ffmpegOut, err := ffmpeg.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
framesChan := make(chan []byte, 100000)
|
||||
go func() {
|
||||
for {
|
||||
voiceChannel.OpusSend <- <-framesChan
|
||||
}
|
||||
}()
|
||||
|
||||
runtime.LockOSThread()
|
||||
err = ffmpeg.Start()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
packets := [][]byte{}
|
||||
|
||||
for {
|
||||
// I read in the RFC that frames will not be bigger than this size
|
||||
p := make([]byte, 960)
|
||||
n, err := ffmpegOut.Read(p)
|
||||
if err != nil {
|
||||
log.Printf("Bytes: %d", n)
|
||||
if err == io.EOF {
|
||||
log.Println("Done streaming")
|
||||
break
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Sending opus frame: %d bytes", n)
|
||||
packets = append(packets, p[:n])
|
||||
}
|
||||
|
||||
log.Println("Iterating through packets")
|
||||
|
||||
for _, p := range packets {
|
||||
log.Printf("%d bytes", len(p))
|
||||
}
|
||||
|
||||
for _, p := range packets {
|
||||
log.Printf("Sending packet: %d bytes", len(p))
|
||||
voiceChannel.OpusSend <- p
|
||||
}
|
||||
|
||||
voiceChannel.Speaking(false)
|
||||
log.Println("Disconnecting from voice channel")
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
voiceChannel.Disconnect()
|
||||
log.Println("Disconnected")
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user