small pixel drawing of a pufferfish neoarkbot

main.go

package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/kkdai/youtube/v2"
	"layeh.com/gumble/gumble"
	"layeh.com/gumble/gumbleffmpeg"
	"layeh.com/gumble/gumbleutil"
	_ "layeh.com/gumble/opus"
)

func main() {
	files := make(map[string]string)
	var stream *gumbleffmpeg.Stream

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s: [flags] [audio files...]\n", os.Args[0])
		flag.PrintDefaults()
	}

	gumbleutil.Main(gumbleutil.AutoBitrate, gumbleutil.Listener{
		Connect: func(e *gumble.ConnectEvent) {
			// hardcode access token cuz idgaf
			e.Client.Config.Tokens = []string{"welcome"}
			e.Client.Send(e.Client.Config.Tokens)

			for _, file := range flag.Args() {
				key := filepath.Base(file)
				key = strings.TrimSuffix(key, filepath.Ext(key))
				files[key] = file
			}

			fmt.Printf("audio player loaded! (%d files)\n", len(files))
		},

		UserChange: func(e *gumble.UserChangeEvent) {
			fmt.Println("entered userchangeevent")
			if e.Type.Has(gumble.UserChangeConnected) {
				fmt.Println("entered userchangeconnected")
				file := "sounds/intro-" + e.User.Name
				fmt.Println(file)
				if stream != nil && stream.State() == gumbleffmpeg.StatePlaying {
					stream.Stop()
				}
				stream = gumbleffmpeg.New(e.Client, gumbleffmpeg.SourceFile(file))
				if err := stream.Play(); err != nil {
					fmt.Printf("%s\n", err)
				} else {
					fmt.Printf("playing %s\n", file)
					time.Sleep(5 * time.Second)
					stream.Stop()
				}
			}
		},

		TextMessage: func(e *gumble.TextMessageEvent) {
			if e.Sender == nil {
				return
			}
			// old commands started with #
			if strings.HasPrefix(e.Message, "#") {
				fmt.Println("old detected")
				// shittily trim the string
				e.Message = e.Message[1:]
			}
			if e.Message == "stop" {
				fmt.Println("stopping")
				stream.Stop()
				return
			}
			if e.Message == "!help" {
				helpmsg := `
				# help
				!help
				# list sounds
				list
				# make youtube thing
				!https://www.youtube.com/watch?v=dQw4w9WgXcQ > rickroll
				# make personal intro
				!intro rickroll`
				e.Sender.Send(helpmsg)
			}
			if strings.HasPrefix(e.Message, "!intro ") {
				introSelection := strings.Split(e.Message, " ")[1]
				original, err := os.Open("sounds/" + introSelection)
				if err != nil {
					e.Sender.Send("sound not found: " + introSelection)
					return
				}
				defer original.Close()
				new, err := os.Create("sounds/" + "intro-" + e.Sender.Name)
				if err != nil {
					e.Sender.Send("error during creation check logs")
					fmt.Println(err)
				}
				defer new.Close()
				fmt.Println("intro src: " + original.Name())
				fmt.Println("intro dst: " + new.Name())
				_, err = io.Copy(new, original)
				if err != nil {
					log.Fatal(err)
				}
				e.Sender.Send("your intro has been set to " + introSelection)
			}
			volmatched, err := regexp.MatchString(`^vol [0-9]+$`, e.Message)
			if err != nil {
				fmt.Printf("regex match blew up: %s", err)
				return
			}
			if volmatched {
				r := regexp.MustCompile(`[0-9]+`)
				vol := r.FindString(e.Message)
				vol64, _ := strconv.ParseFloat(vol, 32)
				vol32 := float32(vol64)
				truevol := vol32 / 100.0
				if vol32 > 100 {
					e.Sender.Send("volume too DAMN high")
					return
				}
				stream.Volume = truevol
				return
			}
			if e.Message == "list" || e.Message == "!list" {
				// send list to sender
				fmt.Println("listing")
				var keys []string
				for k, _ := range files {
					if strings.HasPrefix(k, "intro-") {
						continue
					}
					if strings.HasPrefix(k, "s-") {
						continue
					}
					keys = append(keys, k)
				}
				sort.Strings(keys)
				selectionScopeStart := 0
				selectionScopeEnd := 200
				for i := len(keys); i > 0; {
					if selectionScopeEnd > len(keys) {
						selectionScopeEnd = len(keys)
					}
					listThing := strings.Join(keys[selectionScopeStart:selectionScopeEnd], " ")
					selectionScopeStart += 200
					selectionScopeEnd += 200
					e.Sender.Send(listThing)
					i = i - 200
				}
			}
			var file string
			matched, err := regexp.MatchString(`https:\/\/(www.)?youtube\.com\/watch\?v=[A-z_\-0-9]{11}`, e.Message)
			if err != nil {
				fmt.Printf("regex match blew up: %s", err)
				return
			}
			if matched && strings.HasPrefix(e.Message, "!") {
				m := regexp.MustCompile(`https:\/\/(www.)?youtube\.com\/watch\?v=[A-z_\-0-9]{11}`)
				videoUrl := m.FindString(e.Message)
				fmt.Println("downloading...")
				fmt.Println("videoUrl: ", videoUrl)

				// !rick=https://www.youtube.com/watch?v=dQw4w9WgXcQ
				// this is handled separately because of weird mumble HTML
				// business
				setcmd := regexp.MustCompile(` > [a-z0-9-]+`)
				cmd := setcmd.FindString(e.Message)
				fmt.Println(e.Message)
				fmt.Println(cmd)
				cmdname := "video.mp4"
				if cmd != "" {
					splits := strings.Split(cmd, " ")
					// the name
					cmdname = "sounds/" + splits[2]
					files[splits[2]] = cmdname
				}

				fmt.Println(cmdname)
				parts := strings.Split(videoUrl, "=")
				fmt.Printf("%v", parts)
				if len(parts) != 2 {
					fmt.Println("youtube url is weird")
					return
				}
				fmt.Println(parts[1])
				videoID := parts[1]
				client := youtube.Client{}
				fmt.Printf("videoID: %s", videoID)
				video, err := client.GetVideo(videoID)
				if err != nil {
					fmt.Println(err)
					return
				}

				formats := video.Formats.WithAudioChannels()
				stream, _, err := client.GetStream(video, &formats[0])
				if err != nil {
					fmt.Println(err)
					return
				}
				wfile, err := os.Create(cmdname)
				if err != nil {
					fmt.Println(err)
					return
				}
				defer wfile.Close()

				_, err = io.Copy(wfile, stream)
				if err != nil {
					fmt.Println(err)
					return
				}
				file = cmdname
			} else {
				var ok bool
				file, ok = files[e.Message]
				if !ok {
					return
				}
			}
			if stream != nil && stream.State() == gumbleffmpeg.StatePlaying {
				stream.Stop()
			}
			stream = gumbleffmpeg.New(e.Client, gumbleffmpeg.SourceFile(file))
			if err := stream.Play(); err != nil {
				fmt.Printf("%s\n", err)
			} else {
				fmt.Printf("playing %s\n", file)
			}
		},
	})
}