This repository has been archived on 2019-06-23. You can view files and clone it, but cannot push or open issues or pull requests.
mumbledj/commands.go
Matthieu Grieger a90b4671e9 Commented code
2014-12-27 10:05:13 -08:00

234 lines
6.9 KiB
Go

/*
* MumbleDJ
* By Matthieu Grieger
* commands.go
* Copyright (c) 2014 Matthieu Grieger (MIT License)
*/
package main
import (
"errors"
"fmt"
"github.com/kennygrant/sanitize"
"github.com/layeh/gumble/gumble"
"os"
"regexp"
"strconv"
"strings"
)
// Called on text message event. Checks the message for a command string, and processes it accordingly if
// it contains a command.
func parseCommand(user *gumble.User, username, command string) {
var com, argument string
if strings.Contains(command, " ") {
sanitizedCommand := sanitize.HTML(command)
parsedCommand := strings.Split(sanitizedCommand, " ")
com, argument = parsedCommand[0], parsedCommand[1]
} else {
com = command
argument = ""
}
switch com {
// Add command
case dj.conf.Aliases.AddAlias:
if dj.HasPermission(username, dj.conf.Permissions.AdminAdd) {
if argument == "" {
user.Send(NO_ARGUMENT_MSG)
} else {
if songTitle, err := add(username, argument); err == nil {
dj.client.Self().Channel().Send(fmt.Sprintf(SONG_ADDED_HTML, username, songTitle), false)
if dj.queue.Len() == 1 && !dj.audioStream.IsPlaying() {
dj.currentSong = dj.queue.NextSong()
if err := dj.currentSong.Download(); err == nil {
dj.currentSong.Play()
} else {
panic(err)
}
}
} else {
user.Send(INVALID_URL_MSG)
}
}
} else {
user.Send(NO_PERMISSION_MSG)
}
// Skip command
case dj.conf.Aliases.SkipAlias:
if dj.HasPermission(username, dj.conf.Permissions.AdminSkip) {
if err := skip(username, false); err == nil {
dj.client.Self().Channel().Send(fmt.Sprintf(SKIP_ADDED_HTML, username), false)
}
} else {
user.Send(NO_PERMISSION_MSG)
}
// Forceskip command
case dj.conf.Aliases.AdminSkipAlias:
if dj.HasPermission(username, true) {
if err := skip(username, true); err == nil {
dj.client.Self().Channel().Send(ADMIN_SONG_SKIP_MSG, false)
}
} else {
user.Send(NO_PERMISSION_MSG)
}
// Volume command
case dj.conf.Aliases.VolumeAlias:
if dj.HasPermission(username, dj.conf.Permissions.AdminVolume) {
if argument == "" {
dj.client.Self().Channel().Send(fmt.Sprintf(CUR_VOLUME_HTML, dj.audioStream.Volume()), false)
} else {
if err := volume(username, argument); err == nil {
dj.client.Self().Channel().Send(fmt.Sprintf(VOLUME_SUCCESS_HTML, username, argument), false)
} else {
user.Send(fmt.Sprintf(NOT_IN_VOLUME_RANGE_MSG, dj.conf.Volume.LowestVolume, dj.conf.Volume.HighestVolume))
}
}
} else {
user.Send(NO_PERMISSION_MSG)
}
// Move command
case dj.conf.Aliases.MoveAlias:
if dj.HasPermission(username, dj.conf.Permissions.AdminMove) {
if argument == "" {
user.Send(NO_ARGUMENT_MSG)
} else {
if err := move(argument); err == nil {
fmt.Printf("%s has been moved to %s.", dj.client.Self().Name(), argument)
} else {
user.Send(CHANNEL_DOES_NOT_EXIST_MSG)
}
}
} else {
user.Send(NO_PERMISSION_MSG)
}
// Reload command
case dj.conf.Aliases.ReloadAlias:
if dj.HasPermission(username, dj.conf.Permissions.AdminReload) {
err := loadConfiguration()
if err == nil {
user.Send(CONFIG_RELOAD_SUCCESS_MSG)
} else {
panic(err)
}
} else {
user.Send(NO_PERMISSION_MSG)
}
// Kill command
case dj.conf.Aliases.KillAlias:
if dj.HasPermission(username, dj.conf.Permissions.AdminKill) {
if err := kill(); err == nil {
fmt.Println("Kill successful. Goodbye!")
os.Exit(0)
} else {
user.Send(KILL_ERROR_MSG)
}
} else {
user.Send(NO_PERMISSION_MSG)
}
default:
user.Send(COMMAND_DOESNT_EXIST_MSG)
}
}
// Performs add functionality. Checks input URL for YouTube format, and adds
// the URL to the queue if the format matches.
func add(user, url string) (string, error) {
youtubePatterns := []string{
`https?:\/\/www\.youtube\.com\/watch\?v=([\w-]+)`,
`https?:\/\/youtube\.com\/watch\?v=([\w-]+)`,
`https?:\/\/youtu.be\/([\w-]+)`,
`https?:\/\/youtube.com\/v\/([\w-]+)`,
`https?:\/\/www.youtube.com\/v\/([\w-]+)`,
}
matchFound := false
for _, pattern := range youtubePatterns {
if re, err := regexp.Compile(pattern); err == nil {
if re.MatchString(url) {
matchFound = true
break
}
}
}
if matchFound {
urlMatch := strings.Split(url, "=")
shortUrl := urlMatch[1]
newSong := NewSong(user, shortUrl)
if err := dj.queue.AddSong(newSong); err == nil {
return newSong.title, nil
} else {
return "", errors.New("Could not add the Song to the queue.")
}
} else {
return "", errors.New("The URL provided did not match a YouTube URL.")
}
}
// Performs skip functionality. Adds a skip to the skippers slice for the current song, and then
// evaluates if a skip should be performed. Both skip and forceskip are implemented here.
func skip(user string, admin bool) error {
if err := dj.currentSong.AddSkip(user); err == nil {
if dj.currentSong.SkipReached(len(dj.client.Self().Channel().Users())) || admin {
if err := dj.audioStream.Stop(); err == nil {
dj.OnSongFinished()
return nil
} else {
return errors.New("An error occurred while stopping the current song.")
}
} else {
return errors.New("Not enough skips have been reached to skip the song.")
}
} else {
return errors.New("An error occurred while adding a skip to the current song.")
}
}
// Performs volume functionality. Checks input value against LowestVolume and HighestVolume from
// config to determine if the volume should be applied. If in the correct range, the new volume
// is applied and is immediately in effect.
func volume(user, value string) error {
if parsedVolume, err := strconv.ParseFloat(value, 32); err == nil {
newVolume := float32(parsedVolume)
if newVolume >= dj.conf.Volume.LowestVolume && newVolume <= dj.conf.Volume.HighestVolume {
dj.audioStream.SetVolume(newVolume)
return nil
} else {
return errors.New("The volume supplied was not in the allowed range.")
}
} else {
return errors.New("An error occurred while parsing the volume string.")
}
}
// Performs move functionality. Determines if the supplied channel is valid and moves the bot
// to the channel if it is.
func move(channel string) error {
if dj.client.Channels().Find(channel) != nil {
dj.client.Self().Move(dj.client.Channels().Find(channel))
return nil
} else {
return errors.New("The channel provided does not exist.")
}
}
// Performs kill functionality. First cleans the ~/.mumbledj/songs directory to get rid of any
// excess m4a files. The bot then safely disconnects from the server.
func kill() error {
songsDir := fmt.Sprintf("%s/.mumbledj/songs", dj.homeDir)
if err := os.RemoveAll(songsDir); err != nil {
return errors.New("An error occurred while deleting the audio files.")
} else {
if err := os.Mkdir(songsDir, 0777); err != nil {
return errors.New("An error occurred while recreating the songs directory.")
}
}
if err := dj.client.Disconnect(); err == nil {
return nil
} else {
return errors.New("An error occurred while disconnecting from the server.")
}
}