lbry-desktop/ui/page/livestream/view.jsx

194 lines
7.1 KiB
React
Raw Normal View History

// @flow
import { formatLbryChannelName } from 'util/url';
import { lazyImport } from 'util/lazyImport';
2022-03-16 18:35:27 +01:00
import { LIVESTREAM_STARTS_SOON_BUFFER, LIVESTREAM_STARTED_RECENTLY_BUFFER } from 'constants/livestream';
import analytics from 'analytics';
import LivestreamLayout from 'component/livestreamLayout';
import moment from 'moment';
import Page from 'component/page';
import React from 'react';
2022-03-16 22:39:09 +01:00
import { useIsMobile } from 'effects/use-screensize';
2022-03-16 18:35:27 +01:00
import useFetchLiveStatus from 'effects/use-fetch-live';
const LivestreamChatLayout = lazyImport(() => import('component/livestreamChatLayout' /* webpackChunkName: "chat" */));
type Props = {
activeLivestreamForChannel: any,
activeLivestreamInitialized: boolean,
channelClaimId: ?string,
chatDisabled: boolean,
claim: StreamClaim,
isAuthenticated: boolean,
uri: string,
socketConnected: boolean,
2022-03-15 17:18:08 +01:00
doSetPrimaryUri: (uri: ?string) => void,
doCommentSocketConnect: (string, string, string) => void,
doFetchChannelLiveStatus: (string) => void,
doUserSetReferrer: (string) => void,
};
2022-03-21 15:11:26 +01:00
export const LivestreamContext = React.createContext<any>();
2022-03-16 22:39:09 +01:00
export default function LivestreamPage(props: Props) {
const {
activeLivestreamForChannel,
activeLivestreamInitialized,
channelClaimId,
chatDisabled,
claim,
isAuthenticated,
uri,
socketConnected,
2022-03-15 17:18:08 +01:00
doSetPrimaryUri,
doCommentSocketConnect,
doFetchChannelLiveStatus,
doUserSetReferrer,
} = props;
2021-03-30 01:05:18 +02:00
2022-03-16 22:39:09 +01:00
const isMobile = useIsMobile();
const [activeStreamUri, setActiveStreamUri] = React.useState(false);
const [showLivestream, setShowLivestream] = React.useState(false);
const [showScheduledInfo, setShowScheduledInfo] = React.useState(false);
const [hideComments, setHideComments] = React.useState(false);
2022-03-16 22:39:09 +01:00
const [layountRendered, setLayountRendered] = React.useState(chatDisabled || isMobile);
const isInitialized = Boolean(activeLivestreamForChannel) || activeLivestreamInitialized;
const isChannelBroadcasting = Boolean(activeLivestreamForChannel);
const claimId = claim && claim.claim_id;
const isCurrentClaimLive = isChannelBroadcasting && activeLivestreamForChannel.claimId === claimId;
const livestreamChannelId = channelClaimId || '';
const releaseTime: moment = moment.unix(claim?.value?.release_time || 0);
const stringifiedClaim = JSON.stringify(claim);
React.useEffect(() => {
// TODO: This should not be needed once we unify the livestream player (?)
analytics.playerLoadedEvent('livestream', false);
}, []);
2022-03-16 12:35:58 +01:00
const { signing_channel: channelClaim } = claim || {};
const { canonical_url: channelUrl } = channelClaim || {};
// On livestream page, only connect, fileRenderFloating will handle disconnect.
// (either by leaving page with floating player off, or by closing the player)
React.useEffect(() => {
if (!claim || socketConnected) return;
const { claim_id: claimId, signing_channel: channelClaim } = claim;
2022-03-16 12:35:58 +01:00
const channelName = channelClaim && formatLbryChannelName(channelUrl);
if (claimId && channelName) {
doCommentSocketConnect(uri, channelName, claimId);
2021-03-30 01:05:18 +02:00
}
// only listen to socketConnected on initial mount
// eslint-disable-next-line react-hooks/exhaustive-deps
2022-03-16 12:35:58 +01:00
}, [channelUrl, claim, doCommentSocketConnect, uri]);
2022-03-16 03:45:16 +01:00
const claimReleaseStartingSoonStatic = () =>
releaseTime.isBetween(moment(), moment().add(LIVESTREAM_STARTS_SOON_BUFFER, 'minutes'));
2022-03-16 03:45:16 +01:00
const claimReleaseStartedRecentlyStatic = () =>
releaseTime.isBetween(moment().subtract(LIVESTREAM_STARTED_RECENTLY_BUFFER, 'minutes'), moment());
2022-03-16 03:45:16 +01:00
// Find out current channels status + active live claim every 30 seconds (or 15 if not live)
const fasterPoll = !isCurrentClaimLive && (claimReleaseStartingSoonStatic() || claimReleaseStartedRecentlyStatic());
2022-03-16 18:35:27 +01:00
useFetchLiveStatus(livestreamChannelId, doFetchChannelLiveStatus, fasterPoll);
React.useEffect(() => {
setActiveStreamUri(!isCurrentClaimLive && isChannelBroadcasting ? activeLivestreamForChannel.claimUri : false);
}, [isCurrentClaimLive, isChannelBroadcasting]); // eslint-disable-line react-hooks/exhaustive-deps
React.useEffect(() => {
if (!isInitialized) return;
const claimReleaseInFuture = () => releaseTime.isAfter();
const claimReleaseInPast = () => releaseTime.isBefore();
const claimReleaseStartingSoon = () =>
releaseTime.isBetween(moment(), moment().add(LIVESTREAM_STARTS_SOON_BUFFER, 'minutes'));
const claimReleaseStartedRecently = () =>
releaseTime.isBetween(moment().subtract(LIVESTREAM_STARTED_RECENTLY_BUFFER, 'minutes'), moment());
const checkShowLivestream = () =>
2022-03-16 03:45:16 +01:00
isChannelBroadcasting &&
isCurrentClaimLive &&
(claimReleaseInPast() || claimReleaseStartingSoon() || claimReleaseInFuture());
const checkShowScheduledInfo = () =>
(!isChannelBroadcasting && (claimReleaseInFuture() || claimReleaseStartedRecently())) ||
(isChannelBroadcasting &&
((!isCurrentClaimLive && (claimReleaseInFuture() || claimReleaseStartedRecently())) ||
(isCurrentClaimLive && claimReleaseInFuture() && !claimReleaseStartingSoon())));
const checkCommentsDisabled = () => chatDisabled || (claimReleaseInFuture() && !claimReleaseStartingSoon());
const calculateStreamReleaseState = () => {
setShowLivestream(checkShowLivestream());
setShowScheduledInfo(checkShowScheduledInfo());
setHideComments(checkCommentsDisabled());
};
calculateStreamReleaseState();
2022-03-16 03:45:16 +01:00
const intervalId = setInterval(calculateStreamReleaseState, 5000);
if (isCurrentClaimLive && claimReleaseInPast() && isChannelBroadcasting === true) {
clearInterval(intervalId);
}
return () => clearInterval(intervalId);
}, [chatDisabled, isChannelBroadcasting, releaseTime, isCurrentClaimLive, isInitialized]);
React.useEffect(() => {
if (uri && stringifiedClaim) {
const jsonClaim = JSON.parse(stringifiedClaim);
if (!isAuthenticated) {
const uri = jsonClaim.signing_channel && jsonClaim.signing_channel.permanent_url;
if (uri) doUserSetReferrer(uri.replace('lbry://', ''));
}
}
}, [uri, stringifiedClaim, isAuthenticated, doUserSetReferrer]);
React.useEffect(() => {
2022-03-16 22:39:09 +01:00
if (!layountRendered) return;
2022-03-15 17:18:08 +01:00
doSetPrimaryUri(uri);
2022-02-07 17:51:07 +01:00
2022-03-15 17:18:08 +01:00
return () => doSetPrimaryUri(null);
2022-03-16 22:39:09 +01:00
}, [doSetPrimaryUri, layountRendered, uri]);
return (
<Page
className="file-page scheduledLivestream-wrapper"
noFooter
livestream
chatDisabled={hideComments}
rightSide={
!hideComments &&
isInitialized && (
<React.Suspense fallback={null}>
2022-03-16 22:39:09 +01:00
<LivestreamChatLayout uri={uri} setLayountRendered={setLayountRendered} />
</React.Suspense>
)
}
>
{isInitialized && (
2022-03-21 15:11:26 +01:00
<LivestreamContext.Provider value={{ livestreamPage: true, layountRendered }}>
2022-03-16 22:39:09 +01:00
<LivestreamLayout
uri={uri}
hideComments={hideComments}
releaseTimeMs={releaseTime.unix() * 1000}
2022-03-16 22:39:09 +01:00
isCurrentClaimLive={isCurrentClaimLive}
showLivestream={showLivestream}
showScheduledInfo={showScheduledInfo}
activeStreamUri={activeStreamUri}
/>
2022-03-21 15:11:26 +01:00
</LivestreamContext.Provider>
)}
</Page>
);
}