Merge branch 'master' into gek/current-stream-duration
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
<body class="bg-gray-300 text-gray-800">
|
||||
|
||||
<div id="app-container" class="flex no-chat">
|
||||
<div id="app-container" class="flex chat">
|
||||
<div id="top-content">
|
||||
<header class="flex border-b border-gray-900 border-solid shadow-md">
|
||||
<h1 v-cloak class="flex text-gray-400">
|
||||
@@ -84,7 +84,7 @@
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<section id="user-content" v-if="layout === 'desktop'" aria-label="User information">
|
||||
<section id="user-content" aria-label="User information">
|
||||
<user-details
|
||||
v-bind:logo="logo"
|
||||
v-bind:platforms="socialHandles"
|
||||
@@ -96,13 +96,13 @@
|
||||
|
||||
</section>
|
||||
|
||||
<owncast-footer v-if="layout === 'desktop'" v-bind:app-version="appVersion"></owncast-footer>
|
||||
<owncast-footer v-bind:app-version="appVersion"></owncast-footer>
|
||||
|
||||
</div>
|
||||
|
||||
<section id="chat-container-wrap" class="flex">
|
||||
|
||||
<div v-if="layout !== 'desktop'" id="user-content-touch">
|
||||
<!-- <div v-if="layout !== 'desktop'" id="user-content-touch">
|
||||
<user-details
|
||||
v-bind:logo="logo"
|
||||
v-bind:platforms="socialHandles"
|
||||
@@ -114,7 +114,7 @@
|
||||
|
||||
<owncast-footer v-bind:app-version="appVersion"></owncast-footer>
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div id="chat-container" class="bg-gray-800">
|
||||
<div id="messages-container">
|
||||
@@ -165,7 +165,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script src="js/usercolors.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/message.js"></script>
|
||||
@@ -179,5 +178,32 @@
|
||||
app.init();
|
||||
})();
|
||||
</script>
|
||||
|
||||
<noscript>
|
||||
<style>
|
||||
[v-cloak] { display: none; }
|
||||
.noscript {
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.noscript a {
|
||||
display: inline;
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
<div class="noscript">
|
||||
<img src="https://github.com/gabek/owncast/raw/master/doc/logo.png">
|
||||
<br/>
|
||||
<p>
|
||||
This <a href="https://github.com/gabek/owncast" target="_blank">Owncast</a> stream requires Javascript to play.
|
||||
</p>
|
||||
</div>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
@@ -46,7 +46,6 @@ class Owncast {
|
||||
el: '#app-container',
|
||||
data: {
|
||||
isOnline: false,
|
||||
layout: hasTouchScreen() ? 'touch' : 'desktop',
|
||||
messages: [],
|
||||
overallMaxViewerCount: 0,
|
||||
sessionMaxViewerCount: 0,
|
||||
@@ -86,6 +85,8 @@ class Owncast {
|
||||
onError: this.handlePlayerError,
|
||||
});
|
||||
this.player.init();
|
||||
|
||||
this.getChatHistory();
|
||||
};
|
||||
|
||||
setConfigData(data) {
|
||||
@@ -132,17 +133,21 @@ class Owncast {
|
||||
return;
|
||||
}
|
||||
const message = new Message(model);
|
||||
const existing = this.vueApp.messages.filter(function (item) {
|
||||
return item.id === message.id;
|
||||
})
|
||||
if (existing.length === 0 || !existing) {
|
||||
this.vueApp.messages = [...this.vueApp.messages, message];
|
||||
}
|
||||
this.addMessage(message);
|
||||
};
|
||||
this.websocket = ws;
|
||||
this.messagingInterface.setWebsocket(this.websocket);
|
||||
};
|
||||
|
||||
addMessage(message) {
|
||||
const existing = this.vueApp.messages.filter(function (item) {
|
||||
return item.id === message.id;
|
||||
})
|
||||
if (existing.length === 0 || !existing) {
|
||||
this.vueApp.messages = [...this.vueApp.messages, message];
|
||||
}
|
||||
}
|
||||
|
||||
// fetch /config data
|
||||
getConfig() {
|
||||
fetch(URL_CONFIG)
|
||||
@@ -296,4 +301,18 @@ class Owncast {
|
||||
this.handleOfflineMode();
|
||||
// stop timers?
|
||||
};
|
||||
|
||||
async getChatHistory() {
|
||||
const url = "/chat";
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
const messages = data.map(function (message) {
|
||||
return new Message(message);
|
||||
})
|
||||
this.setChatHistory(messages);
|
||||
}
|
||||
|
||||
setChatHistory(messages) {
|
||||
this.vueApp.messages = messages.concat(this.vueApp.messages);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,13 +74,11 @@ class MessagingInterface {
|
||||
this.initLocalStates();
|
||||
|
||||
if (hasTouchScreen()) {
|
||||
this.scrollableMessagesContainer = document.body;
|
||||
setVHvar();
|
||||
window.addEventListener("orientationchange", setVHvar);
|
||||
this.tagAppContainer.classList.add('touch-screen');
|
||||
window.onorientationchange = this.handleOrientationChange.bind(this);
|
||||
this.handleOrientationChange();
|
||||
} else {
|
||||
this.tagAppContainer.classList.add('desktop');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setWebsocket(socket) {
|
||||
@@ -93,7 +91,7 @@ class MessagingInterface {
|
||||
getLocalStorage(KEY_AVATAR) || generateAvatar(`${this.username}${Date.now()}`);
|
||||
this.updateUsernameFields(this.username);
|
||||
|
||||
this.chatDisplayed = getLocalStorage(KEY_CHAT_DISPLAYED) || false;
|
||||
this.chatDisplayed = getLocalStorage(KEY_CHAT_DISPLAYED) || true;
|
||||
this.displayChat();
|
||||
}
|
||||
|
||||
@@ -112,22 +110,9 @@ class MessagingInterface {
|
||||
this.tagAppContainer.classList.add('no-chat');
|
||||
this.tagAppContainer.classList.remove('chat');
|
||||
}
|
||||
this.setChatPlaceholderText();
|
||||
}
|
||||
|
||||
handleOrientationChange() {
|
||||
var isPortrait = Math.abs(window.orientation % 180) === 0;
|
||||
if(!isPortrait) {
|
||||
if (document.body.clientWidth < 1024) {
|
||||
this.tagAppContainer.classList.add('no-chat');
|
||||
this.tagAppContainer.classList.add('landscape');
|
||||
}
|
||||
} else {
|
||||
if (this.chatDisplayed) {
|
||||
this.tagAppContainer.classList.remove('no-chat');
|
||||
}
|
||||
this.tagAppContainer.classList.remove('landscape');
|
||||
}
|
||||
}
|
||||
|
||||
handleChatToggle() {
|
||||
this.chatDisplayed = !this.chatDisplayed;
|
||||
@@ -241,6 +226,12 @@ class MessagingInterface {
|
||||
// clear out things.
|
||||
this.formMessageInput.value = '';
|
||||
this.tagMessageFormWarning.innerText = '';
|
||||
|
||||
const hasSentFirstChatMessage = getLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT);
|
||||
if (!hasSentFirstChatMessage) {
|
||||
setLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT, true);
|
||||
this.setChatPlaceholderText();
|
||||
}
|
||||
}
|
||||
|
||||
disableChat() {
|
||||
@@ -248,14 +239,22 @@ class MessagingInterface {
|
||||
this.formMessageInput.disabled = true;
|
||||
this.formMessageInput.placeholder = "Chat is offline."
|
||||
}
|
||||
// also show "disabled" text/message somewhere.
|
||||
}
|
||||
enableChat() {
|
||||
if (this.formMessageInput) {
|
||||
this.formMessageInput.disabled = false;
|
||||
this.formMessageInput.placeholder = "Message"
|
||||
this.setChatPlaceholderText();
|
||||
}
|
||||
}
|
||||
|
||||
setChatPlaceholderText() {
|
||||
const firstMessageChatPlacholderText = "Type here to chat, no account necessary.";
|
||||
const chatPlaceholderText = "Message"
|
||||
|
||||
const hasSentFirstChatMessage = getLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT);
|
||||
this.formMessageInput.placeholder = hasSentFirstChatMessage ? chatPlaceholderText : firstMessageChatPlacholderText
|
||||
}
|
||||
|
||||
// handle Vue.js message display
|
||||
onReceivedMessages(newMessages, oldMessages) {
|
||||
if (newMessages.length !== oldMessages.length) {
|
||||
|
||||
@@ -32,6 +32,9 @@ const VIDEO_SRC = {
|
||||
const VIDEO_OPTIONS = {
|
||||
autoplay: false,
|
||||
liveui: true, // try this
|
||||
liveTracker: {
|
||||
trackingThreshold: 0,
|
||||
},
|
||||
sources: [VIDEO_SRC],
|
||||
};
|
||||
|
||||
@@ -39,6 +42,7 @@ const VIDEO_OPTIONS = {
|
||||
const KEY_USERNAME = 'owncast_username';
|
||||
const KEY_AVATAR = 'owncast_avatar';
|
||||
const KEY_CHAT_DISPLAYED = 'owncast_chat';
|
||||
const KEY_CHAT_FIRST_MESSAGE_SENT = 'owncast_first_message_sent';
|
||||
|
||||
const TIMER_STATUS_UPDATE = 5000; // ms
|
||||
const TIMER_WEBSOCKET_RECONNECT = 5000; // ms
|
||||
@@ -154,4 +158,11 @@ function secondsToHMMSS(seconds = 0) {
|
||||
const secsString = secs < 10 ? `0${secs}` : `${secs}`;
|
||||
|
||||
return hoursString + minString + secsString;
|
||||
}
|
||||
}
|
||||
|
||||
function setVHvar() {
|
||||
var vh = window.innerHeight * 0.01;
|
||||
// Then we set the value in the --vh custom property to the root of the document
|
||||
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
||||
console.log("== new vh", vh)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ body {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* vuejs attribute to hide things before content ready */
|
||||
[v-cloak] { visibility: hidden; }
|
||||
|
||||
::-webkit-scrollbar {
|
||||
@@ -323,9 +323,11 @@ h2 {
|
||||
#video {
|
||||
transition: opacity .5s;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.online #video {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -364,6 +366,9 @@ h2 {
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.touch-screen #chat-container {
|
||||
height: calc(100vh - var(--header-height) - 3vh);
|
||||
}
|
||||
|
||||
|
||||
#messages-container {
|
||||
@@ -426,83 +431,6 @@ h2 {
|
||||
|
||||
/* ************************************************8 */
|
||||
|
||||
.landscape #chat-toggle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ************************************************8 */
|
||||
/* ************************************************8 */
|
||||
|
||||
.touch-screen header {
|
||||
position: relative;
|
||||
}
|
||||
.touch-screen #top-content {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
|
||||
.touch-screen .user-content {
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
}
|
||||
.touch-screen .user-image {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
.touch-screen #stream-info {
|
||||
height: 2.5em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.touch-screen #chat-container-wrap {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
margin-top: calc(var(--header-height) + var(--video-container-height) + 2.5em);
|
||||
}
|
||||
.touch-screen #chat-container {
|
||||
height: auto;
|
||||
position: relative;
|
||||
right: unset;
|
||||
top: unset;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
.touch-screen.chat #video-container,
|
||||
.touch-screen.chat #stream-info,
|
||||
.touch-screen.chat #user-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.touch-screen #video-container {
|
||||
margin-top: 0;
|
||||
}
|
||||
.touch-screen .owncast-video-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.touch-screen #user-content-touch {
|
||||
display: none;
|
||||
}
|
||||
.touch-screen #chat-container {
|
||||
display: block;
|
||||
}
|
||||
.touch-screen.no-chat #user-content-touch {
|
||||
display: block;
|
||||
}
|
||||
.touch-screen.no-chat #chat-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ************************************************8 */
|
||||
|
||||
@media screen and (max-width: 860px) {
|
||||
:root {
|
||||
@@ -516,33 +444,12 @@ h2 {
|
||||
|
||||
}
|
||||
|
||||
/* single col layout */
|
||||
@media screen and (max-width: 640px ) {
|
||||
:root {
|
||||
--video-container-height: 36vh;
|
||||
--right-col-width: 0;
|
||||
--video-container-height: 40vh;
|
||||
}
|
||||
|
||||
.desktop {
|
||||
--video-container-height: 50vh;
|
||||
}
|
||||
.desktop #chat-container {
|
||||
height: auto;
|
||||
position: relative;
|
||||
right: unset;
|
||||
top: unset;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
.desktop.chat #video-container,
|
||||
.desktop.chat #stream-info,
|
||||
.desktop.chat #user-content {
|
||||
width: 100%;
|
||||
}
|
||||
.desktop #footer,
|
||||
.desktop.chat #user-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
#logo-container {
|
||||
display: none;
|
||||
}
|
||||
@@ -552,29 +459,60 @@ h2 {
|
||||
#user-options-container {
|
||||
max-width: 41%;
|
||||
}
|
||||
|
||||
#chat-container {
|
||||
width: 100%;
|
||||
position: static;
|
||||
/* min-height: calc(100vh - var(--header-height)); */
|
||||
height: calc(100vh - var(--header-height) - var(--video-container-height) - 3vh)
|
||||
}
|
||||
#messages-container {
|
||||
min-height: unset;
|
||||
}
|
||||
#user-content {
|
||||
width: 100%;
|
||||
}
|
||||
#stream-info {
|
||||
width: 100%;
|
||||
}
|
||||
#video-container {
|
||||
width: 100%;
|
||||
}
|
||||
.chat #video-container {
|
||||
width: 100%;
|
||||
}
|
||||
.chat #user-content {
|
||||
display: none;
|
||||
}
|
||||
.chat footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (orientation: landscape) and (min-width: 1024px) {
|
||||
/* try not making the video fixed position for now */
|
||||
@media (min-height: 861px) {
|
||||
/* main {
|
||||
position: fixed;
|
||||
z-index: 9;
|
||||
width: 100%;
|
||||
}
|
||||
#user-content {
|
||||
margin-top: calc(var(--video-container-height) + var(--header-height) + 2em)
|
||||
} */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@media screen and (max-height: 860px ) {
|
||||
:root {
|
||||
--video-container-height: 65vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (orientation: landscape) and (max-width: 1024px) {
|
||||
:root .landscape {
|
||||
--video-container-height: 75vh;
|
||||
}
|
||||
.touch-screen.landscape #chat-container-wrap {
|
||||
margin-top: calc(var(--header-height) + var(--video-container-height));
|
||||
}
|
||||
.touch-screen.landscape .user-content {
|
||||
display: block;
|
||||
}
|
||||
.touch-screen.landscape #chat-container {
|
||||
display: none;
|
||||
}
|
||||
.touch-screen.landscape #chat-toggle {
|
||||
display: none;
|
||||
--video-container-height: 40vh;
|
||||
}
|
||||
.user-content {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user