|
|
|
@ -3,6 +3,7 @@ package irc |
|
|
|
|
import ( |
|
|
|
|
"bufio" |
|
|
|
|
"encoding/json" |
|
|
|
|
"encoding/base64" |
|
|
|
|
"errors" |
|
|
|
|
"fmt" |
|
|
|
|
"io" |
|
|
|
@ -15,6 +16,8 @@ import ( |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
rgb "github.com/foresthoffman/rgblog" |
|
|
|
|
scribble "github.com/nanobox-io/golang-scribble" |
|
|
|
|
uuid "github.com/google/uuid" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
const PSTFormat = "Jan 2 15:04:05 PST" |
|
|
|
@ -38,9 +41,6 @@ type OAuthCred struct { |
|
|
|
|
|
|
|
|
|
// The developer application client ID. Used for API calls to Twitch.
|
|
|
|
|
ClientID string `json:"client_id,omitempty"` |
|
|
|
|
|
|
|
|
|
// List of Channels to join
|
|
|
|
|
Channels []string `json:"channels,omitempty"` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type KardBot struct { |
|
|
|
@ -54,6 +54,16 @@ type KardBot struct { |
|
|
|
|
Server string |
|
|
|
|
startTime time.Time |
|
|
|
|
Prompts []string |
|
|
|
|
Database scribble.Driver |
|
|
|
|
channelData map[string]ChannelData |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type ChannelData struct { |
|
|
|
|
Name string `json:"name"` |
|
|
|
|
AdminKey string `json:"value,omitempty"` |
|
|
|
|
CustomCommand string `json:"customcommand,omitempty"` |
|
|
|
|
ExtraStrings string `json:"extrastrings,omitempty"` |
|
|
|
|
JoinTime time.Time `json:"jointime"` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Connects the bot to the Twitch IRC server. The bot will continue to try to connect until it
|
|
|
|
@ -134,7 +144,7 @@ func (bb *KardBot) HandleChat() error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// channel-owner specific commands
|
|
|
|
|
if userName == bb.Channel { |
|
|
|
|
if userName == channel { |
|
|
|
|
switch cmd { |
|
|
|
|
case "tbdown": |
|
|
|
|
rgb.CPrintf( |
|
|
|
@ -144,6 +154,14 @@ func (bb *KardBot) HandleChat() error { |
|
|
|
|
|
|
|
|
|
bb.Disconnect() |
|
|
|
|
return nil |
|
|
|
|
case "wat": |
|
|
|
|
magicCode := bb.readOrCreateChannelKey(channel) |
|
|
|
|
rgb.CPrintf( |
|
|
|
|
"[%s] Magic code is %s - https://karaokards.ing.martyn.berlin/admin/%s/%s\n", |
|
|
|
|
TimeStamp(), |
|
|
|
|
magicCode, userName, magicCode, |
|
|
|
|
) |
|
|
|
|
bb.Say("Ack.") |
|
|
|
|
default: |
|
|
|
|
// do nothing
|
|
|
|
|
} |
|
|
|
@ -232,15 +250,24 @@ func (bb *KardBot) Start() { |
|
|
|
|
err := bb.ReadCredentials() |
|
|
|
|
if nil != err { |
|
|
|
|
fmt.Println(err) |
|
|
|
|
fmt.Println("Aborting...") |
|
|
|
|
fmt.Println("Aborting!") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err = bb.readChannelData() |
|
|
|
|
if nil != err { |
|
|
|
|
fmt.Println(err) |
|
|
|
|
fmt.Println("Aborting!") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for { |
|
|
|
|
bb.Connect() |
|
|
|
|
bb.Login() |
|
|
|
|
if len(bb.Credentials.Channels) > 0 { |
|
|
|
|
bb.JoinChannel(bb.Credentials.Channels...) |
|
|
|
|
if len(bb.channelData) > 0 { |
|
|
|
|
for channelName := range(bb.channelData) { |
|
|
|
|
bb.JoinChannel(channelName) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
bb.JoinChannel() |
|
|
|
|
} |
|
|
|
@ -257,10 +284,67 @@ func (bb *KardBot) Start() { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (bb *KardBot) readChannelData() error { |
|
|
|
|
records, err := bb.Database.ReadAll("channelData") |
|
|
|
|
if err != nil { |
|
|
|
|
// no db? initialise one?
|
|
|
|
|
record := ChannelData{Name: bb.Channel, JoinTime: time.Now()} |
|
|
|
|
rgb.YPrintf("[%s] No channel data for #%s exists, creating...\n", TimeStamp(), bb.Channel) |
|
|
|
|
if err := bb.Database.Write("channelData", bb.Channel, record); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
bb.channelData = make(map[string]ChannelData) |
|
|
|
|
bb.channelData[bb.Channel] = record; |
|
|
|
|
} else { |
|
|
|
|
bb.channelData = make(map[string]ChannelData) |
|
|
|
|
} |
|
|
|
|
for _, data := range records { |
|
|
|
|
record := ChannelData{} |
|
|
|
|
err := json.Unmarshal([]byte(data), &record); |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
bb.channelData[record.Name] = record |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (bb *KardBot) readOrCreateChannelKey(channel string) string { |
|
|
|
|
magicCode := "" |
|
|
|
|
var err error |
|
|
|
|
var record ChannelData |
|
|
|
|
if record, ok := bb.channelData[channel]; !ok { |
|
|
|
|
rgb.YPrintf("[%s] No channel data for #%s exists, creating\n", TimeStamp(), channel) |
|
|
|
|
err = bb.Database.Read("channelData", channel, &record); |
|
|
|
|
if err == nil { |
|
|
|
|
bb.channelData[channel] = record |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
record = bb.channelData[channel] |
|
|
|
|
if err != nil || record.AdminKey == "" { |
|
|
|
|
rgb.YPrintf("[%s] No channel key for #%s exists, creating one\n", TimeStamp(), channel) |
|
|
|
|
newuu, _ := uuid.NewRandom() |
|
|
|
|
magicCode = base64.StdEncoding.EncodeToString([]byte(newuu.String())) |
|
|
|
|
record.AdminKey = magicCode |
|
|
|
|
if record.Name == "" { |
|
|
|
|
record.Name = channel |
|
|
|
|
} |
|
|
|
|
if err := bb.Database.Write("channelData", channel, record); err != nil { |
|
|
|
|
rgb.RPrintf("[%s] Error writing channel data for #%s\n", TimeStamp(), channel) |
|
|
|
|
} |
|
|
|
|
bb.channelData[record.Name] = record |
|
|
|
|
rgb.YPrintf("[%s] Cached channel key for #%s\n", TimeStamp(), record.Name) |
|
|
|
|
} else { |
|
|
|
|
magicCode = record.AdminKey |
|
|
|
|
rgb.YPrintf("[%s] Loaded data for #%s\n", TimeStamp(), channel) |
|
|
|
|
} |
|
|
|
|
return magicCode |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TimeStamp() string { |
|
|
|
|
return TimeStampFmt(PSTFormat) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TimeStampFmt(format string) string { |
|
|
|
|
return time.Now().Format(format) |
|
|
|
|
} |
|
|
|
|
} |