Add stream start to active live streams, and refactor how data active claim is stored in redux
This commit is contained in:
parent
72c1a8ae25
commit
d382671616
18 changed files with 192 additions and 203 deletions
14
flow-typed/livestream.js
vendored
14
flow-typed/livestream.js
vendored
|
@ -21,17 +21,6 @@ declare type LivestreamReplayItem = {
|
|||
}
|
||||
declare type LivestreamReplayData = Array<LivestreamReplayItem>;
|
||||
|
||||
declare type CurrentLiveClaim = {
|
||||
claimId: string | null,
|
||||
claimUri: string | null,
|
||||
}
|
||||
|
||||
declare type LivestreamChannelStatus = {
|
||||
channelId: null | string,
|
||||
isBroadcasting: boolean,
|
||||
liveClaim: CurrentLiveClaim,
|
||||
}
|
||||
|
||||
declare type LivestreamState = {
|
||||
fetchingById: {},
|
||||
viewersById: {},
|
||||
|
@ -39,8 +28,7 @@ declare type LivestreamState = {
|
|||
activeLivestreams: ?LivestreamInfo,
|
||||
activeLivestreamsLastFetchedDate: number,
|
||||
activeLivestreamsLastFetchedOptions: {},
|
||||
|
||||
currentChannelStatus: LivestreamChannelStatus,
|
||||
activeLivestreamInitialized: boolean,
|
||||
}
|
||||
|
||||
declare type LivestreamInfo = {
|
||||
|
|
|
@ -14,8 +14,8 @@ import { withRouter } from 'react-router';
|
|||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
import { selectClientSetting, selectShowMatureContent } from 'redux/selectors/settings';
|
||||
import { doFetchActiveLivestream } from 'redux/actions/livestream';
|
||||
import { selectCurrentChannelStatus } from 'redux/selectors/livestream';
|
||||
|
||||
import { selectActiveLivestreamForChannel, selectActiveLivestreamInitialized } from 'redux/selectors/livestream';
|
||||
import { getChannelIdFromClaim } from 'util/claim';
|
||||
import ChannelContent from './view';
|
||||
|
||||
const select = (state, props) => {
|
||||
|
@ -23,6 +23,7 @@ const select = (state, props) => {
|
|||
const urlParams = new URLSearchParams(search);
|
||||
const page = urlParams.get('page') || 0;
|
||||
const claim = props.uri && selectClaimForUri(state, props.uri);
|
||||
const channelClaimId = getChannelIdFromClaim(claim);
|
||||
|
||||
return {
|
||||
pageOfClaimsInChannel: makeSelectClaimsInChannelForPage(props.uri, page)(state),
|
||||
|
@ -34,7 +35,8 @@ const select = (state, props) => {
|
|||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
showMature: selectShowMatureContent(state),
|
||||
tileLayout: selectClientSetting(state, SETTINGS.TILE_LAYOUT),
|
||||
currentChannelStatus: selectCurrentChannelStatus(state),
|
||||
activeLivestreamForChannel: selectActiveLivestreamForChannel(state, channelClaimId),
|
||||
activeLivestreamInitialized: selectActiveLivestreamInitialized(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ type Props = {
|
|||
claimType: string,
|
||||
empty?: string,
|
||||
doFetchActiveLivestream: (string) => void,
|
||||
currentChannelStatus: LivestreamChannelStatus,
|
||||
activeLivestreamForChannel: any,
|
||||
activeLivestreamInitialized: boolean,
|
||||
};
|
||||
|
||||
function ChannelContent(props: Props) {
|
||||
|
@ -59,7 +60,8 @@ function ChannelContent(props: Props) {
|
|||
claimType,
|
||||
empty,
|
||||
doFetchActiveLivestream,
|
||||
currentChannelStatus,
|
||||
activeLivestreamForChannel,
|
||||
activeLivestreamInitialized,
|
||||
} = props;
|
||||
// const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0;
|
||||
const claimsInChannel = 9999;
|
||||
|
@ -252,8 +254,8 @@ function ChannelContent(props: Props) {
|
|||
setSearchResults(null);
|
||||
}, [url]);
|
||||
|
||||
const [isInitialized, setIsInitialized] = React.useState(false);
|
||||
const [isChannelBroadcasting, setIsChannelBroadcasting] = React.useState(false);
|
||||
const isInitialized = Boolean(activeLivestreamForChannel) || activeLivestreamInitialized;
|
||||
const isChannelBroadcasting = Boolean(activeLivestreamForChannel);
|
||||
|
||||
// Find out current channels status + active live claim.
|
||||
React.useEffect(() => {
|
||||
|
@ -262,14 +264,6 @@ function ChannelContent(props: Props) {
|
|||
return () => clearInterval(intervalId);
|
||||
}, [claimId, doFetchActiveLivestream]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const initialized = currentChannelStatus.channelId === claimId;
|
||||
setIsInitialized(initialized);
|
||||
if (initialized) {
|
||||
setIsChannelBroadcasting(currentChannelStatus.isBroadcasting);
|
||||
}
|
||||
}, [currentChannelStatus, claimId]);
|
||||
|
||||
const showScheduledLiveStreams = claimType !== 'collection'; // ie. not on the playlist page.
|
||||
|
||||
return (
|
||||
|
@ -279,7 +273,7 @@ function ChannelContent(props: Props) {
|
|||
)}
|
||||
|
||||
{!fetching && isInitialized && isChannelBroadcasting && !isChannelEmpty && (
|
||||
<LivestreamLink claimUri={currentChannelStatus.liveClaim.claimUri} />
|
||||
<LivestreamLink claimUri={activeLivestreamForChannel.claimUri} />
|
||||
)}
|
||||
|
||||
{!fetching && showScheduledLiveStreams && (
|
||||
|
@ -287,7 +281,7 @@ function ChannelContent(props: Props) {
|
|||
channelIds={[claimId]}
|
||||
tileLayout={tileLayout}
|
||||
liveUris={
|
||||
isChannelBroadcasting && currentChannelStatus.liveClaim ? [currentChannelStatus.liveClaim.claimUri] : []
|
||||
isChannelBroadcasting && activeLivestreamForChannel.claimUri ? [activeLivestreamForChannel.claimUri] : []
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import { createContext } from 'react';
|
||||
|
||||
const ClaimListDiscoverContext = createContext();
|
||||
|
||||
export default ClaimListDiscoverContext;
|
|
@ -5,7 +5,6 @@ import { doClearPublish, doPrepareEdit } from 'redux/actions/publish';
|
|||
import { push } from 'connected-react-router';
|
||||
import ClaimPreviewSubtitle from './view';
|
||||
import { doFetchSubCount, selectSubCountForUri } from 'lbryinc';
|
||||
import { selectIsActiveLivestreamForUri } from 'redux/selectors/livestream';
|
||||
|
||||
const select = (state, props) => {
|
||||
const claim = selectClaimForUri(state, props.uri);
|
||||
|
@ -16,7 +15,6 @@ const select = (state, props) => {
|
|||
pending: makeSelectClaimIsPending(props.uri)(state),
|
||||
isLivestream,
|
||||
subCount: isChannel ? selectSubCountForUri(state, props.uri) : 0,
|
||||
isLivestreamActive: isLivestream && selectIsActiveLivestreamForUri(state, props.uri),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
// @flow
|
||||
import { ENABLE_NO_SOURCE_CLAIMS } from 'config';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
import UriIndicator from 'component/uriIndicator';
|
||||
import DateTime from 'component/dateTime';
|
||||
import LivestreamDateTime from 'component/livestreamDateTime';
|
||||
import Button from 'component/button';
|
||||
import FileViewCountInline from 'component/fileViewCountInline';
|
||||
import { parseURI } from 'util/lbryURI';
|
||||
import ClaimListDiscoverContext from 'component/claimListDiscover/context';
|
||||
import moment from 'moment';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
|
@ -18,12 +17,11 @@ type Props = {
|
|||
isLivestream: boolean,
|
||||
fetchSubCount: (string) => void,
|
||||
subCount: number,
|
||||
isLivestreamActive: boolean,
|
||||
};
|
||||
|
||||
// previews used in channel overview and homepage (and other places?)
|
||||
function ClaimPreviewSubtitle(props: Props) {
|
||||
const { pending, uri, claim, type, beginPublish, isLivestream, isLivestreamActive, fetchSubCount, subCount } = props;
|
||||
const { pending, uri, claim, type, beginPublish, isLivestream, fetchSubCount, subCount } = props;
|
||||
const isChannel = claim && claim.value_type === 'channel';
|
||||
const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0;
|
||||
|
||||
|
@ -41,29 +39,6 @@ function ClaimPreviewSubtitle(props: Props) {
|
|||
({ streamName: name } = parseURI(uri));
|
||||
} catch (e) {}
|
||||
|
||||
const { listingType } = useContext(ClaimListDiscoverContext) || {};
|
||||
|
||||
const LivestreamDateTimeLabel = () => {
|
||||
// If showing in upcoming and in the past. (we allow x time in past to show here if not live yet)
|
||||
if (listingType === 'UPCOMING') {
|
||||
// $FlowFixMe
|
||||
if (moment.unix(claim.value.release_time).isBefore()) {
|
||||
return __('Starting Soon');
|
||||
}
|
||||
} else {
|
||||
// If not in upcoming + live and in the future (started streaming a bit early)
|
||||
// $FlowFixMe
|
||||
if (isLivestreamActive && moment.unix(claim.value.release_time).isAfter()) {
|
||||
return __('Streaming Now');
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{__('Livestream')} <DateTime timeAgo uri={uri} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="media__subtitle">
|
||||
{claim ? (
|
||||
|
@ -82,7 +57,7 @@ function ClaimPreviewSubtitle(props: Props) {
|
|||
|
||||
{!isChannel &&
|
||||
(isLivestream && ENABLE_NO_SOURCE_CLAIMS ? (
|
||||
<LivestreamDateTimeLabel />
|
||||
<LivestreamDateTime uri={uri} />
|
||||
) : (
|
||||
<>
|
||||
<FileViewCountInline uri={uri} isLivestream={isLivestream} />
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// @flow
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { NavLink, withRouter } from 'react-router-dom';
|
||||
import FileThumbnail from 'component/fileThumbnail';
|
||||
import UriIndicator from 'component/uriIndicator';
|
||||
import TruncatedText from 'component/common/truncated-text';
|
||||
import DateTime from 'component/dateTime';
|
||||
import LivestreamDateTime from 'component/livestreamDateTime';
|
||||
import ChannelThumbnail from 'component/channelThumbnail';
|
||||
import FileViewCountInline from 'component/fileViewCountInline';
|
||||
import SubscribeButton from 'component/subscribeButton';
|
||||
|
@ -19,8 +20,6 @@ import FileWatchLaterLink from 'component/fileWatchLaterLink';
|
|||
import ClaimRepostAuthor from 'component/claimRepostAuthor';
|
||||
import ClaimMenuList from 'component/claimMenuList';
|
||||
import CollectionPreviewOverlay from 'component/collectionPreviewOverlay';
|
||||
import ClaimListDiscoverContext from 'component/claimListDiscover/context';
|
||||
import moment from 'moment';
|
||||
// $FlowFixMe cannot resolve ...
|
||||
import PlaceholderTx from 'static/img/placeholderTx.gif';
|
||||
|
||||
|
@ -110,8 +109,6 @@ function ClaimPreviewTile(props: Props) {
|
|||
}
|
||||
}
|
||||
|
||||
const { listingType } = useContext(ClaimListDiscoverContext) || {};
|
||||
|
||||
const signingChannel = claim && claim.signing_channel;
|
||||
const isChannel = claim && claim.value_type === 'channel';
|
||||
const channelUri = !isChannel ? signingChannel && signingChannel.permanent_url : claim && claim.permanent_url;
|
||||
|
@ -175,23 +172,6 @@ function ClaimPreviewTile(props: Props) {
|
|||
liveProperty = (claim) => <>LIVE</>;
|
||||
}
|
||||
|
||||
const LivestreamDateTimeLabel = () => {
|
||||
// If showing in upcoming and in the past. (we allow x time in past to show here if not live yet)
|
||||
if (listingType === 'UPCOMING') {
|
||||
// $FlowFixMe
|
||||
if (moment.unix(claim.value.release_time).isBefore()) {
|
||||
return __('Starting Soon');
|
||||
}
|
||||
} else {
|
||||
// If not in upcoming + live and in the future (started streaming a bit early)
|
||||
// $FlowFixMe
|
||||
if (isLivestreamActive && moment.unix(claim.value.release_time).isAfter()) {
|
||||
return __('Streaming Now');
|
||||
}
|
||||
}
|
||||
return <DateTime timeAgo uri={uri} />;
|
||||
};
|
||||
|
||||
return (
|
||||
<li
|
||||
onClick={handleClick}
|
||||
|
@ -260,7 +240,7 @@ function ClaimPreviewTile(props: Props) {
|
|||
<UriIndicator uri={uri} link />
|
||||
<div className="claim-tile__about--counts">
|
||||
<FileViewCountInline uri={uri} isLivestream={isLivestream} />
|
||||
{isLivestream && <LivestreamDateTimeLabel />}
|
||||
{isLivestream && <LivestreamDateTime uri={uri} />}
|
||||
{!isLivestream && <DateTime timeAgo uri={uri} />}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ import DateTime from 'component/dateTime';
|
|||
import FileViewCount from 'component/fileViewCount';
|
||||
import FileActions from 'component/fileActions';
|
||||
import ClaimPreviewReset from 'component/claimPreviewReset';
|
||||
import LivestreamDateTime from 'component/livestreamDateTime';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
|
@ -13,13 +14,12 @@ type Props = {
|
|||
|
||||
function FileSubtitle(props: Props) {
|
||||
const { uri, livestream = false, isLive = false } = props;
|
||||
const showDateTime = !livestream || (livestream && !isLive);
|
||||
return (
|
||||
<>
|
||||
<div className="media__subtitle--between">
|
||||
<div className="file__viewdate">
|
||||
{showDateTime && <DateTime uri={uri} show={DateTime.SHOW_DATE} />}
|
||||
|
||||
{livestream && isLive && <LivestreamDateTime uri={uri} />}
|
||||
{!livestream && <DateTime uri={uri} show={DateTime.SHOW_DATE} />}
|
||||
<FileViewCount uri={uri} livestream={livestream} isLive={isLive} />
|
||||
</div>
|
||||
|
||||
|
|
14
ui/component/livestreamDateTime/index.js
Normal file
14
ui/component/livestreamDateTime/index.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
||||
import LivestreamDateTime from './view';
|
||||
import { selectActiveLivestreamForUri } from 'redux/selectors/livestream';
|
||||
|
||||
const select = (state, props) => {
|
||||
const claim = props.uri && makeSelectClaimForUri(props.uri)(state);
|
||||
return {
|
||||
claim,
|
||||
activeLivestream: selectActiveLivestreamForUri(state, props.uri),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(select)(LivestreamDateTime);
|
37
ui/component/livestreamDateTime/view.jsx
Normal file
37
ui/component/livestreamDateTime/view.jsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import DateTime from 'component/dateTime';
|
||||
import { LIVESTREAM_STARTED_RECENTLY_BUFFER } from 'constants/livestream';
|
||||
import moment from 'moment';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
claim: any,
|
||||
activeLivestream: any,
|
||||
};
|
||||
|
||||
const LivestreamDateTime = (props: Props) => {
|
||||
const { uri, claim, activeLivestream } = props;
|
||||
|
||||
if (activeLivestream) {
|
||||
return (
|
||||
<span>
|
||||
{__('Started')} <DateTime timeAgo date={activeLivestream.startedStreaming.toDate()} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (
|
||||
moment
|
||||
.unix(claim.value.release_time)
|
||||
.isBetween(moment().subtract(LIVESTREAM_STARTED_RECENTLY_BUFFER, 'minutes'), moment())
|
||||
) {
|
||||
return __('Starting Soon');
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
{__('Live')} <DateTime timeAgo uri={uri} />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default LivestreamDateTime;
|
|
@ -80,7 +80,12 @@ export default function LivestreamLayout(props: Props) {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{activeStreamUri && <LivestreamLink claimUri={activeStreamUri} />}
|
||||
{activeStreamUri && (
|
||||
<LivestreamLink
|
||||
title={__("Click here to access the stream that's currently active")}
|
||||
claimUri={activeStreamUri}
|
||||
/>
|
||||
)}
|
||||
|
||||
<React.Suspense fallback={null}>{isMobile && !hideComments && <LivestreamComments uri={uri} />}</React.Suspense>
|
||||
|
||||
|
|
|
@ -7,17 +7,18 @@ import { useHistory } from 'react-router';
|
|||
import { formatLbryUrlForWeb } from 'util/url';
|
||||
|
||||
type Props = {
|
||||
title?: string,
|
||||
claimUri: string,
|
||||
};
|
||||
|
||||
export default function LivestreamLink(props: Props) {
|
||||
const { claimUri } = props;
|
||||
const { claimUri, title = null } = props;
|
||||
const { push } = useHistory();
|
||||
|
||||
const element = (props: { children: any }) => (
|
||||
<Card
|
||||
className="livestream__channel-link claim-preview__live"
|
||||
title={__('Live stream in progress')}
|
||||
title={title || __('Live stream in progress')}
|
||||
onClick={() => {
|
||||
push(formatLbryUrlForWeb(claimUri));
|
||||
}}
|
||||
|
|
|
@ -8,7 +8,6 @@ import { useIsMediumScreen, useIsLargeScreen } from 'effects/use-screensize';
|
|||
import ClaimListDiscover from 'component/claimListDiscover';
|
||||
import Button from 'component/button';
|
||||
import { LIVESTREAM_UPCOMING_BUFFER } from 'constants/livestream';
|
||||
import ClaimListDiscoverContext from 'component/claimListDiscover/context';
|
||||
|
||||
type Props = {
|
||||
channelIds: Array<string>,
|
||||
|
@ -39,56 +38,54 @@ const ScheduledStreams = (props: Props) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<ClaimListDiscoverContext.Provider value={{ listingType: 'UPCOMING' }}>
|
||||
<div className={'mb-xl'} style={{ display: showUpcomingLivestreams ? 'block' : 'none' }}>
|
||||
<ClaimListDiscover
|
||||
useSkeletonScreen={false}
|
||||
channelIds={channelIds}
|
||||
limitClaimsPerChannel={limitClaimsPerChannel}
|
||||
pageSize={50}
|
||||
streamType={'all'}
|
||||
hasNoSource
|
||||
orderBy={CS.ORDER_BY_NEW_ASC}
|
||||
tileLayout={tileLayout}
|
||||
releaseTime={`>${moment().subtract(LIVESTREAM_UPCOMING_BUFFER, 'minutes').startOf('minute').unix()}`}
|
||||
hideAdvancedFilter
|
||||
hideFilters
|
||||
infiniteScroll={false}
|
||||
showNoSourceClaims
|
||||
hideLayoutButton
|
||||
header={__('Upcoming Livestreams')}
|
||||
maxClaimRender={upcomingMax}
|
||||
excludeUris={liveUris}
|
||||
loadedCallback={loadedCallback}
|
||||
/>
|
||||
{totalUpcomingLivestreams > upcomingMax && !showAllUpcoming && (
|
||||
<div className="livestream-list--view-more">
|
||||
<Button
|
||||
label={__('Show more upcoming livestreams')}
|
||||
button="link"
|
||||
iconRight={ICONS.ARROW_RIGHT}
|
||||
className="claim-grid__title--secondary"
|
||||
onClick={() => {
|
||||
setShowAllUpcoming(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showAllUpcoming && (
|
||||
<div className="livestream-list--view-more">
|
||||
<Button
|
||||
label={__('Show less upcoming livestreams')}
|
||||
button="link"
|
||||
iconRight={ICONS.ARROW_RIGHT}
|
||||
className="claim-grid__title--secondary"
|
||||
onClick={() => {
|
||||
setShowAllUpcoming(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ClaimListDiscoverContext.Provider>
|
||||
<div className={'mb-xl'} style={{ display: showUpcomingLivestreams ? 'block' : 'none' }}>
|
||||
<ClaimListDiscover
|
||||
useSkeletonScreen={false}
|
||||
channelIds={channelIds}
|
||||
limitClaimsPerChannel={limitClaimsPerChannel}
|
||||
pageSize={50}
|
||||
streamType={'all'}
|
||||
hasNoSource
|
||||
orderBy={CS.ORDER_BY_NEW_ASC}
|
||||
tileLayout={tileLayout}
|
||||
releaseTime={`>${moment().subtract(LIVESTREAM_UPCOMING_BUFFER, 'minutes').startOf('minute').unix()}`}
|
||||
hideAdvancedFilter
|
||||
hideFilters
|
||||
infiniteScroll={false}
|
||||
showNoSourceClaims
|
||||
hideLayoutButton
|
||||
header={__('Upcoming Livestreams')}
|
||||
maxClaimRender={upcomingMax}
|
||||
excludeUris={liveUris}
|
||||
loadedCallback={loadedCallback}
|
||||
/>
|
||||
{totalUpcomingLivestreams > upcomingMax && !showAllUpcoming && (
|
||||
<div className="livestream-list--view-more">
|
||||
<Button
|
||||
label={__('Show more upcoming livestreams')}
|
||||
button="link"
|
||||
iconRight={ICONS.ARROW_RIGHT}
|
||||
className="claim-grid__title--secondary"
|
||||
onClick={() => {
|
||||
setShowAllUpcoming(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showAllUpcoming && (
|
||||
<div className="livestream-list--view-more">
|
||||
<Button
|
||||
label={__('Show less upcoming livestreams')}
|
||||
button="link"
|
||||
iconRight={ICONS.ARROW_RIGHT}
|
||||
className="claim-grid__title--secondary"
|
||||
onClick={() => {
|
||||
setShowAllUpcoming(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -6,16 +6,20 @@ import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
|||
import { DISABLE_COMMENTS_TAG } from 'constants/tags';
|
||||
import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket';
|
||||
import { getChannelIdFromClaim } from 'util/claim';
|
||||
import { selectCurrentChannelStatus } from 'redux/selectors/livestream';
|
||||
import { selectActiveLivestreamForChannel, selectActiveLivestreamInitialized } from 'redux/selectors/livestream';
|
||||
import { doFetchActiveLivestream } from 'redux/actions/livestream';
|
||||
import LivestreamPage from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
channelClaimId: getChannelIdFromClaim(selectClaimForUri(state, props.uri)),
|
||||
chatDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state),
|
||||
currentChannelStatus: selectCurrentChannelStatus(state),
|
||||
});
|
||||
const select = (state, props) => {
|
||||
const channelClaimId = getChannelIdFromClaim(selectClaimForUri(state, props.uri));
|
||||
return {
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
channelClaimId,
|
||||
chatDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state),
|
||||
activeLivestreamForChannel: selectActiveLivestreamForChannel(state, channelClaimId),
|
||||
activeLivestreamInitialized: selectActiveLivestreamInitialized(state),
|
||||
};
|
||||
};
|
||||
|
||||
const perform = {
|
||||
doSetPlayingUri,
|
||||
|
|
|
@ -20,7 +20,8 @@ type Props = {
|
|||
doCommentSocketConnect: (string, string) => void,
|
||||
doCommentSocketDisconnect: (string) => void,
|
||||
doFetchActiveLivestream: (string) => void,
|
||||
currentChannelStatus: LivestreamChannelStatus,
|
||||
activeLivestreamForChannel: any,
|
||||
activeLivestreamInitialized: boolean,
|
||||
};
|
||||
|
||||
export default function LivestreamPage(props: Props) {
|
||||
|
@ -35,7 +36,8 @@ export default function LivestreamPage(props: Props) {
|
|||
doCommentSocketConnect,
|
||||
doCommentSocketDisconnect,
|
||||
doFetchActiveLivestream,
|
||||
currentChannelStatus,
|
||||
activeLivestreamForChannel,
|
||||
activeLivestreamInitialized,
|
||||
} = props;
|
||||
|
||||
React.useEffect(() => {
|
||||
|
@ -58,10 +60,9 @@ export default function LivestreamPage(props: Props) {
|
|||
};
|
||||
}, [claimId, uri, doCommentSocketConnect, doCommentSocketDisconnect]);
|
||||
|
||||
const [isInitialized, setIsInitialized] = React.useState(false);
|
||||
const [isChannelBroadcasting, setIsChannelBroadcasting] = React.useState(false);
|
||||
const [isCurrentClaimLive, setIsCurrentClaimLive] = React.useState(false);
|
||||
|
||||
const isInitialized = Boolean(activeLivestreamForChannel) || activeLivestreamInitialized;
|
||||
const isChannelBroadcasting = Boolean(activeLivestreamForChannel);
|
||||
const isCurrentClaimLive = isChannelBroadcasting && activeLivestreamForChannel.claimId === claimId;
|
||||
const livestreamChannelId = channelClaimId || '';
|
||||
|
||||
// Find out current channels status + active live claim.
|
||||
|
@ -71,19 +72,10 @@ export default function LivestreamPage(props: Props) {
|
|||
return () => clearInterval(intervalId);
|
||||
}, [livestreamChannelId, doFetchActiveLivestream]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const initialized = currentChannelStatus.channelId === livestreamChannelId;
|
||||
setIsInitialized(initialized);
|
||||
if (initialized) {
|
||||
setIsChannelBroadcasting(currentChannelStatus.isBroadcasting);
|
||||
setIsCurrentClaimLive(currentChannelStatus.liveClaim.claimId === claimId);
|
||||
}
|
||||
}, [currentChannelStatus, livestreamChannelId, claimId]);
|
||||
|
||||
const [activeStreamUri, setActiveStreamUri] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setActiveStreamUri(!isCurrentClaimLive && isChannelBroadcasting ? currentChannelStatus.liveClaim.claimUri : false);
|
||||
setActiveStreamUri(!isCurrentClaimLive && isChannelBroadcasting ? activeLivestreamForChannel.claimUri : false);
|
||||
}, [isCurrentClaimLive, isChannelBroadcasting]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
// $FlowFixMe
|
||||
|
|
|
@ -165,14 +165,18 @@ export const doFetchActiveLivestream = (channelId: string) => {
|
|||
const liveChannel = await fetchLiveChannel(channelId);
|
||||
const currentlyLiveClaims = await findActiveStreams([channelId], ['release_time'], liveChannel, dispatch);
|
||||
const liveClaim = currentlyLiveClaims[channelId];
|
||||
|
||||
liveChannel[channelId].claimId = liveClaim.stream.claim_id;
|
||||
liveChannel[channelId].claimUri = liveClaim.stream.canonical_url;
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_ACTIVE_LIVESTREAM_COMPLETED,
|
||||
data: { liveClaim: { claimId: liveClaim.stream.claim_id, claimUri: liveClaim.stream.canonical_url } },
|
||||
data: {
|
||||
...liveChannel,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
dispatch({ type: ACTIONS.FETCH_ACTIVE_LIVESTREAM_FAILED });
|
||||
} finally {
|
||||
dispatch({ type: ACTIONS.FETCH_ACTIVE_LIVESTREAM_FINISHED, data: { channelId } });
|
||||
dispatch({ type: ACTIONS.FETCH_ACTIVE_LIVESTREAM_FAILED, data: { channelId } });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,15 +3,6 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
|
||||
const currentChannelStatus: LivestreamChannelStatus = {
|
||||
channelId: null,
|
||||
isBroadcasting: false,
|
||||
liveClaim: {
|
||||
claimId: null,
|
||||
claimUri: null,
|
||||
},
|
||||
};
|
||||
|
||||
const defaultState: LivestreamState = {
|
||||
fetchingById: {},
|
||||
viewersById: {},
|
||||
|
@ -19,10 +10,7 @@ const defaultState: LivestreamState = {
|
|||
activeLivestreams: null,
|
||||
activeLivestreamsLastFetchedDate: 0,
|
||||
activeLivestreamsLastFetchedOptions: {},
|
||||
|
||||
currentChannelStatus: {
|
||||
...currentChannelStatus,
|
||||
},
|
||||
activeLivestreamInitialized: false,
|
||||
};
|
||||
|
||||
export default handleActions(
|
||||
|
@ -70,24 +58,14 @@ export default handleActions(
|
|||
activeLivestreamsLastFetchedOptions,
|
||||
};
|
||||
},
|
||||
|
||||
[ACTIONS.FETCH_ACTIVE_LIVESTREAM_COMPLETED]: (state: LivestreamState, action: any) => {
|
||||
const currentChannelStatus = Object.assign({}, state.currentChannelStatus, {
|
||||
isBroadcasting: true,
|
||||
liveClaim: action.data.liveClaim,
|
||||
});
|
||||
return { ...state, currentChannelStatus };
|
||||
const activeLivestreams = Object.assign({}, state.activeLivestreams || {}, action.data);
|
||||
return { ...state, activeLivestreams, activeLivestreamInitialized: true };
|
||||
},
|
||||
[ACTIONS.FETCH_ACTIVE_LIVESTREAM_FAILED]: (state: LivestreamState) => {
|
||||
const currentChannelStatus = Object.assign({}, state.currentChannelStatus, {
|
||||
isBroadcasting: false,
|
||||
liveClaim: { claimId: null, claimUri: null },
|
||||
});
|
||||
return { ...state, currentChannelStatus };
|
||||
},
|
||||
[ACTIONS.FETCH_ACTIVE_LIVESTREAM_FINISHED]: (state: LivestreamState, action: any) => {
|
||||
const currentChannelStatus = Object.assign({}, state.currentChannelStatus, { channelId: action.data.channelId });
|
||||
return { ...state, currentChannelStatus };
|
||||
[ACTIONS.FETCH_ACTIVE_LIVESTREAM_FAILED]: (state: LivestreamState, action: any) => {
|
||||
const activeLivestreams = state.activeLivestreams;
|
||||
if (activeLivestreams) delete activeLivestreams[action.data.channelId];
|
||||
return { ...state, activeLivestreams: Object.assign({}, activeLivestreams), activeLivestreamInitialized: true };
|
||||
},
|
||||
},
|
||||
defaultState
|
||||
|
|
|
@ -62,6 +62,31 @@ export const selectIsActiveLivestreamForUri = createCachedSelector(
|
|||
}
|
||||
)((state, uri) => String(uri));
|
||||
|
||||
export const selectActiveLivestreamForUri = createCachedSelector(
|
||||
(state, uri) => uri,
|
||||
selectActiveLivestreams,
|
||||
(uri, activeLivestreams) => {
|
||||
if (!uri || !activeLivestreams) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const activeLivestreamValues = Object.values(activeLivestreams);
|
||||
// $FlowFixMe - unable to resolve claimUri
|
||||
return activeLivestreamValues.find((v) => v.claimUri === uri) || null;
|
||||
}
|
||||
)((state, uri) => String(uri));
|
||||
|
||||
export const selectActiveLivestreamForChannel = createCachedSelector(
|
||||
(state, channelId) => channelId,
|
||||
selectActiveLivestreams,
|
||||
(channelId, activeLivestreams) => {
|
||||
if (!channelId || !activeLivestreams) {
|
||||
return null;
|
||||
}
|
||||
return activeLivestreams[channelId] || null;
|
||||
}
|
||||
)((state, channelId) => String(channelId));
|
||||
|
||||
export const selectFetchingActiveLivestreams = (state: State) => selectState(state).fetchingActiveLivestreams;
|
||||
|
||||
export const selectCurrentChannelStatus = (state: State) => selectState(state).currentChannelStatus;
|
||||
export const selectActiveLivestreamInitialized = (state: State) => selectState(state).activeLivestreamInitialized;
|
||||
|
|
Loading…
Reference in a new issue