mirror of
https://github.com/owncast/owncast.git
synced 2024-10-10 19:16:02 +00:00
display last online time (#1125)
* - if offline calculate and display last online time to address https://github.com/owncast/owncast/issues/1111 - clean up status bar styles * clean up console
This commit is contained in:
parent
d19ecab90c
commit
c45e43c378
@ -12,7 +12,7 @@ import { OwncastPlayer } from './components/player.js';
|
|||||||
import Websocket from './utils/websocket.js';
|
import Websocket from './utils/websocket.js';
|
||||||
const websocket = new Websocket();
|
const websocket = new Websocket();
|
||||||
|
|
||||||
import { addNewlines, pluralize } from './utils/helpers.js';
|
import { addNewlines, makeLastOnlineString, pluralize } from './utils/helpers.js';
|
||||||
import {
|
import {
|
||||||
URL_CONFIG,
|
URL_CONFIG,
|
||||||
URL_STATUS,
|
URL_STATUS,
|
||||||
@ -38,6 +38,7 @@ export default class VideoOnly extends Component {
|
|||||||
//status
|
//status
|
||||||
streamStatusMessage: MESSAGE_OFFLINE,
|
streamStatusMessage: MESSAGE_OFFLINE,
|
||||||
viewerCount: '',
|
viewerCount: '',
|
||||||
|
lastDisconnectTime: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
@ -134,9 +135,7 @@ export default class VideoOnly extends Component {
|
|||||||
if (!status) {
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { viewerCount, online } = status;
|
const { viewerCount, online, lastDisconnectTime } = status;
|
||||||
|
|
||||||
this.lastDisconnectTime = status.lastDisconnectTime;
|
|
||||||
|
|
||||||
if (status.online && !curStreamOnline) {
|
if (status.online && !curStreamOnline) {
|
||||||
// stream has just come online.
|
// stream has just come online.
|
||||||
@ -148,6 +147,7 @@ export default class VideoOnly extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
viewerCount,
|
viewerCount,
|
||||||
streamOnline: online,
|
streamOnline: online,
|
||||||
|
lastDisconnectTime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,15 +215,18 @@ export default class VideoOnly extends Component {
|
|||||||
playerActive,
|
playerActive,
|
||||||
streamOnline,
|
streamOnline,
|
||||||
streamStatusMessage,
|
streamStatusMessage,
|
||||||
|
lastDisconnectTime,
|
||||||
isPlaying,
|
isPlaying,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
const { logo = TEMP_IMAGE, customStyles } = configData;
|
const { logo = TEMP_IMAGE, customStyles } = configData;
|
||||||
|
|
||||||
const viewerCountMessage =
|
let viewerCountMessage = '';
|
||||||
streamOnline && viewerCount > 0
|
if (streamOnline && viewerCount > 0) {
|
||||||
? html`${viewerCount} ${pluralize('viewer', viewerCount)}`
|
viewerCountMessage = html`${viewerCount} ${pluralize('viewer', viewerCount)}`;
|
||||||
: null;
|
} else if (lastDisconnectTime) {
|
||||||
|
viewerCountMessage = makeLastOnlineString(lastDisconnectTime);
|
||||||
|
}
|
||||||
|
|
||||||
const mainClass = playerActive ? 'online' : '';
|
const mainClass = playerActive ? 'online' : '';
|
||||||
|
|
||||||
@ -252,10 +255,10 @@ export default class VideoOnly extends Component {
|
|||||||
<section
|
<section
|
||||||
id="stream-info"
|
id="stream-info"
|
||||||
aria-label="Stream status"
|
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"
|
class="flex flex-row justify-between font-mono py-2 px-4 bg-gray-900 text-indigo-200 shadow-md border-b border-gray-100 border-solid"
|
||||||
>
|
>
|
||||||
<span>${streamStatusMessage}</span>
|
<span class="text-xs">${streamStatusMessage}</span>
|
||||||
<span id="stream-viewer-count">${viewerCountMessage}</span>
|
<span id="stream-viewer-count" class="text-xs text-right">${viewerCountMessage}</span>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
`;
|
`;
|
||||||
|
@ -8,11 +8,6 @@ import UsernameForm from './components/chat/username.js';
|
|||||||
import VideoPoster from './components/video-poster.js';
|
import VideoPoster from './components/video-poster.js';
|
||||||
import Chat from './components/chat/chat.js';
|
import Chat from './components/chat/chat.js';
|
||||||
import Websocket from './utils/websocket.js';
|
import Websocket from './utils/websocket.js';
|
||||||
import {
|
|
||||||
parseSecondsToDurationString,
|
|
||||||
hasTouchScreen,
|
|
||||||
getOrientation,
|
|
||||||
} from './utils/helpers.js';
|
|
||||||
import ExternalActionModal, {
|
import ExternalActionModal, {
|
||||||
ExternalActionButton,
|
ExternalActionButton,
|
||||||
} from './components/external-action-modal.js';
|
} from './components/external-action-modal.js';
|
||||||
@ -24,6 +19,10 @@ import {
|
|||||||
debounce,
|
debounce,
|
||||||
generateUsername,
|
generateUsername,
|
||||||
getLocalStorage,
|
getLocalStorage,
|
||||||
|
getOrientation,
|
||||||
|
hasTouchScreen,
|
||||||
|
makeLastOnlineString,
|
||||||
|
parseSecondsToDurationString,
|
||||||
pluralize,
|
pluralize,
|
||||||
setLocalStorage,
|
setLocalStorage,
|
||||||
} from './utils/helpers.js';
|
} from './utils/helpers.js';
|
||||||
@ -72,6 +71,7 @@ export default class App extends Component {
|
|||||||
// status
|
// status
|
||||||
streamStatusMessage: MESSAGE_OFFLINE,
|
streamStatusMessage: MESSAGE_OFFLINE,
|
||||||
viewerCount: '',
|
viewerCount: '',
|
||||||
|
lastDisconnectTime: null,
|
||||||
|
|
||||||
// dom
|
// dom
|
||||||
windowWidth: window.innerWidth,
|
windowWidth: window.innerWidth,
|
||||||
@ -208,9 +208,7 @@ export default class App extends Component {
|
|||||||
if (!status) {
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { viewerCount, online, lastConnectTime, streamTitle } = status;
|
const { viewerCount, online, lastConnectTime, streamTitle, lastDisconnectTime } = status;
|
||||||
|
|
||||||
this.lastDisconnectTime = status.lastDisconnectTime;
|
|
||||||
|
|
||||||
if (status.online && !curStreamOnline) {
|
if (status.online && !curStreamOnline) {
|
||||||
// stream has just come online.
|
// stream has just come online.
|
||||||
@ -225,6 +223,7 @@ export default class App extends Component {
|
|||||||
lastConnectTime,
|
lastConnectTime,
|
||||||
streamOnline: online,
|
streamOnline: online,
|
||||||
streamTitle,
|
streamTitle,
|
||||||
|
lastDisconnectTime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +259,7 @@ export default class App extends Component {
|
|||||||
clearInterval(this.streamDurationTimer);
|
clearInterval(this.streamDurationTimer);
|
||||||
const remainingChatTime =
|
const remainingChatTime =
|
||||||
TIMER_DISABLE_CHAT_AFTER_OFFLINE -
|
TIMER_DISABLE_CHAT_AFTER_OFFLINE -
|
||||||
(Date.now() - new Date(this.lastDisconnectTime));
|
(Date.now() - new Date(this.state.lastDisconnectTime));
|
||||||
const countdown = remainingChatTime < 0 ? 0 : remainingChatTime;
|
const countdown = remainingChatTime < 0 ? 0 : remainingChatTime;
|
||||||
this.disableChatTimer = setTimeout(this.disableChatInput, countdown);
|
this.disableChatTimer = setTimeout(this.disableChatInput, countdown);
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -501,6 +500,7 @@ export default class App extends Component {
|
|||||||
windowHeight,
|
windowHeight,
|
||||||
windowWidth,
|
windowWidth,
|
||||||
externalAction,
|
externalAction,
|
||||||
|
lastDisconnectTime,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -520,10 +520,13 @@ export default class App extends Component {
|
|||||||
|
|
||||||
const tagList = tags !== null && tags.length > 0 && tags.join(' #');
|
const tagList = tags !== null && tags.length > 0 && tags.join(' #');
|
||||||
|
|
||||||
const viewerCountMessage =
|
let viewerCountMessage = '';
|
||||||
streamOnline && viewerCount > 0
|
if (streamOnline && viewerCount > 0) {
|
||||||
? html`${viewerCount} ${pluralize('viewer', viewerCount)}`
|
viewerCountMessage = html`${viewerCount} ${pluralize('viewer', viewerCount)}`;
|
||||||
: null;
|
} else if (lastDisconnectTime) {
|
||||||
|
viewerCountMessage = makeLastOnlineString(lastDisconnectTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const mainClass = playerActive ? 'online' : '';
|
const mainClass = playerActive ? 'online' : '';
|
||||||
const isPortrait =
|
const isPortrait =
|
||||||
@ -647,10 +650,10 @@ export default class App extends Component {
|
|||||||
<section
|
<section
|
||||||
id="stream-info"
|
id="stream-info"
|
||||||
aria-label="Stream status"
|
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"
|
class="flex text-center flex-row justify-between font-mono py-2 px-4 bg-gray-900 text-indigo-200 shadow-md border-b border-gray-100 border-solid"
|
||||||
>
|
>
|
||||||
<span>${streamStatusMessage}</span>
|
<span class="text-xs">${streamStatusMessage}</span>
|
||||||
<span id="stream-viewer-count">${viewerCountMessage}</span>
|
<span id="stream-viewer-count" class="text-xs text-right">${viewerCountMessage}</span>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
} from '../../utils/user-colors.js';
|
} from '../../utils/user-colors.js';
|
||||||
import { convertToText } from '../../utils/chat.js';
|
import { convertToText } from '../../utils/chat.js';
|
||||||
import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js';
|
import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js';
|
||||||
|
import { getDiffInDaysFromNow } from '../../utils/helpers.js';
|
||||||
|
|
||||||
export default class ChatMessageView extends Component {
|
export default class ChatMessageView extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -155,7 +156,7 @@ function formatTimestamp(sentAt) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let diffInDays = (new Date() - sentAt) / (24 * 3600 * 1000);
|
let diffInDays = getDiffInDaysFromNow(sentAt); //(new Date() - sentAt) / (24 * 3600 * 1000);
|
||||||
if (diffInDays >= 1) {
|
if (diffInDays >= 1) {
|
||||||
return (
|
return (
|
||||||
`Sent at ${sentAt.toLocaleDateString('en-US', {
|
`Sent at ${sentAt.toLocaleDateString('en-US', {
|
||||||
|
@ -156,3 +156,26 @@ export function debounce(fn, time) {
|
|||||||
timeout = setTimeout(functionCall, time);
|
timeout = setTimeout(functionCall, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getDiffInDaysFromNow(timestamp) {
|
||||||
|
const time = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
|
||||||
|
return (new Date() - time) / (24 * 3600 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Last live today at [time]" or "last live [date]"
|
||||||
|
export function makeLastOnlineString(timestamp) {
|
||||||
|
if (!timestamp) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
let string = '';
|
||||||
|
const time = new Date(timestamp);
|
||||||
|
let diffInDays = getDiffInDaysFromNow(time);
|
||||||
|
if (diffInDays > 1) {
|
||||||
|
string = time.toLocaleDateString();
|
||||||
|
} else {
|
||||||
|
const atTime = time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||||
|
string = `Today ${atTime}`;
|
||||||
|
}
|
||||||
|
return `Last live: ${string}`;
|
||||||
|
}
|
||||||
|
@ -78,17 +78,6 @@ header {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#stream-info span {
|
|
||||||
font-size: .70rem;
|
|
||||||
}
|
|
||||||
#stream-viewer-count {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.online #stream-viewer-count {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#external-actions-container {
|
#external-actions-container {
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
|
|
||||||
|
@ -24,8 +24,3 @@ The styles in this file mostly ovveride those coming from chat.css
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#video-only #stream-info {
|
|
||||||
height: 3rem;
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user