// @flow import { SITE_NAME } from 'config'; import React from 'react'; import classnames from 'classnames'; import FileRender from 'component/fileRender'; import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle'; import Spinner from 'component/spinner'; import Button from 'component/button'; import Card from 'component/common/card'; import { formatLbryUrlForWeb, formatLbryChannelName } from 'util/url'; import { useHistory } from 'react-router'; import { getThumbnailCdnUrl } from 'util/thumbnail'; import Yrbl from 'component/yrbl'; // $FlowFixMe cannot resolve ... import FileRenderPlaceholder from 'static/img/fileRenderPlaceholder.png'; const LIVESTREAM_STATUS_CHECK_INTERVAL = 30 * 1000; type Props = { uri: string, claim: ?any, costInfo: any, streamingUrl: string, isResolvingUri: boolean, blackListedOutpoints: Array<{ txid: string, nout: number }>, isCurrentClaimLive: boolean, isLivestreamClaim: boolean, claimThumbnail?: string, obscurePreview: boolean, activeLivestreamInitialized: boolean, geoRestriction: ?GeoRestriction, doResolveUri: (uri: string) => void, doPlayUri: (uri: string) => void, doFetchCostInfoForUri: (uri: string) => void, doFetchChannelLiveStatus: (string) => void, doCommentSocketConnect: (string, string, string) => void, doCommentSocketDisconnect: (string, string) => void, doFetchActiveLivestreams: () => void, }; export const EmbedContext = React.createContext(); const EmbedWrapperPage = (props: Props) => { const { uri, claim, costInfo, streamingUrl, isResolvingUri, blackListedOutpoints, isCurrentClaimLive, isLivestreamClaim, claimThumbnail, obscurePreview, activeLivestreamInitialized, geoRestriction, doResolveUri, doPlayUri, doFetchCostInfoForUri, doFetchChannelLiveStatus, doCommentSocketConnect, doCommentSocketDisconnect, doFetchActiveLivestreams, } = props; const { location: { search }, } = useHistory(); const { claim_id: claimId, canonical_url: canonicalUrl, signing_channel: channelClaim } = claim || {}; const containerRef = React.useRef(); const [thumbnail, setThumbnail] = React.useState(FileRenderPlaceholder); const [livestreamsFetched, setLivestreamsFetched] = React.useState(false); const channelUrl = channelClaim && formatLbryChannelName(channelClaim.canonical_url); const urlParams = new URLSearchParams(search); const embedLightBackground = urlParams.get('embedBackgroundLight'); const haveClaim = Boolean(claim); const readyToDisplay = isCurrentClaimLive || (claim && streamingUrl); const isLiveClaimFetching = isLivestreamClaim && !activeLivestreamInitialized; const isLiveClaimStopped = isLivestreamClaim && !isLiveClaimFetching && !readyToDisplay; const loading = (!claim && isResolvingUri) || isLiveClaimFetching; const noContentFound = claim === null && !isResolvingUri; const isPaidContent = costInfo && costInfo.cost > 0; const contentLink = formatLbryUrlForWeb(uri); const signingChannel = claim && claim.signing_channel; const isClaimBlackListed = claim && blackListedOutpoints && blackListedOutpoints.some( (outpoint) => (signingChannel && outpoint.txid === signingChannel.txid && outpoint.nout === signingChannel.nout) || (outpoint.txid === claim.txid && outpoint.nout === claim.nout) ); React.useEffect(() => { if (!claimThumbnail) return; setTimeout(() => { let newThumbnail = claimThumbnail; if ( containerRef.current && containerRef.current.parentElement && containerRef.current.parentElement.offsetWidth ) { const w = containerRef.current.parentElement.offsetWidth; newThumbnail = getThumbnailCdnUrl({ thumbnail: newThumbnail, width: w, height: w }); } if (newThumbnail !== thumbnail) { setThumbnail(newThumbnail); } }, 200); }, [claimThumbnail, thumbnail]); React.useEffect(() => { if (doFetchActiveLivestreams && isLivestreamClaim) { doFetchActiveLivestreams(); setLivestreamsFetched(true); } }, [doFetchActiveLivestreams, isLivestreamClaim]); // Establish web socket connection for viewer count. React.useEffect(() => { if (!isLivestreamClaim || !claimId || !channelUrl || !canonicalUrl) return; const channelName = formatLbryChannelName(channelUrl); doCommentSocketConnect(canonicalUrl, channelName, claimId); return () => { if (claimId) { doCommentSocketDisconnect(claimId, channelName); } }; }, [canonicalUrl, channelUrl, claimId, doCommentSocketConnect, doCommentSocketDisconnect, isLivestreamClaim]); React.useEffect(() => { if (doResolveUri && uri && !haveClaim) { doResolveUri(uri); } if (uri && haveClaim && costInfo && costInfo.cost === 0) { doPlayUri(uri); } }, [doResolveUri, uri, doPlayUri, haveClaim, costInfo]); React.useEffect(() => { if (haveClaim && uri && doFetchCostInfoForUri) { doFetchCostInfoForUri(uri); } }, [uri, haveClaim, doFetchCostInfoForUri]); // Find out current channels status + active live claim every 30 seconds React.useEffect(() => { if (!channelClaim || !livestreamsFetched) return; const { claim_id: channelClaimId } = channelClaim || {}; doFetchChannelLiveStatus(channelClaimId); const intervalId = setInterval(() => doFetchChannelLiveStatus(channelClaimId), LIVESTREAM_STATUS_CHECK_INTERVAL); return () => clearInterval(intervalId); }, [livestreamsFetched, channelClaim, doFetchChannelLiveStatus]); if (isClaimBlackListed) { return (