react-frontend #2
|
@ -12,4 +12,7 @@
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
|
# Frontend compiled version gets built from source
|
||||||
|
/web/react-frontend
|
||||||
|
|
||||||
/twitchsingstools
|
/twitchsingstools
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -10,6 +10,11 @@ test:
|
||||||
build:
|
build:
|
||||||
go build ${LDFLAGS}
|
go build ${LDFLAGS}
|
||||||
|
|
||||||
|
build-frontend:
|
||||||
|
cd build/react-frontend && npm run build
|
||||||
|
rm -rf web/react-frontend ; mkdir -p web/react-frontend
|
||||||
|
cp -r build/react-frontend/build/* web/react-frontend/
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
go get
|
go get
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,11 @@ steps:
|
||||||
- make test
|
- make test
|
||||||
- make
|
- make
|
||||||
|
|
||||||
|
- name: build-frontend
|
||||||
|
image: node
|
||||||
|
commands:
|
||||||
|
- make frontend
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
ref:
|
ref:
|
||||||
- refs/heads/main
|
- refs/heads/main
|
||||||
|
|
|
@ -5,9 +5,14 @@ COPY internal/ /go/src/git.martyn.berlin/martyn/twitchsingstools/internal/
|
||||||
COPY Makefile /go/src/git.martyn.berlin/martyn/twitchsingstools/
|
COPY Makefile /go/src/git.martyn.berlin/martyn/twitchsingstools/
|
||||||
RUN cd /go/src/git.martyn.berlin/martyn/twitchsingstools/; make deps ; make static
|
RUN cd /go/src/git.martyn.berlin/martyn/twitchsingstools/; make deps ; make static
|
||||||
|
|
||||||
FROM scratch
|
FROM library/node:14.7.0-stretch AS frontend
|
||||||
|
COPY build/react-frontend /frontend
|
||||||
|
RUN cd /frontend; npm run build
|
||||||
|
|
||||||
|
FROM debian
|
||||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
COPY --from=builder /go/src/git.martyn.berlin/martyn/twitchsingstools /app/
|
COPY --from=builder /go/src/git.martyn.berlin/martyn/twitchsingstools /app/
|
||||||
COPY web/ /app/web/
|
COPY web/ /app/web/
|
||||||
|
COPY --from=frontend /frontend/build /app/web/react-frontend
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
CMD ["/app/twitchsingstools"]
|
CMD ["/app/twitchsingstools"]
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5d2ed3c5be7d050e48b6bedbd2591543d732bf52
|
|
@ -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) {
|
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("/healthz", HealthHandler)
|
r.HandleFunc("/healthz", HealthHandler)
|
||||||
r.HandleFunc("/web/{.*}", TemplateHandler)
|
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("/csv/{channel}/{key}", CSVHandler)
|
||||||
r.HandleFunc("/tsv/{channel}/{key}", CSVHandler)
|
r.HandleFunc("/tsv/{channel}/{key}", CSVHandler)
|
||||||
//r.HandleFunc("/twitchadmin", TwitchAdminHandler)
|
r.HandleFunc("/json/{channel}/{key}", JSONHandler)
|
||||||
//r.HandleFunc("/twitchtobackend", TwitchBackendHandler)
|
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("/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.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)
|
http.Handle("/", r)
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Handler: loggedRouter,
|
Handler: loggedRouter,
|
||||||
|
|
|
@ -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 }}]
|
|
@ -0,0 +1,4 @@
|
||||||
|
[{{ range $index, $data := .TopNSingers }}{{ if $index }},{{end}}{
|
||||||
|
"singerName": "{{ .SingerName }}",
|
||||||
|
"singCount": "{{ .Sings }}"
|
||||||
|
}{{ end }}]
|
|
@ -0,0 +1,4 @@
|
||||||
|
[{{ range $index, $data := .TopNSongs }}{{ if $index }},{{end}}{
|
||||||
|
"songName": "{{ .SongTitle }}",
|
||||||
|
"singCount": "{{ .Sings }}"
|
||||||
|
}{{ end }}]
|
Loading…
Reference in New Issue