Admin panel with leave option
Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
This commit is contained in:
		
							parent
							
								
									3950f8b672
								
							
						
					
					
						commit
						4803122aad
					
				
					 7 changed files with 423 additions and 22 deletions
				
			
		| 
						 | 
					@ -55,13 +55,13 @@ type KardBot struct {
 | 
				
			||||||
	startTime   time.Time
 | 
						startTime   time.Time
 | 
				
			||||||
	Prompts     []string
 | 
						Prompts     []string
 | 
				
			||||||
	Database	scribble.Driver
 | 
						Database	scribble.Driver
 | 
				
			||||||
	channelData map[string]ChannelData
 | 
						ChannelData map[string]ChannelData
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ChannelData struct {
 | 
					type ChannelData struct {
 | 
				
			||||||
	Name          string `json:"name"`
 | 
						Name          string `json:"name"`
 | 
				
			||||||
	AdminKey	  string `json:"value,omitempty"`
 | 
						AdminKey	  string `json:"value,omitempty"`
 | 
				
			||||||
	CustomCommand string `json:"customcommand,omitempty"`
 | 
						Command       string `json:"customcommand,omitempty"`
 | 
				
			||||||
	ExtraStrings  string `json:"extrastrings,omitempty"`
 | 
						ExtraStrings  string `json:"extrastrings,omitempty"`
 | 
				
			||||||
	JoinTime      time.Time `json:"jointime"`
 | 
						JoinTime      time.Time `json:"jointime"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -136,8 +136,9 @@ func (bb *KardBot) HandleChat() error {
 | 
				
			||||||
					if nil != cmdMatches {
 | 
										if nil != cmdMatches {
 | 
				
			||||||
						cmd := cmdMatches[1]
 | 
											cmd := cmdMatches[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											rgb.YPrintf("[%s] Checking cmd %s against %s\n", TimeStamp(), cmd, bb.ChannelData[channel].Command)
 | 
				
			||||||
						switch cmd {
 | 
											switch cmd {
 | 
				
			||||||
						case "card":
 | 
											case bb.ChannelData[channel].Command:
 | 
				
			||||||
							rgb.CPrintf("[%s] Card asked for by %s on %s' channel!\n", TimeStamp(), userName, channel)
 | 
												rgb.CPrintf("[%s] Card asked for by %s on %s' channel!\n", TimeStamp(), userName, channel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							bb.Say("Your prompt is : "+bb.Prompts[rand.Intn(len(bb.Prompts))], channel)
 | 
												bb.Say("Your prompt is : "+bb.Prompts[rand.Intn(len(bb.Prompts))], channel)
 | 
				
			||||||
| 
						 | 
					@ -184,6 +185,15 @@ func (bb *KardBot) Login() {
 | 
				
			||||||
	bb.conn.Write([]byte("NICK " + bb.Name + "\r\n"))
 | 
						bb.conn.Write([]byte("NICK " + bb.Name + "\r\n"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (bb *KardBot) LeaveChannel(channels ...string) {
 | 
				
			||||||
 | 
						for _, channel := range channels {
 | 
				
			||||||
 | 
							rgb.YPrintf("[%s] Leaving #%s...\n", TimeStamp(), channel)
 | 
				
			||||||
 | 
							bb.conn.Write([]byte("PART #" + channel + "\r\n"))
 | 
				
			||||||
 | 
							rgb.YPrintf("[%s] Left #%s as @%s!\n", TimeStamp(), channel, bb.Name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Makes the bot join its pre-specified channel.
 | 
					// Makes the bot join its pre-specified channel.
 | 
				
			||||||
func (bb *KardBot) JoinChannel(channels ...string) {
 | 
					func (bb *KardBot) JoinChannel(channels ...string) {
 | 
				
			||||||
	if len(channels) == 0 {
 | 
						if len(channels) == 0 {
 | 
				
			||||||
| 
						 | 
					@ -264,8 +274,8 @@ func (bb *KardBot) Start() {
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		bb.Connect()
 | 
							bb.Connect()
 | 
				
			||||||
		bb.Login()
 | 
							bb.Login()
 | 
				
			||||||
		if len(bb.channelData) > 0 {
 | 
							if len(bb.ChannelData) > 0 {
 | 
				
			||||||
			for channelName := range(bb.channelData) {
 | 
								for channelName := range(bb.ChannelData) {
 | 
				
			||||||
				bb.JoinChannel(channelName)
 | 
									bb.JoinChannel(channelName)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					@ -288,15 +298,15 @@ func (bb *KardBot) readChannelData() error {
 | 
				
			||||||
	records, err := bb.Database.ReadAll("channelData")
 | 
						records, err := bb.Database.ReadAll("channelData")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		// no db? initialise one?
 | 
							// no db? initialise one?
 | 
				
			||||||
		record := ChannelData{Name: bb.Channel, JoinTime: time.Now()}
 | 
							record := ChannelData{Name: bb.Channel, JoinTime: time.Now(), Command: "card"}
 | 
				
			||||||
		rgb.YPrintf("[%s] No channel data for #%s exists, creating...\n", TimeStamp(), bb.Channel)
 | 
							rgb.YPrintf("[%s] No channel table for #%s exists, creating...\n", TimeStamp(), bb.Channel)
 | 
				
			||||||
		if err := bb.Database.Write("channelData", bb.Channel, record); err != nil {
 | 
							if err := bb.Database.Write("channelData", bb.Channel, record); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bb.channelData = make(map[string]ChannelData)
 | 
							bb.ChannelData = make(map[string]ChannelData)
 | 
				
			||||||
		bb.channelData[bb.Channel] = record;
 | 
							bb.ChannelData[bb.Channel] = record;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		bb.channelData = make(map[string]ChannelData)
 | 
							bb.ChannelData = make(map[string]ChannelData)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, data := range records {
 | 
						for _, data := range records {
 | 
				
			||||||
		record := ChannelData{}
 | 
							record := ChannelData{}
 | 
				
			||||||
| 
						 | 
					@ -304,8 +314,29 @@ func (bb *KardBot) readChannelData() error {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bb.channelData[record.Name] = record
 | 
							if record.Name != "" {
 | 
				
			||||||
 | 
								if record.Command == "" {
 | 
				
			||||||
 | 
									record.Command = "card"
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									rgb.YPrintf("[%s] Rewriting data for #%s...\n", TimeStamp(), bb.Channel)
 | 
				
			||||||
 | 
									if err := bb.Database.Write("channelData", record.Name, record); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								bb.ChannelData[record.Name] = record
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Managed to leave the main channel!?
 | 
				
			||||||
 | 
						if bb.ChannelData[bb.Channel].Name == "" {
 | 
				
			||||||
 | 
							rgb.YPrintf("[%s] No channel data for #%s exists, creating...\n", TimeStamp(), bb.Channel)
 | 
				
			||||||
 | 
							record := ChannelData{Name: bb.Channel, JoinTime: time.Now(), Command: "card"}
 | 
				
			||||||
 | 
							bb.ChannelData[bb.Channel] = record
 | 
				
			||||||
 | 
							if err := bb.Database.Write("channelData", bb.Channel, record); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							records, err = bb.Database.ReadAll("channelData")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rgb.YPrintf("[%s] Read channel data for %d channels\n", TimeStamp(), len(bb.ChannelData))
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -313,14 +344,14 @@ func (bb *KardBot) readOrCreateChannelKey(channel string) string {
 | 
				
			||||||
	magicCode := ""
 | 
						magicCode := ""
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	var record ChannelData
 | 
						var record ChannelData
 | 
				
			||||||
	if record, ok := bb.channelData[channel]; !ok {
 | 
						if record, ok := bb.ChannelData[channel]; !ok {
 | 
				
			||||||
		rgb.YPrintf("[%s] No channel data for #%s exists, creating\n", TimeStamp(), channel)
 | 
							rgb.YPrintf("[%s] No channel data for #%s exists, creating\n", TimeStamp(), channel)
 | 
				
			||||||
		err = bb.Database.Read("channelData", channel, &record);
 | 
							err = bb.Database.Read("channelData", channel, &record);
 | 
				
			||||||
		if err == nil {
 | 
							if err == nil {
 | 
				
			||||||
			bb.channelData[channel] = record
 | 
								bb.ChannelData[channel] = record
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	record = bb.channelData[channel]
 | 
						record = bb.ChannelData[channel]
 | 
				
			||||||
	if err != nil || record.AdminKey == "" {
 | 
						if err != nil || record.AdminKey == "" {
 | 
				
			||||||
		rgb.YPrintf("[%s] No channel key for #%s exists, creating one\n", TimeStamp(), channel)
 | 
							rgb.YPrintf("[%s] No channel key for #%s exists, creating one\n", TimeStamp(), channel)
 | 
				
			||||||
		newuu, _ := uuid.NewRandom()
 | 
							newuu, _ := uuid.NewRandom()
 | 
				
			||||||
| 
						 | 
					@ -332,7 +363,7 @@ func (bb *KardBot) readOrCreateChannelKey(channel string) string {
 | 
				
			||||||
		if err := bb.Database.Write("channelData", channel, record); err != nil {
 | 
							if err := bb.Database.Write("channelData", channel, record); err != nil {
 | 
				
			||||||
			rgb.RPrintf("[%s] Error writing channel data for #%s\n", TimeStamp(), channel)
 | 
								rgb.RPrintf("[%s] Error writing channel data for #%s\n", TimeStamp(), channel)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bb.channelData[record.Name] = record
 | 
							bb.ChannelData[record.Name] = record
 | 
				
			||||||
		rgb.YPrintf("[%s] Cached channel key for #%s\n", TimeStamp(), record.Name)
 | 
							rgb.YPrintf("[%s] Cached channel key for #%s\n", TimeStamp(), record.Name)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		magicCode = record.AdminKey
 | 
							magicCode = record.AdminKey
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//var store = sessions.NewCookieStore(os.Getenv("SESSION_KEY"))
 | 
					//var store = sessions.NewCookieStore(os.Getenv("SESSION_KEY"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var ircBot irc.KardBot
 | 
					var ircBot *irc.KardBot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func HealthHandler(response http.ResponseWriter, request *http.Request) {
 | 
					func HealthHandler(response http.ResponseWriter, request *http.Request) {
 | 
				
			||||||
	response.Header().Add("Content-type", "text/plain")
 | 
						response.Header().Add("Content-type", "text/plain")
 | 
				
			||||||
| 
						 | 
					@ -73,7 +73,7 @@ func TemplateHandler(response http.ResponseWriter, request *http.Request) {
 | 
				
			||||||
		// NotFoundHandler(response, request)
 | 
							// NotFoundHandler(response, request)
 | 
				
			||||||
		// return
 | 
							// return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var td = TemplateData{ircBot.Prompts[rand.Intn(len(ircBot.Prompts))], len(ircBot.Prompts), 0, 0}
 | 
						var td = TemplateData{ircBot.Prompts[rand.Intn(len(ircBot.Prompts))], len(ircBot.Prompts), len(ircBot.ChannelData), 0}
 | 
				
			||||||
	err = tmpl.Execute(response, td)
 | 
						err = tmpl.Execute(response, td)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		http.Error(response, err.Error(), http.StatusInternalServerError)
 | 
							http.Error(response, err.Error(), http.StatusInternalServerError)
 | 
				
			||||||
| 
						 | 
					@ -81,19 +81,71 @@ func TemplateHandler(response http.ResponseWriter, request *http.Request) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func AdminHandler(response http.ResponseWriter, request *http.Request) {
 | 
					func LeaveHandler(response http.ResponseWriter, request *http.Request) {
 | 
				
			||||||
	request.URL.Path = "/index.html"
 | 
						request.URL.Path = "/bye.html"
 | 
				
			||||||
	TemplateHandler(response, request)
 | 
						TemplateHandler(response, request)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func HandleHTTP(passedIrcBot irc.KardBot) {
 | 
					func AdminHandler(response http.ResponseWriter, request *http.Request) {
 | 
				
			||||||
 | 
						vars := mux.Vars(request)
 | 
				
			||||||
 | 
						if vars["key"] != ircBot.ChannelData[vars["channel"]].AdminKey {
 | 
				
			||||||
 | 
							UnauthorizedHandler(response, request)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}	
 | 
				
			||||||
 | 
						type TemplateData struct {
 | 
				
			||||||
 | 
							Channel       string
 | 
				
			||||||
 | 
							Command       string
 | 
				
			||||||
 | 
							ExtraStrings  string
 | 
				
			||||||
 | 
							SinceTime     time.Time
 | 
				
			||||||
 | 
							Leaving       bool
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						channelData := ircBot.ChannelData[vars["channel"]]
 | 
				
			||||||
 | 
						var td = TemplateData{channelData.Name, channelData.Command, channelData.ExtraStrings, channelData.JoinTime, false}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if request.Method == "POST" {
 | 
				
			||||||
 | 
							request.ParseForm()
 | 
				
			||||||
 | 
							if strings.Join(request.PostForm["leave"],",") == "Leave twitch channel" {
 | 
				
			||||||
 | 
								td.Leaving = true
 | 
				
			||||||
 | 
							} else if strings.Join(request.PostForm["reallyleave"],",") == "Really leave twitch channel" {
 | 
				
			||||||
 | 
								delete(ircBot.ChannelData,vars["channel"])
 | 
				
			||||||
 | 
								ircBot.Database.Delete("channelData", vars["channel"])
 | 
				
			||||||
 | 
								ircBot.LeaveChannel(vars["channel"])
 | 
				
			||||||
 | 
								LeaveHandler(response, request)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sourceData := ircBot.ChannelData[vars["channel"]]
 | 
				
			||||||
 | 
							if strings.Join(request.PostForm["Command"],",") != ""  {
 | 
				
			||||||
 | 
								sourceData.Command = strings.Join(request.PostForm["Command"],",")
 | 
				
			||||||
 | 
								td.Command = sourceData.Command
 | 
				
			||||||
 | 
								ircBot.ChannelData[vars["channel"]] = sourceData
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if strings.Join(request.PostForm["ExtraStrings"],",") != sourceData.ExtraStrings {
 | 
				
			||||||
 | 
								sourceData.ExtraStrings = strings.Join(request.PostForm["ExtraStrings"],",")
 | 
				
			||||||
 | 
								td.ExtraStrings = sourceData.ExtraStrings
 | 
				
			||||||
 | 
								ircBot.ChannelData[vars["channel"]] = sourceData
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ircBot.Database.Write("channelData", vars["channel"], sourceData);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tmpl := template.Must(template.ParseFiles("web/admin.html"))
 | 
				
			||||||
 | 
						tmpl.Execute(response, td)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func UnauthorizedHandler(response http.ResponseWriter, request *http.Request) {
 | 
				
			||||||
 | 
						response.Header().Add("X-Template-File", "html"+request.URL.Path)
 | 
				
			||||||
 | 
						response.WriteHeader(401)
 | 
				
			||||||
 | 
						tmpl := template.Must(template.ParseFiles("web/401.html"))
 | 
				
			||||||
 | 
						tmpl.Execute(response, nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func HandleHTTP(passedIrcBot *irc.KardBot) {
 | 
				
			||||||
	ircBot = passedIrcBot
 | 
						ircBot = passedIrcBot
 | 
				
			||||||
	r := mux.NewRouter()
 | 
						r := mux.NewRouter()
 | 
				
			||||||
	loggedRouter := handlers.LoggingHandler(os.Stdout, r)
 | 
						loggedRouter := handlers.LoggingHandler(os.Stdout, r)
 | 
				
			||||||
	r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
 | 
						r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
 | 
				
			||||||
	r.HandleFunc("/", RootHandler)
 | 
						r.HandleFunc("/", RootHandler)
 | 
				
			||||||
	r.HandleFunc("/healthz", HealthHandler)
 | 
						r.HandleFunc("/healthz", HealthHandler)
 | 
				
			||||||
	r.HandleFunc("/example/{.*}", TemplateHandler)
 | 
						r.HandleFunc("/web/{.*}", TemplateHandler)
 | 
				
			||||||
 | 
						r.PathPrefix("/static/").Handler(http.FileServer(http.Dir("./web/")))
 | 
				
			||||||
	r.HandleFunc("/cover.css", CSSHandler)
 | 
						r.HandleFunc("/cover.css", CSSHandler)
 | 
				
			||||||
	r.HandleFunc("/admin/{channel}/{key}", AdminHandler)
 | 
						r.HandleFunc("/admin/{channel}/{key}", AdminHandler)
 | 
				
			||||||
	http.Handle("/", r)
 | 
						http.Handle("/", r)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								main.go
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
										
									
									
									
								
							| 
						 | 
					@ -208,7 +208,7 @@ func main() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		rgb.YPrintf("[%s] Starting webserver on port %s\n", irc.TimeStamp(), "5353")
 | 
							rgb.YPrintf("[%s] Starting webserver on port %s\n", irc.TimeStamp(), "5353")
 | 
				
			||||||
		webserver.HandleHTTP(myBot)
 | 
							webserver.HandleHTTP(&myBot)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	myBot.Start()
 | 
						myBot.Start()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										107
									
								
								web/401.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										107
									
								
								web/401.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					      <html>
 | 
				
			||||||
 | 
					        <!doctype html>
 | 
				
			||||||
 | 
					        <html lang="en">
 | 
				
			||||||
 | 
					          <head>
 | 
				
			||||||
 | 
					            <meta charset="utf-8">
 | 
				
			||||||
 | 
					            <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 | 
				
			||||||
 | 
					            <meta name="description" content="Karaokards">
 | 
				
			||||||
 | 
					            <meta name="author" content="Martyn Ranyard">
 | 
				
			||||||
 | 
					            <title>The great unknown!</title>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            <!-- Bootstrap core CSS -->
 | 
				
			||||||
 | 
					            <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
 | 
				
			||||||
 | 
					            <!-- Custom styles for this template -->
 | 
				
			||||||
 | 
					            <link href="/cover.css" rel="stylesheet">
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            <style>
 | 
				
			||||||
 | 
					              .bd-placeholder-img {
 | 
				
			||||||
 | 
					                font-size: 1.125rem;
 | 
				
			||||||
 | 
					                text-anchor: middle;
 | 
				
			||||||
 | 
					                -webkit-user-select: none;
 | 
				
			||||||
 | 
					                -moz-user-select: none;
 | 
				
			||||||
 | 
					                -ms-user-select: none;
 | 
				
			||||||
 | 
					                user-select: none;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					              @media (min-width: 768px) {
 | 
				
			||||||
 | 
					                .bd-placeholder-img-lg {
 | 
				
			||||||
 | 
					                  font-size: 3.5rem;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    li.match-nomatch{
 | 
				
			||||||
 | 
					                        background-color: #1e2122;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-matchtrack{
 | 
				
			||||||
 | 
					                        background-color: #E9B000;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-fullmatch{
 | 
				
			||||||
 | 
					                        background-color: #008F95;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-matchtrackfuzzt{
 | 
				
			||||||
 | 
					                        background-color: darkgray;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-fullmatchfuzzy{
 | 
				
			||||||
 | 
					                        background-color: darkgray;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    a{
 | 
				
			||||||
 | 
					                        text-decoration-line: underline;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            </style>
 | 
				
			||||||
 | 
					          </head>
 | 
				
			||||||
 | 
					          <body class="text-center">
 | 
				
			||||||
 | 
					                <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
 | 
				
			||||||
 | 
					                <header class="masthead mb-auto">
 | 
				
			||||||
 | 
					                <div class="inner">
 | 
				
			||||||
 | 
					                  <h3 class="masthead-brand">k8s-zoo</h3>
 | 
				
			||||||
 | 
					                  <nav class="nav nav-masthead justify-content-center">
 | 
				
			||||||
 | 
					                    <a class="nav-link active" href="/">Home</a>
 | 
				
			||||||
 | 
					                  </nav>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </header>
 | 
				
			||||||
 | 
					                <main role="main" class="inner cover">
 | 
				
			||||||
 | 
					                        <h1 class="cover-heading">Scary user alert!</h1>
 | 
				
			||||||
 | 
					                        <img src="https://http.cat/401" alt="Cat sat outside a door that has a sign depictinging no cats allowed" />
 | 
				
			||||||
 | 
					                        <p>It seems you've gone somewhere you shouldn't!  401 NOT AUTHORIZED!</p>
 | 
				
			||||||
 | 
					                        <p/>
 | 
				
			||||||
 | 
					                        <p>I'm not quite sure how you got here to be honest, if it was via a link on the site, let me know via twitch DM, if it was from someone else, let them know.</p>
 | 
				
			||||||
 | 
					                        <p>Shameless self-promotion : Follow me on twitch - <a href="https://www.twitch.tv/iMartynOnTwitch">iMartynOnTwitch</a>, oddly enough, I do a lot of twitchsings!</p>
 | 
				
			||||||
 | 
					                      </main>
 | 
				
			||||||
 | 
					        <footer class="mastfoot mt-auto">
 | 
				
			||||||
 | 
					                <div class="inner">
 | 
				
			||||||
 | 
					                  <p>Cover template for <a href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </footer>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <script>
 | 
				
			||||||
 | 
					                function directToResults() {
 | 
				
			||||||
 | 
					                    var url = document.createElement('a');
 | 
				
			||||||
 | 
					                    url.setAttribute("href", window.location.href);
 | 
				
			||||||
 | 
					                    if ((url.port != 80) && (url.port != 443)) {
 | 
				
			||||||
 | 
					                        customPort = ":"+url.port
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        customPort = ""
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    var destination = url.protocol + "//" + url.hostname + customPort + "/" + document.getElementById("mode").value + "/" + document.getElementById("spotifyid").value
 | 
				
			||||||
 | 
					                    window.location.href = destination
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                function toggleUnfound() {
 | 
				
			||||||
 | 
					                    var unmatched = document.getElementsByClassName('match-nomatch'), i;
 | 
				
			||||||
 | 
					                    if (document.getElementById("showhidebutton").getAttribute("tracksHidden") != "true") {
 | 
				
			||||||
 | 
					                        document.getElementById("showhidebutton").setAttribute("tracksHidden","true")
 | 
				
			||||||
 | 
					                        for (i = 0; i < unmatched.length; i += 1) {
 | 
				
			||||||
 | 
					                                unmatched[i].style.display = 'none';
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        document.getElementById("showhidebutton").setAttribute("tracksHidden","false")
 | 
				
			||||||
 | 
					                        for (i = 0; i < unmatched.length; i += 1) {
 | 
				
			||||||
 | 
					                                unmatched[i].style.display = 'list-item';
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                </script>
 | 
				
			||||||
 | 
					                </body>
 | 
				
			||||||
 | 
					                </html>
 | 
				
			||||||
 | 
					    </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										136
									
								
								web/admin.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										136
									
								
								web/admin.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,136 @@
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					        <!doctype html>
 | 
				
			||||||
 | 
					        <html lang="en">
 | 
				
			||||||
 | 
					          <head>
 | 
				
			||||||
 | 
					            <meta charset="utf-8">
 | 
				
			||||||
 | 
					            <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 | 
				
			||||||
 | 
					            <meta name="description" content="Karaokards bot for twitch chat">
 | 
				
			||||||
 | 
					            <meta name="author" content="Martyn Ranyard">
 | 
				
			||||||
 | 
					            <title>Karaokards</title>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            <!-- Bootstrap core CSS -->
 | 
				
			||||||
 | 
					            <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
 | 
				
			||||||
 | 
					            <!-- Custom styles for this template -->
 | 
				
			||||||
 | 
					            <link href="/cover.css" rel="stylesheet">
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            <style>
 | 
				
			||||||
 | 
					              .bd-placeholder-img {
 | 
				
			||||||
 | 
					                font-size: 1.125rem;
 | 
				
			||||||
 | 
					                text-anchor: middle;
 | 
				
			||||||
 | 
					                -webkit-user-select: none;
 | 
				
			||||||
 | 
					                -moz-user-select: none;
 | 
				
			||||||
 | 
					                -ms-user-select: none;
 | 
				
			||||||
 | 
					                user-select: none;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					              @media (min-width: 768px) {
 | 
				
			||||||
 | 
					                .bd-placeholder-img-lg {
 | 
				
			||||||
 | 
					                  font-size: 3.5rem;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    li.match-nomatch{
 | 
				
			||||||
 | 
					                        background-color: #1e2122;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-matchtrack{
 | 
				
			||||||
 | 
					                        background-color: #E9B000;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-fullmatch{
 | 
				
			||||||
 | 
					                        background-color: #008F95;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-matchtrackfuzzt{
 | 
				
			||||||
 | 
					                        background-color: darkgray;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-fullmatchfuzzy{
 | 
				
			||||||
 | 
					                        background-color: darkgray;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    a{
 | 
				
			||||||
 | 
					                        text-decoration-line: underline;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    .displaySetting{
 | 
				
			||||||
 | 
					                      display: inline
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    .hiddenDisplaySetting{
 | 
				
			||||||
 | 
					                      display: none;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    .hiddenSave {
 | 
				
			||||||
 | 
					                      display: none;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    .editSetting{
 | 
				
			||||||
 | 
					                      display: none;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    .visibleEditSetting{
 | 
				
			||||||
 | 
					                      display: inline;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    .visibleSave {
 | 
				
			||||||
 | 
					                      display: inline;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            </style>
 | 
				
			||||||
 | 
					          </head>
 | 
				
			||||||
 | 
					          <body class="text-center">
 | 
				
			||||||
 | 
					                <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
 | 
				
			||||||
 | 
					                <header class="masthead mb-auto">
 | 
				
			||||||
 | 
					                <div class="inner">
 | 
				
			||||||
 | 
					                  <h3 class="masthead-brand">Karaokards</h3>
 | 
				
			||||||
 | 
					                  <nav class="nav nav-masthead justify-content-center">
 | 
				
			||||||
 | 
					                    <a class="nav-link active" href="/">Home</a>
 | 
				
			||||||
 | 
					                  </nav>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </header>
 | 
				
			||||||
 | 
					                <main role="main" class="inner cover">
 | 
				
			||||||
 | 
					                  
 | 
				
			||||||
 | 
					                <script>
 | 
				
			||||||
 | 
					                    function editMode() {
 | 
				
			||||||
 | 
					                        var alldisps = document.getElementsByClassName("displaySetting");
 | 
				
			||||||
 | 
					                        for (item of alldisps) {
 | 
				
			||||||
 | 
					                          item.classList.add("hiddenDisplaySetting")
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        for (item of alldisps) {
 | 
				
			||||||
 | 
					                          item.classList.remove("displaySetting")
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var alldisps = document.getElementsByClassName("editSetting");
 | 
				
			||||||
 | 
					                        for (item of alldisps) {
 | 
				
			||||||
 | 
					                          item.classList.add("visibleEditSetting")
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        for (item of alldisps) {
 | 
				
			||||||
 | 
					                          item.classList.remove("editSetting")
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        document.getElementById("saveButton").classList.remove("hiddenSave")
 | 
				
			||||||
 | 
					                        document.getElementById("saveButton").classList.add("visibleSave")
 | 
				
			||||||
 | 
					                        document.getElementById("leaveButton").classList.remove("hiddenSave")
 | 
				
			||||||
 | 
					                        document.getElementById("leaveButton").classList.add("visibleSave")
 | 
				
			||||||
 | 
					                        document.getElementById("yuhateme").classList.remove("hiddenSave")
 | 
				
			||||||
 | 
					                        document.getElementById("yuhateme").classList.add("visibleSave")
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    </script>
 | 
				
			||||||
 | 
					                        <h1 class="cover-heading">Karaokards admin panel for {{.Channel}}!!!</h1>
 | 
				
			||||||
 | 
					                        <form method="POST">
 | 
				
			||||||
 | 
					                        {{ if .Leaving }}
 | 
				
			||||||
 | 
					                        <h2>Do you really want this bot to leave your channel? Right now you would have to ask Martyn to re-add it.</h2>
 | 
				
			||||||
 | 
					                        <p><input id="leaveButton" type="submit" name="reallyleave" value="Really leave twitch channel"></p>
 | 
				
			||||||
 | 
					                        {{ else }}
 | 
				
			||||||
 | 
					                        <table>
 | 
				
			||||||
 | 
					                          <thead><tr><td>Channel Data :</td><td><input type="button" value="Edit" onclick="javascript:editMode();"></td></tr></thead>
 | 
				
			||||||
 | 
					                          <tbody>
 | 
				
			||||||
 | 
					                          <tr><td>Member of channel since {{.SinceTime}}</td></tr>
 | 
				
			||||||
 | 
					                          <tr><td>Command for prompt:</td><td class="displaySetting"></tdclass>{{.Command}}</td><td class="editSetting"><input type="text" name="Command" value="{{.Command}}"></td></tr>
 | 
				
			||||||
 | 
					                          <tr><td>Extra prompts (one per line):</td><td class="displaySetting">{{.ExtraStrings}}</td><td class="editSetting"><textarea name="ExtraStrings" >{{.ExtraStrings}}</textarea></td></tr>
 | 
				
			||||||
 | 
					                          <tr><td> </td><td><input id="saveButton" type="submit" class="hiddenSave" name="save" value="Save changes"></td></tr>
 | 
				
			||||||
 | 
					                          <tr id="yuhateme" class="hiddenSave"><td>Or... please don't go but...</td></tr>
 | 
				
			||||||
 | 
					                          <tr><td><input id="leaveButton" type="submit" class="hiddenSave" name="leave" value="Leave twitch channel"></td></tr>
 | 
				
			||||||
 | 
					                        </tbody>
 | 
				
			||||||
 | 
					                        </table>
 | 
				
			||||||
 | 
					                        {{ end }}
 | 
				
			||||||
 | 
					                        </form>
 | 
				
			||||||
 | 
					                </main>
 | 
				
			||||||
 | 
					        <footer class="mastfoot mt-auto">
 | 
				
			||||||
 | 
					                <div class="inner">
 | 
				
			||||||
 | 
					                  <p>Cover template for <a href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </footer>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </body>
 | 
				
			||||||
 | 
					                </html>
 | 
				
			||||||
 | 
					    </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										75
									
								
								web/bye.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										75
									
								
								web/bye.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,75 @@
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					        <!doctype html>
 | 
				
			||||||
 | 
					        <html lang="en">
 | 
				
			||||||
 | 
					          <head>
 | 
				
			||||||
 | 
					            <meta charset="utf-8">
 | 
				
			||||||
 | 
					            <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 | 
				
			||||||
 | 
					            <meta name="description" content="Karaokards bot for twitch chat">
 | 
				
			||||||
 | 
					            <meta name="author" content="Martyn Ranyard">
 | 
				
			||||||
 | 
					            <title>Karaokards</title>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            <!-- Bootstrap core CSS -->
 | 
				
			||||||
 | 
					            <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
 | 
				
			||||||
 | 
					            <!-- Custom styles for this template -->
 | 
				
			||||||
 | 
					            <link href="/cover.css" rel="stylesheet">
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            <style>
 | 
				
			||||||
 | 
					              .bd-placeholder-img {
 | 
				
			||||||
 | 
					                font-size: 1.125rem;
 | 
				
			||||||
 | 
					                text-anchor: middle;
 | 
				
			||||||
 | 
					                -webkit-user-select: none;
 | 
				
			||||||
 | 
					                -moz-user-select: none;
 | 
				
			||||||
 | 
					                -ms-user-select: none;
 | 
				
			||||||
 | 
					                user-select: none;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					              @media (min-width: 768px) {
 | 
				
			||||||
 | 
					                .bd-placeholder-img-lg {
 | 
				
			||||||
 | 
					                  font-size: 3.5rem;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    li.match-nomatch{
 | 
				
			||||||
 | 
					                        background-color: #1e2122;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-matchtrack{
 | 
				
			||||||
 | 
					                        background-color: #E9B000;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-fullmatch{
 | 
				
			||||||
 | 
					                        background-color: #008F95;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-matchtrackfuzzt{
 | 
				
			||||||
 | 
					                        background-color: darkgray;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    li.match-fullmatchfuzzy{
 | 
				
			||||||
 | 
					                        background-color: darkgray;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    a{
 | 
				
			||||||
 | 
					                        text-decoration-line: underline;
 | 
				
			||||||
 | 
					                    }        
 | 
				
			||||||
 | 
					            </style>
 | 
				
			||||||
 | 
					          </head>
 | 
				
			||||||
 | 
					          <body class="text-center">
 | 
				
			||||||
 | 
					                <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
 | 
				
			||||||
 | 
					                <header class="masthead mb-auto">
 | 
				
			||||||
 | 
					                <div class="inner">
 | 
				
			||||||
 | 
					                  <h3 class="masthead-brand">Karaokards</h3>
 | 
				
			||||||
 | 
					                  <nav class="nav nav-masthead justify-content-center">
 | 
				
			||||||
 | 
					                    <a class="nav-link active" href="/">Home</a>
 | 
				
			||||||
 | 
					                  </nav>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </header>
 | 
				
			||||||
 | 
					                <main role="main" class="inner cover">
 | 
				
			||||||
 | 
					                        <h1 class="cover-heading">Left channel!!!</h1>
 | 
				
			||||||
 | 
					                        <p><img src="/static/okaybye.gif" alt="animation of dissappointed sister from Frozen saying Okay, bye..."/></p>
 | 
				
			||||||
 | 
					                </main>
 | 
				
			||||||
 | 
					        <footer class="mastfoot mt-auto">
 | 
				
			||||||
 | 
					                <div class="inner">
 | 
				
			||||||
 | 
					                  <p>Cover template for <a href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </footer>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </body>
 | 
				
			||||||
 | 
					                </html>
 | 
				
			||||||
 | 
					    </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								web/static/okaybye.gif
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/static/okaybye.gif
									
										
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 263 KiB  | 
		Loading…
	
	Add table
		
		Reference in a new issue