diff --git a/.gitignore b/.gitignore index bcdff6f..7497f1c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,7 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +# Frontend compiled version gets built from source +/web/react-frontend + /twitchsingstools diff --git a/internal/webserver/webserver.go b/internal/webserver/webserver.go index ecb4e06..d1e240f 100755 --- a/internal/webserver/webserver.go +++ b/internal/webserver/webserver.go @@ -778,23 +778,80 @@ func CSVHandler(response http.ResponseWriter, request *http.Request) { } } +func JSONHandler(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 + SinceTimeUTC string + Leaving bool + HasLeft bool + SongData []AugmentedSingsVideoStruct + TopNSongs []SongSings + TopNSingers []SingerSings + } + channelData := ircBot.ChannelData[vars["channel"]] + if time.Now().Sub(ircBot.ChannelData[vars["channel"]].VideoCacheUpdated).Hours() > 1 { + fmt.Printf("Cache of %d performances is older than an hour - %.1f hours old to be precise... fetching.\n", len(ircBot.ChannelData[vars["channel"]].VideoCache), time.Now().Sub(ircBot.ChannelData[vars["channel"]].VideoCacheUpdated).Hours()) + vids, err := fetchAllVoDs(channelData.TwitchUserID, channelData.Bearer) + if err != nil { + errCache := make([]irc.SingsVideoStruct, 0) + var ret irc.SingsVideoStruct + ret.FullTitle = "Error fetching videos: " + err.Error() + errCache = append(errCache, ret) + vids = errCache + } + updateCalculatedFields(vids) + ircBot.UpdateVideoCache(vars["channel"], vids) + } else { + fmt.Printf("Cache of %d performances is younger than an hour - %.1f hours old to be precise... not fetching.\n", len(ircBot.ChannelData[vars["channel"]].VideoCache), time.Now().Sub(ircBot.ChannelData[vars["channel"]].VideoCacheUpdated).Hours()) + } + topNSongs := calculateTopNSongs(channelData.VideoCache, 10) + topNSingers := calculateTopNSingers(channelData.VideoCache, 10) + var td = TemplateData{channelData.Name, channelData.Command, channelData.ExtraStrings, channelData.JoinTime, channelData.JoinTime.Format(irc.UTCFormat), false, channelData.HasLeft, AugmentSingsVideoStructSlice(channelData.VideoCache), topNSongs, topNSingers} + response.Header().Add("Content-type", "application/json") + if request.URL.Path[0:5] == "/json" { + tmpl := template.Must(template.ParseFiles("web/data.json")) + tmpl.Execute(response, td) + } else if request.URL.Path[0:9] == "/topsongs" { + tmpl := template.Must(template.ParseFiles("web/topsongs.json")) + tmpl.Execute(response, td) + } else { // top 10 singers! + tmpl := template.Must(template.ParseFiles("web/topsingers.json")) + tmpl.Execute(response, td) + } +} + +func ReactIndexHandler(entrypoint string) func(w http.ResponseWriter, r *http.Request) { + fn := func(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, entrypoint) + } + + return http.HandlerFunc(fn) +} + func HandleHTTP(passedIrcBot *irc.KardBot) { ircBot = passedIrcBot r := mux.NewRouter() loggedRouter := handlers.LoggingHandler(os.Stdout, r) r.NotFoundHandler = http.HandlerFunc(NotFoundHandler) - r.HandleFunc("/", RootHandler) r.HandleFunc("/healthz", HealthHandler) r.HandleFunc("/web/{.*}", TemplateHandler) - r.PathPrefix("/static/").Handler(http.FileServer(http.Dir("./web/"))) - r.HandleFunc("/cover.css", CSSHandler) - r.HandleFunc("/admin/{channel}/{key}", AdminHandler) r.HandleFunc("/csv/{channel}/{key}", CSVHandler) r.HandleFunc("/tsv/{channel}/{key}", CSVHandler) - //r.HandleFunc("/twitchadmin", TwitchAdminHandler) - //r.HandleFunc("/twitchtobackend", TwitchBackendHandler) + r.HandleFunc("/json/{channel}/{key}", JSONHandler) + r.HandleFunc("/topsongs/{channel}/{key}", JSONHandler) + r.HandleFunc("/topsingers/{channel}/{key}", JSONHandler) r.Path("/twitchtobackend").Queries("access_token", "{access_token}", "scope", "{scope}", "token_type", "{token_type}").HandlerFunc(TwitchBackendHandler) r.Path("/twitchadmin").Queries("code", "{code}", "scope", "{scope}").HandlerFunc(TwitchAdminHandler) + r.PathPrefix("/static").Handler(http.StripPrefix("/static", http.FileServer(http.Dir("./web/react-frontend/static")))) + r.PathPrefix("/").HandlerFunc(ReactIndexHandler("./web/react-frontend/index.html")) http.Handle("/", r) srv := &http.Server{ Handler: loggedRouter, diff --git a/web/data.json b/web/data.json new file mode 100755 index 0000000..a1f16be --- /dev/null +++ b/web/data.json @@ -0,0 +1,10 @@ +[{{ range $index, $data := .SongData }}{{ if $index }},{{end}}{ + "publishDate": "{{ $data.Date }}", + "displayPublishDate": "{{ $data.NiceDate }}", + "songName": "{{ $data.SongTitle }}", + "singerName": "{{ $data.OtherSinger }}", + "lastSongDate": "{{ $data.LastSungSong }}", + "displayLastSongDate": "{{ $data.NiceLastSungSong }}", + "lastDuetDate": "{{ $data.LastSungSinger }}", + "displayLastDuetDate": "{{ $data.NiceLastSungSinger }}" +}{{ end }}] diff --git a/web/topsingers.json b/web/topsingers.json new file mode 100755 index 0000000..0f1e1f5 --- /dev/null +++ b/web/topsingers.json @@ -0,0 +1,4 @@ +[{{ range $index, $data := .TopNSingers }}{{ if $index }},{{end}}{ + "singerName": "{{ .SingerName }}", + "singCount": "{{ .Sings }}" +}{{ end }}] diff --git a/web/topsongs.json b/web/topsongs.json new file mode 100755 index 0000000..16315d1 --- /dev/null +++ b/web/topsongs.json @@ -0,0 +1,4 @@ +[{{ range $index, $data := .TopNSongs }}{{ if $index }},{{end}}{ + "songName": "{{ .SongTitle }}", + "singCount": "{{ .Sings }}" +}{{ end }}]