Files
2026-08-13 16:47:43 +07:00

94 lines
1.9 KiB
Go

package main
import (
"context"
"log"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/bwmarrin/discordgo"
)
func main() {
token := os.Getenv("DISCORD_TOKEN")
channelID := os.Getenv("CHANNEL_ID")
if token == "" || channelID == "" {
log.Fatal("DISCORD_TOKEN and CHANNEL_ID are required")
}
session, err := discordgo.New("Bot " + token)
if err != nil {
log.Fatal(err)
}
session.Identify.Intents = discordgo.IntentsGuilds | discordgo.IntentsGuildVoiceStates
if err := session.Open(); err != nil {
log.Fatal(err)
}
defer session.Close()
channel, err := session.Channel(channelID)
if err != nil {
log.Fatal(err)
}
if channel.Type != discordgo.ChannelTypeGuildVoice {
log.Fatal("CHANNEL_ID must identify a guild voice channel")
}
var joinMu sync.Mutex
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
join := func() {
joinMu.Lock()
defer joinMu.Unlock()
for {
select {
case <-ctx.Done():
return
default:
}
if _, err := session.ChannelVoiceJoin(ctx, channel.GuildID, channelID, false, true); err == nil {
log.Printf("joined voice channel %s", channelID)
return
} else {
log.Printf("voice join failed: %v; retrying in 5s", err)
}
select {
case <-ctx.Done():
return
case <-time.After(5 * time.Second):
}
}
}
session.AddHandler(func(s *discordgo.Session, update *discordgo.VoiceStateUpdate) {
if s.State.User == nil || update.UserID != s.State.User.ID || update.ChannelID == channelID {
return
}
log.Print("bot left target voice channel; reconnecting")
go join()
})
join()
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
<-signals
cancel()
session.RLock()
voice := session.VoiceConnections[channel.GuildID]
session.RUnlock()
if voice != nil {
_ = voice.Disconnect(context.Background())
}
log.Print("bot stopped")
}