2019-03-10 16:42:12 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"html"
|
|
|
|
"strings"
|
2019-03-30 20:39:04 +01:00
|
|
|
"time"
|
2019-03-13 06:09:24 +01:00
|
|
|
|
|
|
|
"github.com/zorchenhimer/MovieNight/common"
|
2019-03-10 16:42:12 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type CommandControl struct {
|
2019-03-11 17:05:00 +01:00
|
|
|
user map[string]Command
|
|
|
|
mod map[string]Command
|
|
|
|
admin map[string]Command
|
|
|
|
}
|
|
|
|
|
|
|
|
type Command struct {
|
|
|
|
HelpText string
|
|
|
|
Function CommandFunction
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
type CommandFunction func(client *Client, args []string) (string, error)
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
var commands = &CommandControl{
|
|
|
|
user: map[string]Command{
|
|
|
|
common.CNMe.String(): Command{
|
|
|
|
HelpText: "Display an action message.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(client *Client, args []string) (string, error) {
|
2019-03-23 20:16:02 +01:00
|
|
|
if len(args) != 0 {
|
|
|
|
client.Me(strings.Join(args, " "))
|
2019-04-12 03:50:31 +02:00
|
|
|
return "", nil
|
2019-03-23 20:16:02 +01:00
|
|
|
}
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Missing a message")
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNHelp.String(): Command{
|
|
|
|
HelpText: "This help text.",
|
|
|
|
Function: cmdHelp,
|
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-11-29 18:48:17 +01:00
|
|
|
common.CNEmotes.String(): Command{
|
|
|
|
HelpText: "Display a list of available emotes.",
|
|
|
|
Function: func(client *Client, args []string) (string, error) {
|
|
|
|
client.SendChatData(common.NewChatCommand(common.CmdEmotes, []string{"/emotes"}))
|
|
|
|
return "Opening emote list in new window.", nil
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNCount.String(): Command{
|
|
|
|
HelpText: "Display number of users in chat.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(client *Client, args []string) (string, error) {
|
|
|
|
return fmt.Sprintf("Users in chat: %d", client.belongsTo.UserCount()), nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-28 23:40:49 +01:00
|
|
|
common.CNColor.String(): Command{
|
|
|
|
HelpText: "Change user color.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-28 23:40:49 +01:00
|
|
|
if len(args) > 2 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Too many arguments!")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
2019-04-12 04:00:14 +02:00
|
|
|
// If the caller is privileged enough, they can change the color of another user
|
2019-03-28 23:40:49 +01:00
|
|
|
if len(args) == 2 {
|
|
|
|
if cl.CmdLevel == common.CmdlUser {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("You cannot change someone else's color. PeepoSus")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
name, color := "", ""
|
|
|
|
|
|
|
|
if strings.ToLower(args[0]) == strings.ToLower(args[1]) ||
|
|
|
|
(common.IsValidColor(args[0]) && common.IsValidColor(args[1])) {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Name and color are ambiguous. Prefix the name with '@' or color with '#'")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check for explicit name
|
|
|
|
if strings.HasPrefix(args[0], "@") {
|
|
|
|
name = strings.TrimLeft(args[0], "@")
|
|
|
|
color = args[1]
|
|
|
|
common.LogDebugln("[color:mod] Found explicit name: ", name)
|
|
|
|
} else if strings.HasPrefix(args[1], "@") {
|
|
|
|
name = strings.TrimLeft(args[1], "@")
|
|
|
|
color = args[0]
|
|
|
|
common.LogDebugln("[color:mod] Found explicit name: ", name)
|
|
|
|
|
|
|
|
// Check for explicit color
|
|
|
|
} else if strings.HasPrefix(args[0], "#") {
|
|
|
|
name = strings.TrimPrefix(args[1], "@") // this shouldn't be needed, but just in case.
|
|
|
|
color = args[0]
|
|
|
|
common.LogDebugln("[color:mod] Found explicit color: ", color)
|
|
|
|
} else if strings.HasPrefix(args[1], "#") {
|
|
|
|
name = strings.TrimPrefix(args[0], "@") // this shouldn't be needed, but just in case.
|
|
|
|
color = args[1]
|
|
|
|
common.LogDebugln("[color:mod] Found explicit color: ", color)
|
|
|
|
|
|
|
|
// Guess
|
|
|
|
} else if common.IsValidColor(args[0]) {
|
|
|
|
name = strings.TrimPrefix(args[1], "@")
|
|
|
|
color = args[0]
|
|
|
|
common.LogDebugln("[color:mod] Guessed name: ", name, " and color: ", color)
|
|
|
|
} else if common.IsValidColor(args[1]) {
|
|
|
|
name = strings.TrimPrefix(args[0], "@")
|
|
|
|
color = args[1]
|
|
|
|
common.LogDebugln("[color:mod] Guessed name: ", name, " and color: ", color)
|
|
|
|
}
|
|
|
|
|
|
|
|
if name == "" {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Cannot determine name. Prefix name with @.")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
if color == "" {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Cannot determine color. Prefix name with @.")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if color == "" {
|
|
|
|
common.LogInfof("[color:mod] %s missing color\n", cl.name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Missing color")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if name == "" {
|
|
|
|
common.LogInfof("[color:mod] %s missing name\n", cl.name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Missing name")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := cl.belongsTo.ForceColorChange(name, color); err != nil {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", err
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
2019-04-12 03:06:55 +02:00
|
|
|
return fmt.Sprintf("Color changed for user %s to %s\n", name, color), nil
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
// Don't allow an unprivileged user to change their color if
|
2019-03-28 23:40:49 +01:00
|
|
|
// it was changed by a mod
|
|
|
|
if cl.IsColorForced {
|
|
|
|
common.LogInfof("[color] %s tried to change a forced color\n", cl.name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("You are not allowed to change your color.")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
2019-03-30 20:39:04 +01:00
|
|
|
if time.Now().Before(cl.nextColor) && cl.CmdLevel == common.CmdlUser {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Slow down. You can change your color in %0.0f seconds.", time.Until(cl.nextColor).Seconds())
|
2019-03-30 20:39:04 +01:00
|
|
|
}
|
|
|
|
|
2019-03-28 23:40:49 +01:00
|
|
|
if len(args) == 0 {
|
2019-03-29 01:01:48 +01:00
|
|
|
cl.setColor(common.RandomColor())
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Random color chosen: " + cl.color, nil
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-28 23:40:49 +01:00
|
|
|
// Change the color of the user
|
|
|
|
if !common.IsValidColor(args[0]) {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("To choose a specific color use the format <i>/color #c029ce</i>. Hex values expected.")
|
2019-03-28 23:40:49 +01:00
|
|
|
}
|
|
|
|
|
2019-03-30 20:39:04 +01:00
|
|
|
cl.nextColor = time.Now().Add(time.Second * settings.RateLimitColor)
|
|
|
|
|
2019-03-29 01:01:48 +01:00
|
|
|
err := cl.setColor(args[0])
|
|
|
|
if err != nil {
|
|
|
|
common.LogErrorf("[color] could not send color update to client: %v\n", err)
|
|
|
|
}
|
|
|
|
|
2019-03-28 23:40:49 +01:00
|
|
|
common.LogInfof("[color] %s new color: %s\n", cl.name, cl.color)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Color changed successfully.", nil
|
2019-03-28 23:40:49 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
common.CNWhoAmI.String(): Command{
|
|
|
|
HelpText: "Shows debug user info",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-28 23:40:49 +01:00
|
|
|
return fmt.Sprintf("Name: %s IsMod: %t IsAdmin: %t",
|
|
|
|
cl.name,
|
|
|
|
cl.CmdLevel >= common.CmdlMod,
|
2019-04-12 03:06:55 +02:00
|
|
|
cl.CmdLevel == common.CmdlAdmin), nil
|
2019-03-28 23:40:49 +01:00
|
|
|
},
|
|
|
|
},
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNAuth.String(): Command{
|
|
|
|
HelpText: "Authenticate to admin",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-24 14:24:57 +01:00
|
|
|
if cl.CmdLevel == common.CmdlAdmin {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("You are already authenticated.")
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
// TODO: handle back off policy
|
2019-03-30 20:39:04 +01:00
|
|
|
if time.Now().Before(cl.nextAuth) {
|
|
|
|
cl.nextAuth = time.Now().Add(time.Second * settings.RateLimitAuth)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Slow down.")
|
2019-03-30 20:39:04 +01:00
|
|
|
}
|
|
|
|
cl.authTries += 1 // this isn't used yet
|
|
|
|
cl.nextAuth = time.Now().Add(time.Second * settings.RateLimitAuth)
|
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
pw := html.UnescapeString(strings.Join(args, " "))
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
if settings.AdminPassword == pw {
|
2019-03-24 14:24:57 +01:00
|
|
|
cl.CmdLevel = common.CmdlAdmin
|
2019-03-15 21:03:02 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " used the admin password")
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[auth] %s used the admin password\n", cl.name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Admin rights granted.", nil
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
if cl.belongsTo.redeemModPass(pw) {
|
2019-03-24 14:24:57 +01:00
|
|
|
cl.CmdLevel = common.CmdlMod
|
2019-03-15 21:03:02 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " used a mod password")
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[auth] %s used a mod password\n", cl.name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Moderator privileges granted.", nil
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-13 21:47:32 +01:00
|
|
|
|
2019-03-15 21:03:02 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " attempted to auth without success")
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[auth] %s gave an invalid password\n", cl.name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Invalid password.")
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNUsers.String(): Command{
|
|
|
|
HelpText: "Show a list of users in chat",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-14 02:24:14 +01:00
|
|
|
names := cl.belongsTo.GetNames()
|
2020-05-05 21:04:42 +02:00
|
|
|
formatNames := func(names []string) []string {
|
|
|
|
result := make([]string, len(names))
|
|
|
|
for _, name := range names {
|
|
|
|
if strings.HasPrefix(name, "@") {
|
|
|
|
result = append(result, name)
|
|
|
|
} else {
|
|
|
|
result = append(result, "@"+name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
return strings.Join(formatNames(names), " "), nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
|
|
|
},
|
2019-03-19 22:03:34 +01:00
|
|
|
|
|
|
|
common.CNNick.String(): Command{
|
|
|
|
HelpText: "Change display name",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-11-10 01:24:27 +01:00
|
|
|
if time.Now().Before(cl.nextNick) && cl.CmdLevel == common.CmdlUser {
|
2019-03-30 20:39:04 +01:00
|
|
|
//cl.nextNick = time.Now().Add(time.Second * settings.RateLimitNick)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Slow down. You can change your nick in %0.0f seconds.", time.Until(cl.nextNick).Seconds())
|
2019-03-30 20:39:04 +01:00
|
|
|
}
|
|
|
|
cl.nextNick = time.Now().Add(time.Second * settings.RateLimitNick)
|
|
|
|
|
2019-03-19 22:03:34 +01:00
|
|
|
if len(args) == 0 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Missing name to change to.")
|
2019-03-19 22:03:34 +01:00
|
|
|
}
|
|
|
|
|
2019-03-24 20:15:28 +01:00
|
|
|
newName := strings.TrimLeft(args[0], "@")
|
2019-03-19 22:03:34 +01:00
|
|
|
oldName := cl.name
|
|
|
|
forced := false
|
2019-03-24 20:15:28 +01:00
|
|
|
|
|
|
|
// Two arguments to force a name change on another user: `/nick OldName NewName`
|
2019-03-19 22:03:34 +01:00
|
|
|
if len(args) == 2 {
|
2019-11-10 01:24:27 +01:00
|
|
|
if cl.CmdLevel == common.CmdlUser {
|
|
|
|
return "", fmt.Errorf("Only admins and mods can do that PeepoSus")
|
2019-03-19 22:03:34 +01:00
|
|
|
}
|
|
|
|
|
2019-03-24 20:15:28 +01:00
|
|
|
oldName = strings.TrimLeft(args[0], "@")
|
|
|
|
newName = strings.TrimLeft(args[1], "@")
|
2019-03-19 22:03:34 +01:00
|
|
|
forced = true
|
|
|
|
}
|
|
|
|
|
2019-03-24 14:24:57 +01:00
|
|
|
if len(args) == 1 && cl.IsNameForced && cl.CmdLevel != common.CmdlAdmin {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("You cannot change your name once it has been changed by an admin.")
|
2019-03-19 22:03:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
err := cl.belongsTo.changeName(oldName, newName, forced)
|
|
|
|
if err != nil {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Unable to change name: " + err.Error())
|
2019-03-19 22:03:34 +01:00
|
|
|
}
|
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", nil
|
2019-03-19 22:03:34 +01:00
|
|
|
},
|
|
|
|
},
|
2019-04-14 06:25:49 +02:00
|
|
|
|
|
|
|
common.CNStats.String(): Command{
|
|
|
|
HelpText: "Show some stats for stream.",
|
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
|
|
|
cl.belongsTo.clientsMtx.Lock()
|
|
|
|
users := len(cl.belongsTo.clients)
|
|
|
|
cl.belongsTo.clientsMtx.Unlock()
|
|
|
|
|
|
|
|
// Just print max users and time alive here
|
|
|
|
return fmt.Sprintf("Current users in chat: <b>%d</b><br />Max users in chat: <b>%d</b><br />Server uptime: <b>%s</b><br />Stream uptime: <b>%s</b>",
|
|
|
|
users,
|
|
|
|
stats.getMaxUsers(),
|
|
|
|
time.Since(stats.start),
|
|
|
|
stats.getStreamLength(),
|
|
|
|
), nil
|
|
|
|
},
|
|
|
|
},
|
2019-09-22 23:02:09 +02:00
|
|
|
|
|
|
|
common.CNPin.String(): Command{
|
|
|
|
HelpText: "Display the current room access type and pin/password (if applicable).",
|
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
|
|
|
switch settings.RoomAccess {
|
|
|
|
case AccessPin:
|
|
|
|
return "Room is secured via PIN. Current PIN: " + settings.RoomAccessPin, nil
|
|
|
|
case AccessRequest:
|
|
|
|
return "Room is secured via access requests. Users must request to be granted access.", nil
|
|
|
|
}
|
|
|
|
return "Room is open access. Anybody can join.", nil
|
|
|
|
},
|
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
mod: map[string]Command{
|
|
|
|
common.CNSv.String(): Command{
|
|
|
|
HelpText: "Send a server announcement message. It will show up red with a border in chat.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-14 02:24:14 +01:00
|
|
|
if len(args) == 0 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Missing message")
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-19 22:03:34 +01:00
|
|
|
svmsg := formatLinks(strings.Join(common.ParseEmotesArray(args), " "))
|
2019-03-15 21:03:02 +01:00
|
|
|
cl.belongsTo.AddModNotice("Server message from " + cl.name)
|
2019-03-14 02:24:14 +01:00
|
|
|
cl.belongsTo.AddMsg(cl, false, true, svmsg)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", nil
|
2019-03-11 17:05:00 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNPlaying.String(): Command{
|
|
|
|
HelpText: "Set the title text and info link.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-14 02:24:14 +01:00
|
|
|
// Clear/hide title if sent with no arguments.
|
|
|
|
if len(args) == 0 {
|
|
|
|
cl.belongsTo.ClearPlaying()
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Title cleared", nil
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
|
|
|
link := ""
|
|
|
|
title := ""
|
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
// pick out the link (can be anywhere, as long as there are no spaces).
|
2019-03-14 02:24:14 +01:00
|
|
|
for _, word := range args {
|
|
|
|
word = html.UnescapeString(word)
|
|
|
|
if strings.HasPrefix(word, "http://") || strings.HasPrefix(word, "https://") {
|
|
|
|
link = word
|
|
|
|
} else {
|
|
|
|
title = title + " " + word
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-15 21:03:02 +01:00
|
|
|
title = strings.TrimSpace(title)
|
|
|
|
link = strings.TrimSpace(link)
|
|
|
|
|
2019-03-17 02:04:11 +01:00
|
|
|
if len(title) > settings.TitleLength {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Title too long (%d/%d)", len(title), settings.TitleLength)
|
2019-03-17 02:04:11 +01:00
|
|
|
}
|
|
|
|
|
2019-03-15 21:03:02 +01:00
|
|
|
// Send a notice to the mods and admins
|
|
|
|
if len(link) == 0 {
|
|
|
|
cl.belongsTo.AddModNotice(cl.name + " set the playing title to '" + title + "' with no link")
|
|
|
|
} else {
|
|
|
|
cl.belongsTo.AddModNotice(cl.name + " set the playing title to '" + title + "' with link '" + link + "'")
|
|
|
|
}
|
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
cl.belongsTo.SetPlaying(title, link)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNUnmod.String(): Command{
|
|
|
|
HelpText: "Revoke a user's moderator privilages. Moderators can only unmod themselves.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-24 14:24:57 +01:00
|
|
|
if len(args) > 0 && cl.CmdLevel != common.CmdlAdmin && cl.name != args[0] {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("You can only unmod yourself, not others.")
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-24 20:15:28 +01:00
|
|
|
if len(args) == 0 || (len(args) == 1 && strings.TrimLeft(args[0], "@") == cl.name) {
|
2019-03-14 02:24:14 +01:00
|
|
|
cl.Unmod()
|
2019-03-15 21:03:02 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " has unmodded themselves")
|
2019-04-12 03:06:55 +02:00
|
|
|
return "You have unmodded yourself.", nil
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-24 20:15:28 +01:00
|
|
|
name := strings.TrimLeft(args[0], "@")
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-24 20:15:28 +01:00
|
|
|
if err := cl.belongsTo.Unmod(name); err != nil {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", err
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-24 20:15:28 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " has unmodded " + name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNKick.String(): Command{
|
|
|
|
HelpText: "Kick a user from chat.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-14 02:24:14 +01:00
|
|
|
if len(args) == 0 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Missing name to kick.")
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", cl.belongsTo.Kick(strings.TrimLeft(args[0], "@"))
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNBan.String(): Command{
|
|
|
|
HelpText: "Ban a user from chat. They will not be able to re-join chat, but will still be able to view the stream.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-14 02:24:14 +01:00
|
|
|
if len(args) == 0 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("missing name to ban.")
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-24 20:15:28 +01:00
|
|
|
|
|
|
|
name := strings.TrimLeft(args[0], "@")
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[ban] Attempting to ban %s\n", name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", cl.belongsTo.Ban(name)
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNUnban.String(): Command{
|
|
|
|
HelpText: "Remove a ban on a user.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-14 02:24:14 +01:00
|
|
|
if len(args) == 0 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("missing name to unban.")
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-24 20:15:28 +01:00
|
|
|
name := strings.TrimLeft(args[0], "@")
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[ban] Attempting to unban %s\n", name)
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-24 20:15:28 +01:00
|
|
|
err := settings.RemoveBan(name)
|
2019-03-14 02:24:14 +01:00
|
|
|
if err != nil {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", err
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-24 20:15:28 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " has unbanned " + name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-18 03:29:31 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
common.CNPurge.String(): Command{
|
|
|
|
HelpText: "Purge the chat.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfoln("[purge] clearing chat")
|
2019-03-18 03:29:31 +01:00
|
|
|
cl.belongsTo.AddCmdMsg(common.CmdPurgeChat, nil)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", nil
|
2019-03-18 03:29:31 +01:00
|
|
|
},
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
admin: map[string]Command{
|
|
|
|
common.CNMod.String(): Command{
|
|
|
|
HelpText: "Grant moderator privilages to a user.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-14 02:24:14 +01:00
|
|
|
if len(args) == 0 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Missing user to mod.")
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-24 20:15:28 +01:00
|
|
|
|
|
|
|
name := strings.TrimLeft(args[0], "@")
|
|
|
|
if err := cl.belongsTo.Mod(name); err != nil {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", err
|
2019-03-14 02:24:14 +01:00
|
|
|
}
|
2019-03-24 20:15:28 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " has modded " + name)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNReloadPlayer.String(): Command{
|
|
|
|
HelpText: "Reload the stream player for everybody in chat.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-15 21:03:02 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " has modded forced a player reload")
|
2019-03-14 02:24:14 +01:00
|
|
|
cl.belongsTo.AddCmdMsg(common.CmdRefreshPlayer, nil)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Reloading player for all chatters.", nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNReloadEmotes.String(): Command{
|
|
|
|
HelpText: "Reload the emotes on the server.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-09-22 22:51:13 +02:00
|
|
|
go commandReloadEmotes(cl)
|
2019-06-19 04:13:53 +02:00
|
|
|
return "Reloading emotes...", nil
|
2019-03-10 16:42:12 +01:00
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-11 17:05:00 +01:00
|
|
|
|
2019-03-14 02:24:14 +01:00
|
|
|
common.CNModpass.String(): Command{
|
|
|
|
HelpText: "Generate a single-use mod password.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-16 21:59:12 +01:00
|
|
|
cl.belongsTo.AddModNotice(cl.name + " generated a mod password")
|
2019-03-14 02:24:14 +01:00
|
|
|
password := cl.belongsTo.generateModPass()
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Single use password: " + password, nil
|
2019-03-23 02:39:55 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
common.CNRoomAccess.String(): Command{
|
|
|
|
HelpText: "Change the room access type.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-23 02:39:55 +01:00
|
|
|
// Print current access type if no arguments given
|
|
|
|
if len(args) == 0 {
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Current room access type: " + string(settings.RoomAccess), nil
|
2019-03-23 02:39:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
switch AccessMode(strings.ToLower(args[0])) {
|
|
|
|
case AccessOpen:
|
|
|
|
settings.RoomAccess = AccessOpen
|
2019-03-30 21:15:22 +01:00
|
|
|
common.LogInfoln("[access] Room set to open")
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Room access set to open", nil
|
2019-03-23 02:39:55 +01:00
|
|
|
|
|
|
|
case AccessPin:
|
|
|
|
// A pin/password was provided, use it.
|
|
|
|
if len(args) == 2 {
|
2019-04-22 17:50:42 +02:00
|
|
|
// TODO: make this a bit more robust. Currently, only accepts a single word as a pin/password
|
2019-03-23 02:39:55 +01:00
|
|
|
settings.RoomAccessPin = args[1]
|
|
|
|
|
|
|
|
// A pin/password was not provided, generate a new one.
|
|
|
|
} else {
|
|
|
|
_, err := settings.generateNewPin()
|
|
|
|
if err != nil {
|
2019-03-30 21:15:22 +01:00
|
|
|
common.LogErrorln("Error generating new access pin: ", err.Error())
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Unable to generate a new pin, access unchanged: " + err.Error())
|
2019-03-23 02:39:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
settings.RoomAccess = AccessPin
|
2019-03-30 21:15:22 +01:00
|
|
|
common.LogInfoln("[access] Room set to pin: " + settings.RoomAccessPin)
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Room access set to Pin: " + settings.RoomAccessPin, nil
|
2019-03-23 02:39:55 +01:00
|
|
|
|
|
|
|
case AccessRequest:
|
|
|
|
settings.RoomAccess = AccessRequest
|
2019-03-30 21:15:22 +01:00
|
|
|
common.LogInfoln("[access] Room set to request")
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Room access set to request. WARNING: this isn't implemented yet.", nil
|
2019-03-23 02:39:55 +01:00
|
|
|
|
|
|
|
default:
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Invalid access mode")
|
2019-03-23 02:39:55 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
2019-03-26 16:58:46 +01:00
|
|
|
|
2019-03-23 21:53:36 +01:00
|
|
|
common.CNIP.String(): Command{
|
2019-03-24 23:51:39 +01:00
|
|
|
HelpText: "List users and IP in the server console. Requires logging level to be set to info or above.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-23 21:53:36 +01:00
|
|
|
cl.belongsTo.clientsMtx.Lock()
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfoln("Clients:")
|
2019-04-13 21:56:49 +02:00
|
|
|
for id, client := range cl.belongsTo.clients {
|
|
|
|
common.LogInfof(" [%d] %s %s\n", id, client.name, client.conn.Host())
|
2019-03-23 21:53:36 +01:00
|
|
|
}
|
|
|
|
cl.belongsTo.clientsMtx.Unlock()
|
2019-04-12 03:06:55 +02:00
|
|
|
return "see console for output", nil
|
2019-03-23 21:53:36 +01:00
|
|
|
},
|
|
|
|
},
|
2019-03-28 21:47:58 +01:00
|
|
|
|
|
|
|
common.CNAddEmotes.String(): Command{
|
|
|
|
HelpText: "Add emotes from a given twitch channel.",
|
2019-04-12 03:06:55 +02:00
|
|
|
Function: func(cl *Client, args []string) (string, error) {
|
2019-03-28 21:47:58 +01:00
|
|
|
// Fire this off in it's own goroutine so the client doesn't
|
|
|
|
// block waiting for the emote download to finish.
|
|
|
|
go func() {
|
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
// Pretty sure this breaks on partial downloads (eg, one good channel and one non-existent)
|
2019-06-02 01:41:28 +02:00
|
|
|
err := getEmotes(args)
|
2019-03-28 21:47:58 +01:00
|
|
|
if err != nil {
|
|
|
|
cl.SendChatData(common.NewChatMessage("", "",
|
|
|
|
err.Error(),
|
|
|
|
common.CmdlUser, common.MsgCommandResponse))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-06-02 01:41:28 +02:00
|
|
|
// If the emotes were able to be downloaded, add the channels to settings
|
2020-01-30 20:32:46 +01:00
|
|
|
settings.AddApprovedEmotes(args)
|
2019-06-02 01:41:28 +02:00
|
|
|
|
2019-03-28 21:47:58 +01:00
|
|
|
// reload emotes now that new ones were added
|
2019-06-02 01:41:28 +02:00
|
|
|
err = loadEmotes()
|
2019-03-28 21:47:58 +01:00
|
|
|
if err != nil {
|
|
|
|
cl.SendChatData(common.NewChatMessage("", "",
|
|
|
|
err.Error(),
|
|
|
|
common.CmdlUser, common.MsgCommandResponse))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
cl.belongsTo.AddModNotice(cl.name + " has added emotes from the following channels: " + strings.Join(args, ", "))
|
2019-09-22 22:51:13 +02:00
|
|
|
|
|
|
|
commandReloadEmotes(cl)
|
2019-03-28 21:47:58 +01:00
|
|
|
}()
|
2019-04-12 03:06:55 +02:00
|
|
|
return "Emote download initiated for the following channels: " + strings.Join(args, ", "), nil
|
2019-03-28 21:47:58 +01:00
|
|
|
},
|
|
|
|
},
|
2019-03-14 02:24:14 +01:00
|
|
|
},
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
func (cc *CommandControl) RunCommand(command string, args []string, sender *Client) (string, error) {
|
2019-03-14 05:21:41 +01:00
|
|
|
// get correct command from combined commands
|
|
|
|
cmd := common.GetFullChatCommand(command)
|
|
|
|
|
2019-03-10 16:42:12 +01:00
|
|
|
// Look for user command
|
2019-03-14 05:21:41 +01:00
|
|
|
if userCmd, ok := cc.user[cmd]; ok {
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[user] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
2019-03-11 17:05:00 +01:00
|
|
|
return userCmd.Function(sender, args)
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Look for mod command
|
2019-03-14 05:21:41 +01:00
|
|
|
if modCmd, ok := cc.mod[cmd]; ok {
|
2019-03-24 14:24:57 +01:00
|
|
|
if sender.CmdLevel >= common.CmdlMod {
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[mod] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
2019-03-11 17:05:00 +01:00
|
|
|
return modCmd.Function(sender, args)
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
|
|
|
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[mod REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("You are not a mod Jebaited")
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Look for admin command
|
2019-03-14 05:21:41 +01:00
|
|
|
if adminCmd, ok := cc.admin[cmd]; ok {
|
2019-03-24 14:24:57 +01:00
|
|
|
if sender.CmdLevel == common.CmdlAdmin {
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[admin] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
2019-03-11 17:05:00 +01:00
|
|
|
return adminCmd.Function(sender, args)
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
2019-03-24 23:51:39 +01:00
|
|
|
common.LogInfof("[admin REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("You are not the admin Jebaited")
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Command not found
|
2019-09-22 23:02:09 +02:00
|
|
|
common.LogInfof("[cmd|error] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
2019-04-12 03:06:55 +02:00
|
|
|
return "", fmt.Errorf("Invalid command.")
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
|
|
|
|
2019-04-12 03:06:55 +02:00
|
|
|
func cmdHelp(cl *Client, args []string) (string, error) {
|
2019-03-11 17:05:00 +01:00
|
|
|
url := "/help"
|
2019-03-24 14:24:57 +01:00
|
|
|
|
|
|
|
if cl.CmdLevel >= common.CmdlMod {
|
|
|
|
url += "?mod=1"
|
2019-03-11 17:05:00 +01:00
|
|
|
}
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-24 14:24:57 +01:00
|
|
|
if cl.CmdLevel == common.CmdlAdmin {
|
|
|
|
url += "&admin=1"
|
2019-03-11 17:05:00 +01:00
|
|
|
}
|
2019-03-10 16:42:12 +01:00
|
|
|
|
2019-03-16 21:15:45 +01:00
|
|
|
cl.SendChatData(common.NewChatCommand(common.CmdHelp, []string{url}))
|
2019-04-12 03:06:55 +02:00
|
|
|
return `Opening help in new window.`, nil
|
2019-03-11 17:05:00 +01:00
|
|
|
}
|
|
|
|
|
2019-03-16 21:15:45 +01:00
|
|
|
func getHelp(lvl common.CommandLevel) map[string]string {
|
|
|
|
var cmdList map[string]Command
|
|
|
|
switch lvl {
|
2019-03-24 14:24:57 +01:00
|
|
|
case common.CmdlUser:
|
2019-03-16 21:15:45 +01:00
|
|
|
cmdList = commands.user
|
2019-03-24 14:24:57 +01:00
|
|
|
case common.CmdlMod:
|
2019-03-16 21:15:45 +01:00
|
|
|
cmdList = commands.mod
|
2019-03-24 14:24:57 +01:00
|
|
|
case common.CmdlAdmin:
|
2019-03-16 21:15:45 +01:00
|
|
|
cmdList = commands.admin
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
2019-03-11 01:47:59 +01:00
|
|
|
|
2019-03-16 21:15:45 +01:00
|
|
|
helptext := map[string]string{}
|
|
|
|
for name, cmd := range cmdList {
|
|
|
|
helptext[name] = cmd.HelpText
|
2019-03-10 16:42:12 +01:00
|
|
|
}
|
2019-03-16 21:15:45 +01:00
|
|
|
return helptext
|
2019-03-11 17:05:00 +01:00
|
|
|
}
|
2019-09-22 22:51:13 +02:00
|
|
|
|
|
|
|
func commandReloadEmotes(cl *Client) {
|
|
|
|
cl.SendServerMessage("Reloading emotes")
|
|
|
|
err := loadEmotes()
|
|
|
|
if err != nil {
|
|
|
|
common.LogErrorf("Unbale to reload emotes: %s\n", err)
|
|
|
|
//return "", err
|
|
|
|
|
|
|
|
cl.SendChatData(common.NewChatMessage("", "",
|
|
|
|
err.Error(),
|
|
|
|
common.CmdlUser, common.MsgCommandResponse))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
cl.belongsTo.AddChatMsg(common.NewChatHiddenMessage(common.CdEmote, common.Emotes))
|
|
|
|
cl.belongsTo.AddModNotice(cl.name + " has reloaded emotes")
|
|
|
|
|
|
|
|
num := len(common.Emotes)
|
|
|
|
common.LogInfof("Loaded %d emotes\n", num)
|
|
|
|
cl.belongsTo.AddModNotice(fmt.Sprintf("%s reloaded %d emotes.", cl.name, num))
|
|
|
|
}
|