|
|
@ -9,27 +9,31 @@ import Chat from './components/chat/chat.js'; |
|
|
|
import Websocket from './utils/websocket.js'; |
|
|
|
import Websocket from './utils/websocket.js'; |
|
|
|
|
|
|
|
|
|
|
|
import { |
|
|
|
import { |
|
|
|
getLocalStorage, |
|
|
|
addNewlines, |
|
|
|
setLocalStorage, |
|
|
|
classNames, |
|
|
|
clearLocalStorage, |
|
|
|
clearLocalStorage, |
|
|
|
|
|
|
|
debounce, |
|
|
|
generateAvatar, |
|
|
|
generateAvatar, |
|
|
|
generateUsername, |
|
|
|
generateUsername, |
|
|
|
addNewlines, |
|
|
|
getLocalStorage, |
|
|
|
pluralize, |
|
|
|
pluralize, |
|
|
|
|
|
|
|
setLocalStorage, |
|
|
|
} from './utils/helpers.js'; |
|
|
|
} from './utils/helpers.js'; |
|
|
|
import { |
|
|
|
import { |
|
|
|
URL_OWNCAST, |
|
|
|
HEIGHT_SHORT_WIDE, |
|
|
|
URL_CONFIG, |
|
|
|
|
|
|
|
URL_STATUS, |
|
|
|
|
|
|
|
TIMER_STATUS_UPDATE, |
|
|
|
|
|
|
|
TIMER_DISABLE_CHAT_AFTER_OFFLINE, |
|
|
|
|
|
|
|
TIMER_STREAM_DURATION_COUNTER, |
|
|
|
|
|
|
|
TEMP_IMAGE, |
|
|
|
|
|
|
|
MESSAGE_OFFLINE, |
|
|
|
|
|
|
|
MESSAGE_ONLINE, |
|
|
|
|
|
|
|
KEY_USERNAME, |
|
|
|
|
|
|
|
KEY_AVATAR, |
|
|
|
KEY_AVATAR, |
|
|
|
KEY_CHAT_DISPLAYED, |
|
|
|
KEY_CHAT_DISPLAYED, |
|
|
|
|
|
|
|
KEY_USERNAME, |
|
|
|
|
|
|
|
MESSAGE_OFFLINE, |
|
|
|
|
|
|
|
MESSAGE_ONLINE, |
|
|
|
|
|
|
|
TEMP_IMAGE, |
|
|
|
|
|
|
|
TIMER_DISABLE_CHAT_AFTER_OFFLINE, |
|
|
|
|
|
|
|
TIMER_STATUS_UPDATE, |
|
|
|
|
|
|
|
TIMER_STREAM_DURATION_COUNTER, |
|
|
|
|
|
|
|
URL_CONFIG, |
|
|
|
|
|
|
|
URL_OWNCAST, |
|
|
|
|
|
|
|
URL_STATUS, |
|
|
|
|
|
|
|
WIDTH_SINGLE_COL, |
|
|
|
} from './utils/constants.js'; |
|
|
|
} from './utils/constants.js'; |
|
|
|
|
|
|
|
|
|
|
|
export default class App extends Component { |
|
|
|
export default class App extends Component { |
|
|
@ -41,7 +45,8 @@ export default class App extends Component { |
|
|
|
displayChat: getLocalStorage(KEY_CHAT_DISPLAYED), // chat panel state
|
|
|
|
displayChat: getLocalStorage(KEY_CHAT_DISPLAYED), // chat panel state
|
|
|
|
chatEnabled: false, // chat input box state
|
|
|
|
chatEnabled: false, // chat input box state
|
|
|
|
username: getLocalStorage(KEY_USERNAME) || generateUsername(), |
|
|
|
username: getLocalStorage(KEY_USERNAME) || generateUsername(), |
|
|
|
userAvatarImage: getLocalStorage(KEY_AVATAR) || generateAvatar(`${this.username}${Date.now()}`), |
|
|
|
userAvatarImage: |
|
|
|
|
|
|
|
getLocalStorage(KEY_AVATAR) || generateAvatar(`${this.username}${Date.now()}`), |
|
|
|
|
|
|
|
|
|
|
|
configData: {}, |
|
|
|
configData: {}, |
|
|
|
extraUserContent: '', |
|
|
|
extraUserContent: '', |
|
|
@ -49,11 +54,15 @@ export default class App extends Component { |
|
|
|
playerActive: false, // player object is active
|
|
|
|
playerActive: false, // player object is active
|
|
|
|
streamOnline: false, // stream is active/online
|
|
|
|
streamOnline: false, // stream is active/online
|
|
|
|
|
|
|
|
|
|
|
|
//status
|
|
|
|
// status
|
|
|
|
streamStatusMessage: MESSAGE_OFFLINE, |
|
|
|
streamStatusMessage: MESSAGE_OFFLINE, |
|
|
|
viewerCount: '', |
|
|
|
viewerCount: '', |
|
|
|
sessionMaxViewerCount: '', |
|
|
|
sessionMaxViewerCount: '', |
|
|
|
overallMaxViewerCount: '', |
|
|
|
overallMaxViewerCount: '', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// dom
|
|
|
|
|
|
|
|
windowWidth: window.innerWidth, |
|
|
|
|
|
|
|
windowHeight: window.innerHeight, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// timers
|
|
|
|
// timers
|
|
|
@ -66,6 +75,7 @@ export default class App extends Component { |
|
|
|
// misc dom events
|
|
|
|
// misc dom events
|
|
|
|
this.handleChatPanelToggle = this.handleChatPanelToggle.bind(this); |
|
|
|
this.handleChatPanelToggle = this.handleChatPanelToggle.bind(this); |
|
|
|
this.handleUsernameChange = this.handleUsernameChange.bind(this); |
|
|
|
this.handleUsernameChange = this.handleUsernameChange.bind(this); |
|
|
|
|
|
|
|
this.handleWindowResize = debounce(this.handleWindowResize.bind(this), 400); |
|
|
|
|
|
|
|
|
|
|
|
this.handleOfflineMode = this.handleOfflineMode.bind(this); |
|
|
|
this.handleOfflineMode = this.handleOfflineMode.bind(this); |
|
|
|
this.handleOnlineMode = this.handleOnlineMode.bind(this); |
|
|
|
this.handleOnlineMode = this.handleOnlineMode.bind(this); |
|
|
@ -81,12 +91,11 @@ export default class App extends Component { |
|
|
|
this.getConfig = this.getConfig.bind(this); |
|
|
|
this.getConfig = this.getConfig.bind(this); |
|
|
|
this.getStreamStatus = this.getStreamStatus.bind(this); |
|
|
|
this.getStreamStatus = this.getStreamStatus.bind(this); |
|
|
|
this.getExtraUserContent = this.getExtraUserContent.bind(this); |
|
|
|
this.getExtraUserContent = this.getExtraUserContent.bind(this); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
componentDidMount() { |
|
|
|
componentDidMount() { |
|
|
|
this.getConfig(); |
|
|
|
this.getConfig(); |
|
|
|
|
|
|
|
window.addEventListener('resize', this.handleWindowResize); |
|
|
|
|
|
|
|
|
|
|
|
this.player = new OwncastPlayer(); |
|
|
|
this.player = new OwncastPlayer(); |
|
|
|
this.player.setupPlayerCallbacks({ |
|
|
|
this.player.setupPlayerCallbacks({ |
|
|
@ -161,7 +170,6 @@ export default class App extends Component { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setConfigData(data = {}) { |
|
|
|
setConfigData(data = {}) { |
|
|
|
const { title, extraUserInfoFileName, summary } = data; |
|
|
|
const { title, extraUserInfoFileName, summary } = data; |
|
|
|
|
|
|
|
|
|
|
@ -301,21 +309,30 @@ export default class App extends Component { |
|
|
|
console.log(`>>> App Error: ${error}`); |
|
|
|
console.log(`>>> App Error: ${error}`); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleWindowResize() { |
|
|
|
|
|
|
|
this.setState({ |
|
|
|
|
|
|
|
windowWidth: window.innerWidth, |
|
|
|
|
|
|
|
windowHeight: window.innerHeight, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
render(props, state) { |
|
|
|
render(props, state) { |
|
|
|
const { |
|
|
|
const { |
|
|
|
username, |
|
|
|
chatEnabled, |
|
|
|
userAvatarImage, |
|
|
|
|
|
|
|
websocket, |
|
|
|
|
|
|
|
configData, |
|
|
|
configData, |
|
|
|
extraUserContent, |
|
|
|
|
|
|
|
displayChat, |
|
|
|
displayChat, |
|
|
|
viewerCount, |
|
|
|
extraUserContent, |
|
|
|
sessionMaxViewerCount, |
|
|
|
|
|
|
|
overallMaxViewerCount, |
|
|
|
overallMaxViewerCount, |
|
|
|
playerActive, |
|
|
|
playerActive, |
|
|
|
|
|
|
|
sessionMaxViewerCount, |
|
|
|
streamOnline, |
|
|
|
streamOnline, |
|
|
|
streamStatusMessage, |
|
|
|
streamStatusMessage, |
|
|
|
chatEnabled, |
|
|
|
userAvatarImage, |
|
|
|
|
|
|
|
username, |
|
|
|
|
|
|
|
viewerCount, |
|
|
|
|
|
|
|
websocket, |
|
|
|
|
|
|
|
windowHeight, |
|
|
|
|
|
|
|
windowWidth, |
|
|
|
} = state; |
|
|
|
} = state; |
|
|
|
|
|
|
|
|
|
|
|
const { |
|
|
|
const { |
|
|
@ -347,14 +364,23 @@ export default class App extends Component { |
|
|
|
</li> |
|
|
|
</li> |
|
|
|
`);
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const chatClass = displayChat ? 'chat' : 'no-chat'; |
|
|
|
|
|
|
|
const mainClass = playerActive ? 'online' : ''; |
|
|
|
const mainClass = playerActive ? 'online' : ''; |
|
|
|
const streamInfoClass = streamOnline ? 'online' : ''; |
|
|
|
const streamInfoClass = streamOnline ? 'online' : ''; // need?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const shortHeight = windowHeight <= HEIGHT_SHORT_WIDE; |
|
|
|
|
|
|
|
const singleColMode = windowWidth <= WIDTH_SINGLE_COL && !shortHeight; |
|
|
|
|
|
|
|
const extraAppClasses = classNames({ |
|
|
|
|
|
|
|
'chat': displayChat, |
|
|
|
|
|
|
|
'no-chat': !displayChat, |
|
|
|
|
|
|
|
'single-col': singleColMode, |
|
|
|
|
|
|
|
'bg-gray-800': singleColMode && displayChat, |
|
|
|
|
|
|
|
'short-wide': shortHeight, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
html` |
|
|
|
html` |
|
|
|
<div id="app-container" class="flex w-full flex-col justify-start relative ${chatClass}"> |
|
|
|
<div id="app-container" class="flex w-full flex-col justify-start relative ${extraAppClasses}"> |
|
|
|
<div id="top-content"> |
|
|
|
<div id="top-content" class="z-50"> |
|
|
|
<header class="flex border-b border-gray-900 border-solid shadow-md fixed z-10 w-full top-0 left-0 flex flex-row justify-between flex-no-wrap"> |
|
|
|
<header class="flex border-b border-gray-900 border-solid shadow-md fixed z-10 w-full top-0 left-0 flex flex-row justify-between flex-no-wrap"> |
|
|
|
<h1 class="flex flex-row items-center justify-start p-2 uppercase text-gray-400 text-xl font-thin tracking-wider overflow-hidden whitespace-no-wrap"> |
|
|
|
<h1 class="flex flex-row items-center justify-start p-2 uppercase text-gray-400 text-xl font-thin tracking-wider overflow-hidden whitespace-no-wrap"> |
|
|
|
<span |
|
|
|
<span |
|
|
@ -392,7 +418,6 @@ export default class App extends Component { |
|
|
|
></video> |
|
|
|
></video> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<section id="stream-info" aria-label="Stream status" class="flex text-center flex-row justify-between font-mono py-2 px-8 bg-gray-900 text-indigo-200 shadow-md border-b border-gray-100 border-solid ${streamInfoClass}"> |
|
|
|
<section id="stream-info" aria-label="Stream status" class="flex text-center flex-row justify-between font-mono py-2 px-8 bg-gray-900 text-indigo-200 shadow-md border-b border-gray-100 border-solid ${streamInfoClass}"> |
|
|
|
<span>${streamStatusMessage}</span> |
|
|
|
<span>${streamStatusMessage}</span> |
|
|
|
<span>${viewerCount} ${pluralize('viewer', viewerCount)}.</span> |
|
|
|
<span>${viewerCount} ${pluralize('viewer', viewerCount)}.</span> |
|
|
@ -440,16 +465,15 @@ export default class App extends Component { |
|
|
|
<span class="mx-1 inline-block">Version ${appVersion}</span> |
|
|
|
<span class="mx-1 inline-block">Version ${appVersion}</span> |
|
|
|
</footer> |
|
|
|
</footer> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<${Chat} |
|
|
|
<${Chat} |
|
|
|
websocket=${websocket} |
|
|
|
websocket=${websocket} |
|
|
|
username=${username} |
|
|
|
username=${username} |
|
|
|
userAvatarImage=${userAvatarImage} |
|
|
|
userAvatarImage=${userAvatarImage} |
|
|
|
chatEnabled //=${chatEnabled}
|
|
|
|
chatEnabled=${chatEnabled} |
|
|
|
/> |
|
|
|
/> |
|
|
|
</div> |
|
|
|
|
|
|
|
` |
|
|
|
</div> |
|
|
|
); |
|
|
|
`);
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|