Incremental livestream performance fixes (#307)
This commit is contained in:
commit
6382238834
12 changed files with 52 additions and 47 deletions
|
@ -1,6 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { MAX_LIVESTREAM_COMMENTS } from 'constants/livestream';
|
||||||
import { selectShowMatureContent } from 'redux/selectors/settings';
|
import { selectShowMatureContent } from 'redux/selectors/settings';
|
||||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
import { selectSubscriptionUris } from 'redux/selectors/subscriptions';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
||||||
import { doResolveUris } from 'redux/actions/claims';
|
import { doResolveUris } from 'redux/actions/claims';
|
||||||
|
@ -8,8 +9,12 @@ import { selectTopLevelCommentsForUri } from 'redux/selectors/comments';
|
||||||
import ChannelMentionSuggestions from './view';
|
import ChannelMentionSuggestions from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const subscriptionUris = selectSubscriptions(state).map(({ uri }) => uri);
|
const subscriptionUris = selectSubscriptionUris(state);
|
||||||
const topLevelComments = selectTopLevelCommentsForUri(state, props.uri);
|
const topLevelComments = selectTopLevelCommentsForUri(
|
||||||
|
state,
|
||||||
|
props.uri,
|
||||||
|
props.isLivestream ? MAX_LIVESTREAM_COMMENTS : -1
|
||||||
|
);
|
||||||
|
|
||||||
const commentorUris = [];
|
const commentorUris = [];
|
||||||
// Avoid repeated commentors
|
// Avoid repeated commentors
|
||||||
|
|
|
@ -8,12 +8,11 @@ import ClaimPreviewReset from 'component/claimPreviewReset';
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
livestream?: boolean,
|
livestream?: boolean,
|
||||||
activeViewers?: number,
|
|
||||||
isLive?: boolean,
|
isLive?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function FileSubtitle(props: Props) {
|
function FileSubtitle(props: Props) {
|
||||||
const { uri, livestream = false, activeViewers, isLive = false } = props;
|
const { uri, livestream = false, isLive = false } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -21,7 +20,7 @@ function FileSubtitle(props: Props) {
|
||||||
<div className="file__viewdate">
|
<div className="file__viewdate">
|
||||||
{livestream ? <span>{__('Right now')}</span> : <DateTime uri={uri} show={DateTime.SHOW_DATE} />}
|
{livestream ? <span>{__('Right now')}</span> : <DateTime uri={uri} show={DateTime.SHOW_DATE} />}
|
||||||
|
|
||||||
<FileViewCount uri={uri} livestream={livestream} activeViewers={activeViewers} isLive={isLive} />
|
<FileViewCount uri={uri} livestream={livestream} isLive={isLive} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FileActions uri={uri} hideRepost={livestream} livestream={livestream} />
|
<FileActions uri={uri} hideRepost={livestream} livestream={livestream} />
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doFetchSubCount, selectSubCountForUri } from 'lbryinc';
|
import { doFetchSubCount, selectSubCountForUri } from 'lbryinc';
|
||||||
import { selectTitleForUri, makeSelectClaimForUri } from 'redux/selectors/claims';
|
import { selectTitleForUri, selectClaimForUri } from 'redux/selectors/claims';
|
||||||
import { makeSelectInsufficientCreditsForUri } from 'redux/selectors/content';
|
import { makeSelectInsufficientCreditsForUri } from 'redux/selectors/content';
|
||||||
import { makeSelectViewersForId } from 'redux/selectors/livestream';
|
|
||||||
import FileTitleSection from './view';
|
import FileTitleSection from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const claim = makeSelectClaimForUri(props.uri)(state);
|
const claim = selectClaimForUri(state, props.uri);
|
||||||
const viewers = claim && makeSelectViewersForId(claim.claim_id)(state);
|
|
||||||
const channelClaimId = claim && claim.signing_channel ? claim.signing_channel.claim_id : undefined;
|
const channelClaimId = claim && claim.signing_channel ? claim.signing_channel.claim_id : undefined;
|
||||||
const channelUri = claim && claim.signing_channel ? claim.signing_channel.canonical_url : undefined;
|
const channelUri = claim && claim.signing_channel ? claim.signing_channel.canonical_url : undefined;
|
||||||
const subCount = channelUri && selectSubCountForUri(state, channelUri);
|
const subCount = channelUri && selectSubCountForUri(state, channelUri);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
viewers,
|
|
||||||
isInsufficientCredits: makeSelectInsufficientCreditsForUri(props.uri)(state),
|
isInsufficientCredits: makeSelectInsufficientCreditsForUri(props.uri)(state),
|
||||||
title: selectTitleForUri(state, props.uri),
|
title: selectTitleForUri(state, props.uri),
|
||||||
channelClaimId,
|
channelClaimId,
|
||||||
|
|
|
@ -21,7 +21,6 @@ type Props = {
|
||||||
isNsfwBlocked: boolean,
|
isNsfwBlocked: boolean,
|
||||||
livestream?: boolean,
|
livestream?: boolean,
|
||||||
isLive?: boolean,
|
isLive?: boolean,
|
||||||
viewers?: number,
|
|
||||||
subCount: number,
|
subCount: number,
|
||||||
channelClaimId?: string,
|
channelClaimId?: string,
|
||||||
fetchSubCount: (string) => void,
|
fetchSubCount: (string) => void,
|
||||||
|
@ -35,7 +34,6 @@ function FileTitleSection(props: Props) {
|
||||||
isNsfwBlocked,
|
isNsfwBlocked,
|
||||||
livestream = false,
|
livestream = false,
|
||||||
isLive = false,
|
isLive = false,
|
||||||
viewers,
|
|
||||||
subCount,
|
subCount,
|
||||||
channelClaimId,
|
channelClaimId,
|
||||||
fetchSubCount,
|
fetchSubCount,
|
||||||
|
@ -66,7 +64,7 @@ function FileTitleSection(props: Props) {
|
||||||
body={
|
body={
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<ClaimInsufficientCredits uri={uri} />
|
<ClaimInsufficientCredits uri={uri} />
|
||||||
<FileSubtitle uri={uri} isLive={isLive} livestream={livestream} activeViewers={viewers} />
|
<FileSubtitle uri={uri} isLive={isLive} livestream={livestream} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
actions={
|
actions={
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
import { selectClaimIdForUri } from 'redux/selectors/claims';
|
||||||
|
import { selectViewersForId } from 'redux/selectors/livestream';
|
||||||
import { doFetchViewCount, selectViewCountForUri } from 'lbryinc';
|
import { doFetchViewCount, selectViewCountForUri } from 'lbryinc';
|
||||||
import { doAnalyticsView } from 'redux/actions/app';
|
import { doAnalyticsView } from 'redux/actions/app';
|
||||||
import FileViewCount from './view';
|
import FileViewCount from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => {
|
||||||
claim: makeSelectClaimForUri(props.uri)(state),
|
const claimId = selectClaimIdForUri(state, props.uri);
|
||||||
|
return {
|
||||||
|
claimId,
|
||||||
viewCount: selectViewCountForUri(state, props.uri),
|
viewCount: selectViewCountForUri(state, props.uri),
|
||||||
});
|
activeViewers: props.livestream && props.isLive && claimId ? selectViewersForId(state, claimId) : undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
fetchViewCount: (claimId) => dispatch(doFetchViewCount(claimId)),
|
fetchViewCount: (claimId) => dispatch(doFetchViewCount(claimId)),
|
||||||
|
|
|
@ -4,20 +4,19 @@ import React from 'react';
|
||||||
import HelpLink from 'component/common/help-link';
|
import HelpLink from 'component/common/help-link';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: ?StreamClaim,
|
livestream?: boolean,
|
||||||
|
isLive?: boolean,
|
||||||
|
// --- redux ---
|
||||||
|
claimId: ?string,
|
||||||
fetchViewCount: (string) => void,
|
fetchViewCount: (string) => void,
|
||||||
fetchingViewCount: boolean,
|
|
||||||
uri: string,
|
uri: string,
|
||||||
viewCount: string,
|
viewCount: string,
|
||||||
livestream?: boolean,
|
|
||||||
activeViewers?: number,
|
activeViewers?: number,
|
||||||
isLive?: boolean,
|
|
||||||
doAnalyticsView: (string) => void,
|
doAnalyticsView: (string) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
function FileViewCount(props: Props) {
|
function FileViewCount(props: Props) {
|
||||||
const { claim, uri, fetchViewCount, viewCount, livestream, activeViewers, isLive = false, doAnalyticsView } = props;
|
const { claimId, uri, fetchViewCount, viewCount, livestream, activeViewers, isLive = false, doAnalyticsView } = props;
|
||||||
const claimId = claim && claim.claim_id;
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (livestream) {
|
if (livestream) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { MAX_LIVESTREAM_COMMENTS } from 'constants/livestream';
|
||||||
import { doResolveUris } from 'redux/actions/claims';
|
import { doResolveUris } from 'redux/actions/claims';
|
||||||
import { selectClaimForUri, selectMyClaimIdsRaw } from 'redux/selectors/claims';
|
import { selectClaimForUri, selectMyClaimIdsRaw } from 'redux/selectors/claims';
|
||||||
import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket';
|
import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket';
|
||||||
|
@ -10,9 +11,8 @@ import {
|
||||||
selectSuperChatTotalAmountForUri,
|
selectSuperChatTotalAmountForUri,
|
||||||
selectPinnedCommentsForUri,
|
selectPinnedCommentsForUri,
|
||||||
} from 'redux/selectors/comments';
|
} from 'redux/selectors/comments';
|
||||||
import LivestreamComments from './view';
|
|
||||||
|
|
||||||
const MAX_LIVESTREAM_COMMENTS = 75;
|
import LivestreamComments from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
claim: selectClaimForUri(state, props.uri),
|
claim: selectClaimForUri(state, props.uri),
|
||||||
|
|
|
@ -16,7 +16,6 @@ import { parseSticker } from 'util/comments';
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
claim: ?StreamClaim,
|
claim: ?StreamClaim,
|
||||||
activeViewers: number,
|
|
||||||
embed?: boolean,
|
embed?: boolean,
|
||||||
doCommentSocketConnect: (string, string) => void,
|
doCommentSocketConnect: (string, string) => void,
|
||||||
doCommentSocketDisconnect: (string) => void,
|
doCommentSocketDisconnect: (string) => void,
|
||||||
|
|
|
@ -3,3 +3,5 @@ export const LIVESTREAM_LIVE_API = 'https://api.live.odysee.com/v1/odysee/live';
|
||||||
export const LIVESTREAM_REPLAY_API = 'https://api.live.odysee.com/v1/replays/odysee';
|
export const LIVESTREAM_REPLAY_API = 'https://api.live.odysee.com/v1/replays/odysee';
|
||||||
export const LIVESTREAM_RTMP_URL = 'rtmp://stream.odysee.com/live';
|
export const LIVESTREAM_RTMP_URL = 'rtmp://stream.odysee.com/live';
|
||||||
export const LIVESTREAM_KILL = 'https://api.stream.odysee.com/stream/kill';
|
export const LIVESTREAM_KILL = 'https://api.stream.odysee.com/stream/kill';
|
||||||
|
|
||||||
|
export const MAX_LIVESTREAM_COMMENTS = 75;
|
||||||
|
|
|
@ -51,12 +51,11 @@ export const selectCommentsByUri = createSelector(selectState, (state) => {
|
||||||
|
|
||||||
export const selectPinnedCommentsById = (state: State) => selectState(state).pinnedCommentsById;
|
export const selectPinnedCommentsById = (state: State) => selectState(state).pinnedCommentsById;
|
||||||
export const selectPinnedCommentsForUri = createCachedSelector(
|
export const selectPinnedCommentsForUri = createCachedSelector(
|
||||||
selectCommentsByUri,
|
selectClaimIdForUri,
|
||||||
selectCommentsById,
|
selectCommentsById,
|
||||||
selectPinnedCommentsById,
|
selectPinnedCommentsById,
|
||||||
(state, uri) => uri,
|
(state, uri) => uri,
|
||||||
(byUri, byId, pinnedCommentsById, uri) => {
|
(claimId, byId, pinnedCommentsById, uri) => {
|
||||||
const claimId = byUri[uri];
|
|
||||||
const pinnedCommentIds = pinnedCommentsById && pinnedCommentsById[claimId];
|
const pinnedCommentIds = pinnedCommentsById && pinnedCommentsById[claimId];
|
||||||
const pinnedComments = [];
|
const pinnedComments = [];
|
||||||
|
|
||||||
|
@ -199,10 +198,9 @@ export const selectFetchingBlockedWords = (state: State) => selectState(state).f
|
||||||
export const selectCommentsForUri = createCachedSelector(
|
export const selectCommentsForUri = createCachedSelector(
|
||||||
(state, uri) => uri,
|
(state, uri) => uri,
|
||||||
selectCommentsByClaimId,
|
selectCommentsByClaimId,
|
||||||
selectCommentsByUri,
|
selectClaimIdForUri,
|
||||||
...Object.values(filterCommentsDepOnList),
|
...Object.values(filterCommentsDepOnList),
|
||||||
(uri, byClaimId, byUri, ...filterInputs) => {
|
(uri, byClaimId, claimId, ...filterInputs) => {
|
||||||
const claimId = byUri[uri];
|
|
||||||
const comments = byClaimId && byClaimId[claimId];
|
const comments = byClaimId && byClaimId[claimId];
|
||||||
return filterComments(comments, claimId, filterInputs);
|
return filterComments(comments, claimId, filterInputs);
|
||||||
}
|
}
|
||||||
|
@ -212,22 +210,18 @@ export const selectTopLevelCommentsForUri = createCachedSelector(
|
||||||
(state, uri) => uri,
|
(state, uri) => uri,
|
||||||
(state, uri, maxCount) => maxCount,
|
(state, uri, maxCount) => maxCount,
|
||||||
selectTopLevelCommentsByClaimId,
|
selectTopLevelCommentsByClaimId,
|
||||||
selectCommentsByUri,
|
selectClaimIdForUri,
|
||||||
...Object.values(filterCommentsDepOnList),
|
...Object.values(filterCommentsDepOnList),
|
||||||
(uri, maxCount = -1, byClaimId, byUri, ...filterInputs) => {
|
(uri, maxCount = -1, byClaimId, claimId, ...filterInputs) => {
|
||||||
const claimId = byUri[uri];
|
|
||||||
const comments = byClaimId && byClaimId[claimId];
|
const comments = byClaimId && byClaimId[claimId];
|
||||||
const filtered = filterComments(comments, claimId, filterInputs);
|
if (comments) {
|
||||||
return maxCount > 0 ? filtered.slice(0, maxCount) : filtered;
|
return filterComments(maxCount > 0 ? comments.slice(0, maxCount) : comments, claimId, filterInputs);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)((state, uri, maxCount = -1) => `${String(uri)}:${maxCount}`);
|
)((state, uri, maxCount = -1) => `${String(uri)}:${maxCount}`);
|
||||||
|
|
||||||
export const makeSelectTopLevelTotalCommentsForUri = (uri: string) =>
|
|
||||||
createSelector(selectState, selectCommentsByUri, (state, byUri) => {
|
|
||||||
const claimId = byUri[uri];
|
|
||||||
return state.topLevelTotalCommentsById[claimId] || 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const makeSelectTopLevelTotalPagesForUri = (uri: string) =>
|
export const makeSelectTopLevelTotalPagesForUri = (uri: string) =>
|
||||||
createSelector(selectState, selectCommentsByUri, (state, byUri) => {
|
createSelector(selectState, selectCommentsByUri, (state, byUri) => {
|
||||||
const claimId = byUri[uri];
|
const claimId = byUri[uri];
|
||||||
|
|
|
@ -29,8 +29,10 @@ export const selectViewersById = (state: State) => selectState(state).viewersByI
|
||||||
export const makeSelectIsFetchingLivestreams = (channelId: string) =>
|
export const makeSelectIsFetchingLivestreams = (channelId: string) =>
|
||||||
createSelector(selectFetchingLivestreams, (fetchingLivestreams) => Boolean(fetchingLivestreams[channelId]));
|
createSelector(selectFetchingLivestreams, (fetchingLivestreams) => Boolean(fetchingLivestreams[channelId]));
|
||||||
|
|
||||||
export const makeSelectViewersForId = (channelId: string) =>
|
export const selectViewersForId = (state: State, channelId: string) => {
|
||||||
createSelector(selectViewersById, (viewers) => viewers[channelId]);
|
const viewers = selectViewersById(state);
|
||||||
|
return viewers[channelId];
|
||||||
|
};
|
||||||
|
|
||||||
export const makeSelectPendingLivestreamsForChannelId = (channelId: string) =>
|
export const makeSelectPendingLivestreamsForChannelId = (channelId: string) =>
|
||||||
createSelector(selectPendingClaims, (pendingClaims) => {
|
createSelector(selectPendingClaims, (pendingClaims) => {
|
||||||
|
|
|
@ -20,6 +20,11 @@ export const selectSubscriptions = createSelector(
|
||||||
(state) => state.subscriptions && state.subscriptions.sort((a, b) => a.channelName.localeCompare(b.channelName))
|
(state) => state.subscriptions && state.subscriptions.sort((a, b) => a.channelName.localeCompare(b.channelName))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectSubscriptionUris = createSelector(
|
||||||
|
selectSubscriptions,
|
||||||
|
(subscriptions) => subscriptions && subscriptions.map((sub) => sub.uri)
|
||||||
|
);
|
||||||
|
|
||||||
export const selectFollowing = createSelector(selectState, (state) => state.following && state.following);
|
export const selectFollowing = createSelector(selectState, (state) => state.following && state.following);
|
||||||
|
|
||||||
// Fetching list of users subscriptions
|
// Fetching list of users subscriptions
|
||||||
|
|
Loading…
Reference in a new issue