diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index 390939f6d..2bd5ce96a 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -2,17 +2,17 @@ import 'antd/dist/antd.compact.css'; import "../styles/globals.scss"; import { AppProps } from 'next/app'; -import BroadcastStatusProvider from '../utils/broadcast-status-context'; +import ServerStatusProvider from '../utils/server-status-context'; import MainLayout from './components/main-layout'; function App({ Component, pageProps }: AppProps) { return ( - + - + ) } diff --git a/web/pages/broadcast-info.tsx b/web/pages/broadcast-info.tsx index 5c3ad36bd..2cd8a7a63 100644 --- a/web/pages/broadcast-info.tsx +++ b/web/pages/broadcast-info.tsx @@ -1,9 +1,9 @@ import React, { useContext } from 'react'; -import { BroadcastStatusContext } from '../utils/broadcast-status-context'; +import { ServerStatusContext } from '../utils/server-status-context'; export default function BroadcastInfo() { - const context = useContext(BroadcastStatusContext); + const context = useContext(ServerStatusContext); const { broadcaster } = context || {}; const { remoteAddr, time, streamDetails } = broadcaster || {}; diff --git a/web/pages/components/main-layout.tsx b/web/pages/components/main-layout.tsx index a100bc0e7..1b7ff11cb 100644 --- a/web/pages/components/main-layout.tsx +++ b/web/pages/components/main-layout.tsx @@ -18,15 +18,17 @@ import { upgradeVersionAvailable } from "../../utils/apis"; import { parseSecondsToDurationString } from '../../utils/format' import OwncastLogo from './logo'; -import { BroadcastStatusContext } from '../../utils/broadcast-status-context'; +import { ServerStatusContext } from '../../utils/server-status-context'; import adminStyles from '../../styles/styles.module.css'; +let performedUpgradeCheck = false; + export default function MainLayout(props) { const { children } = props; - const context = useContext(BroadcastStatusContext); - const { broadcastActive, broadcaster } = context || {}; + const context = useContext(ServerStatusContext); + const { online, broadcaster, versionNumber } = context || {}; const router = useRouter(); const { route } = router || {}; @@ -34,19 +36,15 @@ export default function MainLayout(props) { const { Header, Footer, Content, Sider } = Layout; const { SubMenu } = Menu; - const streamDurationString = broadcastActive ? - parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(broadcaster.time))) : "" + const streamDurationString = online ? parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(broadcaster.time))) : ""; - const statusIcon = broadcastActive ? - : ; - const statusMessage = broadcastActive - ? `Online ${ streamDurationString}` - : "Offline"; + const statusIcon = online ? : ; + const statusMessage = online ? `Online ${streamDurationString}` : "Offline"; const [upgradeVersion, setUpgradeVersion] = useState(null); const checkForUpgrade = async () => { try { - const result = await upgradeVersionAvailable(); + const result = await upgradeVersionAvailable(versionNumber); setUpgradeVersion(result); } catch (error) { console.log("==== error", error); @@ -54,13 +52,17 @@ export default function MainLayout(props) { }; useEffect(() => { - checkForUpgrade(); - }, []); + if (!performedUpgradeCheck && !context.disableUpgradeChecks) { + checkForUpgrade(); + console.log('checking') + performedUpgradeCheck = true + } + }); const appClass = classNames({ - 'owncast-layout': true, - [adminStyles.online]: broadcastActive, - }) + "owncast-layout": true, + [adminStyles.online]: online, + }); const upgradeMenuItemStyle = upgradeVersion ? 'block' : 'none'; const upgradeVersionString = upgradeVersion || ''; @@ -98,7 +100,7 @@ export default function MainLayout(props) { Viewers - {broadcastActive ? ( + {online ? ( }> Disconnect Stream... @@ -151,7 +153,7 @@ export default function MainLayout(props) { {children} diff --git a/web/pages/index.tsx b/web/pages/index.tsx index 1b7077f0e..112108a22 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -11,12 +11,12 @@ import React, { useState, useEffect, useContext } from "react"; import { Row, Skeleton, Result, List, Typography, Card } from "antd"; import { UserOutlined, ClockCircleOutlined } from "@ant-design/icons"; import { formatDistanceToNow, formatRelative } from "date-fns"; -import { BroadcastStatusContext } from "../utils/broadcast-status-context"; +import { ServerStatusContext } from "../utils/server-status-context"; import StatisticItem from "./components/statistic" import LogTable from "./components/log-table"; import { - STREAM_STATUS, + STATUS, SERVER_CONFIG, LOGS_WARN, fetchData, @@ -82,7 +82,7 @@ function Offline() { } export default function Stats() { - const context = useContext(BroadcastStatusContext); + const context = useContext(ServerStatusContext); const { broadcaster } = context || {}; const { remoteAddr, streamDetails } = broadcaster || {}; @@ -90,7 +90,7 @@ export default function Stats() { const [stats, setStats] = useState(null); const getStats = async () => { try { - const result = await fetchData(STREAM_STATUS); + const result = await fetchData(STATUS); setStats(result); } catch (error) { console.log(error); @@ -182,7 +182,7 @@ export default function Stats() { }); const logTable = logs.length > 0 ? : null - const { viewerCount, sessionMaxViewerCount, lastConnectTime } = stats; + const { viewerCount, sessionMaxViewerCount } = stats; const streamVideoDetailString = `${streamDetails.videoCodec} ${streamDetails.videoBitrate} kbps ${streamDetails.width}x${streamDetails.height}`; const streamAudioDetailString = `${streamDetails.audioCodec} ${streamDetails.audioBitrate} kpbs`; @@ -192,10 +192,10 @@ export default function Stats() { } /> -

+ <a href={release.html_url}>{release.name}</a> - </h2> - <h1>{release.created_at}</h1> - <ReactMarkdown>{release.body}</ReactMarkdown>; - - <h3>Downloads</h3> + + {new Date(release.created_at).toDateString()} + {release.body};

Downloads

); diff --git a/web/pages/viewer-info.tsx b/web/pages/viewer-info.tsx index fb39f6af6..04977adf3 100644 --- a/web/pages/viewer-info.tsx +++ b/web/pages/viewer-info.tsx @@ -7,23 +7,27 @@ import { SortOrder } from "antd/lib/table/interface"; import Chart from "./components/chart"; import StatisticItem from "./components/statistic"; -import { BroadcastStatusContext } from '../utils/broadcast-status-context'; +import { ServerStatusContext } from '../utils/server-status-context'; import { CONNECTED_CLIENTS, - STREAM_STATUS, VIEWERS_OVER_TIME, + VIEWERS_OVER_TIME, fetchData, } from "../utils/apis"; const FETCH_INTERVAL = 5 * 60 * 1000; // 5 mins export default function ViewersOverTime() { - const context = useContext(BroadcastStatusContext); - const { broadcastActive } = context || {}; + const context = useContext(ServerStatusContext); + const { + broadcastActive, + viewerCount, + overallPeakViewerCount, + sessionPeakViewerCount, + } = context || {}; const [viewerInfo, setViewerInfo] = useState([]); const [clients, setClients] = useState([]); - const [stats, setStats] = useState(null); const getInfo = async () => { try { @@ -39,14 +43,6 @@ export default function ViewersOverTime() { } catch (error) { console.log("==== error", error); } - - try { - const result = await fetchData(STREAM_STATUS); - setStats(result); - } catch (error) { - console.log(error); - } - }; useEffect(() => { @@ -111,12 +107,17 @@ export default function ViewersOverTime() { } /> } + /> + } /> diff --git a/web/utils/apis.ts b/web/utils/apis.ts index fc581818f..4085631ba 100644 --- a/web/utils/apis.ts +++ b/web/utils/apis.ts @@ -8,7 +8,7 @@ const API_LOCATION = `${NEXT_PUBLIC_API_HOST}api/admin/`; export const FETCH_INTERVAL = 15000; // Current inbound broadcaster info -export const BROADCASTER = `${API_LOCATION}broadcaster`; +export const STATUS = `${API_LOCATION}status`; // Disconnect inbound stream export const DISCONNECT = `${API_LOCATION}disconnect`; @@ -36,11 +36,6 @@ export const LOGS_WARN = `${API_LOCATION}logs/warnings`; const GITHUB_RELEASE_URL = "https://api.github.com/repos/owncast/owncast/releases/latest"; -// Current Stream status. -// This is literally the same as /api/status except it supports -// auth. -export const STREAM_STATUS = `${API_LOCATION}status`; - export async function fetchData(url) { const encoded = btoa(`${ADMIN_USERNAME}:${ADMIN_STREAMKEY}`); @@ -81,8 +76,7 @@ export async function getGithubRelease() { // Make a request to the server status API and the Github releases API // and return a release if it's newer than the server version. -export async function upgradeVersionAvailable() { - const serverVersion = await fetchData(STREAM_STATUS) +export async function upgradeVersionAvailable(currentVersion) { const recentRelease = await getGithubRelease(); let recentReleaseVersion = recentRelease.tag_name; @@ -90,7 +84,7 @@ export async function upgradeVersionAvailable() { recentReleaseVersion = recentReleaseVersion.substr(1) } - if (!upToDate(serverVersion.versionNumber, recentReleaseVersion)) { + if (!upToDate(currentVersion, recentReleaseVersion)) { return recentReleaseVersion } diff --git a/web/utils/broadcast-status-context.tsx b/web/utils/broadcast-status-context.tsx deleted file mode 100644 index 309c2152d..000000000 --- a/web/utils/broadcast-status-context.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; - -import { BROADCASTER, fetchData, FETCH_INTERVAL } from './apis'; - -const initialState = { - broadcastActive: false, - message: '', - broadcaster: null, -}; - -export const BroadcastStatusContext = React.createContext(initialState); - -const BroadcastStatusProvider = ({ children }) => { - const [broadcasterStatus, setBroadcasterStatus] = useState(initialState); - - const getBroadcastStatus = async () => { - try { - const result = await fetchData(BROADCASTER); - const broadcastActive = !!result.broadcaster || result.success; - setBroadcasterStatus({ ...result, broadcastActive }); - - } catch (error) { - setBroadcasterStatus({ ...broadcasterStatus, message: error.message }); - } - }; - - useEffect(() => { - let getStatusIntervalId = null; - - getBroadcastStatus(); - getStatusIntervalId = setInterval(getBroadcastStatus, FETCH_INTERVAL); - - // returned function will be called on component unmount - return () => { - clearInterval(getStatusIntervalId); - } - }, []) - - return ( - - {children} - - ); -} - -BroadcastStatusProvider.propTypes = { - children: PropTypes.element.isRequired, -}; - -export default BroadcastStatusProvider; \ No newline at end of file diff --git a/web/utils/server-status-context.tsx b/web/utils/server-status-context.tsx new file mode 100644 index 000000000..f0c63aa43 --- /dev/null +++ b/web/utils/server-status-context.tsx @@ -0,0 +1,55 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; + +import { STATUS, fetchData, FETCH_INTERVAL } from './apis'; + +const initialState = { + broadcastActive: false, + broadcaster: null, + online: false, + viewerCount: 0, + sessionPeakViewerCount: 0, + overallPeakViewerCount: 0, + disableUpgradeChecks: true, + versionNumber: '0.0.0', +}; + +export const ServerStatusContext = React.createContext(initialState); + +const ServerStatusProvider = ({ children }) => { + const [status, setStatus] = useState(initialState); + + const getStatus = async () => { + try { + const result = await fetchData(STATUS); + setStatus({ ...result }); + + } catch (error) { + // setBroadcasterStatus({ ...broadcasterStatus, message: error.message }); + } + }; + + useEffect(() => { + let getStatusIntervalId = null; + + getStatus(); + getStatusIntervalId = setInterval(getStatus, FETCH_INTERVAL); + + // returned function will be called on component unmount + return () => { + clearInterval(getStatusIntervalId); + } + }, []) + + return ( + + {children} + + ); +} + +ServerStatusProvider.propTypes = { + children: PropTypes.element.isRequired, +}; + +export default ServerStatusProvider; \ No newline at end of file