index.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import React from 'react';
  2. import { useRecoilValue } from 'recoil';
  3. import { useRouter } from 'next/router';
  4. import { Skeleton } from 'antd';
  5. import {
  6. clientConfigStateAtom,
  7. ClientConfigStore,
  8. isOnlineSelector,
  9. serverStatusState,
  10. appStateAtom,
  11. } from '../../../components/stores/ClientConfigStore';
  12. import { OfflineBanner } from '../../../components/ui/OfflineBanner/OfflineBanner';
  13. import { Statusbar } from '../../../components/ui/Statusbar/Statusbar';
  14. import { OwncastPlayer } from '../../../components/video/OwncastPlayer/OwncastPlayer';
  15. import { ClientConfig } from '../../../interfaces/client-config.model';
  16. import { ServerStatus } from '../../../interfaces/server-status.model';
  17. import { AppStateOptions } from '../../../components/stores/application-state';
  18. import { Theme } from '../../../components/theme/Theme';
  19. export default function VideoEmbed() {
  20. const status = useRecoilValue<ServerStatus>(serverStatusState);
  21. const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
  22. const appState = useRecoilValue<AppStateOptions>(appStateAtom);
  23. const { name } = clientConfig;
  24. const { offlineMessage } = clientConfig;
  25. const { viewerCount, lastConnectTime, lastDisconnectTime, streamTitle } = status;
  26. const online = useRecoilValue<boolean>(isOnlineSelector);
  27. const router = useRouter();
  28. /**
  29. * router.query isn't initialized until hydration
  30. * (see https://github.com/vercel/next.js/discussions/11484)
  31. * but router.asPath is initialized earlier, so we parse the
  32. * query parameters ourselves
  33. */
  34. const path = router.asPath.split('?')[1] ?? '';
  35. const query = path.split('&').reduce((currQuery, part) => {
  36. const [key, value] = part.split('=');
  37. return { ...currQuery, [key]: value };
  38. }, {} as Record<string, string>);
  39. const initiallyMuted = query.initiallyMuted === 'true';
  40. const loadingState = <Skeleton active style={{ padding: '10px' }} paragraph={{ rows: 10 }} />;
  41. const offlineState = (
  42. <OfflineBanner streamName={name} customText={offlineMessage} notificationsEnabled={false} />
  43. );
  44. const onlineState = (
  45. <>
  46. <OwncastPlayer
  47. source="/hls/stream.m3u8"
  48. online={online}
  49. initiallyMuted={initiallyMuted}
  50. title={streamTitle || name}
  51. fill
  52. />
  53. <Statusbar
  54. online={online}
  55. lastConnectTime={lastConnectTime}
  56. lastDisconnectTime={lastDisconnectTime}
  57. viewerCount={viewerCount}
  58. />
  59. </>
  60. );
  61. const getView = () => {
  62. if (appState.appLoading) {
  63. return loadingState;
  64. }
  65. if (online) {
  66. return onlineState;
  67. }
  68. return offlineState;
  69. };
  70. return (
  71. <>
  72. <ClientConfigStore />
  73. <Theme />
  74. <div className="video-embed">{getView()}</div>
  75. </>
  76. );
  77. }