[feat] Add LiveStreaming Support #5691

Merged
neb-b merged 35 commits from feat/go-live into master 2021-03-23 00:48:10 +01:00
6 changed files with 74 additions and 99 deletions
Showing only changes of commit ca569dc4a7 - Show all commits

View file

@ -9,6 +9,7 @@ import Button from 'component/button';
import ClaimListDiscover from 'component/claimListDiscover'; import ClaimListDiscover from 'component/claimListDiscover';
import Ads from 'web/component/ads'; import Ads from 'web/component/ads';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import LivestreamLink from 'component/livestreamLink';
import { Form, FormField } from 'component/common/form'; import { Form, FormField } from 'component/common/form';
import { DEBOUNCE_WAIT_DURATION_MS } from 'constants/search'; import { DEBOUNCE_WAIT_DURATION_MS } from 'constants/search';
import { lighthouse } from 'redux/actions/search'; import { lighthouse } from 'redux/actions/search';
@ -106,6 +107,8 @@ function ChannelContent(props: Props) {
<HiddenNsfwClaims uri={uri} /> <HiddenNsfwClaims uri={uri} />
)} )}
<LivestreamLink uri={uri} />
{!fetching && channelIsBlackListed && ( {!fetching && channelIsBlackListed && (
<section className="card card--section"> <section className="card card--section">
<p> <p>

View file

@ -7,16 +7,21 @@ import FileActions from 'component/fileActions';
type Props = { type Props = {
uri: string, uri: string,
livestream?: boolean, livestream?: boolean,
activeViewers?: number,
}; };
function FileSubtitle(props: Props) { function FileSubtitle(props: Props) {
const { uri, livestream = false } = props; const { uri, livestream = false, activeViewers = 0 } = props;
return ( return (
<div className="media__subtitle--between"> <div className="media__subtitle--between">
<div className="file__viewdate"> <div className="file__viewdate">
{livestream ? <span>{__('Right now')}</span> : <DateTime uri={uri} show={DateTime.SHOW_DATE} />} {livestream ? <span>{__('Right now')}</span> : <DateTime uri={uri} show={DateTime.SHOW_DATE} />}
<FileViewCount uri={uri} /> {livestream ? (
<span>{__('%viewer_count% currently watching', { viewer_count: activeViewers })}</span>
) : (
<FileViewCount uri={uri} />
)}
</div> </div>
<FileActions uri={uri} /> <FileActions uri={uri} />

View file

@ -19,10 +19,11 @@ type Props = {
nsfw: boolean, nsfw: boolean,
isNsfwBlocked: boolean, isNsfwBlocked: boolean,
livestream?: boolean, livestream?: boolean,
activeViewers?: number,
}; };
function FileTitleSection(props: Props) { function FileTitleSection(props: Props) {
const { title, uri, nsfw, isNsfwBlocked, livestream = false } = props; const { title, uri, nsfw, isNsfwBlocked, livestream = false, activeViewers } = props;
return ( return (
<Card <Card
@ -42,7 +43,7 @@ function FileTitleSection(props: Props) {
body={ body={
<React.Fragment> <React.Fragment>
<ClaimInsufficientCredits uri={uri} /> <ClaimInsufficientCredits uri={uri} />
<FileSubtitle uri={uri} livestream={livestream} /> <FileSubtitle uri={uri} livestream={livestream} activeViewers={activeViewers} />
</React.Fragment> </React.Fragment>
} }
actions={ actions={

View file

@ -3,7 +3,6 @@ import { BITWAVE_EMBED_URL } from 'constants/livestream';
import React from 'react'; import React from 'react';
import FileTitleSection from 'component/fileTitleSection'; import FileTitleSection from 'component/fileTitleSection';
import LivestreamComments from 'component/livestreamComments'; import LivestreamComments from 'component/livestreamComments';
import FileThumbnail from 'component/fileThumbnail';
type Props = { type Props = {
uri: string, uri: string,
@ -15,26 +14,23 @@ type Props = {
export default function LivestreamLayout(props: Props) { export default function LivestreamLayout(props: Props) {
const { claim, uri, isLive, activeViewers } = props; const { claim, uri, isLive, activeViewers } = props;
if (!claim) { if (!claim || !claim.signing_channel) {
return null; return null;
} }
const channelName = claim.signing_channel && claim.signing_channel.name; const channelName = claim.signing_channel.name;
const channelClaimId = claim.signing_channel.claim_id;
return ( return (
<> <>
<div className="section card-stack"> <div className="section card-stack">
<div className="file-render file-render--video livestream"> <div className="file-render file-render--video livestream">
<div className="file-viewer"> <div className="file-viewer">
{isLive ? ( <iframe
<iframe src={`${BITWAVE_EMBED_URL}/${channelClaimId}?skin=odysee&autoplay=1`}
src={`${BITWAVE_EMBED_URL}/${'doomtube'}?skin=odysee&autoplay=1`} scrolling="no"
scrolling="no" allowFullScreen
allowFullScreen />
/>
) : (
<FileThumbnail uri={uri} />
)}
</div> </div>
</div> </div>
@ -45,7 +41,7 @@ export default function LivestreamLayout(props: Props) {
})} })}
</div> </div>
)} )}
<FileTitleSection uri={uri} livestream activeViewers={activeViewers} /> <FileTitleSection uri={uri} livestream isLive={isLive} activeViewers={activeViewers} />
</div> </div>
<LivestreamComments uri={uri} /> <LivestreamComments uri={uri} />
</> </>

View file

@ -1,4 +1,5 @@
// @flow // @flow
import { BITWAVE_API } from 'constants/livestream';
import React from 'react'; import React from 'react';
import Card from 'component/common/card'; import Card from 'component/common/card';
import ClaimPreview from 'component/claimPreview'; import ClaimPreview from 'component/claimPreview';
@ -30,27 +31,27 @@ export default function LivestreamLink(props: Props) {
}, [livestreamChannelId]); }, [livestreamChannelId]);
React.useEffect(() => { React.useEffect(() => {
// function fetchIsStreaming() { function fetchIsStreaming() {
// // fetch(``) fetch(`${BITWAVE_API}/MarkPugner`)
// // .then((res) => res.json()) .then((res) => res.json())
// // .then((res) => { .then((res) => {
// // if (res && res.data && res.data.live) { if (res && res.data && res.data.live) {
// // setIsLivestreaming(true); setIsLivestreaming(true);
// // } else { } else {
// // setIsLivestreaming(false); setIsLivestreaming(false);
// // } }
// // }) })
// // .catch((e) => {}); .catch((e) => {});
// } }
// let interval; let interval;
// if (livestreamChannelId) { if (livestreamChannelId) {
// interval = setInterval(fetchIsStreaming, 5000); interval = setInterval(fetchIsStreaming, 5000);
// } }
// return () => { return () => {
// if (interval) { if (interval) {
// clearInterval(interval); clearInterval(interval);
// } }
// }; };
}, [livestreamChannelId]); }, [livestreamChannelId]);
if (!livestreamClaim || !isLivestreaming) { if (!livestreamClaim || !isLivestreaming) {

View file

@ -1,5 +1,5 @@
// @flow // @flow
// import { BITWAVE_API } from 'constants/livestream'; import { BITWAVE_API } from 'constants/livestream';
import React from 'react'; import React from 'react';
import Page from 'component/page'; import Page from 'component/page';
import LivestreamLayout from 'component/livestreamLayout'; import LivestreamLayout from 'component/livestreamLayout';
@ -16,67 +16,36 @@ type Props = {
export default function LivestreamPage(props: Props) { export default function LivestreamPage(props: Props) {
const { uri, claim, doSetPlayingUri, isAuthenticated, doUserSetReferrer } = props; const { uri, claim, doSetPlayingUri, isAuthenticated, doUserSetReferrer } = props;
const [activeViewers, setActiveViewers] = React.useState(0); const [activeViewers, setActiveViewers] = React.useState(0);
const [isLive, setIsLive] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
// function checkIsLive() { function checkIsLive() {
// fetch(`${BITWAVE_API}/`) fetch(`${BITWAVE_API}/MarkPugner`)
// .then((res) => res.json()) .then((res) => res.json())
// .then((res) => { .then((res) => {
// if (!res || !res.data) { if (!res || !res.data) {
// setIsLive(false); setIsLive(false);
// return; return;
// } }
// setActiveViewers(res.data.viewCount);
// if (res.data.live) { setActiveViewers(res.data.viewCount);
// setDisplayCountdown(false);
// setIsLive(true); if (res.data.live) {
// setIsFetching(false); setIsLive(true);
// return; }
// } });
// // Not live, but see if we can display the countdown; }
// const scheduledTime = res.data.scheduled;
// if (scheduledTime) { let interval;
// const scheduledDate = new Date(scheduledTime); checkIsLive();
// const lastLiveTimestamp = res.data.timestamp; if (uri) {
// let isLivestreamOver = false; interval = setInterval(checkIsLive, 10000);
// if (lastLiveTimestamp) { }
// const timestampDate = new Date(lastLiveTimestamp); return () => {
// isLivestreamOver = timestampDate.getTime() > scheduledDate.getTime(); if (interval) {
// } clearInterval(interval);
// if (isLivestreamOver) { }
// setDisplayCountdown(false); };
// setIsLive(false);
// } else {
// const datePlusTenMinuteBuffer = scheduledDate.setMinutes(10, 0, 0);
// const isInFuture = Date.now() < datePlusTenMinuteBuffer;
// if (isInFuture) {
// setDisplayCountdown(true);
// setIsLive(false);
// } else {
// setDisplayCountdown(false);
// setIsLive(false);
// }
// }
// setIsFetching(false);
// } else {
// // Offline and no countdown happening
// setIsLive(false);
// setDisplayCountdown(false);
// setActiveViewers(0);
// setIsFetching(false);
// }
// });
// }
// let interval;
// checkIsLive();
// if (uri) {
// interval = setInterval(checkIsLive, 10000);
// }
// return () => {
// if (interval) {
// clearInterval(interval);
// }
// };
}, [uri]); }, [uri]);
const stringifiedClaim = JSON.stringify(claim); const stringifiedClaim = JSON.stringify(claim);
@ -108,7 +77,7 @@ export default function LivestreamPage(props: Props) {
return ( return (
<Page className="file-page" filePage livestream> <Page className="file-page" filePage livestream>
<LivestreamLayout uri={uri} activeViewers={activeViewers} /> <LivestreamLayout uri={uri} activeViewers={activeViewers} isLive={isLive} />
</Page> </Page>
); );
} }