Also add support for embeds
This commit is contained in:
parent
6b2427768c
commit
239bde0752
6 changed files with 93 additions and 17 deletions
|
@ -55,6 +55,7 @@ const oneTrustScriptSrc = 'https://cdn.cookielaw.org/scripttemplates/otSDKStub.j
|
||||||
|
|
||||||
const LATEST_PATH = `/$/${PAGES.LATEST}/`;
|
const LATEST_PATH = `/$/${PAGES.LATEST}/`;
|
||||||
const LIVE_PATH = `/$/${PAGES.LIVE_NOW}/`;
|
const LIVE_PATH = `/$/${PAGES.LIVE_NOW}/`;
|
||||||
|
const EMBED_PATH = `/$/${PAGES.EMBED}/`;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
language: string,
|
language: string,
|
||||||
|
@ -143,7 +144,7 @@ function App(props: Props) {
|
||||||
const rawReferrerParam = urlParams.get('r');
|
const rawReferrerParam = urlParams.get('r');
|
||||||
const fromLbrytvParam = urlParams.get('sunset');
|
const fromLbrytvParam = urlParams.get('sunset');
|
||||||
const sanitizedReferrerParam = rawReferrerParam && rawReferrerParam.replace(':', '#');
|
const sanitizedReferrerParam = rawReferrerParam && rawReferrerParam.replace(':', '#');
|
||||||
const embedPath = pathname.startsWith(`/$/${PAGES.EMBED}`);
|
const embedPath = pathname.startsWith(EMBED_PATH);
|
||||||
const shouldHideNag = embedPath || pathname.startsWith(`/$/${PAGES.AUTH_VERIFY}`);
|
const shouldHideNag = embedPath || pathname.startsWith(`/$/${PAGES.AUTH_VERIFY}`);
|
||||||
const userId = user && user.id;
|
const userId = user && user.id;
|
||||||
const hasMyChannels = myChannelClaimIds && myChannelClaimIds.length > 0;
|
const hasMyChannels = myChannelClaimIds && myChannelClaimIds.length > 0;
|
||||||
|
@ -156,11 +157,13 @@ function App(props: Props) {
|
||||||
const urlPath = pathname + hash;
|
const urlPath = pathname + hash;
|
||||||
const latestContentPath = urlPath.startsWith(LATEST_PATH);
|
const latestContentPath = urlPath.startsWith(LATEST_PATH);
|
||||||
const liveContentPath = urlPath.startsWith(LIVE_PATH);
|
const liveContentPath = urlPath.startsWith(LIVE_PATH);
|
||||||
const isNewestPath = latestContentPath || liveContentPath;
|
const featureParam = urlParams.get('feature');
|
||||||
|
const embedLatestPath = embedPath && (featureParam === PAGES.LATEST || featureParam === PAGES.LIVE_NOW);
|
||||||
|
const isNewestPath = latestContentPath || liveContentPath || embedLatestPath;
|
||||||
|
|
||||||
let path;
|
let path;
|
||||||
if (isNewestPath) {
|
if (isNewestPath) {
|
||||||
path = urlPath.replace(latestContentPath ? LATEST_PATH : LIVE_PATH, '');
|
path = urlPath.replace(embedLatestPath ? EMBED_PATH : latestContentPath ? LATEST_PATH : LIVE_PATH, '');
|
||||||
} else {
|
} else {
|
||||||
// Remove the leading "/" added by the browser
|
// Remove the leading "/" added by the browser
|
||||||
path = urlPath.slice(1);
|
path = urlPath.slice(1);
|
||||||
|
@ -515,7 +518,7 @@ function App(props: Props) {
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Router uri={uri} />
|
<Router uri={uri} embedLatestPath={embedLatestPath} />
|
||||||
<ModalRouter />
|
<ModalRouter />
|
||||||
|
|
||||||
<React.Suspense fallback={null}>{renderFiledrop && <FileDrop />}</React.Suspense>
|
<React.Suspense fallback={null}>{renderFiledrop && <FileDrop />}</React.Suspense>
|
||||||
|
|
|
@ -136,6 +136,7 @@ type Props = {
|
||||||
hideTitleNotificationCount: boolean,
|
hideTitleNotificationCount: boolean,
|
||||||
hasDefaultChannel: boolean,
|
hasDefaultChannel: boolean,
|
||||||
doSetActiveChannel: (claimId: ?string, override?: boolean) => void,
|
doSetActiveChannel: (claimId: ?string, override?: boolean) => void,
|
||||||
|
embedLatestPath: ?boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
type PrivateRouteProps = Props & {
|
type PrivateRouteProps = Props & {
|
||||||
|
@ -179,6 +180,7 @@ function AppRouter(props: Props) {
|
||||||
hideTitleNotificationCount,
|
hideTitleNotificationCount,
|
||||||
hasDefaultChannel,
|
hasDefaultChannel,
|
||||||
doSetActiveChannel,
|
doSetActiveChannel,
|
||||||
|
embedLatestPath,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const defaultChannelRef = React.useRef(hasDefaultChannel);
|
const defaultChannelRef = React.useRef(hasDefaultChannel);
|
||||||
|
@ -397,7 +399,11 @@ function AppRouter(props: Props) {
|
||||||
|
|
||||||
<Route path={`/$/${PAGES.POPOUT}/:channelName/:streamName`} component={PopoutChatPage} />
|
<Route path={`/$/${PAGES.POPOUT}/:channelName/:streamName`} component={PopoutChatPage} />
|
||||||
|
|
||||||
<Route path={`/$/${PAGES.EMBED}/:claimName`} exact component={EmbedWrapperPage} />
|
<Route
|
||||||
|
path={`/$/${PAGES.EMBED}/:claimName`}
|
||||||
|
exact
|
||||||
|
component={embedLatestPath ? () => <EmbedWrapperPage uri={uri} /> : EmbedWrapperPage}
|
||||||
|
/>
|
||||||
<Route path={`/$/${PAGES.EMBED}/:claimName/:claimId`} exact component={EmbedWrapperPage} />
|
<Route path={`/$/${PAGES.EMBED}/:claimName/:claimId`} exact component={EmbedWrapperPage} />
|
||||||
|
|
||||||
{/* Below need to go at the end to make sure we don't match any of our pages first */}
|
{/* Below need to go at the end to make sure we don't match any of our pages first */}
|
||||||
|
|
|
@ -1,31 +1,60 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import EmbedWrapperPage from './view';
|
import EmbedWrapperPage from './view';
|
||||||
import { selectClaimForUri, selectIsUriResolving, selectGeoRestrictionForUri } from 'redux/selectors/claims';
|
import * as PAGES from 'constants/pages';
|
||||||
|
import {
|
||||||
|
selectClaimForUri,
|
||||||
|
selectIsUriResolving,
|
||||||
|
selectGeoRestrictionForUri,
|
||||||
|
selectLatestClaimByUri,
|
||||||
|
} from 'redux/selectors/claims';
|
||||||
import { makeSelectStreamingUrlForUri } from 'redux/selectors/file_info';
|
import { makeSelectStreamingUrlForUri } from 'redux/selectors/file_info';
|
||||||
import { doResolveUri } from 'redux/actions/claims';
|
import { doResolveUri, doFetchLatestClaimForChannel } from 'redux/actions/claims';
|
||||||
import { buildURI } from 'util/lbryURI';
|
import { buildURI } from 'util/lbryURI';
|
||||||
import { doPlayUri } from 'redux/actions/content';
|
import { doPlayUri } from 'redux/actions/content';
|
||||||
import { selectShouldObscurePreviewForUri } from 'redux/selectors/content';
|
import { selectShouldObscurePreviewForUri } from 'redux/selectors/content';
|
||||||
import { selectCostInfoForUri, doFetchCostInfoForUri, selectBlackListedOutpoints } from 'lbryinc';
|
import { selectCostInfoForUri, doFetchCostInfoForUri, selectBlackListedOutpoints } from 'lbryinc';
|
||||||
import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket';
|
import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket';
|
||||||
import { doFetchActiveLivestreams, doFetchChannelLiveStatus } from 'redux/actions/livestream';
|
import { doFetchActiveLivestreams, doFetchChannelLiveStatus } from 'redux/actions/livestream';
|
||||||
import { selectIsActiveLivestreamForUri, selectActiveLivestreamInitialized } from 'redux/selectors/livestream';
|
import {
|
||||||
|
selectIsActiveLivestreamForUri,
|
||||||
|
selectActiveLivestreamInitialized,
|
||||||
|
selectActiveLiveClaimForChannel,
|
||||||
|
} from 'redux/selectors/livestream';
|
||||||
import { getThumbnailFromClaim, isStreamPlaceholderClaim } from 'util/claim';
|
import { getThumbnailFromClaim, isStreamPlaceholderClaim } from 'util/claim';
|
||||||
import { doUserSetReferrerWithUri } from 'redux/actions/user';
|
import { doUserSetReferrerWithUri } from 'redux/actions/user';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const { match } = props;
|
const { search } = state.router.location;
|
||||||
const { params } = match;
|
const { match } = props || {};
|
||||||
const { claimName, claimId } = params;
|
|
||||||
const uri = claimName ? buildURI({ claimName, claimId }) : '';
|
let uri = props.uri;
|
||||||
|
let claimId;
|
||||||
|
if (match) {
|
||||||
|
const { params } = match;
|
||||||
|
const { claimName } = params;
|
||||||
|
claimId = params.claimId;
|
||||||
|
uri = claimName ? buildURI({ claimName, claimId }) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams(search);
|
||||||
|
const featureParam = urlParams.get('feature');
|
||||||
|
const isNewestPath = featureParam === PAGES.LIVE_NOW || featureParam === PAGES.LATEST;
|
||||||
|
|
||||||
const claim = selectClaimForUri(state, uri);
|
const claim = selectClaimForUri(state, uri);
|
||||||
const { canonical_url: canonicalUrl, signing_channel: channelClaim, txid, nout } = claim || {};
|
const { canonical_url: canonicalUrl, signing_channel: channelClaim, txid, nout } = claim || {};
|
||||||
|
if (isNewestPath) claimId = claim?.claim_id;
|
||||||
|
|
||||||
const { claim_id: channelClaimId, canonical_url: channelUri, txid: channelTxid, channelNout } = channelClaim || {};
|
const { claim_id: channelClaimId, canonical_url: channelUri, txid: channelTxid, channelNout } = channelClaim || {};
|
||||||
const haveClaim = Boolean(claim);
|
const haveClaim = Boolean(claim);
|
||||||
const nullClaim = claim === null;
|
const nullClaim = claim === null;
|
||||||
|
|
||||||
|
const latestContentClaim =
|
||||||
|
featureParam === PAGES.LIVE_NOW
|
||||||
|
? selectActiveLiveClaimForChannel(state, claimId)
|
||||||
|
: selectLatestClaimByUri(state, canonicalUrl);
|
||||||
|
const latestClaimUrl = latestContentClaim && latestContentClaim.canonical_url;
|
||||||
|
if (latestClaimUrl) uri = latestClaimUrl;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uri,
|
uri,
|
||||||
claimId,
|
claimId,
|
||||||
|
@ -38,11 +67,13 @@ const select = (state, props) => {
|
||||||
channelClaimId,
|
channelClaimId,
|
||||||
channelTxid,
|
channelTxid,
|
||||||
channelNout,
|
channelNout,
|
||||||
|
latestClaimUrl,
|
||||||
|
isNewestPath,
|
||||||
costInfo: uri && selectCostInfoForUri(state, uri),
|
costInfo: uri && selectCostInfoForUri(state, uri),
|
||||||
streamingUrl: uri && makeSelectStreamingUrlForUri(uri)(state),
|
streamingUrl: uri && makeSelectStreamingUrlForUri(uri)(state),
|
||||||
isResolvingUri: uri && selectIsUriResolving(state, uri),
|
isResolvingUri: uri && selectIsUriResolving(state, uri),
|
||||||
blackListedOutpoints: haveClaim && selectBlackListedOutpoints(state),
|
blackListedOutpoints: haveClaim && selectBlackListedOutpoints(state),
|
||||||
isCurrentClaimLive: canonicalUrl && selectIsActiveLivestreamForUri(state, canonicalUrl),
|
isCurrentClaimLive: selectIsActiveLivestreamForUri(state, isNewestPath ? latestClaimUrl : canonicalUrl),
|
||||||
isLivestreamClaim: isStreamPlaceholderClaim(claim),
|
isLivestreamClaim: isStreamPlaceholderClaim(claim),
|
||||||
obscurePreview: selectShouldObscurePreviewForUri(state, uri),
|
obscurePreview: selectShouldObscurePreviewForUri(state, uri),
|
||||||
claimThumbnail: getThumbnailFromClaim(claim),
|
claimThumbnail: getThumbnailFromClaim(claim),
|
||||||
|
@ -60,6 +91,7 @@ const perform = {
|
||||||
doCommentSocketDisconnect,
|
doCommentSocketDisconnect,
|
||||||
doFetchActiveLivestreams,
|
doFetchActiveLivestreams,
|
||||||
setReferrer: doUserSetReferrerWithUri,
|
setReferrer: doUserSetReferrerWithUri,
|
||||||
|
fetchLatestClaimForChannel: doFetchLatestClaimForChannel,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(select, perform)(EmbedWrapperPage);
|
export default connect(select, perform)(EmbedWrapperPage);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { SITE_NAME } from 'config';
|
import { SITE_NAME } from 'config';
|
||||||
|
import * as PAGES from 'constants/pages';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import FileRender from 'component/fileRender';
|
import FileRender from 'component/fileRender';
|
||||||
|
@ -36,6 +37,9 @@ type Props = {
|
||||||
obscurePreview: boolean,
|
obscurePreview: boolean,
|
||||||
activeLivestreamInitialized: boolean,
|
activeLivestreamInitialized: boolean,
|
||||||
geoRestriction: ?GeoRestriction,
|
geoRestriction: ?GeoRestriction,
|
||||||
|
latestClaimUrl: ?string,
|
||||||
|
isNewestPath: ?boolean,
|
||||||
|
fetchLatestClaimForChannel: (uri: string, isEmbed: boolean) => void,
|
||||||
doResolveUri: (uri: string) => void,
|
doResolveUri: (uri: string) => void,
|
||||||
doPlayUri: (uri: string) => void,
|
doPlayUri: (uri: string) => void,
|
||||||
doFetchCostInfoForUri: (uri: string) => void,
|
doFetchCostInfoForUri: (uri: string) => void,
|
||||||
|
@ -71,6 +75,9 @@ export default function EmbedWrapperPage(props: Props) {
|
||||||
obscurePreview,
|
obscurePreview,
|
||||||
activeLivestreamInitialized,
|
activeLivestreamInitialized,
|
||||||
geoRestriction,
|
geoRestriction,
|
||||||
|
latestClaimUrl,
|
||||||
|
isNewestPath,
|
||||||
|
fetchLatestClaimForChannel,
|
||||||
doResolveUri,
|
doResolveUri,
|
||||||
doPlayUri,
|
doPlayUri,
|
||||||
doFetchCostInfoForUri,
|
doFetchCostInfoForUri,
|
||||||
|
@ -90,6 +97,9 @@ export default function EmbedWrapperPage(props: Props) {
|
||||||
|
|
||||||
const channelUrl = channelUri && formatLbryChannelName(channelUri);
|
const channelUrl = channelUri && formatLbryChannelName(channelUri);
|
||||||
const urlParams = new URLSearchParams(search);
|
const urlParams = new URLSearchParams(search);
|
||||||
|
const featureParam = urlParams.get('feature');
|
||||||
|
const latestContentPath = featureParam === PAGES.LATEST;
|
||||||
|
const liveContentPath = featureParam === PAGES.LIVE_NOW;
|
||||||
const rawReferrerParam = urlParams.get('r');
|
const rawReferrerParam = urlParams.get('r');
|
||||||
const sanitizedReferrerParam = rawReferrerParam && rawReferrerParam.replace(':', '#');
|
const sanitizedReferrerParam = rawReferrerParam && rawReferrerParam.replace(':', '#');
|
||||||
const embedLightBackground = urlParams.get('embedBackgroundLight');
|
const embedLightBackground = urlParams.get('embedBackgroundLight');
|
||||||
|
@ -111,6 +121,18 @@ export default function EmbedWrapperPage(props: Props) {
|
||||||
|
|
||||||
const thumbnail = useThumbnail(claimThumbnail, containerRef);
|
const thumbnail = useThumbnail(claimThumbnail, containerRef);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!latestClaimUrl && liveContentPath && claimId) {
|
||||||
|
doFetchChannelLiveStatus(claimId);
|
||||||
|
}
|
||||||
|
}, [claimId, doFetchChannelLiveStatus, latestClaimUrl, liveContentPath]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!latestClaimUrl && latestContentPath && canonicalUrl) {
|
||||||
|
fetchLatestClaimForChannel(canonicalUrl, true);
|
||||||
|
}
|
||||||
|
}, [canonicalUrl, fetchLatestClaimForChannel, latestClaimUrl, latestContentPath]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!sanitizedReferrerParam) setReferrer(uri);
|
if (!sanitizedReferrerParam) setReferrer(uri);
|
||||||
}, [sanitizedReferrerParam, setReferrer, uri]);
|
}, [sanitizedReferrerParam, setReferrer, uri]);
|
||||||
|
@ -142,10 +164,10 @@ export default function EmbedWrapperPage(props: Props) {
|
||||||
doResolveUri(uri);
|
doResolveUri(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri && haveClaim && costInfo && costInfo.cost === 0) {
|
if (uri && (isNewestPath ? latestClaimUrl : haveClaim) && costInfo && costInfo.cost === 0) {
|
||||||
doPlayUri(uri);
|
doPlayUri(uri);
|
||||||
}
|
}
|
||||||
}, [doPlayUri, doResolveUri, haveClaim, costInfo, uri]);
|
}, [doPlayUri, doResolveUri, haveClaim, costInfo, uri, isNewestPath, latestClaimUrl]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (haveClaim && uri && doFetchCostInfoForUri) {
|
if (haveClaim && uri && doFetchCostInfoForUri) {
|
||||||
|
@ -155,6 +177,15 @@ export default function EmbedWrapperPage(props: Props) {
|
||||||
|
|
||||||
useFetchLiveStatus(livestreamsFetched ? channelClaimId : undefined, doFetchChannelLiveStatus);
|
useFetchLiveStatus(livestreamsFetched ? channelClaimId : undefined, doFetchChannelLiveStatus);
|
||||||
|
|
||||||
|
// Wait for latest claim fetch
|
||||||
|
if (isNewestPath && latestClaimUrl === undefined) {
|
||||||
|
return (
|
||||||
|
<div className="main--empty">
|
||||||
|
<Spinner delayed />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (isClaimBlackListed) {
|
if (isClaimBlackListed) {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
|
|
@ -1135,7 +1135,10 @@ export const doCheckPendingClaims = (onChannelConfirmed: Function) => (dispatch:
|
||||||
}, 30000);
|
}, 30000);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const doFetchLatestClaimForChannel = (uri: string) => (dispatch: Dispatch, getState: GetState) => {
|
export const doFetchLatestClaimForChannel = (uri: string, isEmbed?: boolean) => (
|
||||||
|
dispatch: Dispatch,
|
||||||
|
getState: GetState
|
||||||
|
) => {
|
||||||
const searchOptions = {
|
const searchOptions = {
|
||||||
limit_claims_per_channel: 1,
|
limit_claims_per_channel: 1,
|
||||||
channel: uri,
|
channel: uri,
|
||||||
|
@ -1143,6 +1146,7 @@ export const doFetchLatestClaimForChannel = (uri: string) => (dispatch: Dispatch
|
||||||
order_by: ['release_time'],
|
order_by: ['release_time'],
|
||||||
page: 1,
|
page: 1,
|
||||||
has_source: true,
|
has_source: true,
|
||||||
|
stream_types: isEmbed ? ['audio', 'video'] : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
return dispatch(doClaimSearch(searchOptions))
|
return dispatch(doClaimSearch(searchOptions))
|
||||||
|
|
|
@ -66,7 +66,7 @@ export const selectIsActiveLivestreamForUri = createCachedSelector(
|
||||||
|
|
||||||
const activeLivestreamValues = Object.values(activeLivestreams);
|
const activeLivestreamValues = Object.values(activeLivestreams);
|
||||||
// $FlowFixMe - unable to resolve claimUri
|
// $FlowFixMe - unable to resolve claimUri
|
||||||
return activeLivestreamValues.some((v) => v.claimUri === uri);
|
return activeLivestreamValues.some((v) => v?.claimUri === uri);
|
||||||
}
|
}
|
||||||
)((state, uri) => String(uri));
|
)((state, uri) => String(uri));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue