diff --git a/webroot/index.html b/webroot/index.html index 4d0845695..aaf48f3fb 100644 --- a/webroot/index.html +++ b/webroot/index.html @@ -59,7 +59,7 @@ -
+
- - -
-
+
Chat
-
-
- - -
diff --git a/webroot/js/app.js b/webroot/js/app.js index 5d9d5dc6e..cfbc36ed3 100644 --- a/webroot/js/app.js +++ b/webroot/js/app.js @@ -1,7 +1,6 @@ class Owncast { constructor() { this.player; - this.streamStatus = null; this.websocket = null; this.configData; @@ -14,10 +13,10 @@ class Owncast { this.offlineTimer = null; this.statusTimer = null; this.disableChatTimer = null; + this.streamDurationTimer = null; // misc - this.streamIsOnline = false; - this.lastDisconnectTime = null; + this.streamStatus = null; Vue.filter('plural', pluralize); @@ -36,6 +35,7 @@ class Owncast { this.handlePlayerPlaying = this.handlePlayerPlaying.bind(this); this.handlePlayerEnded = this.handlePlayerEnded.bind(this); this.handlePlayerError = this.handlePlayerError.bind(this); + this.setCurrentStreamDuration = this.setCurrentStreamDuration.bind(this); } init() { @@ -45,7 +45,7 @@ class Owncast { this.vueApp = new Vue({ el: '#app-container', data: { - isOnline: false, + playerOn: false, messages: [], overallMaxViewerCount: 0, sessionMaxViewerCount: 0, @@ -86,7 +86,7 @@ class Owncast { }); this.player.init(); - this.getChatHistory(); + // this.getChatHistory(); }; setConfigData(data) { @@ -202,7 +202,10 @@ class Owncast { }; // handle UI things from stream status result - updateStreamStatus(status) { + updateStreamStatus(status = {}) { + if (!status) { + return; + } // update UI this.vueApp.streamStatus = status.online ? MESSAGE_ONLINE : MESSAGE_OFFLINE; this.vueApp.viewerCount = status.viewerCount; @@ -211,40 +214,53 @@ class Owncast { this.lastDisconnectTime = status.lastDisconnectTime; - if (status.online && !this.streamIsOnline) { - // stream has just come online. - this.handleOnlineMode(); - } else if (!status.online && !this.streamStatus) { - // stream has just gone offline. + if (!this.streamStatus) { // display offline mode the first time we get status, and it's offline. - this.handleOfflineMode(); + if (!status.online) { + this.handleOfflineMode(); + } else { + this.handleOnlineMode(); + } + } else { + if (status.online && !this.streamStatus.online) { + // stream has just come online. + this.handleOnlineMode(); + } else if (!status.online && this.streamStatus.online) { + // stream has just flipped offline. + this.handleOfflineMode(); + } } + // if (status.online && !this.streamIsOnline) { + + // } else if (!status.online && !this.streamStatus) { + // this.handleOfflineMode(); + // } else if (!status.online && this.streamIsOnline) { + // // we've just flipped from online to offline + // clearInterval(this.streamDurationTimer); + // this.handleOfflineMode(); + // } + + // keep a local copy + this.streamStatus = status; + if (status.online) { // only do this if video is paused, so no unnecessary img fetches if (this.player.vjsPlayer && this.player.vjsPlayer.paused()) { this.player.setPoster(); } } - - this.streamStatus = status; - this.setCurrentStreamDuration(); }; + // update vueApp.streamStatus text when online setCurrentStreamDuration() { - // If we're offline then don't update any of the UI. - if (!this.streamStatus.online) { - return; - } - // Default to something - let streamDurationString = "" + let streamDurationString = ''; - if (this.streamStatus.online && this.streamStatus.lastConnectTime) { + if (this.streamStatus.lastConnectTime) { const diff = (Date.now() - Date.parse(this.streamStatus.lastConnectTime)) / 1000; streamDurationString = secondsToHMMSS(diff); } - this.vueApp.streamStatus = `${MESSAGE_ONLINE} ${streamDurationString}.` } @@ -253,13 +269,12 @@ class Owncast { }; // basically hide video and show underlying "poster" + // primarily called when video onEnded was called because some video has been buffered to play after stream has gone offline. handleOfflineMode() { - this.streamIsOnline = false; - this.vueApp.isOnline = false; + clearInterval(this.streamDurationTimer); this.vueApp.streamStatus = MESSAGE_OFFLINE; - - if (this.lastDisconnectTime) { - const remainingChatTime = TIMER_DISABLE_CHAT_AFTER_OFFLINE - (Date.now() - new Date(this.lastDisconnectTime)); + if (this.streamStatus) { + const remainingChatTime = TIMER_DISABLE_CHAT_AFTER_OFFLINE - (Date.now() - new Date(this.streamStatus.lastDisconnectTime)); const countdown = (remainingChatTime < 0) ? 0 : remainingChatTime; this.disableChatTimer = setTimeout(this.messagingInterface.disableChat, countdown); } @@ -267,8 +282,7 @@ class Owncast { // play video! handleOnlineMode() { - this.streamIsOnline = true; - this.vueApp.isOnline = true; + this.vueApp.playerOn = true; this.vueApp.streamStatus = MESSAGE_ONLINE; this.player.startPlayer(); @@ -276,7 +290,8 @@ class Owncast { this.disableChatTimer = null; this.messagingInterface.enableChat(); - setInterval(this.setCurrentStreamDuration.bind(this), 1000); + this.streamDurationTimer = + setInterval(this.setCurrentStreamDuration, TIMER_STREAM_DURATION_COUNTER); } // when videojs player is ready, start polling for stream @@ -291,20 +306,21 @@ class Owncast { }; + // likely called some time after stream status has gone offline. + // disable chat after some time. handlePlayerEnded() { - // do something? - this.handleOfflineMode(); + this.vueApp.playerOn = false; }; handlePlayerError() { // do something? this.handleOfflineMode(); + this.handlePlayerEnded(); // stop timers? }; async getChatHistory() { - const url = "/chat"; - const response = await fetch(url); + const response = await fetch(URL_CHAT_HISTORY); const data = await response.json(); const messages = data.map(function (message) { return new Message(message); diff --git a/webroot/js/utils.js b/webroot/js/utils.js index 3ecebe06c..9c15ec4c5 100644 --- a/webroot/js/utils.js +++ b/webroot/js/utils.js @@ -4,6 +4,7 @@ const LOCAL_TEST = window.location.href.indexOf('localhost:') >= 0; const URL_PREFIX = LOCAL_TEST ? 'http://localhost:8080' : ''; const URL_STATUS = `${URL_PREFIX}/status`; +const URL_CHAT_HISTORY = `${URL_PREFIX}/chat`; const URL_STREAM = `${URL_PREFIX}/hls/stream.m3u8`; const URL_WEBSOCKET = LOCAL_TEST ? 'wss://goth.land/entry' @@ -47,6 +48,7 @@ const KEY_CHAT_FIRST_MESSAGE_SENT = 'owncast_first_message_sent'; const TIMER_STATUS_UPDATE = 5000; // ms const TIMER_WEBSOCKET_RECONNECT = 5000; // ms const TIMER_DISABLE_CHAT_AFTER_OFFLINE = 5 * 60 * 1000; // 5 mins +const TIMER_STREAM_DURATION_COUNTER = 1000; const TEMP_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';