From bc8520f72225e84cb2206140c711068c4736402e Mon Sep 17 00:00:00 2001 From: Fl_GUI Date: Fri, 14 Nov 2025 20:30:21 +0100 Subject: [PATCH] initial discord voice join --- channelSelect/channelselect.go | 143 +++++++++++++++++++++++++++++++++ go.mod | 47 +++++++++++ go.sum | 92 +++++++++++++++++++++ main.go | 116 ++++++++++++++++++++++++++ sessionProvider/provider.go | 56 +++++++++++++ voiceActivity/activity.go | 29 +++++++ 6 files changed, 483 insertions(+) create mode 100644 channelSelect/channelselect.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 sessionProvider/provider.go create mode 100644 voiceActivity/activity.go diff --git a/channelSelect/channelselect.go b/channelSelect/channelselect.go new file mode 100644 index 0000000..76b8802 --- /dev/null +++ b/channelSelect/channelselect.go @@ -0,0 +1,143 @@ +package channelselect + +import ( + "context" + "fmt" + "sync" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/widget" + "github.com/bwmarrin/discordgo" +) + +type ChannelSelect struct { + Container *fyne.Container + OnVoice func(*discordgo.VoiceConnection) +} + +func NewChannelSelect(session *discordgo.Session) *ChannelSelect { + csel := new(ChannelSelect) + + mapping, guilds, channels := allChannels(session) + + tree := widget.NewTree( + func(id widget.TreeNodeID) []widget.TreeNodeID { + channels, _ := mapping[id] + return channels + }, + func(id widget.TreeNodeID) bool { + _, ok := mapping[id] + return ok + }, + func(isBranch bool) fyne.CanvasObject { + if isBranch { + return newGuildTemplate() + } else { + return newChannelTemplate() + } + }, + func(id widget.TreeNodeID, isBranch bool, obj fyne.CanvasObject) { + if isBranch { + updateGuildTemplate(guilds[id], obj) + } else { + ch := channels[id] + onSelect := func() { + conn, err := session.ChannelVoiceJoin( + context.Background(), + ch.GuildID, + ch.ID, + true, + false, + ) + if err != nil { + if _, ok := session.VoiceConnections[ch.GuildID]; !ok { + panic(fmt.Errorf("Fl_GUI forgot to handle this error: %s", err)) + } + } + csel.OnVoice(conn) + } + updateChannelTemplate(ch, obj, onSelect) + } + }, + ) + csel.Container = container.NewMax(tree) + return csel +} + +func newGuildTemplate() fyne.CanvasObject { + return widget.NewLabel("guild") +} + +func updateGuildTemplate(guild *discordgo.UserGuild, obj fyne.CanvasObject) { + obj.(*widget.Label).Text = guild.Name +} + +func newChannelTemplate() fyne.CanvasObject { + return container.NewHBox( + widget.NewLabel("channel"), + layout.NewSpacer(), + widget.NewButton("join", func() {}), + ) +} + +func updateChannelTemplate(channel *discordgo.Channel, obj fyne.CanvasObject, onSelect func()) { + container := obj.(*fyne.Container) + container.Objects[0].(*widget.Label).Text = channel.Name + container.Objects[2].(*widget.Button).OnTapped = onSelect +} + +func allChannels(session *discordgo.Session) (channelStructure map[string][]string, guilds map[string]*discordgo.UserGuild, channels map[string]*discordgo.Channel) { + // get all guids + userguilds, err := session.UserGuilds(10, "", "", false) + if err != nil { + // better error handling + panic(fmt.Errorf("Fl_GUI forgot to handle this error: %s", err)) + } + + // get all channels + allChannels := make([][]*discordgo.Channel, len(userguilds)) + var wg sync.WaitGroup + for i, guild := range userguilds { + wg.Add(1) + go func() { + defer wg.Done() + channels, err := session.GuildChannels(guild.ID) + if err == nil { + voiceChannels := make([]*discordgo.Channel, 0) + for _, c := range channels { + if c.Type == discordgo.ChannelTypeGuildVoice { + voiceChannels = append(voiceChannels, c) + } + } + allChannels[i] = voiceChannels + } + }() + } + wg.Wait() + + // collect result + channelStructure = make(map[string][]string) + guilds = make(map[string]*discordgo.UserGuild) + channels = make(map[string]*discordgo.Channel) + + guildIds := make([]string, len(userguilds)) + + for i, gld := range userguilds { + guildIds[i] = gld.ID + guilds[gld.ID] = gld + guildChannels := allChannels[i] + channelIds := make([]string, len(guildChannels)) + for j, ch := range guildChannels { + channels[ch.ID] = ch + channelIds[j] = ch.ID + } + channelStructure[gld.ID] = channelIds + } + + // "" is used as the root of a fyne/v2/widget.Tree + channelStructure[""] = guildIds + + return +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5e7d770 --- /dev/null +++ b/go.mod @@ -0,0 +1,47 @@ +module va4s + +go 1.25.4 + +require ( + fyne.io/fyne/v2 v2.7.0 + github.com/bwmarrin/discordgo v0.29.0 +) + +require ( + fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fredbi/uri v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fyne-io/gl-js v0.2.0 // indirect + github.com/fyne-io/glfw-js v0.3.0 // indirect + github.com/fyne-io/image v0.1.1 // indirect + github.com/fyne-io/oksvg v0.2.0 // indirect + github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect + github.com/go-text/render v0.2.0 // indirect + github.com/go-text/typesetting v0.2.1 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/hack-pad/go-indexeddb v0.3.2 // indirect + github.com/hack-pad/safejs v0.1.0 // indirect + github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect + github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect + github.com/kr/text v0.1.0 // indirect + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rymdport/portal v0.4.2 // indirect + github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect + github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect + github.com/stretchr/testify v1.11.1 // indirect + github.com/yuin/goldmark v1.7.8 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/image v0.24.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/bwmarrin/discordgo v0.29.0 => github.com/ozraru/discordgo v0.26.2-0.20251101184423-6792228f3271 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..02de60c --- /dev/null +++ b/go.sum @@ -0,0 +1,92 @@ +fyne.io/fyne/v2 v2.7.0 h1:GvZSpE3X0liU/fqstInVvRsaboIVpIWQ4/sfjDGIGGQ= +fyne.io/fyne/v2 v2.7.0/go.mod h1:xClVlrhxl7D+LT+BWYmcrW4Nf+dJTvkhnPgji7spAwE= +fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58 h1:eA5/u2XRd8OUkoMqEv3IBlFYSruNlXD8bRHDiqm0VNI= +fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/fredbi/uri v1.1.1 h1:xZHJC08GZNIUhbP5ImTHnt5Ya0T8FI2VAwI/37kh2Ko= +github.com/fredbi/uri v1.1.1/go.mod h1:4+DZQ5zBjEwQCDmXW5JdIjz0PUA+yJbvtBv+u+adr5o= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fyne-io/gl-js v0.2.0 h1:+EXMLVEa18EfkXBVKhifYB6OGs3HwKO3lUElA0LlAjs= +github.com/fyne-io/gl-js v0.2.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI= +github.com/fyne-io/glfw-js v0.3.0 h1:d8k2+Y7l+zy2pc7wlGRyPfTgZoqDf3AI4G+2zOWhWUk= +github.com/fyne-io/glfw-js v0.3.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk= +github.com/fyne-io/image v0.1.1 h1:WH0z4H7qfvNUw5l4p3bC1q70sa5+YWVt6HCj7y4VNyA= +github.com/fyne-io/image v0.1.1/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM= +github.com/fyne-io/oksvg v0.2.0 h1:mxcGU2dx6nwjJsSA9PCYZDuoAcsZ/OuJlvg/Q9Njfo8= +github.com/fyne-io/oksvg v0.2.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI= +github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA= +github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc= +github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU= +github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8= +github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M= +github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0= +github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +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/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A= +github.com/hack-pad/go-indexeddb v0.3.2/go.mod h1:QvfTevpDVlkfomY498LhstjwbPW6QC4VC/lxYb0Kom0= +github.com/hack-pad/safejs v0.1.0 h1:qPS6vjreAqh2amUqj4WNG1zIw7qlRQJ9K10eDKMCnE8= +github.com/hack-pad/safejs v0.1.0/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio= +github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade h1:FmusiCI1wHw+XQbvL9M+1r/C3SPqKrmBaIOYwVfQoDE= +github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o= +github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M= +github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk= +github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/ozraru/discordgo v0.26.2-0.20251101184423-6792228f3271 h1:iV0N6GNraEyE1hPNYZpq7eib4phq74P6SXH9+NEBOB8= +github.com/ozraru/discordgo v0.26.2-0.20251101184423-6792228f3271/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= +github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU= +github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4= +github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE= +github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= +github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= +github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= +github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= +golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..bf1f58c --- /dev/null +++ b/main.go @@ -0,0 +1,116 @@ +package main + +import ( + "context" + channelselect "va4s/channelSelect" + "va4s/sessionProvider" + voiceactivity "va4s/voiceActivity" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "github.com/bwmarrin/discordgo" +) + +type Va4s struct { + app fyne.App + window fyne.Window + session *discordgo.Session + voice *discordgo.VoiceConnection +} + +func main() { + va4s := new(Va4s) + va4s.Init() + + // #1 discord session provider + va4s.SetTokenEntry() + + va4s.window.SetOnClosed(func() { + va4s.Close() + }) + + va4s.window.ShowAndRun() +} + +func (v *Va4s) Init() { + v.app = app.New() + v.window = v.app.NewWindow("Voice activity 4 Sammi CORE") + v.window.SetContent(container.NewBorder( + container.NewStack(widget.NewButton("back", func() {})), + nil, + nil, + container.NewStack(), + )) +} + +func (v *Va4s) setContent(obj fyne.CanvasObject) { + cont := v.window.Content() + cont.(*fyne.Container).Objects[1] = obj + cont.Refresh() +} + +func (v *Va4s) setBack(backAction func()) { + cont := v.window.Content() + stack := cont.(*fyne.Container).Objects[0].(*fyne.Container) + stack.Objects[0].(*widget.Button).OnTapped = backAction +} + +func (v *Va4s) SetTokenEntry() { + prov := sessionProvider.NewProvider() + + v.setContent(prov.Container) + v.setBack(func() { + v.app.Quit() + }) + prov.OnSession = func(s *discordgo.Session) { + v.session = s + // #2 channel selector + v.SetChannelSelect() + } +} + +func (v *Va4s) SetChannelSelect() { + if v.session == nil { + v.SetTokenEntry() + return + } + + channelSelect := channelselect.NewChannelSelect(v.session) + v.setContent(channelSelect.Container) + v.setBack(func() { + v.session.Close() + v.session = nil + v.SetTokenEntry() + }) + channelSelect.OnVoice = func(vc *discordgo.VoiceConnection) { + v.voice = vc + // #3 display voice activity + v.SetVoiceActivity() + } +} + +func (v *Va4s) SetVoiceActivity() { + if v.voice == nil { + v.SetChannelSelect() + return + } + + activity := voiceactivity.NewVoiceActivity(v.voice) + v.setContent(activity.Container) + v.setBack(func() { + v.voice.Disconnect(context.Background()) + v.voice = nil + v.SetChannelSelect() + }) +} + +func (v *Va4s) Close() { + if v.voice != nil { + v.voice.Disconnect(context.Background()) + } + if v.session != nil { + v.session.Close() + } +} diff --git a/sessionProvider/provider.go b/sessionProvider/provider.go new file mode 100644 index 0000000..260edca --- /dev/null +++ b/sessionProvider/provider.go @@ -0,0 +1,56 @@ +package sessionProvider + +import ( + "fmt" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/widget" + "github.com/bwmarrin/discordgo" +) + +type Provider struct { + Container *fyne.Container + OnSession func(*discordgo.Session) +} + +func NewProvider() *Provider { + prov := new(Provider) + + tokenEntry := widget.NewEntry() + tokenEntry.MultiLine = false + tokenEntry.PlaceHolder = "6mNvJRX3iwoEP7ZFiu4qdveqx52pyYKLYTelHzY.COYQ_Z.R9VrMznE1d1G1yo+v814BJdrH/leiX7a" + tokenEntry.MultiLine = false + tokenEntry.AlwaysShowValidationError = true + tokenEntry.Wrapping = fyne.TextWrapOff + tokenEntry.Scroll = fyne.ScrollNone + + tokenEntry.OnChanged = func(s string) { + tokenEntry.SetValidationError(nil) + } + + form := widget.NewForm( + widget.NewFormItem("Bot token", tokenEntry), + ) + + form.OnSubmit = func() { + session, err := discordgo.New(fmt.Sprintf("Bot %s", tokenEntry.Text)) + if err != nil { + tokenEntry.SetValidationError(fmt.Errorf("Bad discord bot token: %s", err)) + return + } + err = session.Open() + if err != nil { + tokenEntry.SetValidationError(fmt.Errorf("Could not open connection: %s", err)) + return + } + prov.OnSession(session) + } + + // TODO remove this + tokenEntry.Text = "NjMwMTA3MzA1OTExOTEwNDUx.GwWhIb.09Och4l8wI7eD4Ff9cbKWITnj-cyMnMsxbCwxQ" + + prov.Container = container.NewVBox(layout.NewSpacer(), form, layout.NewSpacer()) + return prov +} diff --git a/voiceActivity/activity.go b/voiceActivity/activity.go new file mode 100644 index 0000000..cb2825b --- /dev/null +++ b/voiceActivity/activity.go @@ -0,0 +1,29 @@ +package voiceactivity + +import ( + "fmt" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "github.com/bwmarrin/discordgo" +) + +type VoiceActivity struct { + Container *fyne.Container +} + +func NewVoiceActivity(vc *discordgo.VoiceConnection) *VoiceActivity { + va := new(VoiceActivity) + va.Container = container.NewStack(widget.NewLabel("todo")) + vc.AddHandler(va.handleVoiceUpdate) + return va +} + +func (va *VoiceActivity) handleVoiceUpdate(vc *discordgo.VoiceConnection, vs *discordgo.VoiceSpeakingUpdate) { + if vs.Speaking { + fmt.Printf("%s is speaking\n", vs.UserID) + } else { + fmt.Printf("%s is not speaking\n", vs.UserID) + } +} -- 2.49.0