diff --git a/package.json b/package.json index 0c662a04b..8498b29d3 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "imagesloaded": "^4.1.4", "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", - "lbry-redux": "lbryio/lbry-redux#c494c92505cd531048de20bc37dc4d192b6ace01", + "lbry-redux": "lbryio/lbry-redux#db27091f5add9a6bb91c38471a369fca144fc96f", "lbryinc": "lbryio/lbryinc#7faea40d87b78ec91b901c62f501499dc4737025", "lint-staged": "^7.0.2", "localforage": "^1.7.1", diff --git a/ui/component/claimPreview/view.jsx b/ui/component/claimPreview/view.jsx index eb952e9e8..588e67a2b 100644 --- a/ui/component/claimPreview/view.jsx +++ b/ui/component/claimPreview/view.jsx @@ -249,106 +249,110 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { 'claim-preview__wrapper--small': type === 'small', })} > - {!hideRepostLabel && } + <> + {!hideRepostLabel && } -
- {isChannelUri && claim ? ( - - - - ) : ( - <> - {!pending ? ( - - - {/* @if TARGET='app' */} - {claim && ( -
- -
- )} - {/* @endif */} - {!isRepost && !isChannelUri && !isLivestream && ( -
- -
- )} -
-
- ) : ( - - )} - - )} - -
-
-
- {pending ? ( - - ) : ( +
+ {isChannelUri && claim ? ( + + + + ) : ( + <> + {!pending ? ( - + + {/* @if TARGET='app' */} + {claim && ( +
+ +
+ )} + {/* @endif */} + {!isRepost && !isChannelUri && !isLivestream && ( +
+ +
+ )} +
+ ) : ( + )} + + )} - {/* {type !== 'small' && !isChannelUri && signingChannel && SIMPLE_SITE && ( +
+
+
+ {pending ? ( + + ) : ( + + + + )} + + {/* {type !== 'small' && !isChannelUri && signingChannel && SIMPLE_SITE && ( )} */} +
+ + {(pending || !!reflectingProgress) && }
- - {(pending || !!reflectingProgress) && } + {type !== 'small' && ( +
+ {!pending && ( + <> + {renderActions && claim && renderActions(claim)} + {shouldHideActions || renderActions ? null : actions !== undefined ? ( + actions + ) : ( +
+ {!isChannelUri && signingChannel && ( +
+ +
+ )} + + {isChannelUri && !channelIsBlocked && !claimIsMine && ( + + )} + + {includeSupportAction && } +
+ )} + + )} + {claim && ( + + {typeof properties === 'function' ? ( + properties(claim) + ) : properties !== undefined ? ( + properties + ) : ( + + )} + + )} +
+ )}
- {type !== 'small' && ( -
- {!pending && ( - <> - {renderActions && claim && renderActions(claim)} - {shouldHideActions || renderActions ? null : actions !== undefined ? ( - actions - ) : ( -
- {!isChannelUri && signingChannel && ( -
- -
- )} - - {isChannelUri && !channelIsBlocked && !claimIsMine && ( - - )} - - {includeSupportAction && } -
- )} - - )} - {claim && ( - - {typeof properties === 'function' ? ( - properties(claim) - ) : properties !== undefined ? ( - properties - ) : ( - - )} - - )} -
- )}
-
- {!hideMenu && } + {!hideMenu && } + ); }); diff --git a/ui/component/claimPreviewTile/index.js b/ui/component/claimPreviewTile/index.js index aba27e1ac..256ca5f45 100644 --- a/ui/component/claimPreviewTile/index.js +++ b/ui/component/claimPreviewTile/index.js @@ -8,7 +8,7 @@ import { doFileGet, makeSelectChannelForClaimUri, makeSelectClaimIsNsfw, - makeSelectClaimHasSource, + makeSelectClaimIsStreamPlaceholder, } from 'lbry-redux'; import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; @@ -26,7 +26,7 @@ const select = (state, props) => ({ blockedChannelUris: selectMutedChannels(state), showMature: selectShowMatureContent(state), isMature: makeSelectClaimIsNsfw(props.uri)(state), - isLivestream: !makeSelectClaimHasSource(props.uri)(state), + isLivestream: makeSelectClaimIsStreamPlaceholder(props.uri)(state), }); const perform = (dispatch) => ({ diff --git a/ui/component/common/card.jsx b/ui/component/common/card.jsx index f3b06deb1..c87122339 100644 --- a/ui/component/common/card.jsx +++ b/ui/component/common/card.jsx @@ -21,6 +21,7 @@ type Props = { nag?: Node, smallTitle?: boolean, onClick?: () => void, + children?: any, // not sure how this works }; export default function Card(props: Props) { @@ -39,6 +40,7 @@ export default function Card(props: Props) { defaultExpand, nag, onClick, + children, } = props; const [expanded, setExpanded] = useState(defaultExpand); const expandable = defaultExpand !== undefined; @@ -102,6 +104,7 @@ export default function Card(props: Props) {
)} {actions &&
{actions}
} + {children &&
{children}
} )} diff --git a/ui/component/livestreamLink/view.jsx b/ui/component/livestreamLink/view.jsx index 39a1eaf13..a576c1ebc 100644 --- a/ui/component/livestreamLink/view.jsx +++ b/ui/component/livestreamLink/view.jsx @@ -64,11 +64,12 @@ export default function LivestreamLink(props: Props) { return null; } - return ( - } - /> + // gonna pass the wrapper in so I don't have to rewrite the dmca/blocking logic in claimPreview. + const element = (props: { children: any }) => ( + + {props.children} + ); + + return ; } diff --git a/ui/component/router/view.jsx b/ui/component/router/view.jsx index 1634bcb7c..65e46eac9 100644 --- a/ui/component/router/view.jsx +++ b/ui/component/router/view.jsx @@ -49,7 +49,6 @@ import BuyPage from 'page/buy'; import NotificationsPage from 'page/notifications'; import SignInWalletPasswordPage from 'page/signInWalletPassword'; import YoutubeSyncPage from 'page/youtubeSync'; -import LiveStreamPage from 'page/livestream'; import { LINKED_COMMENT_QUERY_PARAM } from 'constants/comment'; import { parseURI, isURIValid } from 'lbry-redux'; @@ -286,8 +285,6 @@ function AppRouter(props: Props) { - - {/* Below need to go at the end to make sure we don't match any of our pages first */} diff --git a/ui/page/file/index.js b/ui/page/file/index.js index 07e6511e9..360a4eb55 100644 --- a/ui/page/file/index.js +++ b/ui/page/file/index.js @@ -9,7 +9,7 @@ import { SETTINGS, makeSelectTagInClaimOrChannelForUri, makeSelectClaimIsMine, - makeSelectClaimHasSource, + makeSelectClaimIsStreamPlaceholder, } from 'lbry-redux'; import { makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc'; import { selectShowMatureContent, makeSelectClientSetting } from 'redux/selectors/settings'; @@ -35,7 +35,7 @@ const select = (state, props) => { videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state), commentsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state), claimIsMine: makeSelectClaimIsMine(props.uri)(state), - isLivestream: !makeSelectClaimHasSource(props.uri)(state), + isLivestream: makeSelectClaimIsStreamPlaceholder(props.uri)(state), }; }; diff --git a/ui/page/livestream/view.jsx b/ui/page/livestream/view.jsx index 1d70dd7c7..8115dac8c 100644 --- a/ui/page/livestream/view.jsx +++ b/ui/page/livestream/view.jsx @@ -4,6 +4,7 @@ import React from 'react'; import Page from 'component/page'; import LivestreamLayout from 'component/livestreamLayout'; import analytics from 'analytics'; +import { Lbry } from 'lbry-redux'; type Props = { uri: string, @@ -19,8 +20,41 @@ export default function LivestreamPage(props: Props) { const [activeViewers, setActiveViewers] = React.useState(0); const [isLive, setIsLive] = React.useState(false); const livestreamChannelId = channelClaim && channelClaim.signing_channel && channelClaim.signing_channel.claim_id; + const [hasLivestreamClaim, setHasLivestreamClaim] = React.useState(false); + + const STREAMING_POLL_INTERVAL_IN_MS = 10000; + const LIVESTREAM_CLAIM_POLL_IN_MS = 60000; + + // the component needs to check if the channel has published a new livestream, so we know if it should check + React.useEffect(() => { + let checkClaimsInterval; + function checkHasLivestreamClaim() { + Lbry.claim_search({ + channel_ids: [livestreamChannelId], + has_no_source: true, + claim_type: ['stream'], + }) + .then((res) => { + if (res && res.items && res.items.length > 0) { + setHasLivestreamClaim(true); + } + }) + .catch(() => {}); + } + if (livestreamChannelId && !isLive) { + if (!checkClaimsInterval) checkHasLivestreamClaim(); + checkClaimsInterval = setInterval(checkHasLivestreamClaim, LIVESTREAM_CLAIM_POLL_IN_MS); + + return () => { + if (checkClaimsInterval) { + clearInterval(checkClaimsInterval); + } + }; + } + }, [livestreamChannelId, isLive]); React.useEffect(() => { + let interval; function checkIsLive() { // $FlowFixMe Bitwave's API can handle garbage fetch(`${BITWAVE_API}/${livestreamChannelId}`) @@ -38,19 +72,17 @@ export default function LivestreamPage(props: Props) { } }); } - - let interval; - if (livestreamChannelId) { + if (livestreamChannelId && hasLivestreamClaim) { if (!interval) checkIsLive(); - interval = setInterval(checkIsLive, 10 * 1000); - } + interval = setInterval(checkIsLive, STREAMING_POLL_INTERVAL_IN_MS); - return () => { - if (interval) { - clearInterval(interval); - } - }; - }, [livestreamChannelId]); + return () => { + if (interval) { + clearInterval(interval); + } + }; + } + }, [livestreamChannelId, hasLivestreamClaim]); const stringifiedClaim = JSON.stringify(claim); React.useEffect(() => { diff --git a/ui/page/livestreamSetup/view.jsx b/ui/page/livestreamSetup/view.jsx index 6783fbb1b..a4cad24a5 100644 --- a/ui/page/livestreamSetup/view.jsx +++ b/ui/page/livestreamSetup/view.jsx @@ -24,16 +24,34 @@ type Props = { }; export default function LivestreamSetupPage(props: Props) { + const LIVESTREAM_CLAIM_POLL_IN_MS = 60000; const { channels, fetchingChannels, activeChannelClaim, pendingClaims } = props; const [sigData, setSigData] = React.useState({ signature: undefined, signing_ts: undefined }); const [showHelpTest, setShowHelpTest] = usePersistedState('livestream-help-seen', true); const [spin, setSpin] = React.useState(true); + const [livestreamClaims, setLivestreamClaims] = React.useState([]); const hasChannels = channels && channels.length > 0; const activeChannelClaimStr = JSON.stringify(activeChannelClaim); - const streamKey = createStreamKey(); + 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 streamKey = createStreamKey(); + const pendingLiveStreamClaims = pendingClaims + ? pendingClaims.filter( + (claim) => + // $FlowFixMe + claim.value_type === 'stream' && !(claim.value && claim.value.source) + ) + : []; + const pendingLength = pendingLiveStreamClaims.length; + const totalLivestreamClaims = pendingLiveStreamClaims.concat(livestreamClaims); const helpText = (

@@ -76,6 +94,7 @@ export default function LivestreamSetupPage(props: Props) {

{__(`Click Save and you are done!`)}

); + React.useEffect(() => { if (activeChannelClaimStr) { const channelClaim = JSON.parse(activeChannelClaimStr); @@ -96,47 +115,44 @@ export default function LivestreamSetupPage(props: Props) { } }, [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 [livestreamClaims, setLivestreamClaims] = React.useState([]); - const pendingLiveStreamClaims = - // $FlowFixMe - pendingClaims ? pendingClaims.filter((claim) => !(claim && claim.value && claim.value.source)) : []; - const pendingLength = pendingLiveStreamClaims.length; - const totalLivestreamClaims = pendingLiveStreamClaims.concat(livestreamClaims); - React.useEffect(() => { + let checkClaimsInterval; if (!activeChannelClaimStr) return; - const channelClaim = JSON.parse(activeChannelClaimStr); - Lbry.claim_search({ - channel_ids: [channelClaim.claim_id], - has_no_source: true, - claim_type: ['stream'], - }) - .then((res) => { - if (res && res.items && res.items.length > 0) { - setLivestreamClaims(res.items.reverse()); - } else { - setLivestreamClaims([]); - } - setSpin(false); + function checkLivestreamClaims() { + Lbry.claim_search({ + channel_ids: [channelClaim.claim_id], + has_no_source: true, + claim_type: ['stream'], }) - .catch(() => { - setLivestreamClaims([]); - setSpin(false); - }); + .then((res) => { + if (res && res.items && res.items.length > 0) { + setLivestreamClaims(res.items.reverse()); + } else { + setLivestreamClaims([]); + } + setSpin(false); + }) + .catch(() => { + setLivestreamClaims([]); + setSpin(false); + }); + } + if (!checkClaimsInterval) { + checkLivestreamClaims(); + checkClaimsInterval = setInterval(checkLivestreamClaims, LIVESTREAM_CLAIM_POLL_IN_MS); + } + return () => { + if (checkClaimsInterval) { + clearInterval(checkClaimsInterval); + } + }; }, [activeChannelClaimStr, pendingLength, setSpin]); return ( - {fetchingChannels && ( + {(fetchingChannels || spin) && (
diff --git a/yarn.lock b/yarn.lock index 6ee4766f6..1cb821a86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6950,9 +6950,9 @@ lazy-val@^1.0.4: yargs "^13.2.2" zstd-codec "^0.1.1" -lbry-redux@lbryio/lbry-redux#c494c92505cd531048de20bc37dc4d192b6ace01: +lbry-redux@lbryio/lbry-redux#db27091f5add9a6bb91c38471a369fca144fc96f: version "0.0.1" - resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/c494c92505cd531048de20bc37dc4d192b6ace01" + resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/db27091f5add9a6bb91c38471a369fca144fc96f" dependencies: proxy-polyfill "0.1.6" reselect "^3.0.0"