rename livestream + livestreamsetup pages
This commit is contained in:
parent
17d0d9f1e0
commit
372c6d0d9f
6 changed files with 341 additions and 361 deletions
|
@ -1,13 +1,18 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectMyChannelClaims, selectFetchingMyChannels } from 'lbry-redux';
|
import { doResolveUri } from 'lbry-redux';
|
||||||
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
import { doSetPlayingUri } from 'redux/actions/content';
|
||||||
import { doSetActiveChannel } from 'redux/actions/app';
|
import { doUserSetReferrer } from 'redux/actions/user';
|
||||||
import CreatorDashboardPage from './view';
|
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||||
|
import { selectHasUnclaimedRefereeReward } from 'redux/selectors/rewards';
|
||||||
|
import LivestreamPage from './view';
|
||||||
|
|
||||||
const select = (state) => ({
|
const select = (state) => ({
|
||||||
channels: selectMyChannelClaims(state),
|
hasUnclaimedRefereeReward: selectHasUnclaimedRefereeReward(state),
|
||||||
fetchingChannels: selectFetchingMyChannels(state),
|
isAuthenticated: selectUserVerifiedEmail(state),
|
||||||
activeChannelClaim: selectActiveChannelClaim(state),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, { doSetActiveChannel })(CreatorDashboardPage);
|
export default connect(select, {
|
||||||
|
doSetPlayingUri,
|
||||||
|
doResolveUri,
|
||||||
|
doUserSetReferrer,
|
||||||
|
})(LivestreamPage);
|
||||||
|
|
|
@ -1,240 +1,114 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as PAGES from 'constants/pages';
|
// import { LIVE_STREAM_TAG, BITWAVE_API } from 'constants/livestream';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import Spinner from 'component/spinner';
|
import LivestreamLayout from 'component/livestreamLayout';
|
||||||
import Button from 'component/button';
|
import analytics from 'analytics';
|
||||||
import ChannelSelector from 'component/channelSelector';
|
|
||||||
import Yrbl from 'component/yrbl';
|
|
||||||
import { Lbry } from 'lbry-redux';
|
|
||||||
import { toHex } from '../../util/hex';
|
|
||||||
import ClaimPreview from '../../component/claimPreview';
|
|
||||||
import { FormField } from '../../component/common/form';
|
|
||||||
import * as PUBLISH_MODES from '../../constants/publish_types';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channels: Array<ChannelClaim>,
|
uri: string,
|
||||||
fetchingChannels: boolean,
|
claim: StreamClaim,
|
||||||
activeChannelClaim: ?ChannelClaim,
|
doSetPlayingUri: ({ uri: ?string }) => void,
|
||||||
|
isAuthenticated: boolean,
|
||||||
|
doUserSetReferrer: (string) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CreatorDashboardPage(props: Props) {
|
export default function LivestreamPage(props: Props) {
|
||||||
const { channels, fetchingChannels, activeChannelClaim } = props;
|
const { uri, claim, doSetPlayingUri, isAuthenticated, doUserSetReferrer } = props;
|
||||||
|
const [activeViewers, setActiveViewers] = React.useState(0);
|
||||||
const [sigData, setSigData] = React.useState({ signature: undefined, signing_ts: undefined });
|
|
||||||
|
|
||||||
const hasChannels = channels && channels.length > 0;
|
|
||||||
const activeChannelClaimStr = JSON.stringify(activeChannelClaim);
|
|
||||||
const streamKey = createStreamKey();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (activeChannelClaimStr) {
|
// function checkIsLive() {
|
||||||
const channelClaim = JSON.parse(activeChannelClaimStr);
|
// fetch(`${BITWAVE_API}/`)
|
||||||
|
// .then((res) => res.json())
|
||||||
|
// .then((res) => {
|
||||||
|
// if (!res || !res.data) {
|
||||||
|
// setIsLive(false);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// setActiveViewers(res.data.viewCount);
|
||||||
|
// if (res.data.live) {
|
||||||
|
// setDisplayCountdown(false);
|
||||||
|
// setIsLive(true);
|
||||||
|
// setIsFetching(false);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// // Not live, but see if we can display the countdown;
|
||||||
|
// const scheduledTime = res.data.scheduled;
|
||||||
|
// if (scheduledTime) {
|
||||||
|
// const scheduledDate = new Date(scheduledTime);
|
||||||
|
// const lastLiveTimestamp = res.data.timestamp;
|
||||||
|
// let isLivestreamOver = false;
|
||||||
|
// if (lastLiveTimestamp) {
|
||||||
|
// const timestampDate = new Date(lastLiveTimestamp);
|
||||||
|
// isLivestreamOver = timestampDate.getTime() > scheduledDate.getTime();
|
||||||
|
// }
|
||||||
|
// 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]);
|
||||||
|
|
||||||
// ensure we have a channel
|
const stringifiedClaim = JSON.stringify(claim);
|
||||||
if (channelClaim.claim_id) {
|
React.useEffect(() => {
|
||||||
Lbry.channel_sign({
|
if (uri && stringifiedClaim) {
|
||||||
channel_id: channelClaim.claim_id,
|
const jsonClaim = JSON.parse(stringifiedClaim);
|
||||||
hexdata: toHex(channelClaim.name),
|
|
||||||
})
|
if (jsonClaim) {
|
||||||
.then((data) => {
|
const { txid, nout, claim_id: claimId } = jsonClaim;
|
||||||
console.log(data);
|
const outpoint = `${txid}:${nout}`;
|
||||||
setSigData(data);
|
|
||||||
})
|
analytics.apiLogView(uri, outpoint, claimId);
|
||||||
.catch((error) => {
|
}
|
||||||
setSigData({ signature: null, signing_ts: null });
|
|
||||||
console.error(error);
|
if (!isAuthenticated) {
|
||||||
});
|
const uri = jsonClaim.signing_channel && jsonClaim.signing_channel.permanent_url;
|
||||||
|
if (uri) {
|
||||||
|
doUserSetReferrer(uri.replace('lbry://', ''));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [ activeChannelClaimStr, setSigData ]);
|
}, [uri, stringifiedClaim, isAuthenticated]);
|
||||||
|
|
||||||
function createStreamKey() {
|
|
||||||
if (!activeChannelClaim || !sigData.signature || !sigData.signing_ts) return null;
|
|
||||||
return `${activeChannelClaim.claim_id}?d=${toHex(activeChannelClaim.name)}&s=${sigData.signature}&t=${sigData.signing_ts}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******/
|
|
||||||
|
|
||||||
const LIVE_STREAM_TAG = 'odysee-livestream';
|
|
||||||
|
|
||||||
const [isFetching, setIsFetching] = React.useState(true);
|
|
||||||
const [isLive, setIsLive] = React.useState(false);
|
|
||||||
const [livestreamClaim, setLivestreamClaim] = React.useState(false);
|
|
||||||
const [livestreamClaims, setLivestreamClaims] = React.useState([]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!activeChannelClaimStr) return;
|
// Set playing uri to null so the popout player doesnt start playing the dummy claim if a user navigates back
|
||||||
|
// This can be removed when we start using the app video player, not a bitwave iframe
|
||||||
const channelClaim = JSON.parse(activeChannelClaimStr);
|
doSetPlayingUri({ uri: null });
|
||||||
|
}, [doSetPlayingUri]);
|
||||||
Lbry.claim_search({
|
|
||||||
channel_ids: [channelClaim.claim_id],
|
|
||||||
any_tags: [LIVE_STREAM_TAG],
|
|
||||||
claim_type: ['stream'],
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res && res.items && res.items.length > 0) {
|
|
||||||
const claim = res.items[res.items.length - 1];
|
|
||||||
setLivestreamClaim(claim);
|
|
||||||
setLivestreamClaims(res.items.reverse());
|
|
||||||
} else {
|
|
||||||
setIsFetching(false);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setIsFetching(false);
|
|
||||||
});
|
|
||||||
}, [activeChannelClaimStr]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page className="file-page" filePage livestream>
|
||||||
{fetchingChannels && (
|
<LivestreamLayout uri={uri} activeViewers={activeViewers} />
|
||||||
<div className="main--empty">
|
|
||||||
<Spinner delayed />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!fetchingChannels && !hasChannels && (
|
|
||||||
<Yrbl
|
|
||||||
type="happy"
|
|
||||||
title={__("You haven't created a channel yet, let's fix that!")}
|
|
||||||
actions={
|
|
||||||
<div className="section__actions">
|
|
||||||
<Button
|
|
||||||
button="primary"
|
|
||||||
navigate={`/$/${PAGES.CHANNEL_NEW}`}
|
|
||||||
label={__('Create A Channel')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!fetchingChannels && activeChannelClaim && (
|
|
||||||
<React.Fragment>
|
|
||||||
{/* Channel Selector */}
|
|
||||||
<ChannelSelector hideAnon />
|
|
||||||
|
|
||||||
{/* Display StreamKey */}
|
|
||||||
{ streamKey
|
|
||||||
? (<div>
|
|
||||||
{/* Stream Server Address */}
|
|
||||||
<FormField
|
|
||||||
name={'livestreamServer'}
|
|
||||||
label={'Stream Server'}
|
|
||||||
type={'text'}
|
|
||||||
defaultValue={'rtmp://stream.odysee.com/live'}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Stream Key */}
|
|
||||||
<FormField
|
|
||||||
name={'livestreamKey'}
|
|
||||||
label={'Stream Key'}
|
|
||||||
type={'text'}
|
|
||||||
defaultValue={streamKey}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
</div>)
|
|
||||||
: (
|
|
||||||
<div>
|
|
||||||
<div style={{marginBottom: 'var(--spacing-l)'}}>
|
|
||||||
{JSON.stringify(activeChannelClaim)}
|
|
||||||
</div>
|
|
||||||
{ sigData &&
|
|
||||||
<div>
|
|
||||||
{JSON.stringify(sigData)}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{/* Stream Claim(s) */}
|
|
||||||
{ livestreamClaim && livestreamClaims ? (
|
|
||||||
<div style={{marginTop: 'var(--spacing-l)'}}>
|
|
||||||
<h3>Your LiveStream Claims</h3>
|
|
||||||
|
|
||||||
{livestreamClaims.map(claim => (
|
|
||||||
<ClaimPreview
|
|
||||||
key={claim.uri}
|
|
||||||
uri={claim.permanent_url}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{/*<h3>Your LiveStream Claims</h3>
|
|
||||||
<ClaimPreview
|
|
||||||
uri={livestreamClaim.permanent_url}
|
|
||||||
/>*/}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div style={{marginTop: 'var(--spacing-l)'}}>
|
|
||||||
<div>You must first publish a livestream claim before your stream will be visible!</div>
|
|
||||||
|
|
||||||
{/* Relies on https://github.com/lbryio/lbry-desktop/pull/5669 */}
|
|
||||||
<Button
|
|
||||||
button="primary"
|
|
||||||
navigate={`/$/${PAGES.UPLOAD}?type=${PUBLISH_MODES.LIVESTREAM.toLowerCase()}`}
|
|
||||||
label={__('Create A LiveStream')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Debug Stuff */}
|
|
||||||
{ streamKey && false && (
|
|
||||||
<div style={{marginTop: 'var(--spacing-l)'}}>
|
|
||||||
<h3>Debug Info</h3>
|
|
||||||
|
|
||||||
{/* Channel ID */}
|
|
||||||
<FormField
|
|
||||||
name={'channelId'}
|
|
||||||
label={'Channel ID'}
|
|
||||||
type={'text'}
|
|
||||||
defaultValue={activeChannelClaim.claim_id}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Signature */}
|
|
||||||
<FormField
|
|
||||||
name={'signature'}
|
|
||||||
label={'Signature'}
|
|
||||||
type={'text'}
|
|
||||||
defaultValue={sigData.signature}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Signature TS */}
|
|
||||||
<FormField
|
|
||||||
name={'signaturets'}
|
|
||||||
label={'Signature Timestamp'}
|
|
||||||
type={'text'}
|
|
||||||
defaultValue={sigData.signing_ts}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Hex Data */}
|
|
||||||
<FormField
|
|
||||||
name={'datahex'}
|
|
||||||
label={'Hex Data'}
|
|
||||||
type={'text'}
|
|
||||||
defaultValue={toHex(activeChannelClaim.name)}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Channel Public Key */}
|
|
||||||
<FormField
|
|
||||||
name={'channelpublickey'}
|
|
||||||
label={'Public Key'}
|
|
||||||
type={'text'}
|
|
||||||
defaultValue={activeChannelClaim.value.public_key}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
12
ui/page/livestreamSetup/index.js
Normal file
12
ui/page/livestreamSetup/index.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { selectMyChannelClaims, selectFetchingMyChannels } from 'lbry-redux';
|
||||||
|
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
||||||
|
import LivestreamSetupPage from './view';
|
||||||
|
|
||||||
|
const select = (state) => ({
|
||||||
|
channels: selectMyChannelClaims(state),
|
||||||
|
fetchingChannels: selectFetchingMyChannels(state),
|
||||||
|
activeChannelClaim: selectActiveChannelClaim(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select)(LivestreamSetupPage);
|
221
ui/page/livestreamSetup/view.jsx
Normal file
221
ui/page/livestreamSetup/view.jsx
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
// @flow
|
||||||
|
import * as PAGES from 'constants/pages';
|
||||||
|
import React from 'react';
|
||||||
|
import Page from 'component/page';
|
||||||
|
import Spinner from 'component/spinner';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import ChannelSelector from 'component/channelSelector';
|
||||||
|
import Yrbl from 'component/yrbl';
|
||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
|
import { toHex } from 'util/hex';
|
||||||
|
import ClaimPreview from 'component/claimPreview';
|
||||||
|
import { FormField } from 'component/common/form';
|
||||||
|
import * as PUBLISH_MODES from 'constants/publish_types';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
channels: Array<ChannelClaim>,
|
||||||
|
fetchingChannels: boolean,
|
||||||
|
activeChannelClaim: ?ChannelClaim,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function LivestreamSetupPage(props: Props) {
|
||||||
|
const { channels, fetchingChannels, activeChannelClaim } = props;
|
||||||
|
|
||||||
|
const [sigData, setSigData] = React.useState({ signature: undefined, signing_ts: undefined });
|
||||||
|
|
||||||
|
const hasChannels = channels && channels.length > 0;
|
||||||
|
const activeChannelClaimStr = JSON.stringify(activeChannelClaim);
|
||||||
|
const streamKey = createStreamKey();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (activeChannelClaimStr) {
|
||||||
|
const channelClaim = JSON.parse(activeChannelClaimStr);
|
||||||
|
|
||||||
|
// ensure we have a channel
|
||||||
|
if (channelClaim.claim_id) {
|
||||||
|
Lbry.channel_sign({
|
||||||
|
channel_id: channelClaim.claim_id,
|
||||||
|
hexdata: toHex(channelClaim.name),
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
console.log(data);
|
||||||
|
setSigData(data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setSigData({ signature: null, signing_ts: null });
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [activeChannelClaimStr, setSigData]);
|
||||||
|
|
||||||
|
function createStreamKey() {
|
||||||
|
if (!activeChannelClaim || !sigData.signature || !sigData.signing_ts) return null;
|
||||||
|
return `${activeChannelClaim.claim_id}?d=${toHex(activeChannelClaim.name)}&s=${sigData.signature}&t=${
|
||||||
|
sigData.signing_ts
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******/
|
||||||
|
|
||||||
|
const LIVE_STREAM_TAG = 'odysee-livestream';
|
||||||
|
|
||||||
|
const [isFetching, setIsFetching] = React.useState(true);
|
||||||
|
const [isLive, setIsLive] = React.useState(false);
|
||||||
|
const [livestreamClaim, setLivestreamClaim] = React.useState(false);
|
||||||
|
const [livestreamClaims, setLivestreamClaims] = React.useState([]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!activeChannelClaimStr) return;
|
||||||
|
|
||||||
|
const channelClaim = JSON.parse(activeChannelClaimStr);
|
||||||
|
|
||||||
|
Lbry.claim_search({
|
||||||
|
channel_ids: [channelClaim.claim_id],
|
||||||
|
any_tags: [LIVE_STREAM_TAG],
|
||||||
|
claim_type: ['stream'],
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res && res.items && res.items.length > 0) {
|
||||||
|
const claim = res.items[res.items.length - 1];
|
||||||
|
setLivestreamClaim(claim);
|
||||||
|
setLivestreamClaims(res.items.reverse());
|
||||||
|
} else {
|
||||||
|
setIsFetching(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setIsFetching(false);
|
||||||
|
});
|
||||||
|
}, [activeChannelClaimStr]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
{fetchingChannels && (
|
||||||
|
<div className="main--empty">
|
||||||
|
<Spinner delayed />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!fetchingChannels && !hasChannels && (
|
||||||
|
<Yrbl
|
||||||
|
type="happy"
|
||||||
|
title={__("You haven't created a channel yet, let's fix that!")}
|
||||||
|
actions={
|
||||||
|
<div className="section__actions">
|
||||||
|
<Button button="primary" navigate={`/$/${PAGES.CHANNEL_NEW}`} label={__('Create A Channel')} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!fetchingChannels && activeChannelClaim && (
|
||||||
|
<React.Fragment>
|
||||||
|
{/* Channel Selector */}
|
||||||
|
<ChannelSelector hideAnon />
|
||||||
|
|
||||||
|
{/* Display StreamKey */}
|
||||||
|
{streamKey ? (
|
||||||
|
<div>
|
||||||
|
{/* Stream Server Address */}
|
||||||
|
<FormField
|
||||||
|
name={'livestreamServer'}
|
||||||
|
label={'Stream Server'}
|
||||||
|
type={'text'}
|
||||||
|
defaultValue={'rtmp://stream.odysee.com/live'}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Stream Key */}
|
||||||
|
<FormField name={'livestreamKey'} label={'Stream Key'} type={'text'} defaultValue={streamKey} readOnly />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<div style={{ marginBottom: 'var(--spacing-l)' }}>{JSON.stringify(activeChannelClaim)}</div>
|
||||||
|
{sigData && <div>{JSON.stringify(sigData)}</div>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Stream Claim(s) */}
|
||||||
|
{livestreamClaim && livestreamClaims ? (
|
||||||
|
<div style={{ marginTop: 'var(--spacing-l)' }}>
|
||||||
|
<h3>Your LiveStream Claims</h3>
|
||||||
|
|
||||||
|
{livestreamClaims.map((claim) => (
|
||||||
|
<ClaimPreview key={claim.uri} uri={claim.permanent_url} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/*<h3>Your LiveStream Claims</h3>
|
||||||
|
<ClaimPreview
|
||||||
|
uri={livestreamClaim.permanent_url}
|
||||||
|
/>*/}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div style={{ marginTop: 'var(--spacing-l)' }}>
|
||||||
|
<div>You must first publish a livestream claim before your stream will be visible!</div>
|
||||||
|
|
||||||
|
{/* Relies on https://github.com/lbryio/lbry-desktop/pull/5669 */}
|
||||||
|
<Button
|
||||||
|
button="primary"
|
||||||
|
navigate={`/$/${PAGES.UPLOAD}?type=${PUBLISH_MODES.LIVESTREAM.toLowerCase()}`}
|
||||||
|
label={__('Create A LiveStream')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Debug Stuff */}
|
||||||
|
{streamKey && false && (
|
||||||
|
<div style={{ marginTop: 'var(--spacing-l)' }}>
|
||||||
|
<h3>Debug Info</h3>
|
||||||
|
|
||||||
|
{/* Channel ID */}
|
||||||
|
<FormField
|
||||||
|
name={'channelId'}
|
||||||
|
label={'Channel ID'}
|
||||||
|
type={'text'}
|
||||||
|
defaultValue={activeChannelClaim.claim_id}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Signature */}
|
||||||
|
<FormField
|
||||||
|
name={'signature'}
|
||||||
|
label={'Signature'}
|
||||||
|
type={'text'}
|
||||||
|
defaultValue={sigData.signature}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Signature TS */}
|
||||||
|
<FormField
|
||||||
|
name={'signaturets'}
|
||||||
|
label={'Signature Timestamp'}
|
||||||
|
type={'text'}
|
||||||
|
defaultValue={sigData.signing_ts}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Hex Data */}
|
||||||
|
<FormField
|
||||||
|
name={'datahex'}
|
||||||
|
label={'Hex Data'}
|
||||||
|
type={'text'}
|
||||||
|
defaultValue={toHex(activeChannelClaim.name)}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Channel Public Key */}
|
||||||
|
<FormField
|
||||||
|
name={'channelpublickey'}
|
||||||
|
label={'Public Key'}
|
||||||
|
type={'text'}
|
||||||
|
defaultValue={activeChannelClaim.value.public_key}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,18 +0,0 @@
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { doResolveUri } from 'lbry-redux';
|
|
||||||
import { doSetPlayingUri } from 'redux/actions/content';
|
|
||||||
import { doUserSetReferrer } from 'redux/actions/user';
|
|
||||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
|
||||||
import { selectHasUnclaimedRefereeReward } from 'redux/selectors/rewards';
|
|
||||||
import LivestreamPage from './view';
|
|
||||||
|
|
||||||
const select = (state) => ({
|
|
||||||
hasUnclaimedRefereeReward: selectHasUnclaimedRefereeReward(state),
|
|
||||||
isAuthenticated: selectUserVerifiedEmail(state),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(select, {
|
|
||||||
doSetPlayingUri,
|
|
||||||
doResolveUri,
|
|
||||||
doUserSetReferrer,
|
|
||||||
})(LivestreamPage);
|
|
|
@ -1,114 +0,0 @@
|
||||||
// @flow
|
|
||||||
// import { LIVE_STREAM_TAG, BITWAVE_API } from 'constants/livestream';
|
|
||||||
import React from 'react';
|
|
||||||
import Page from 'component/page';
|
|
||||||
import LivestreamLayout from 'component/livestreamLayout';
|
|
||||||
import analytics from 'analytics';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
uri: string,
|
|
||||||
claim: StreamClaim,
|
|
||||||
doSetPlayingUri: ({ uri: ?string }) => void,
|
|
||||||
isAuthenticated: boolean,
|
|
||||||
doUserSetReferrer: (string) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function LivestreamPage(props: Props) {
|
|
||||||
const { uri, claim, doSetPlayingUri, isAuthenticated, doUserSetReferrer } = props;
|
|
||||||
const [activeViewers, setActiveViewers] = React.useState(0);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
// function checkIsLive() {
|
|
||||||
// fetch(`${BITWAVE_API}/`)
|
|
||||||
// .then((res) => res.json())
|
|
||||||
// .then((res) => {
|
|
||||||
// if (!res || !res.data) {
|
|
||||||
// setIsLive(false);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// setActiveViewers(res.data.viewCount);
|
|
||||||
// if (res.data.live) {
|
|
||||||
// setDisplayCountdown(false);
|
|
||||||
// setIsLive(true);
|
|
||||||
// setIsFetching(false);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// // Not live, but see if we can display the countdown;
|
|
||||||
// const scheduledTime = res.data.scheduled;
|
|
||||||
// if (scheduledTime) {
|
|
||||||
// const scheduledDate = new Date(scheduledTime);
|
|
||||||
// const lastLiveTimestamp = res.data.timestamp;
|
|
||||||
// let isLivestreamOver = false;
|
|
||||||
// if (lastLiveTimestamp) {
|
|
||||||
// const timestampDate = new Date(lastLiveTimestamp);
|
|
||||||
// isLivestreamOver = timestampDate.getTime() > scheduledDate.getTime();
|
|
||||||
// }
|
|
||||||
// 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]);
|
|
||||||
|
|
||||||
const stringifiedClaim = JSON.stringify(claim);
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (uri && stringifiedClaim) {
|
|
||||||
const jsonClaim = JSON.parse(stringifiedClaim);
|
|
||||||
|
|
||||||
if (jsonClaim) {
|
|
||||||
const { txid, nout, claim_id: claimId } = jsonClaim;
|
|
||||||
const outpoint = `${txid}:${nout}`;
|
|
||||||
|
|
||||||
analytics.apiLogView(uri, outpoint, claimId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isAuthenticated) {
|
|
||||||
const uri = jsonClaim.signing_channel && jsonClaim.signing_channel.permanent_url;
|
|
||||||
if (uri) {
|
|
||||||
doUserSetReferrer(uri.replace('lbry://', ''));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [uri, stringifiedClaim, isAuthenticated]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
// Set playing uri to null so the popout player doesnt start playing the dummy claim if a user navigates back
|
|
||||||
// This can be removed when we start using the app video player, not a bitwave iframe
|
|
||||||
doSetPlayingUri({ uri: null });
|
|
||||||
}, [doSetPlayingUri]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page className="file-page" filePage livestream>
|
|
||||||
<LivestreamLayout uri={uri} activeViewers={activeViewers} />
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue