From 049b1c727eaad528414129c555a6ef4a396d9de4 Mon Sep 17 00:00:00 2001 From: infinite-persistence <64950861+infinite-persistence@users.noreply.github.com> Date: Fri, 12 Nov 2021 23:59:11 +0800 Subject: [PATCH] Attempt to speed up sidebar menu for mobile (#283) * Exclude default homepage data at compile time The youtuber IDs alone is pretty huge, and is unused in the `CUSTOM_HOMEPAGE=true` configuration. * Remove Desktop items and other cleanup - Moved constants out of the component. - Remove SIMPLE_SITE check. - Remove Desktop-only items * Sidebar: limit subscription and tag section Too slow for huge lists Limit to 10 initially, and load everything on "Show more" * Fix makeSelectThumbnailForUri - Fix memo - Expose function to extract directly from claim if client already have it. --- ui/component/channelForm/index.js | 4 +- ui/component/channelThumbnail/index.js | 6 +-- ui/component/claimPreviewTile/index.js | 4 +- ui/component/collectionEdit/index.js | 4 +- ui/component/collectionPreviewTile/index.js | 4 +- ui/component/comment/index.js | 6 ++- ui/component/embedPlayButton/index.js | 4 +- ui/component/fileRender/index.js | 4 +- ui/component/fileRenderInitiator/index.js | 4 +- ui/component/previewLink/index.js | 4 +- ui/component/viewers/videoViewer/index.js | 4 +- ui/page/channel/index.js | 4 +- ui/page/collection/index.js | 4 +- ui/redux/selectors/claims.js | 13 +++-- ui/util/buildHomepage.js | 53 ++++++++++++--------- 15 files changed, 68 insertions(+), 54 deletions(-) diff --git a/ui/component/channelForm/index.js b/ui/component/channelForm/index.js index 43e054f7e..17ef05479 100644 --- a/ui/component/channelForm/index.js +++ b/ui/component/channelForm/index.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { makeSelectTitleForUri, - makeSelectThumbnailForUri, + selectThumbnailForUri, makeSelectCoverForUri, makeSelectMetadataItemForUri, makeSelectAmountForUri, @@ -22,7 +22,7 @@ import ChannelForm from './view'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), title: makeSelectTitleForUri(props.uri)(state), - thumbnailUrl: makeSelectThumbnailForUri(props.uri)(state), + thumbnailUrl: selectThumbnailForUri(state, props.uri), coverUrl: makeSelectCoverForUri(props.uri)(state), description: makeSelectMetadataItemForUri(props.uri, 'description')(state), website: makeSelectMetadataItemForUri(props.uri, 'website_url')(state), diff --git a/ui/component/channelThumbnail/index.js b/ui/component/channelThumbnail/index.js index ebedaff1a..c5ac39490 100644 --- a/ui/component/channelThumbnail/index.js +++ b/ui/component/channelThumbnail/index.js @@ -1,11 +1,11 @@ import { connect } from 'react-redux'; -import { makeSelectThumbnailForUri, makeSelectClaimForUri, makeSelectIsUriResolving } from 'redux/selectors/claims'; +import { selectThumbnailForUri, selectClaimForUri, makeSelectIsUriResolving } from 'redux/selectors/claims'; import { doResolveUri } from 'redux/actions/claims'; import ChannelThumbnail from './view'; const select = (state, props) => ({ - thumbnail: makeSelectThumbnailForUri(props.uri)(state), - claim: makeSelectClaimForUri(props.uri)(state), + thumbnail: selectThumbnailForUri(state, props.uri), + claim: selectClaimForUri(state, props.uri), isResolving: makeSelectIsUriResolving(props.uri)(state), }); diff --git a/ui/component/claimPreviewTile/index.js b/ui/component/claimPreviewTile/index.js index 7d1e558d4..80c1d7c49 100644 --- a/ui/component/claimPreviewTile/index.js +++ b/ui/component/claimPreviewTile/index.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { makeSelectClaimForUri, makeSelectIsUriResolving, - makeSelectThumbnailForUri, + getThumbnailFromClaim, makeSelectTitleForUri, makeSelectChannelForClaimUri, makeSelectClaimIsNsfw, @@ -27,7 +27,7 @@ const select = (state, props) => { date: props.uri && selectDateForUri(state, props.uri), channel: props.uri && makeSelectChannelForClaimUri(props.uri)(state), isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state), - thumbnail: props.uri && makeSelectThumbnailForUri(props.uri)(state), + thumbnail: getThumbnailFromClaim(claim), title: props.uri && makeSelectTitleForUri(props.uri)(state), banState: selectBanStateForUri(state, props.uri), blockedChannelUris: selectMutedChannels(state), diff --git a/ui/component/collectionEdit/index.js b/ui/component/collectionEdit/index.js index 54cf51ee3..5ecf17e87 100644 --- a/ui/component/collectionEdit/index.js +++ b/ui/component/collectionEdit/index.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { makeSelectTitleForUri, - makeSelectThumbnailForUri, + selectThumbnailForUri, makeSelectMetadataItemForUri, makeSelectAmountForUri, makeSelectClaimForUri, @@ -26,7 +26,7 @@ import { doSetActiveChannel, doSetIncognito } from 'redux/actions/app'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), title: makeSelectTitleForUri(props.uri)(state), - thumbnailUrl: makeSelectThumbnailForUri(props.uri)(state), + thumbnailUrl: selectThumbnailForUri(state, props.uri), description: makeSelectMetadataItemForUri(props.uri, 'description')(state), tags: makeSelectMetadataItemForUri(props.uri, 'tags')(state), locations: makeSelectMetadataItemForUri(props.uri, 'locations')(state), diff --git a/ui/component/collectionPreviewTile/index.js b/ui/component/collectionPreviewTile/index.js index 706cd974d..aec991b35 100644 --- a/ui/component/collectionPreviewTile/index.js +++ b/ui/component/collectionPreviewTile/index.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { makeSelectIsUriResolving, - makeSelectThumbnailForUri, + getThumbnailFromClaim, makeSelectTitleForUri, makeSelectChannelForClaimUri, makeSelectClaimIsNsfw, @@ -40,7 +40,7 @@ const select = (state, props) => { isResolvingCollectionClaims: makeSelectIsResolvingCollectionForId(collectionId)(state), channelClaim: collectionUri && makeSelectChannelForClaimUri(collectionUri)(state), isResolvingUri: collectionUri && makeSelectIsUriResolving(collectionUri)(state), - thumbnail: collectionUri && makeSelectThumbnailForUri(collectionUri)(state), + thumbnail: getThumbnailFromClaim(claim), title: collectionUri && makeSelectTitleForUri(collectionUri)(state), blackListedOutpoints: selectBlackListedOutpoints(state), filteredOutpoints: selectFilteredOutpoints(state), diff --git a/ui/component/comment/index.js b/ui/component/comment/index.js index 81744b65f..743faac8d 100644 --- a/ui/component/comment/index.js +++ b/ui/component/comment/index.js @@ -2,7 +2,8 @@ import { connect } from 'react-redux'; import { selectTotalStakedAmountForChannelUri, makeSelectClaimForUri, - makeSelectThumbnailForUri, + selectThumbnailForUri, + selectHasChannels, selectMyChannelClaims, } from 'redux/selectors/claims'; import { doCommentUpdate, doCommentList } from 'redux/actions/comments'; @@ -25,11 +26,12 @@ const select = (state, props) => { return { claim: makeSelectClaimForUri(props.uri)(state), - thumbnail: props.authorUri && makeSelectThumbnailForUri(props.authorUri)(state), + thumbnail: props.authorUri && selectThumbnailForUri(state, props.authorUri), channelIsBlocked: props.authorUri && makeSelectChannelIsMuted(props.authorUri)(state), commentingEnabled: true, othersReacts: selectOthersReactsForComment(state, reactionKey), activeChannelClaim, + hasChannels: selectHasChannels(state), // myChannels: selectMyChannelClaims(state), playingUri: selectPlayingUri(state), stakedLevel: selectTotalStakedAmountForChannelUri(state, props.authorUri), diff --git a/ui/component/embedPlayButton/index.js b/ui/component/embedPlayButton/index.js index 70847b149..339f02b3b 100644 --- a/ui/component/embedPlayButton/index.js +++ b/ui/component/embedPlayButton/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectThumbnailForUri, makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectThumbnailForUri, makeSelectClaimForUri } from 'redux/selectors/claims'; import { doResolveUri } from 'redux/actions/claims'; import * as SETTINGS from 'constants/settings'; import { doFetchCostInfoForUri, makeSelectCostInfoForUri } from 'lbryinc'; @@ -11,7 +11,7 @@ import { makeSelectFileRenderModeForUri } from 'redux/selectors/content'; import ChannelThumbnail from './view'; const select = (state, props) => ({ - thumbnail: makeSelectThumbnailForUri(props.uri)(state), + thumbnail: selectThumbnailForUri(state, props.uri), claim: makeSelectClaimForUri(props.uri)(state), floatingPlayerEnabled: makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state), costInfo: makeSelectCostInfoForUri(props.uri)(state), diff --git a/ui/component/fileRender/index.js b/ui/component/fileRender/index.js index 83a29abc0..6ddfd880f 100644 --- a/ui/component/fileRender/index.js +++ b/ui/component/fileRender/index.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { makeSelectDownloadPathForUri, makeSelectStreamingUrlForUri } from 'redux/selectors/file_info'; -import { makeSelectClaimForUri, makeSelectThumbnailForUri, makeSelectContentTypeForUri } from 'redux/selectors/claims'; +import { makeSelectClaimForUri, selectThumbnailForUri, makeSelectContentTypeForUri } from 'redux/selectors/claims'; import * as SETTINGS from 'constants/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectFileRenderModeForUri, makeSelectFileExtensionForUri } from 'redux/selectors/content'; @@ -11,7 +11,7 @@ const select = (state, props) => { return { currentTheme: makeSelectClientSetting(SETTINGS.THEME)(state), claim: makeSelectClaimForUri(props.uri)(state), - thumbnail: makeSelectThumbnailForUri(props.uri)(state), + thumbnail: selectThumbnailForUri(state, props.uri), contentType: makeSelectContentTypeForUri(props.uri)(state), downloadPath: makeSelectDownloadPathForUri(props.uri)(state), fileExtension: makeSelectFileExtensionForUri(props.uri)(state), diff --git a/ui/component/fileRenderInitiator/index.js b/ui/component/fileRenderInitiator/index.js index 4808fcb26..f7a061680 100644 --- a/ui/component/fileRenderInitiator/index.js +++ b/ui/component/fileRenderInitiator/index.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { doPlayUri, doSetPlayingUri, doSetPrimaryUri } from 'redux/actions/content'; -import { makeSelectThumbnailForUri, makeSelectClaimForUri, makeSelectClaimWasPurchased } from 'redux/selectors/claims'; +import { selectThumbnailForUri, makeSelectClaimForUri, makeSelectClaimWasPurchased } from 'redux/selectors/claims'; import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; import * as SETTINGS from 'constants/settings'; import * as COLLECTIONS_CONSTS from 'constants/collections'; @@ -22,7 +22,7 @@ const select = (state, props) => { const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID); return { - claimThumbnail: makeSelectThumbnailForUri(props.uri)(state), + claimThumbnail: selectThumbnailForUri(state, props.uri), fileInfo: makeSelectFileInfoForUri(props.uri)(state), obscurePreview: makeSelectShouldObscurePreview(props.uri)(state), isPlaying: makeSelectIsPlaying(props.uri)(state), diff --git a/ui/component/previewLink/index.js b/ui/component/previewLink/index.js index 9d93d2c63..25a3aad39 100644 --- a/ui/component/previewLink/index.js +++ b/ui/component/previewLink/index.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { selectClaimIsMine, makeSelectTitleForUri, - makeSelectThumbnailForUri, + getThumbnailFromClaim, selectClaimForUri, makeSelectIsUriResolving, makeSelectMetadataItemForUri, @@ -18,7 +18,7 @@ const select = (state, props) => { uri: props.uri, claim, title: makeSelectTitleForUri(props.uri)(state), - thumbnail: makeSelectThumbnailForUri(props.uri)(state), + thumbnail: getThumbnailFromClaim(claim), description: makeSelectMetadataItemForUri(props.uri, 'description')(state), channelIsMine: selectClaimIsMine(state, claim), isResolvingUri: makeSelectIsUriResolving(props.uri)(state), diff --git a/ui/component/viewers/videoViewer/index.js b/ui/component/viewers/videoViewer/index.js index e8907c907..a71b7970c 100644 --- a/ui/component/viewers/videoViewer/index.js +++ b/ui/component/viewers/videoViewer/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectClaimForUri, makeSelectThumbnailForUri } from 'redux/selectors/claims'; +import { makeSelectClaimForUri, selectThumbnailForUri } from 'redux/selectors/claims'; import { makeSelectNextUrlForCollectionAndUrl, makeSelectPreviousUrlForCollectionAndUrl, @@ -56,7 +56,7 @@ const select = (state, props) => { volume: selectVolume(state), muted: selectMute(state), videoPlaybackRate: makeSelectClientSetting(SETTINGS.VIDEO_PLAYBACK_RATE)(state), - thumbnail: makeSelectThumbnailForUri(uri)(state), + thumbnail: selectThumbnailForUri(state, uri), claim: makeSelectClaimForUri(uri)(state), homepageData: selectHomepageData(state), shareTelemetry: selectDaemonSettings(state).share_usage_data, diff --git a/ui/page/channel/index.js b/ui/page/channel/index.js index 4576586d3..8b82e26ee 100644 --- a/ui/page/channel/index.js +++ b/ui/page/channel/index.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { selectClaimIsMine, makeSelectTitleForUri, - makeSelectThumbnailForUri, + getThumbnailFromClaim, makeSelectCoverForUri, selectCurrentChannelPage, selectClaimForUri, @@ -22,7 +22,7 @@ const select = (state, props) => { return { title: makeSelectTitleForUri(props.uri)(state), - thumbnail: makeSelectThumbnailForUri(props.uri)(state), + thumbnail: getThumbnailFromClaim(claim), cover: makeSelectCoverForUri(props.uri)(state), channelIsMine: selectClaimIsMine(state, claim), page: selectCurrentChannelPage(state), diff --git a/ui/page/collection/index.js b/ui/page/collection/index.js index 62585eafe..863a1107d 100644 --- a/ui/page/collection/index.js +++ b/ui/page/collection/index.js @@ -4,7 +4,7 @@ import { withRouter } from 'react-router-dom'; import CollectionPage from './view'; import { makeSelectTitleForUri, - makeSelectThumbnailForUri, + getThumbnailFromClaim, selectClaimIsMine, makeSelectClaimIsPending, makeSelectClaimForClaimId, @@ -39,7 +39,7 @@ const select = (state, props) => { collectionCount: makeSelectCountForCollectionId(collectionId)(state), isResolvingCollection: makeSelectIsResolvingCollectionForId(collectionId)(state), title: makeSelectTitleForUri(uri)(state), - thumbnail: makeSelectThumbnailForUri(uri)(state), + thumbnail: getThumbnailFromClaim(claim), isMyClaim: selectClaimIsMine(state, claim), // or collection is mine? isMyCollection: makeSelectCollectionIsMine(collectionId)(state), claimIsPending: makeSelectClaimIsPending(uri)(state), diff --git a/ui/redux/selectors/claims.js b/ui/redux/selectors/claims.js index fb986fe1f..10e6f74df 100644 --- a/ui/redux/selectors/claims.js +++ b/ui/redux/selectors/claims.js @@ -388,11 +388,14 @@ export const makeSelectContentTypeForUri = (uri: string) => return source ? source.media_type : undefined; }); -export const makeSelectThumbnailForUri = (uri: string) => - createSelector(makeSelectClaimForUri(uri), (claim) => { - const thumbnail = claim && claim.value && claim.value.thumbnail; - return thumbnail && thumbnail.url ? thumbnail.url.trim().replace(/^http:\/\//i, 'https://') : undefined; - }); +export const getThumbnailFromClaim = (claim: Claim) => { + const thumbnail = claim && claim.value && claim.value.thumbnail; + return thumbnail && thumbnail.url ? thumbnail.url.trim().replace(/^http:\/\//i, 'https://') : undefined; +}; + +export const selectThumbnailForUri = createCachedSelector(selectClaimForUri, (claim) => { + return getThumbnailFromClaim(claim); +})((state, uri) => String(uri)); export const makeSelectCoverForUri = (uri: string) => createSelector(makeSelectClaimForUri(uri), (claim) => { diff --git a/ui/util/buildHomepage.js b/ui/util/buildHomepage.js index 6c192889b..f5cb70d1f 100644 --- a/ui/util/buildHomepage.js +++ b/ui/util/buildHomepage.js @@ -144,6 +144,32 @@ export function GetLinksData( let rowData: Array = []; const individualTagDataItems: Array = []; + if (isHomepage && showPersonalizedChannels && subscribedChannels) { + const RECENT_FROM_FOLLOWING = { + title: __('Recent From Following'), + link: `/$/${PAGES.CHANNELS_FOLLOWING}`, + icon: ICONS.SUBSCRIBE, + options: { + orderBy: CS.ORDER_BY_NEW_VALUE, + releaseTime: + subscribedChannels.length > 20 + ? `>${Math.floor(moment().subtract(9, 'months').startOf('week').unix())}` + : `>${Math.floor(moment().subtract(1, 'year').startOf('week').unix())}`, + pageSize: getPageSize(subscribedChannels.length > 3 ? (subscribedChannels.length > 6 ? 16 : 8) : 4), + streamTypes: null, + channelIds: subscribedChannels.map((subscription: Subscription) => { + const { channelClaimId } = parseURI(subscription.uri); + if (channelClaimId) return channelClaimId; + }), + }, + }; + // $FlowFixMe flow thinks this might not be Array + rowData.push(RECENT_FROM_FOLLOWING); + } + + // ************************************************************************** + // @if CUSTOM_HOMEPAGE='false' + const YOUTUBER_CHANNEL_IDS = [ 'fb364ef587872515f545a5b4b3182b58073f230f', '589276465a23c589801d874f484cc39f307d7ec7', @@ -274,28 +300,6 @@ export function GetLinksData( }, }; - if (isHomepage && showPersonalizedChannels && subscribedChannels) { - const RECENT_FROM_FOLLOWING = { - title: __('Recent From Following'), - link: `/$/${PAGES.CHANNELS_FOLLOWING}`, - icon: ICONS.SUBSCRIBE, - options: { - orderBy: CS.ORDER_BY_NEW_VALUE, - releaseTime: - subscribedChannels.length > 20 - ? `>${Math.floor(moment().subtract(9, 'months').startOf('week').unix())}` - : `>${Math.floor(moment().subtract(1, 'year').startOf('week').unix())}`, - pageSize: getPageSize(subscribedChannels.length > 3 ? (subscribedChannels.length > 6 ? 16 : 8) : 4), - streamTypes: null, - channelIds: subscribedChannels.map((subscription: Subscription) => { - const { channelClaimId } = parseURI(subscription.uri); - if (channelClaimId) return channelClaimId; - }), - }, - }; - // $FlowFixMe flow thinks this might not be Array - rowData.push(RECENT_FROM_FOLLOWING); - } if (isHomepage && !CUSTOM_HOMEPAGE) { if (followedTags) { const TRENDING_FOR_TAGS = { @@ -330,6 +334,7 @@ export function GetLinksData( } } } + if (!CUSTOM_HOMEPAGE) { if (!authenticated) { rowData.push(YOUTUBE_CREATOR_ROW); @@ -338,6 +343,10 @@ export function GetLinksData( rowData.push(LATEST_FROM_LBRY); if (!showPersonalizedChannels) rowData.push(TOP_CHANNELS); } + + // @endif + // ************************************************************************** + // TODO: provide better method for exempting from homepage (Object.values(all): any) .filter((row) => !(isHomepage && row.name === 'news'))