From 8ba0b6d7ce3377864b1d66edbfd07cc4b50baf83 Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Sat, 18 Jul 2020 15:06:54 -0700 Subject: [PATCH] Show in the UI how long the user has been streaming for. Closes #59 --- core/stats.go | 2 +- core/status.go | 7 ++++--- models/stats.go | 10 ++++++---- models/status.go | 8 +++----- webroot/js/app.js | 20 ++++++++++++++++++++ webroot/js/utils.js | 16 +++++++++++++++- 6 files changed, 49 insertions(+), 14 deletions(-) diff --git a/core/stats.go b/core/stats.go index 3bf341479..a793f66e0 100644 --- a/core/stats.go +++ b/core/stats.go @@ -68,7 +68,7 @@ func IsStreamConnected() bool { // Kind of a hack. It takes a handful of seconds between a RTMP connection and when HLS data is available. // So account for that with an artificial buffer of four segments. - timeSinceLastConnected := time.Since(_stats.LastConnectTime).Seconds() + timeSinceLastConnected := time.Since(_stats.LastConnectTime.Time).Seconds() if timeSinceLastConnected < float64(config.Config.GetVideoSegmentSecondsLength()*4.0) { return false } diff --git a/core/status.go b/core/status.go index 2eaebb15b..56ec3c468 100644 --- a/core/status.go +++ b/core/status.go @@ -6,6 +6,7 @@ import ( "github.com/gabek/owncast/config" "github.com/gabek/owncast/core/ffmpeg" "github.com/gabek/owncast/models" + "github.com/gabek/owncast/utils" ) //GetStatus gets the status of the system @@ -27,9 +28,9 @@ func GetStatus() models.Status { //SetStreamAsConnected sets the stream as connected func SetStreamAsConnected() { _stats.StreamConnected = true - _stats.LastConnectTime = time.Now() + _stats.LastConnectTime = utils.NullTime{time.Now(), true} - timeSinceDisconnect := time.Since(_stats.LastDisconnectTime).Minutes() + timeSinceDisconnect := time.Since(_stats.LastDisconnectTime.Time).Minutes() if timeSinceDisconnect > 15 { _stats.SessionMaxViewerCount = 0 } @@ -45,7 +46,7 @@ func SetStreamAsConnected() { //SetStreamAsDisconnected sets the stream as disconnected func SetStreamAsDisconnected() { _stats.StreamConnected = false - _stats.LastDisconnectTime = time.Now() + _stats.LastDisconnectTime = utils.NullTime{time.Now(), true} ffmpeg.ShowStreamOfflineState() } diff --git a/models/stats.go b/models/stats.go index 1b6f188f0..da6723e66 100644 --- a/models/stats.go +++ b/models/stats.go @@ -2,15 +2,17 @@ package models import ( "time" + + "github.com/gabek/owncast/utils" ) //Stats holds the stats for the system type Stats struct { - SessionMaxViewerCount int `json:"sessionMaxViewerCount"` - OverallMaxViewerCount int `json:"overallMaxViewerCount"` - LastDisconnectTime time.Time `json:"lastDisconnectTime"` + SessionMaxViewerCount int `json:"sessionMaxViewerCount"` + OverallMaxViewerCount int `json:"overallMaxViewerCount"` + LastDisconnectTime utils.NullTime `json:"lastDisconnectTime"` StreamConnected bool `json:"-"` - LastConnectTime time.Time `json:"-"` + LastConnectTime utils.NullTime `json:"-"` Clients map[string]time.Time `json:"-"` } diff --git a/models/status.go b/models/status.go index f81d747fe..053f337be 100644 --- a/models/status.go +++ b/models/status.go @@ -1,8 +1,6 @@ package models -import ( - "time" -) +import "github.com/gabek/owncast/utils" //Status represents the status of the system type Status struct { @@ -11,6 +9,6 @@ type Status struct { OverallMaxViewerCount int `json:"overallMaxViewerCount"` SessionMaxViewerCount int `json:"sessionMaxViewerCount"` - LastConnectTime time.Time `json:"lastConnectTime"` - LastDisconnectTime time.Time `json:"lastDisconnectTime"` + LastConnectTime utils.NullTime `json:"lastConnectTime"` + LastDisconnectTime utils.NullTime `json:"lastDisconnectTime"` } diff --git a/webroot/js/app.js b/webroot/js/app.js index 04b97512b..5da4e31ef 100644 --- a/webroot/js/app.js +++ b/webroot/js/app.js @@ -223,8 +223,26 @@ class Owncast { } this.streamStatus = status; + this.setCurrentStreamDuration(); }; + setCurrentStreamDuration() { + // If we're offline then don't update any of the UI. + if (!this.streamStatus.online) { + return; + } + + // Default to something + let streamDurationString = "" + + if (this.streamStatus.online && this.streamStatus.lastConnectTime) { + const diff = (Date.now() - Date.parse(this.streamStatus.lastConnectTime)) / 1000; + streamDurationString = secondsToHMMSS(diff); + } + + this.vueApp.streamStatus = `${MESSAGE_ONLINE} ${streamDurationString}.` + } + handleNetworkingError(error) { console.log(`>>> App Error: ${error}`) }; @@ -252,6 +270,8 @@ class Owncast { clearTimeout(this.disableChatTimer); this.disableChatTimer = null; this.messagingInterface.enableChat(); + + setInterval(this.setCurrentStreamDuration.bind(this), 1000); } // when videojs player is ready, start polling for stream diff --git a/webroot/js/utils.js b/webroot/js/utils.js index 103700cee..8114819db 100644 --- a/webroot/js/utils.js +++ b/webroot/js/utils.js @@ -47,7 +47,7 @@ const TIMER_DISABLE_CHAT_AFTER_OFFLINE = 5 * 60 * 1000; // 5 mins const TEMP_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; const MESSAGE_OFFLINE = 'Stream is offline.'; -const MESSAGE_ONLINE = 'Stream is online.'; +const MESSAGE_ONLINE = 'Stream is online'; function getLocalStorage(key) { @@ -141,3 +141,17 @@ function generateUsername() { return `User ${(Math.floor(Math.random() * 42) + 1)}`; } +function secondsToHMMSS(seconds = 0) { + const finiteSeconds = Number.isFinite(+seconds) ? Math.abs(seconds) : 0; + + const hours = Math.floor(finiteSeconds / 3600); + const hoursString = hours ? `${hours}:` : ''; + + const mins = Math.floor((finiteSeconds / 60) % 60); + const minString = mins < 10 ? `0${mins}:` : `${mins}:`; + + const secs = Math.floor(finiteSeconds % 60); + const secsString = secs < 10 ? `0${secs}` : `${secs}`; + + return hoursString + minString + secsString; +} \ No newline at end of file