mirror of
https://github.com/stryan/mumble-discord-bridge.git
synced 2024-12-30 09:55:40 -05:00
initial changes, make it manual linking, show mumble users in status
This commit is contained in:
parent
d9d30929ff
commit
5a96c488ee
57
config.go
Normal file
57
config.go
Normal file
@ -0,0 +1,57 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"layeh.com/gumble/gumble"
|
||||
)
|
||||
|
||||
type YammerConfig struct {
|
||||
Config *gumble.Config
|
||||
MumbleAddr string
|
||||
MumbleInsecure bool
|
||||
Die chan bool
|
||||
ActiveConns map[string]chan bool
|
||||
}
|
||||
|
||||
func lookupEnvOrString(key string, defaultVal string) string {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
return val
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func lookupEnvOrInt(key string, defaultVal int) int {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
v, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
log.Fatalf("LookupEnvOrInt[%s]: %v", key, err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func lookupEnvOrBool(key string, defaultVal bool) bool {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
v, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
log.Fatalf("LookupEnvOrInt[%s]: %v", key, err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func getConfig(fs *flag.FlagSet) []string {
|
||||
cfg := make([]string, 0, 10)
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
cfg = append(cfg, fmt.Sprintf("%s:%q", f.Name, f.Value.String()))
|
||||
})
|
||||
|
||||
return cfg
|
||||
}
|
91
handlers.go
Normal file
91
handlers.go
Normal file
@ -0,0 +1,91 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
func ready(s *discordgo.Session, event *discordgo.Ready) {
|
||||
log.Println("READY event registered")
|
||||
}
|
||||
|
||||
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
|
||||
// Ignore all messages created by the bot itself
|
||||
// This isn't required in this specific example but it's a good practice.
|
||||
log.Println("Checking message")
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(m.Content, "!yammer link") {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Look for the message sender in that guild's current voice states.
|
||||
for _, vs := range g.VoiceStates {
|
||||
if vs.UserID == m.Author.ID {
|
||||
log.Printf("Trying to join GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||
die := make(chan bool)
|
||||
YBConfig.ActiveConns[vs.ChannelID] = die
|
||||
go startBridge(s, g.ID, vs.ChannelID, YBConfig.Config, YBConfig.MumbleAddr, YBConfig.MumbleInsecure, die)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(m.Content, "!yammer unlink") {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Look for the message sender in that guild's current voice states.
|
||||
for _, vs := range g.VoiceStates {
|
||||
if vs.UserID == m.Author.ID {
|
||||
log.Printf("Trying to leave GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||
YBConfig.ActiveConns[vs.ChannelID] <- true
|
||||
YBConfig.ActiveConns[vs.ChannelID] = nil
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, "Mumble-Discord bridge is active")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
121
main.go
121
main.go
@ -1,14 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
@ -17,43 +15,7 @@ import (
|
||||
_ "layeh.com/gumble/opus"
|
||||
)
|
||||
|
||||
func lookupEnvOrString(key string, defaultVal string) string {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
return val
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func lookupEnvOrInt(key string, defaultVal int) int {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
v, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
log.Fatalf("LookupEnvOrInt[%s]: %v", key, err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func lookupEnvOrBool(key string, defaultVal bool) bool {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
v, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
log.Fatalf("LookupEnvOrInt[%s]: %v", key, err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func getConfig(fs *flag.FlagSet) []string {
|
||||
cfg := make([]string, 0, 10)
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
cfg = append(cfg, fmt.Sprintf("%s:%q", f.Name, f.Value.String()))
|
||||
})
|
||||
|
||||
return cfg
|
||||
}
|
||||
var YBConfig *YammerConfig
|
||||
|
||||
func main() {
|
||||
godotenv.Load()
|
||||
@ -98,6 +60,12 @@ func main() {
|
||||
|
||||
// Open Websocket
|
||||
discord.LogLevel = 2
|
||||
discord.StateEnabled = true
|
||||
discord.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsGuilds | discordgo.IntentsGuildMessages | discordgo.IntentsGuildVoiceStates)
|
||||
// register handlers
|
||||
discord.AddHandler(ready)
|
||||
discord.AddHandler(messageCreate)
|
||||
discord.AddHandler(guildCreate)
|
||||
err = discord.Open()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@ -106,75 +74,22 @@ func main() {
|
||||
defer discord.Close()
|
||||
|
||||
log.Println("Discord Bot Connected")
|
||||
|
||||
dgv, err := discord.ChannelVoiceJoin(*discordGID, *discordCID, false, false)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer dgv.Speaking(false)
|
||||
defer dgv.Close()
|
||||
|
||||
discord.ShouldReconnectOnError = true
|
||||
|
||||
// MUMBLE Setup
|
||||
|
||||
config := gumble.NewConfig()
|
||||
config.Username = *mumbleUsername
|
||||
config.Password = *mumblePassword
|
||||
config.AudioInterval = time.Millisecond * 10
|
||||
|
||||
m := MumbleDuplex{}
|
||||
|
||||
var tlsConfig tls.Config
|
||||
if *mumbleInsecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
YBConfig = &YammerConfig{
|
||||
Config: config,
|
||||
MumbleAddr: *mumbleAddr + ":" + strconv.Itoa(*mumblePort),
|
||||
MumbleInsecure: *mumbleInsecure,
|
||||
ActiveConns: make(map[string]chan bool),
|
||||
}
|
||||
|
||||
mumble, err := gumble.DialWithDialer(new(net.Dialer),*mumbleAddr+":"+strconv.Itoa(*mumblePort),config, &tlsConfig)
|
||||
//go startBridge(discord, *discordGID, *discordCID, config, *mumbleAddr+":"+strconv.Itoa(*mumblePort), *mumbleInsecure, die)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer mumble.Disconnect()
|
||||
|
||||
// Shared Channels
|
||||
// Shared channels pass PCM information in 10ms chunks [480]int16
|
||||
var toMumble = mumble.AudioOutgoing()
|
||||
var toDiscord = make(chan []int16, 100)
|
||||
var die = make(chan bool)
|
||||
|
||||
log.Println("Mumble Connected")
|
||||
|
||||
// Start Passing Between
|
||||
// Mumble
|
||||
go m.fromMumbleMixer(toDiscord)
|
||||
config.AudioListeners.Attach(m)
|
||||
//Discord
|
||||
go discordReceivePCM(dgv, die)
|
||||
go fromDiscordMixer(toMumble)
|
||||
go discordSendPCM(dgv, toDiscord, die)
|
||||
|
||||
// Wait for Exit Signal
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
for {
|
||||
<-ticker.C
|
||||
if mumble.State() != 2 {
|
||||
log.Println("Lost mumble connection " + strconv.Itoa(int(mumble.State())))
|
||||
die <- true
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case sig := <-c:
|
||||
log.Printf("\nGot %s signal. Terminating Mumble-Bridge\n", sig)
|
||||
case <-die:
|
||||
log.Println("\nGot internal die request. Terminating Mumble-Bridge")
|
||||
}
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||
<-sc
|
||||
log.Println("Bot shutting down")
|
||||
}
|
||||
|
119
yammer.go
Normal file
119
yammer.go
Normal file
@ -0,0 +1,119 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"layeh.com/gumble/gumble"
|
||||
)
|
||||
|
||||
func startBridge(discord *discordgo.Session, discordGID string, discordCID string, config *gumble.Config, mumbleAddr string, mumbleInsecure bool, die chan bool) {
|
||||
dgv, err := discord.ChannelVoiceJoin(discordGID, discordCID, false, false)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer dgv.Speaking(false)
|
||||
defer dgv.Close()
|
||||
|
||||
discord.ShouldReconnectOnError = true
|
||||
|
||||
// MUMBLE Setup
|
||||
|
||||
m := MumbleDuplex{}
|
||||
|
||||
var tlsConfig tls.Config
|
||||
if mumbleInsecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
mumble, err := gumble.DialWithDialer(new(net.Dialer), mumbleAddr, config, &tlsConfig)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer mumble.Disconnect()
|
||||
|
||||
// Shared Channels
|
||||
// Shared channels pass PCM information in 10ms chunks [480]int16
|
||||
var toMumble = mumble.AudioOutgoing()
|
||||
var toDiscord = make(chan []int16, 100)
|
||||
|
||||
log.Println("Mumble Connected")
|
||||
|
||||
// Start Passing Between
|
||||
// Mumble
|
||||
go m.fromMumbleMixer(toDiscord)
|
||||
config.AudioListeners.Attach(m)
|
||||
//Discord
|
||||
go discordReceivePCM(dgv, die)
|
||||
go fromDiscordMixer(toMumble)
|
||||
go discordSendPCM(dgv, toDiscord, die)
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
for {
|
||||
<-ticker.C
|
||||
if mumble.State() != 2 {
|
||||
log.Println("Lost mumble connection " + strconv.Itoa(int(mumble.State())))
|
||||
die <- true
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case sig := <-c:
|
||||
log.Printf("\nGot %s signal. Terminating Mumble-Bridge\n", sig)
|
||||
case <-die:
|
||||
log.Println("\nGot internal die request. Terminating Mumble-Bridge")
|
||||
dgv.Disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
func pingMumble(host, port string, c chan int) {
|
||||
m, _ := time.ParseDuration("30s")
|
||||
curr := 0
|
||||
log.Println("Started mumble ping loop")
|
||||
for {
|
||||
time.Sleep(3 * time.Second)
|
||||
resp, err := gumble.Ping(host+":"+port, -1, m)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if resp.ConnectedUsers-1 != curr {
|
||||
curr = resp.ConnectedUsers - 1
|
||||
log.Printf("Now %v users in mumble\n", curr)
|
||||
if curr > 0 {
|
||||
c <- curr
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Println("Mumble ping loop broken")
|
||||
}
|
||||
|
||||
func discordStatusUpdate(dg *discordgo.Session, c chan int) {
|
||||
status := ""
|
||||
curr := 0
|
||||
log.Println("Started discord control loop")
|
||||
for {
|
||||
curr = <-c
|
||||
log.Println("Updating discord status")
|
||||
if curr == 0 {
|
||||
status = ""
|
||||
} else {
|
||||
status = fmt.Sprintf("%v users in Mumble\n", curr)
|
||||
}
|
||||
dg.UpdateListeningStatus(status)
|
||||
}
|
||||
log.Println("Discord control loop broken")
|
||||
}
|
Loading…
Reference in New Issue
Block a user