|
|
|
@ -1,24 +1,13 @@ |
|
|
|
/* |
|
|
|
|
|
|
|
Will display an overview with the following datasources: |
|
|
|
|
|
|
|
1. Current broadcaster. |
|
|
|
|
|
|
|
2. Viewer count. |
|
|
|
|
|
|
|
3. Video settings. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TODO: Link each overview value to the sub-page that focuses on it. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import React, { useState, useEffect, useContext } from 'react'; |
|
|
|
import React, { useState, useEffect, useContext } from 'react'; |
|
|
|
import { Skeleton, Card, Statistic } from 'antd'; |
|
|
|
import { Skeleton, Card, Statistic, Row, Col } from 'antd'; |
|
|
|
import { UserOutlined, ClockCircleOutlined } from '@ant-design/icons'; |
|
|
|
import { UserOutlined, ClockCircleOutlined } from '@ant-design/icons'; |
|
|
|
import { formatDistanceToNow, formatRelative } from 'date-fns'; |
|
|
|
import { formatDistanceToNow, formatRelative } from 'date-fns'; |
|
|
|
import { ServerStatusContext } from '../utils/server-status-context'; |
|
|
|
import { ServerStatusContext } from '../utils/server-status-context'; |
|
|
|
import StatisticItem from '../components/statistic'; |
|
|
|
|
|
|
|
import LogTable from '../components/log-table'; |
|
|
|
import LogTable from '../components/log-table'; |
|
|
|
import Offline from './offline-notice'; |
|
|
|
import Offline from './offline-notice'; |
|
|
|
|
|
|
|
|
|
|
|
import { LOGS_WARN, fetchData, FETCH_INTERVAL } from '../utils/apis'; |
|
|
|
import { LOGS_WARN, fetchData, FETCH_INTERVAL } from '../utils/apis'; |
|
|
|
import { formatIPAddress, isEmptyObject } from '../utils/format'; |
|
|
|
import { formatIPAddress, isEmptyObject } from '../utils/format'; |
|
|
|
import { UpdateArgs } from '../types/config-section'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function streamDetailsFormatter(streamDetails) { |
|
|
|
function streamDetailsFormatter(streamDetails) { |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
@ -80,31 +69,34 @@ export default function Home() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// map out settings
|
|
|
|
// map out settings
|
|
|
|
const videoQualitySettings = serverStatusData?.currentBroadcast?.outputSettings?.map( |
|
|
|
const videoQualitySettings = serverStatusData?.currentBroadcast?.outputSettings?.map(setting => { |
|
|
|
(setting, index) => { |
|
|
|
const { audioPassthrough, videoPassthrough, audioBitrate, videoBitrate, framerate } = setting; |
|
|
|
const { audioPassthrough, videoPassthrough, audioBitrate, videoBitrate, framerate } = setting; |
|
|
|
|
|
|
|
|
|
|
|
const audioSetting = audioPassthrough |
|
|
|
const audioSetting = audioPassthrough |
|
|
|
? `${streamDetails.audioCodec || 'Unknown'}, ${streamDetails.audioBitrate} kbps` |
|
|
|
? `${streamDetails.audioCodec || 'Unknown'}, ${streamDetails.audioBitrate} kbps` |
|
|
|
: `${audioBitrate || 'Unknown'} kbps`; |
|
|
|
: `${audioBitrate || 'Unknown'} kbps`; |
|
|
|
|
|
|
|
|
|
|
|
const videoSetting = videoPassthrough |
|
|
|
const videoSetting = videoPassthrough |
|
|
|
? `${streamDetails.videoBitrate || 'Unknown'} kbps, ${streamDetails.framerate} fps ${ |
|
|
|
? `${streamDetails.videoBitrate || 'Unknown'} kbps, ${streamDetails.framerate} fps ${ |
|
|
|
streamDetails.width |
|
|
|
streamDetails.width |
|
|
|
} x ${streamDetails.height}` |
|
|
|
} x ${streamDetails.height}` |
|
|
|
: `${videoBitrate || 'Unknown'} kbps, ${framerate} fps`; |
|
|
|
: `${videoBitrate || 'Unknown'} kbps, ${framerate} fps`; |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
let settingTitle = 'Outbound Stream Details'; |
|
|
|
<div className="stream-details-item-container"> |
|
|
|
settingTitle = |
|
|
|
<Statistic |
|
|
|
videoQualitySettings?.length > 1 ? `${settingTitle} ${index + 1}` : settingTitle; |
|
|
|
className="stream-details-item" |
|
|
|
return ( |
|
|
|
title="Outbound Video Stream" |
|
|
|
<Card title={settingTitle} type="inner" key={`${settingTitle}${index}`}> |
|
|
|
value={videoSetting} |
|
|
|
<StatisticItem title="Outbound Video Stream" value={videoSetting} prefix={null} /> |
|
|
|
/> |
|
|
|
<StatisticItem title="Outbound Audio Stream" value={audioSetting} prefix={null} /> |
|
|
|
<Statistic |
|
|
|
</Card> |
|
|
|
className="stream-details-item" |
|
|
|
); |
|
|
|
title="Outbound Audio Stream" |
|
|
|
}, |
|
|
|
value={audioSetting} |
|
|
|
); |
|
|
|
/> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// inbound
|
|
|
|
// inbound
|
|
|
|
const { viewerCount, sessionPeakViewerCount } = serverStatusData; |
|
|
|
const { viewerCount, sessionPeakViewerCount } = serverStatusData; |
|
|
|
@ -118,57 +110,60 @@ export default function Home() { |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div className="home-container"> |
|
|
|
<div className="home-container"> |
|
|
|
<div className="sections-container"> |
|
|
|
<div className="sections-container"> |
|
|
|
<div className="section online-status-section"> |
|
|
|
<div className="online-status-section"> |
|
|
|
<Card title="Stream is online" type="inner"> |
|
|
|
<Card size="small" type="inner" className="online-details-card"> |
|
|
|
<Statistic |
|
|
|
<Row gutter={[16, 16]} align="middle"> |
|
|
|
title={`Stream started ${formatRelative(broadcastDate, Date.now())}`} |
|
|
|
<Col span={8} sm={24} md={8}> |
|
|
|
value={formatDistanceToNow(broadcastDate)} |
|
|
|
<Statistic |
|
|
|
prefix={<ClockCircleOutlined />} |
|
|
|
title={`Stream started ${formatRelative(broadcastDate, Date.now())}`} |
|
|
|
/> |
|
|
|
value={formatDistanceToNow(broadcastDate)} |
|
|
|
<Statistic title="Viewers" value={viewerCount} prefix={<UserOutlined />} /> |
|
|
|
prefix={<ClockCircleOutlined />} |
|
|
|
<Statistic |
|
|
|
/> |
|
|
|
title="Peak viewer count" |
|
|
|
</Col> |
|
|
|
value={sessionPeakViewerCount} |
|
|
|
<Col span={8} sm={24} md={8}> |
|
|
|
prefix={<UserOutlined />} |
|
|
|
<Statistic title="Viewers" value={viewerCount} prefix={<UserOutlined />} /> |
|
|
|
/> |
|
|
|
</Col> |
|
|
|
|
|
|
|
<Col span={8} sm={24} md={8}> |
|
|
|
|
|
|
|
<Statistic |
|
|
|
|
|
|
|
title="Peak viewer count" |
|
|
|
|
|
|
|
value={sessionPeakViewerCount} |
|
|
|
|
|
|
|
prefix={<UserOutlined />} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</Col> |
|
|
|
|
|
|
|
</Row> |
|
|
|
</Card> |
|
|
|
</Card> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div className="section stream-details-section"> |
|
|
|
<Row gutter={[16, 16]} className="section stream-details-section"> |
|
|
|
<div className="details outbound-details">{videoQualitySettings}</div> |
|
|
|
<Col className="outbound-details" span={12} sm={24} md={24} lg={12}> |
|
|
|
|
|
|
|
<Card size="small" title="Outbound Stream Details" type="inner"> |
|
|
|
|
|
|
|
{videoQualitySettings} |
|
|
|
|
|
|
|
</Card> |
|
|
|
|
|
|
|
</Col> |
|
|
|
|
|
|
|
|
|
|
|
<div className="details other-details"> |
|
|
|
<Col className="inbound-details" span={12} sm={24} md={24} lg={12}> |
|
|
|
<Card title="Inbound Stream Details" type="inner"> |
|
|
|
<Card size="small" title="Inbound Stream Details" type="inner"> |
|
|
|
<StatisticItem |
|
|
|
<Statistic |
|
|
|
|
|
|
|
className="stream-details-item" |
|
|
|
title="Input" |
|
|
|
title="Input" |
|
|
|
value={`${encoder} ${formatIPAddress(remoteAddr)}`} |
|
|
|
value={`${encoder} ${formatIPAddress(remoteAddr)}`} |
|
|
|
prefix={null} |
|
|
|
|
|
|
|
/> |
|
|
|
/> |
|
|
|
<StatisticItem |
|
|
|
<Statistic |
|
|
|
|
|
|
|
className="stream-details-item" |
|
|
|
title="Inbound Video Stream" |
|
|
|
title="Inbound Video Stream" |
|
|
|
value={streamDetails} |
|
|
|
value={streamDetails} |
|
|
|
formatter={streamDetailsFormatter} |
|
|
|
formatter={streamDetailsFormatter} |
|
|
|
prefix={null} |
|
|
|
|
|
|
|
/> |
|
|
|
/> |
|
|
|
<StatisticItem |
|
|
|
<Statistic |
|
|
|
|
|
|
|
className="stream-details-item" |
|
|
|
title="Inbound Audio Stream" |
|
|
|
title="Inbound Audio Stream" |
|
|
|
value={streamAudioDetailString} |
|
|
|
value={streamAudioDetailString} |
|
|
|
prefix={null} |
|
|
|
|
|
|
|
/> |
|
|
|
/> |
|
|
|
</Card> |
|
|
|
</Card> |
|
|
|
|
|
|
|
</Col> |
|
|
|
<div className="server-detail"> |
|
|
|
</Row> |
|
|
|
<Card title="Server Config" type="inner"> |
|
|
|
|
|
|
|
<StatisticItem |
|
|
|
|
|
|
|
title="Directory registration enabled" |
|
|
|
|
|
|
|
value={configData.yp.enabled.toString()} |
|
|
|
|
|
|
|
prefix={null} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</Card> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<br /> |
|
|
|
<LogTable logs={logsData} pageSize={5} /> |
|
|
|
<LogTable logs={logsData} pageSize={5} /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
); |
|
|
|
|