update master with some odysee changes
This commit is contained in:
parent
bfcdbd575f
commit
9468f2b0f2
15 changed files with 424 additions and 310 deletions
|
@ -142,7 +142,7 @@
|
||||||
"imagesloaded": "^4.1.4",
|
"imagesloaded": "^4.1.4",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||||
"lbry-redux": "lbryio/lbry-redux#8e74e3137ae78f5d99819b72ba48eecb51015622",
|
"lbry-redux": "lbryio/lbry-redux#35088a6d1007f877a33baf62d67b37669edea043",
|
||||||
"lbryinc": "lbryio/lbryinc#7faea40d87b78ec91b901c62f501499dc4737025",
|
"lbryinc": "lbryio/lbryinc#7faea40d87b78ec91b901c62f501499dc4737025",
|
||||||
"lint-staged": "^7.0.2",
|
"lint-staged": "^7.0.2",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
|
|
|
@ -20,6 +20,7 @@ import analytics from 'analytics';
|
||||||
import LbcSymbol from 'component/common/lbc-symbol';
|
import LbcSymbol from 'component/common/lbc-symbol';
|
||||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||||
import WalletSpendableBalanceHelp from 'component/walletSpendableBalanceHelp';
|
import WalletSpendableBalanceHelp from 'component/walletSpendableBalanceHelp';
|
||||||
|
import { SIMPLE_SITE } from 'config';
|
||||||
|
|
||||||
const LANG_NONE = 'none';
|
const LANG_NONE = 'none';
|
||||||
|
|
||||||
|
@ -358,7 +359,7 @@ function ChannelForm(props: Props) {
|
||||||
<Card
|
<Card
|
||||||
body={
|
body={
|
||||||
<TagsSearch
|
<TagsSearch
|
||||||
suggestMature
|
suggestMature={!SIMPLE_SITE}
|
||||||
disableAutoFocus
|
disableAutoFocus
|
||||||
limitSelect={MAX_TAG_SELECT}
|
limitSelect={MAX_TAG_SELECT}
|
||||||
tagsPassedIn={params.tags || []}
|
tagsPassedIn={params.tags || []}
|
||||||
|
|
|
@ -248,106 +248,110 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
'claim-preview__wrapper--small': type === 'small',
|
'claim-preview__wrapper--small': type === 'small',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{!hideRepostLabel && <ClaimRepostAuthor uri={uri} />}
|
<>
|
||||||
|
{!hideRepostLabel && <ClaimRepostAuthor uri={uri} />}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={classnames('claim-preview', {
|
className={classnames('claim-preview', {
|
||||||
'claim-preview--small': type === 'small' || type === 'tooltip',
|
'claim-preview--small': type === 'small' || type === 'tooltip',
|
||||||
'claim-preview--large': type === 'large',
|
'claim-preview--large': type === 'large',
|
||||||
'claim-preview--inline': type === 'inline',
|
'claim-preview--inline': type === 'inline',
|
||||||
'claim-preview--tooltip': type === 'tooltip',
|
'claim-preview--tooltip': type === 'tooltip',
|
||||||
'claim-preview--channel': isChannelUri,
|
'claim-preview--channel': isChannelUri,
|
||||||
'claim-preview--visited': !isChannelUri && !claimIsMine && hasVisitedUri,
|
'claim-preview--visited': !isChannelUri && !claimIsMine && hasVisitedUri,
|
||||||
'claim-preview--pending': pending,
|
'claim-preview--pending': pending,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{isChannelUri && claim ? (
|
{isChannelUri && claim ? (
|
||||||
<UriIndicator uri={contentUri} link>
|
<UriIndicator uri={contentUri} link>
|
||||||
<ChannelThumbnail uri={contentUri} />
|
<ChannelThumbnail uri={contentUri} />
|
||||||
</UriIndicator>
|
</UriIndicator>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{!pending ? (
|
{!pending ? (
|
||||||
<NavLink {...navLinkProps}>
|
|
||||||
<FileThumbnail thumbnail={thumbnailUrl}>
|
|
||||||
{/* @if TARGET='app' */}
|
|
||||||
{claim && (
|
|
||||||
<div className="claim-preview__hover-actions">
|
|
||||||
<FileDownloadLink uri={canonicalUrl} hideOpenButton hideDownloadStatus />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* @endif */}
|
|
||||||
{!isRepost && !isChannelUri && (
|
|
||||||
<div className="claim-preview__file-property-overlay">
|
|
||||||
<FileProperties uri={contentUri} small />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</FileThumbnail>
|
|
||||||
</NavLink>
|
|
||||||
) : (
|
|
||||||
<FileThumbnail thumbnail={thumbnailUrl} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="claim-preview__text">
|
|
||||||
<div className="claim-preview-metadata">
|
|
||||||
<div className="claim-preview-info">
|
|
||||||
{pending ? (
|
|
||||||
<ClaimPreviewTitle uri={contentUri} />
|
|
||||||
) : (
|
|
||||||
<NavLink {...navLinkProps}>
|
<NavLink {...navLinkProps}>
|
||||||
<ClaimPreviewTitle uri={uri} />
|
<FileThumbnail thumbnail={thumbnailUrl}>
|
||||||
|
{/* @if TARGET='app' */}
|
||||||
|
{claim && (
|
||||||
|
<div className="claim-preview__hover-actions">
|
||||||
|
<FileDownloadLink uri={canonicalUrl} hideOpenButton hideDownloadStatus />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* @endif */}
|
||||||
|
{!isRepost && !isChannelUri && !isLivestream && (
|
||||||
|
<div className="claim-preview__file-property-overlay">
|
||||||
|
<FileProperties uri={contentUri} small />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</FileThumbnail>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
) : (
|
||||||
|
<FileThumbnail thumbnail={thumbnailUrl} />
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* {type !== 'small' && !isChannelUri && signingChannel && SIMPLE_SITE && (
|
<div className="claim-preview__text">
|
||||||
|
<div className="claim-preview-metadata">
|
||||||
|
<div className="claim-preview-info">
|
||||||
|
{pending ? (
|
||||||
|
<ClaimPreviewTitle uri={contentUri} />
|
||||||
|
) : (
|
||||||
|
<NavLink {...navLinkProps}>
|
||||||
|
<ClaimPreviewTitle uri={uri} />
|
||||||
|
</NavLink>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* {type !== 'small' && !isChannelUri && signingChannel && SIMPLE_SITE && (
|
||||||
<ChannelThumbnail uri={signingChannel.permanent_url} />
|
<ChannelThumbnail uri={signingChannel.permanent_url} />
|
||||||
)} */}
|
)} */}
|
||||||
|
</div>
|
||||||
|
<ClaimPreviewSubtitle uri={uri} type={type} />
|
||||||
|
{(pending || !!reflectingProgress) && <PublishPending uri={uri} />}
|
||||||
</div>
|
</div>
|
||||||
<ClaimPreviewSubtitle uri={uri} type={type} />
|
{type !== 'small' && (
|
||||||
{(pending || !!reflectingProgress) && <PublishPending uri={uri} />}
|
<div className="claim-preview__actions">
|
||||||
|
{!pending && (
|
||||||
|
<>
|
||||||
|
{renderActions && claim && renderActions(claim)}
|
||||||
|
{shouldHideActions || renderActions ? null : actions !== undefined ? (
|
||||||
|
actions
|
||||||
|
) : (
|
||||||
|
<div className="claim-preview__primary-actions">
|
||||||
|
{!isChannelUri && signingChannel && (
|
||||||
|
<div className="claim-preview__channel-staked">
|
||||||
|
<ChannelThumbnail uri={signingChannel.permanent_url} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isChannelUri && !channelIsBlocked && !claimIsMine && (
|
||||||
|
<SubscribeButton
|
||||||
|
uri={contentUri.startsWith('lbry://') ? contentUri : `lbry://${contentUri}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{includeSupportAction && <ClaimSupportButton uri={uri} />}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{claim && (
|
||||||
|
<React.Fragment>
|
||||||
|
{typeof properties === 'function' ? (
|
||||||
|
properties(claim)
|
||||||
|
) : properties !== undefined ? (
|
||||||
|
properties
|
||||||
|
) : (
|
||||||
|
<ClaimTags uri={uri} type={type} />
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{type !== 'small' && (
|
|
||||||
<div className="claim-preview__actions">
|
|
||||||
{!pending && (
|
|
||||||
<>
|
|
||||||
{renderActions && claim && renderActions(claim)}
|
|
||||||
{shouldHideActions || renderActions ? null : actions !== undefined ? (
|
|
||||||
actions
|
|
||||||
) : (
|
|
||||||
<div className="claim-preview__primary-actions">
|
|
||||||
{!isChannelUri && signingChannel && (
|
|
||||||
<div className="claim-preview__channel-staked">
|
|
||||||
<ChannelThumbnail uri={signingChannel.permanent_url} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isChannelUri && !channelIsBlocked && !claimIsMine && (
|
|
||||||
<SubscribeButton uri={contentUri.startsWith('lbry://') ? contentUri : `lbry://${contentUri}`} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{includeSupportAction && <ClaimSupportButton uri={uri} />}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{claim && (
|
|
||||||
<React.Fragment>
|
|
||||||
{typeof properties === 'function' ? (
|
|
||||||
properties(claim)
|
|
||||||
) : properties !== undefined ? (
|
|
||||||
properties
|
|
||||||
) : (
|
|
||||||
<ClaimTags uri={uri} type={type} />
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{!hideMenu && <ClaimMenuList uri={uri} />}
|
||||||
{!hideMenu && <ClaimMenuList uri={uri} />}
|
</>
|
||||||
</WrapperElement>
|
</WrapperElement>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
doFileGet,
|
doFileGet,
|
||||||
makeSelectChannelForClaimUri,
|
makeSelectChannelForClaimUri,
|
||||||
makeSelectClaimIsNsfw,
|
makeSelectClaimIsNsfw,
|
||||||
|
makeSelectClaimIsStreamPlaceholder,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectMutedChannels } from 'redux/selectors/blocked';
|
import { selectMutedChannels } from 'redux/selectors/blocked';
|
||||||
import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc';
|
import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc';
|
||||||
|
@ -25,6 +26,7 @@ const select = (state, props) => ({
|
||||||
blockedChannelUris: selectMutedChannels(state),
|
blockedChannelUris: selectMutedChannels(state),
|
||||||
showMature: selectShowMatureContent(state),
|
showMature: selectShowMatureContent(state),
|
||||||
isMature: makeSelectClaimIsNsfw(props.uri)(state),
|
isMature: makeSelectClaimIsNsfw(props.uri)(state),
|
||||||
|
isLivestream: makeSelectClaimIsStreamPlaceholder(props.uri)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
|
|
|
@ -20,6 +20,8 @@ type Props = {
|
||||||
defaultExpand?: boolean,
|
defaultExpand?: boolean,
|
||||||
nag?: Node,
|
nag?: Node,
|
||||||
smallTitle?: boolean,
|
smallTitle?: boolean,
|
||||||
|
onClick?: () => void,
|
||||||
|
children?: any, // not sure how this works
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Card(props: Props) {
|
export default function Card(props: Props) {
|
||||||
|
@ -37,12 +39,21 @@ export default function Card(props: Props) {
|
||||||
smallTitle = false,
|
smallTitle = false,
|
||||||
defaultExpand,
|
defaultExpand,
|
||||||
nag,
|
nag,
|
||||||
|
onClick,
|
||||||
|
children,
|
||||||
} = props;
|
} = props;
|
||||||
const [expanded, setExpanded] = useState(defaultExpand);
|
const [expanded, setExpanded] = useState(defaultExpand);
|
||||||
const expandable = defaultExpand !== undefined;
|
const expandable = defaultExpand !== undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={classnames(className, 'card')}>
|
<section
|
||||||
|
className={classnames(className, 'card')}
|
||||||
|
onClick={() => {
|
||||||
|
if (onClick) {
|
||||||
|
onClick();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
{(title || subtitle) && (
|
{(title || subtitle) && (
|
||||||
<div
|
<div
|
||||||
className={classnames('card__header--between', {
|
className={classnames('card__header--between', {
|
||||||
|
@ -93,6 +104,7 @@ export default function Card(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{actions && <div className="card__main-actions">{actions}</div>}
|
{actions && <div className="card__main-actions">{actions}</div>}
|
||||||
|
{children && <div className="card__main-actions">{children}</div>}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -64,11 +64,12 @@ export default function LivestreamLink(props: Props) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
// gonna pass the wrapper in so I don't have to rewrite the dmca/blocking logic in claimPreview.
|
||||||
<Card
|
const element = (props: { children: any }) => (
|
||||||
className="livestream__channel-link"
|
<Card className="livestream__channel-link" title={__('Live stream in progress')}>
|
||||||
title={__('Live stream in progress')}
|
{props.children}
|
||||||
actions={<ClaimPreview uri={livestreamClaim.canonical_url} livestream type="inline" />}
|
</Card>
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return <ClaimPreview uri={livestreamClaim.canonical_url} wrapperElement={element} type="inline" />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,6 +256,13 @@ function PublishForm(props: Props) {
|
||||||
}
|
}
|
||||||
}, [name, activeChannelName, resolveUri, updatePublishForm, checkAvailability]);
|
}, [name, activeChannelName, resolveUri, updatePublishForm, checkAvailability]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// because editingURI is lbry://channel_short/claim_long and that particular shape won't map to the claimId yet
|
||||||
|
if (editingURI) {
|
||||||
|
resolveUri(editingURI);
|
||||||
|
}
|
||||||
|
}, [editingURI, resolveUri]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updatePublishForm({
|
updatePublishForm({
|
||||||
isMarkdownPost: mode === PUBLISH_MODES.POST,
|
isMarkdownPost: mode === PUBLISH_MODES.POST,
|
||||||
|
@ -440,7 +447,7 @@ function PublishForm(props: Props) {
|
||||||
{mode === PUBLISH_MODES.FILE && <PublishDescription disabled={formDisabled} />}
|
{mode === PUBLISH_MODES.FILE && <PublishDescription disabled={formDisabled} />}
|
||||||
<Card actions={<SelectThumbnail />} />
|
<Card actions={<SelectThumbnail />} />
|
||||||
<TagsSelect
|
<TagsSelect
|
||||||
suggestMature
|
suggestMature={!SIMPLE_SITE}
|
||||||
disableAutoFocus
|
disableAutoFocus
|
||||||
hideHeader
|
hideHeader
|
||||||
label={__('Selected Tags')}
|
label={__('Selected Tags')}
|
||||||
|
|
|
@ -52,7 +52,7 @@ import YoutubeSyncPage from 'page/youtubeSync';
|
||||||
|
|
||||||
import { LINKED_COMMENT_QUERY_PARAM } from 'constants/comment';
|
import { LINKED_COMMENT_QUERY_PARAM } from 'constants/comment';
|
||||||
import { parseURI, isURIValid } from 'lbry-redux';
|
import { parseURI, isURIValid } from 'lbry-redux';
|
||||||
import { SITE_TITLE, WELCOME_VERSION } from 'config';
|
import { SITE_TITLE, WELCOME_VERSION, SIMPLE_SITE } from 'config';
|
||||||
|
|
||||||
// Tell the browser we are handling scroll restoration
|
// Tell the browser we are handling scroll restoration
|
||||||
if ('scrollRestoration' in history) {
|
if ('scrollRestoration' in history) {
|
||||||
|
@ -218,6 +218,7 @@ function AppRouter(props: Props) {
|
||||||
|
|
||||||
<Route path={`/`} exact component={HomePage} />
|
<Route path={`/`} exact component={HomePage} />
|
||||||
<Route path={`/$/${PAGES.DISCOVER}`} exact component={DiscoverPage} />
|
<Route path={`/$/${PAGES.DISCOVER}`} exact component={DiscoverPage} />
|
||||||
|
{SIMPLE_SITE && <Route path={`/$/${PAGES.WILD_WEST}`} exact component={DiscoverPage} />}
|
||||||
{/* $FlowFixMe */}
|
{/* $FlowFixMe */}
|
||||||
{dynamicRoutes.map((dynamicRouteProps: RowDataItem) => (
|
{dynamicRoutes.map((dynamicRouteProps: RowDataItem) => (
|
||||||
<Route
|
<Route
|
||||||
|
|
|
@ -16,6 +16,8 @@ const select = (state) => ({
|
||||||
...selectPublishFormValues(state),
|
...selectPublishFormValues(state),
|
||||||
myChannels: selectMyChannelClaims(state),
|
myChannels: selectMyChannelClaims(state),
|
||||||
isVid: makeSelectPublishFormValue('fileVid')(state),
|
isVid: makeSelectPublishFormValue('fileVid')(state),
|
||||||
|
publishSuccess: makeSelectPublishFormValue('publishSuccess')(state),
|
||||||
|
publishing: makeSelectPublishFormValue('publishing')(state),
|
||||||
isStillEditing: selectIsStillEditing(state),
|
isStillEditing: selectIsStillEditing(state),
|
||||||
ffmpegStatus: selectFfmpegStatus(state),
|
ffmpegStatus: selectFfmpegStatus(state),
|
||||||
enablePublishPreview: makeSelectClientSetting(SETTINGS.ENABLE_PUBLISH_PREVIEW)(state),
|
enablePublishPreview: makeSelectClientSetting(SETTINGS.ENABLE_PUBLISH_PREVIEW)(state),
|
||||||
|
|
|
@ -41,17 +41,59 @@ type Props = {
|
||||||
setEnablePublishPreview: (boolean) => void,
|
setEnablePublishPreview: (boolean) => void,
|
||||||
isStillEditing: boolean,
|
isStillEditing: boolean,
|
||||||
myChannels: ?Array<ChannelClaim>,
|
myChannels: ?Array<ChannelClaim>,
|
||||||
|
publishSuccess: boolean,
|
||||||
|
publishing: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModalPublishPreview extends React.PureComponent<Props> {
|
// class ModalPublishPreview extends React.PureComponent<Props> {
|
||||||
onConfirmed() {
|
const ModalPublishPreview = (props: Props) => {
|
||||||
const { filePath, publish, closeModal } = this.props;
|
const {
|
||||||
|
filePath,
|
||||||
|
isMarkdownPost,
|
||||||
|
optimize,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
channel,
|
||||||
|
bid,
|
||||||
|
uri,
|
||||||
|
contentIsFree,
|
||||||
|
fee,
|
||||||
|
language,
|
||||||
|
licenseType,
|
||||||
|
otherLicenseDescription,
|
||||||
|
licenseUrl,
|
||||||
|
tags,
|
||||||
|
isVid,
|
||||||
|
ffmpegStatus = {},
|
||||||
|
previewResponse,
|
||||||
|
enablePublishPreview,
|
||||||
|
setEnablePublishPreview,
|
||||||
|
isStillEditing,
|
||||||
|
myChannels,
|
||||||
|
publishSuccess,
|
||||||
|
publishing,
|
||||||
|
publish,
|
||||||
|
closeModal,
|
||||||
|
} = props;
|
||||||
|
const livestream =
|
||||||
|
// $FlowFixMe
|
||||||
|
previewResponse.outputs[0] && previewResponse.outputs[0].value && !previewResponse.outputs[0].value.source;
|
||||||
|
// leave the confirm modal up if we're not going straight to upload/reflecting
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (publishing && IS_WEB && !livestream) {
|
||||||
|
closeModal();
|
||||||
|
} else if (publishSuccess) {
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
}, [publishSuccess, publishing, livestream]);
|
||||||
|
|
||||||
|
// const waitForSuccess = false;
|
||||||
|
function onConfirmed() {
|
||||||
// Publish for real:
|
// Publish for real:
|
||||||
publish(this.resolveFilePathName(filePath), false);
|
publish(getFilePathName(filePath), false);
|
||||||
closeModal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveFilePathName(filePath: string | WebFile) {
|
function getFilePathName(filePath: string | WebFile) {
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
return NO_FILE;
|
return NO_FILE;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +105,7 @@ class ModalPublishPreview extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createRow(label: string, value: any) {
|
function createRow(label: string, value: any) {
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td>{label}</td>
|
<td>{label}</td>
|
||||||
|
@ -72,54 +114,20 @@ class ModalPublishPreview extends React.PureComponent<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
togglePreviewEnabled() {
|
const txFee = previewResponse ? previewResponse['total_fee'] : null;
|
||||||
const { enablePublishPreview, setEnablePublishPreview } = this.props;
|
// $FlowFixMe add outputs[0] etc to PublishResponse type
|
||||||
setEnablePublishPreview(!enablePublishPreview);
|
const isOptimizeAvail = filePath && filePath !== '' && isVid && ffmpegStatus.available;
|
||||||
|
let modalTitle;
|
||||||
|
if (isStillEditing) {
|
||||||
|
modalTitle = __('Confirm Edit');
|
||||||
|
} else if (livestream) {
|
||||||
|
modalTitle = __('Create Livestream');
|
||||||
|
} else {
|
||||||
|
modalTitle = __('Confirm Upload');
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
let confirmBtnText;
|
||||||
const {
|
if (!publishing) {
|
||||||
filePath,
|
|
||||||
isMarkdownPost,
|
|
||||||
optimize,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
channel,
|
|
||||||
bid,
|
|
||||||
uri,
|
|
||||||
contentIsFree,
|
|
||||||
fee,
|
|
||||||
language,
|
|
||||||
licenseType,
|
|
||||||
otherLicenseDescription,
|
|
||||||
licenseUrl,
|
|
||||||
tags,
|
|
||||||
isVid,
|
|
||||||
ffmpegStatus = {},
|
|
||||||
previewResponse,
|
|
||||||
closeModal,
|
|
||||||
enablePublishPreview,
|
|
||||||
setEnablePublishPreview,
|
|
||||||
isStillEditing,
|
|
||||||
myChannels,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const txFee = previewResponse ? previewResponse['total_fee'] : null;
|
|
||||||
// $FlowFixMe add outputs[0] etc to PublishResponse type
|
|
||||||
const livestream =
|
|
||||||
// $FlowFixMe
|
|
||||||
previewResponse.outputs[0] && previewResponse.outputs[0].value && !previewResponse.outputs[0].value.source;
|
|
||||||
const isOptimizeAvail = filePath && filePath !== '' && isVid && ffmpegStatus.available;
|
|
||||||
let modalTitle;
|
|
||||||
if (isStillEditing) {
|
|
||||||
modalTitle = __('Confirm Edit');
|
|
||||||
} else if (livestream) {
|
|
||||||
modalTitle = __('Create Livestream');
|
|
||||||
} else {
|
|
||||||
modalTitle = __('Confirm Upload');
|
|
||||||
}
|
|
||||||
|
|
||||||
let confirmBtnText;
|
|
||||||
if (isStillEditing) {
|
if (isStillEditing) {
|
||||||
confirmBtnText = __('Save');
|
confirmBtnText = __('Save');
|
||||||
} else if (livestream) {
|
} else if (livestream) {
|
||||||
|
@ -127,110 +135,119 @@ class ModalPublishPreview extends React.PureComponent<Props> {
|
||||||
} else {
|
} else {
|
||||||
confirmBtnText = __('Upload');
|
confirmBtnText = __('Upload');
|
||||||
}
|
}
|
||||||
const descriptionValue = description ? (
|
} else {
|
||||||
<div className="media__info-text-preview">
|
if (isStillEditing) {
|
||||||
<MarkdownPreview content={description} simpleLinks />
|
confirmBtnText = __('Saving');
|
||||||
</div>
|
} else if (livestream) {
|
||||||
) : null;
|
confirmBtnText = __('Creating');
|
||||||
|
} else {
|
||||||
const licenseValue =
|
confirmBtnText = __('Uploading');
|
||||||
licenseType === COPYRIGHT ? (
|
|
||||||
<p>© {otherLicenseDescription}</p>
|
|
||||||
) : licenseType === OTHER ? (
|
|
||||||
<p>
|
|
||||||
{otherLicenseDescription}
|
|
||||||
<br />
|
|
||||||
{licenseUrl}
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
<p>{licenseType}</p>
|
|
||||||
);
|
|
||||||
|
|
||||||
const tagsValue =
|
|
||||||
// Do nothing for onClick(). Setting to 'null' results in "View Tag" action -- we don't want to leave the modal.
|
|
||||||
tags.map((tag) => <Tag key={tag.name} title={tag.name} name={tag.name} type={'flow'} onClick={() => {}} />);
|
|
||||||
|
|
||||||
const depositValue = bid ? <LbcSymbol postfix={`${bid}`} size={14} /> : <p>---</p>;
|
|
||||||
|
|
||||||
let priceValue = __('Free');
|
|
||||||
if (!contentIsFree) {
|
|
||||||
if (fee.currency === 'LBC') {
|
|
||||||
priceValue = <LbcSymbol postfix={fee.amount} />;
|
|
||||||
} else {
|
|
||||||
priceValue = `${fee.amount} ${fee.currency}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const channelValue = (channel) => {
|
|
||||||
const channelClaim = myChannels && myChannels.find((x) => x.name === channel);
|
|
||||||
return channel ? (
|
|
||||||
<div className="channel-value">
|
|
||||||
{channelClaim && <ChannelThumbnail uri={channelClaim.permanent_url} />}
|
|
||||||
{channel}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="channel-value">
|
|
||||||
<Icon sectionIcon icon={ICONS.ANONYMOUS} />
|
|
||||||
<i>{__('Anonymous')}</i>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal isOpen contentLabel={modalTitle} type="card" onAborted={closeModal}>
|
|
||||||
<Form onSubmit={() => this.onConfirmed()}>
|
|
||||||
<Card
|
|
||||||
title={modalTitle}
|
|
||||||
body={
|
|
||||||
<>
|
|
||||||
<div className="section">
|
|
||||||
<table className="table table--condensed table--publish-preview">
|
|
||||||
<tbody>
|
|
||||||
{!livestream && !isMarkdownPost && this.createRow(__('File'), this.resolveFilePathName(filePath))}
|
|
||||||
{isOptimizeAvail && this.createRow(__('Transcode'), optimize ? __('Yes') : __('No'))}
|
|
||||||
{this.createRow(__('Title'), title)}
|
|
||||||
{this.createRow(__('Description'), descriptionValue)}
|
|
||||||
{this.createRow(__('Channel'), channelValue(channel))}
|
|
||||||
{this.createRow(__('URL'), uri)}
|
|
||||||
{this.createRow(__('Deposit'), depositValue)}
|
|
||||||
{this.createRow(__('Price'), priceValue)}
|
|
||||||
{this.createRow(__('Language'), language)}
|
|
||||||
{this.createRow(__('License'), licenseValue)}
|
|
||||||
{this.createRow(__('Tags'), tagsValue)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{txFee && (
|
|
||||||
<div className="section" aria-label={__('Estimated transaction fee:')}>
|
|
||||||
<b>{__('Est. transaction fee:')}</b>
|
|
||||||
<em>
|
|
||||||
<LbcSymbol postfix={txFee} />
|
|
||||||
</em>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
actions={
|
|
||||||
<>
|
|
||||||
<div className="section__actions">
|
|
||||||
<Button autoFocus button="primary" label={confirmBtnText} onClick={() => this.onConfirmed()} />
|
|
||||||
<Button button="link" label={__('Cancel')} onClick={closeModal} />
|
|
||||||
</div>
|
|
||||||
<p className="help">{__('Once the transaction is sent, it cannot be reversed.')}</p>
|
|
||||||
<FormField
|
|
||||||
type="checkbox"
|
|
||||||
name="sync_toggle"
|
|
||||||
label={__('Skip preview and confirmation')}
|
|
||||||
checked={!enablePublishPreview}
|
|
||||||
onChange={() => setEnablePublishPreview(!enablePublishPreview)}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const descriptionValue = description ? (
|
||||||
|
<div className="media__info-text-preview">
|
||||||
|
<MarkdownPreview content={description} simpleLinks />
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
const licenseValue =
|
||||||
|
licenseType === COPYRIGHT ? (
|
||||||
|
<p>© {otherLicenseDescription}</p>
|
||||||
|
) : licenseType === OTHER ? (
|
||||||
|
<p>
|
||||||
|
{otherLicenseDescription}
|
||||||
|
<br />
|
||||||
|
{licenseUrl}
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p>{licenseType}</p>
|
||||||
|
);
|
||||||
|
|
||||||
|
const tagsValue =
|
||||||
|
// Do nothing for onClick(). Setting to 'null' results in "View Tag" action -- we don't want to leave the modal.
|
||||||
|
tags.map((tag) => <Tag key={tag.name} title={tag.name} name={tag.name} type={'flow'} onClick={() => {}} />);
|
||||||
|
|
||||||
|
const depositValue = bid ? <LbcSymbol postfix={`${bid}`} size={14} /> : <p>---</p>;
|
||||||
|
|
||||||
|
let priceValue = __('Free');
|
||||||
|
if (!contentIsFree) {
|
||||||
|
if (fee.currency === 'LBC') {
|
||||||
|
priceValue = <LbcSymbol postfix={fee.amount} />;
|
||||||
|
} else {
|
||||||
|
priceValue = `${fee.amount} ${fee.currency}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const channelValue = (channel) => {
|
||||||
|
const channelClaim = myChannels && myChannels.find((x) => x.name === channel);
|
||||||
|
return channel ? (
|
||||||
|
<div className="channel-value">
|
||||||
|
{channelClaim && <ChannelThumbnail uri={channelClaim.permanent_url} />}
|
||||||
|
{channel}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="channel-value">
|
||||||
|
<Icon sectionIcon icon={ICONS.ANONYMOUS} />
|
||||||
|
<i>{__('Anonymous')}</i>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal isOpen contentLabel={modalTitle} type="card" onAborted={closeModal}>
|
||||||
|
<Form onSubmit={onConfirmed}>
|
||||||
|
<Card
|
||||||
|
title={modalTitle}
|
||||||
|
body={
|
||||||
|
<>
|
||||||
|
<div className="section">
|
||||||
|
<table className="table table--condensed table--publish-preview">
|
||||||
|
<tbody>
|
||||||
|
{!livestream && !isMarkdownPost && createRow(__('File'), getFilePathName(filePath))}
|
||||||
|
{isOptimizeAvail && createRow(__('Transcode'), optimize ? __('Yes') : __('No'))}
|
||||||
|
{createRow(__('Title'), title)}
|
||||||
|
{createRow(__('Description'), descriptionValue)}
|
||||||
|
{createRow(__('Channel'), channelValue(channel))}
|
||||||
|
{createRow(__('URL'), uri)}
|
||||||
|
{createRow(__('Deposit'), depositValue)}
|
||||||
|
{createRow(__('Price'), priceValue)}
|
||||||
|
{createRow(__('Language'), language)}
|
||||||
|
{createRow(__('License'), licenseValue)}
|
||||||
|
{createRow(__('Tags'), tagsValue)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{txFee && (
|
||||||
|
<div className="section" aria-label={__('Estimated transaction fee:')}>
|
||||||
|
<b>{__('Est. transaction fee:')}</b>
|
||||||
|
<em>
|
||||||
|
<LbcSymbol postfix={txFee} />
|
||||||
|
</em>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
actions={
|
||||||
|
<>
|
||||||
|
<div className="section__actions">
|
||||||
|
<Button autoFocus button="primary" disabled={publishing} label={confirmBtnText} onClick={onConfirmed} />
|
||||||
|
<Button button="link" label={__('Cancel')} onClick={closeModal} />
|
||||||
|
</div>
|
||||||
|
<p className="help">{__('Once the transaction is sent, it cannot be reversed.')}</p>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="sync_toggle"
|
||||||
|
label={__('Skip preview and confirmation')}
|
||||||
|
checked={!enablePublishPreview}
|
||||||
|
onChange={() => setEnablePublishPreview(!enablePublishPreview)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default ModalPublishPreview;
|
export default ModalPublishPreview;
|
||||||
|
|
|
@ -8,6 +8,8 @@ import {
|
||||||
makeSelectClaimIsNsfw,
|
makeSelectClaimIsNsfw,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
makeSelectTagInClaimOrChannelForUri,
|
makeSelectTagInClaimOrChannelForUri,
|
||||||
|
makeSelectClaimIsMine,
|
||||||
|
makeSelectClaimIsStreamPlaceholder,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc';
|
import { makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc';
|
||||||
import { selectShowMatureContent, makeSelectClientSetting } from 'redux/selectors/settings';
|
import { selectShowMatureContent, makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
@ -32,14 +34,16 @@ const select = (state, props) => {
|
||||||
renderMode: makeSelectFileRenderModeForUri(props.uri)(state),
|
renderMode: makeSelectFileRenderModeForUri(props.uri)(state),
|
||||||
videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state),
|
videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state),
|
||||||
commentsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state),
|
commentsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state),
|
||||||
|
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||||
|
isLivestream: makeSelectClaimIsStreamPlaceholder(props.uri)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = (dispatch) => ({
|
||||||
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
|
fetchFileInfo: (uri) => dispatch(doFetchFileInfo(uri)),
|
||||||
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
fetchCostInfo: (uri) => dispatch(doFetchCostInfoForUri(uri)),
|
||||||
setViewed: uri => dispatch(doSetContentHistoryItem(uri)),
|
setViewed: (uri) => dispatch(doSetContentHistoryItem(uri)),
|
||||||
setPrimaryUri: uri => dispatch(doSetPrimaryUri(uri)),
|
setPrimaryUri: (uri) => dispatch(doSetPrimaryUri(uri)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default withRouter(connect(select, perform)(FilePage));
|
export default withRouter(connect(select, perform)(FilePage));
|
||||||
|
|
|
@ -4,6 +4,7 @@ import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import LivestreamLayout from 'component/livestreamLayout';
|
import LivestreamLayout from 'component/livestreamLayout';
|
||||||
import analytics from 'analytics';
|
import analytics from 'analytics';
|
||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
|
@ -19,8 +20,41 @@ export default function LivestreamPage(props: Props) {
|
||||||
const [activeViewers, setActiveViewers] = React.useState(0);
|
const [activeViewers, setActiveViewers] = React.useState(0);
|
||||||
const [isLive, setIsLive] = React.useState(false);
|
const [isLive, setIsLive] = React.useState(false);
|
||||||
const livestreamChannelId = channelClaim && channelClaim.signing_channel && channelClaim.signing_channel.claim_id;
|
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(() => {
|
React.useEffect(() => {
|
||||||
|
let interval;
|
||||||
function checkIsLive() {
|
function checkIsLive() {
|
||||||
// $FlowFixMe Bitwave's API can handle garbage
|
// $FlowFixMe Bitwave's API can handle garbage
|
||||||
fetch(`${BITWAVE_API}/${livestreamChannelId}`)
|
fetch(`${BITWAVE_API}/${livestreamChannelId}`)
|
||||||
|
@ -38,19 +72,17 @@ export default function LivestreamPage(props: Props) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (livestreamChannelId && hasLivestreamClaim) {
|
||||||
let interval;
|
|
||||||
if (livestreamChannelId) {
|
|
||||||
if (!interval) checkIsLive();
|
if (!interval) checkIsLive();
|
||||||
interval = setInterval(checkIsLive, 10 * 1000);
|
interval = setInterval(checkIsLive, STREAMING_POLL_INTERVAL_IN_MS);
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (interval) {
|
if (interval) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [livestreamChannelId]);
|
}
|
||||||
|
}, [livestreamChannelId, hasLivestreamClaim]);
|
||||||
|
|
||||||
const stringifiedClaim = JSON.stringify(claim);
|
const stringifiedClaim = JSON.stringify(claim);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
|
@ -24,16 +24,34 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function LivestreamSetupPage(props: Props) {
|
export default function LivestreamSetupPage(props: Props) {
|
||||||
|
const LIVESTREAM_CLAIM_POLL_IN_MS = 60000;
|
||||||
const { channels, fetchingChannels, activeChannelClaim, pendingClaims } = props;
|
const { channels, fetchingChannels, activeChannelClaim, pendingClaims } = props;
|
||||||
|
|
||||||
const [sigData, setSigData] = React.useState({ signature: undefined, signing_ts: undefined });
|
const [sigData, setSigData] = React.useState({ signature: undefined, signing_ts: undefined });
|
||||||
const [showHelpTest, setShowHelpTest] = usePersistedState('livestream-help-seen', true);
|
const [showHelpTest, setShowHelpTest] = usePersistedState('livestream-help-seen', true);
|
||||||
const [spin, setSpin] = React.useState(true);
|
const [spin, setSpin] = React.useState(true);
|
||||||
|
const [livestreamClaims, setLivestreamClaims] = React.useState([]);
|
||||||
|
|
||||||
const hasChannels = channels && channels.length > 0;
|
const hasChannels = channels && channels.length > 0;
|
||||||
const activeChannelClaimStr = JSON.stringify(activeChannelClaim);
|
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 = (
|
const helpText = (
|
||||||
<div className="section__subtitle">
|
<div className="section__subtitle">
|
||||||
<p>
|
<p>
|
||||||
|
@ -76,6 +94,7 @@ export default function LivestreamSetupPage(props: Props) {
|
||||||
<p>{__(`Click Save and you are done!`)}</p>
|
<p>{__(`Click Save and you are done!`)}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (activeChannelClaimStr) {
|
if (activeChannelClaimStr) {
|
||||||
const channelClaim = JSON.parse(activeChannelClaimStr);
|
const channelClaim = JSON.parse(activeChannelClaimStr);
|
||||||
|
@ -96,47 +115,44 @@ export default function LivestreamSetupPage(props: Props) {
|
||||||
}
|
}
|
||||||
}, [activeChannelClaimStr, setSigData]);
|
}, [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(() => {
|
React.useEffect(() => {
|
||||||
|
let checkClaimsInterval;
|
||||||
if (!activeChannelClaimStr) return;
|
if (!activeChannelClaimStr) return;
|
||||||
|
|
||||||
const channelClaim = JSON.parse(activeChannelClaimStr);
|
const channelClaim = JSON.parse(activeChannelClaimStr);
|
||||||
|
|
||||||
Lbry.claim_search({
|
function checkLivestreamClaims() {
|
||||||
channel_ids: [channelClaim.claim_id],
|
Lbry.claim_search({
|
||||||
has_no_source: true,
|
channel_ids: [channelClaim.claim_id],
|
||||||
claim_type: ['stream'],
|
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);
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.then((res) => {
|
||||||
setLivestreamClaims([]);
|
if (res && res.items && res.items.length > 0) {
|
||||||
setSpin(false);
|
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]);
|
}, [activeChannelClaimStr, pendingLength, setSpin]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
{fetchingChannels && (
|
{(fetchingChannels || spin) && (
|
||||||
<div className="main--empty">
|
<div className="main--empty">
|
||||||
<Spinner delayed />
|
<Spinner delayed />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,6 +9,8 @@ import {
|
||||||
doCheckPendingClaims,
|
doCheckPendingClaims,
|
||||||
doCheckReflectingFiles,
|
doCheckReflectingFiles,
|
||||||
ACTIONS as LBRY_REDUX_ACTIONS,
|
ACTIONS as LBRY_REDUX_ACTIONS,
|
||||||
|
makeSelectPublishFormValue,
|
||||||
|
makeSelectClaimForUri,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doError } from 'redux/actions/notifications';
|
import { doError } from 'redux/actions/notifications';
|
||||||
import { push } from 'connected-react-router';
|
import { push } from 'connected-react-router';
|
||||||
|
@ -24,7 +26,12 @@ export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispat
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const noFile = !filePath || filePath === NO_FILE;
|
const noFileParam = !filePath || filePath === NO_FILE;
|
||||||
|
const state = getState();
|
||||||
|
const editingUri = makeSelectPublishFormValue('editingURI')(state) || '';
|
||||||
|
const claim = makeSelectClaimForUri(editingUri)(state) || {};
|
||||||
|
const hasSourceFile = claim.value && claim.value.source;
|
||||||
|
const redirectToLivestream = noFileParam && !hasSourceFile;
|
||||||
|
|
||||||
const publishSuccess = (successResponse, lbryFirstError) => {
|
const publishSuccess = (successResponse, lbryFirstError) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
@ -41,6 +48,7 @@ export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispat
|
||||||
actions.push({
|
actions.push({
|
||||||
type: ACTIONS.PUBLISH_SUCCESS,
|
type: ACTIONS.PUBLISH_SUCCESS,
|
||||||
});
|
});
|
||||||
|
|
||||||
// We have to fake a temp claim until the new pending one is returned by claim_list_mine
|
// We have to fake a temp claim until the new pending one is returned by claim_list_mine
|
||||||
// We can't rely on claim_list_mine because there might be some delay before the new claims are returned
|
// We can't rely on claim_list_mine because there might be some delay before the new claims are returned
|
||||||
// Doing this allows us to show the pending claim immediately, it will get overwritten by the real one
|
// Doing this allows us to show the pending claim immediately, it will get overwritten by the real one
|
||||||
|
@ -73,6 +81,11 @@ export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispat
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
dispatch(doCheckReflectingFiles());
|
dispatch(doCheckReflectingFiles());
|
||||||
// @endif
|
// @endif
|
||||||
|
// @if TARGET='web'
|
||||||
|
if (redirectToLivestream) {
|
||||||
|
dispatch(push(`/$/${PAGES.LIVESTREAM}`));
|
||||||
|
}
|
||||||
|
// @endif
|
||||||
};
|
};
|
||||||
|
|
||||||
const publishFail = (error) => {
|
const publishFail = (error) => {
|
||||||
|
@ -93,7 +106,9 @@ export const doPublishDesktop = (filePath: string, preview?: boolean) => (dispat
|
||||||
// on the publishes page. This doesn't exist on desktop so wait until we get a response
|
// on the publishes page. This doesn't exist on desktop so wait until we get a response
|
||||||
// from the SDK
|
// from the SDK
|
||||||
// @if TARGET='web'
|
// @if TARGET='web'
|
||||||
dispatch(push(noFile ? `/$/${PAGES.LIVESTREAM}` : `/$/${PAGES.UPLOADS}`));
|
if (!redirectToLivestream) {
|
||||||
|
dispatch(push(`/$/${PAGES.UPLOADS}`));
|
||||||
|
}
|
||||||
// @endif
|
// @endif
|
||||||
|
|
||||||
dispatch(doPublish(publishSuccess, publishFail));
|
dispatch(doPublish(publishSuccess, publishFail));
|
||||||
|
|
|
@ -6950,9 +6950,9 @@ lazy-val@^1.0.4:
|
||||||
yargs "^13.2.2"
|
yargs "^13.2.2"
|
||||||
zstd-codec "^0.1.1"
|
zstd-codec "^0.1.1"
|
||||||
|
|
||||||
lbry-redux@lbryio/lbry-redux#8e74e3137ae78f5d99819b72ba48eecb51015622:
|
lbry-redux@lbryio/lbry-redux#35088a6d1007f877a33baf62d67b37669edea043:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/8e74e3137ae78f5d99819b72ba48eecb51015622"
|
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/35088a6d1007f877a33baf62d67b37669edea043"
|
||||||
dependencies:
|
dependencies:
|
||||||
proxy-polyfill "0.1.6"
|
proxy-polyfill "0.1.6"
|
||||||
reselect "^3.0.0"
|
reselect "^3.0.0"
|
||||||
|
|
Loading…
Reference in a new issue