diff --git a/player/go.mod b/player/go.mod new file mode 100644 index 0000000..7a726f3 --- /dev/null +++ b/player/go.mod @@ -0,0 +1,3 @@ +module git.kitsu.red/restream-tools/player + +go 1.17 diff --git a/player/main.go b/player/main.go new file mode 100644 index 0000000..4494308 --- /dev/null +++ b/player/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "flag" + "fmt" + "net/http" + "time" +) + +func main() { + var addr = flag.String("addr", ":8080", "http service address") + flag.Parse() + + // Map of active viewers and their last active time + var viewers = make(map[string]int64) + + http.HandleFunc("/viewcount", func(w http.ResponseWriter, r *http.Request) { + // Get the current time + var now = time.Now().Unix() + + // Get the remote address + var ip = r.RemoteAddr + + // Update the last active time + viewers[ip] = now + + // Respond with the number of viewers + fmt.Fprintf(w, "%d", len(viewers)) + }) + + // Periodically remove inactive viewers + go func() { + for { + time.Sleep(time.Second) + + // Get the current time + var now = time.Now().Unix() + + // Remove any viewers that have not been active in the last 10 seconds + for ip, lastActive := range viewers { + if now-lastActive > 10 { + delete(viewers, ip) + } + } + } + }() + + // Handle static files + http.Handle("/", http.FileServer(http.Dir("./static"))) + + // Start the server + fmt.Println("Starting server on", *addr) + err := http.ListenAndServe(*addr, nil) + if err != nil { + fmt.Println(err) + } +} diff --git a/player/index.html b/player/static/index.html similarity index 90% rename from player/index.html rename to player/static/index.html index 2116f03..f82ed91 100644 --- a/player/index.html +++ b/player/static/index.html @@ -15,6 +15,10 @@ region: 'us-east', url: 'https://us.stream.holopirates.moe', }, + { + region: 'us-east-2', + url: 'https://www.kitsu.red', + }, { region: 'sg', url: 'https://restream.kitsune.box.ca', @@ -39,6 +43,7 @@ +
0 viewers
diff --git a/player/player.css b/player/static/player.css similarity index 93% rename from player/player.css rename to player/static/player.css index ca6aabc..a9ccec0 100644 --- a/player/player.css +++ b/player/static/player.css @@ -42,6 +42,17 @@ strong { font-weight: bold; } +a, +a:link, +a:visited { + color: #5bd9ff; + text-decoration: none; +} +a:hover, +a:active { + text-decoration: underline; +} + #viewer-count { flex: 1; text-align: right; diff --git a/player/player.js b/player/static/player.js similarity index 86% rename from player/player.js rename to player/static/player.js index 3b631ed..19b0497 100644 --- a/player/player.js +++ b/player/static/player.js @@ -68,6 +68,7 @@ const reloadVideo = () => { const video = document.getElementById('video'); const mirrorSelect = document.getElementById('mirror-select'); + const mirrorLink = document.getElementById('mirror-link'); const playlistURL = mirrorSelect.value + window.restream_config.playlist; console.log('Reloading video from', playlistURL); @@ -79,12 +80,32 @@ } else { video.src = playlistURL; } + + mirrorLink.href = playlistURL; + mirrorLink.innerText = '[m3u8]'; + }; + + const viewCountLoop = async () => { + const viewCount = document.getElementById('viewer-count-value'); + const url = '/viewcount'; + + while (true) { + const response = await fetchWithTimeout(url, { + timeout: 1000, + mode: 'cors', + }); + viewCount.innerText = await response.text(); + await sleep(5000); + } }; const init = async () => { const video = document.getElementById('video'); const mirrorSelect = document.getElementById('mirror-select'); + // Init viewer counter + viewCountLoop(); + // Set up hls.js if (Hls.isSupported()) { window.restream_config.hls = new Hls();