lbry-desktop/ui/util/buildHomepage.js

374 lines
12 KiB
JavaScript
Raw Normal View History

// @flow
import * as PAGES from 'constants/pages';
import * as ICONS from 'constants/icons';
import * as CS from 'constants/claim_search';
2022-05-23 18:50:59 +02:00
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
import { parseURI } from 'util/lbryURI';
import moment from 'moment';
import { toCapitalCase } from 'util/string';
import { CUSTOM_HOMEPAGE } from 'config';
export type RowDataItem = {
title: any,
link?: string,
help?: any,
icon?: string,
extra?: any,
options?: {
channelIds?: Array<string>,
pageSize?: number,
limitClaimsPerChannel?: number,
2022-05-23 18:50:59 +02:00
languages?: Array<string>,
},
route?: string,
hideForUnauth?: boolean,
};
export type HomepageCat = {
name: string,
icon: string,
label: string,
channelIds?: Array<string>,
daysOfContent?: number,
channelLimit?: string,
pageSize?: number,
claimType?: string,
order?: string,
tags?: Array<string>,
pinnedUrls?: Array<string>,
mixIn?: Array<string>,
};
2021-07-17 00:20:22 +02:00
// type HomepageData = {
// [string]: {
// [string]: HomepageCat,
// },
// };
function getLimitPerChannel(size, isChannel) {
if (isChannel) {
return 1;
} else {
return size < 250 ? (size < 150 ? 3 : 2) : 1;
}
}
2021-07-17 00:20:22 +02:00
export function getAllIds(all: any) {
const idsSet: Set<string> = new Set();
(Object.values(all): any).forEach((cat) => {
if (cat.channelIds) {
cat.channelIds.forEach((id) => idsSet.add(id));
}
});
// $FlowFixMe
return Array.from(idsSet);
}
export const getHomepageRowForCat = (cat: HomepageCat) => {
let orderValue;
switch (cat.order) {
case 'trending':
orderValue = CS.ORDER_BY_TRENDING_VALUE;
break;
case 'top':
orderValue = CS.ORDER_BY_TOP_VALUE;
break;
default:
orderValue = CS.ORDER_BY_NEW_VALUE;
}
let urlParams = new URLSearchParams();
if (cat.claimType) {
urlParams.set(CS.CLAIM_TYPE, cat.claimType);
}
if (cat.channelIds) {
urlParams.set(CS.CHANNEL_IDS_KEY, cat.channelIds.join(','));
}
const isChannelType = cat.claimType && cat.claimType === 'channel';
// can intend no limit, numerica auto limit, specific limit.
let limitClaims;
if (typeof cat.channelLimit === 'string' && cat.channelIds && cat.channelIds.length) {
if (cat.channelLimit === 'auto') {
limitClaims = getLimitPerChannel(cat.channelIds.length, isChannelType);
} else if (cat.channelLimit) {
const limitNumber = Number(cat.channelLimit);
// eslint-disable-next-line
if (limitNumber === limitNumber && limitNumber !== 0) {
// because javascript and NaN !== NaN
limitClaims = Math.floor(limitNumber);
}
}
}
return {
link: `/$/${PAGES.DISCOVER}?${urlParams.toString()}`,
route: cat.name ? `/$/${cat.name}` : undefined,
icon: cat.icon || '', // some default
title: cat.label,
2021-07-23 04:15:45 +02:00
pinnedUrls: cat.pinnedUrls,
options: {
claimType: cat.claimType || 'stream',
channelIds: cat.channelIds,
orderBy: orderValue,
pageSize: cat.pageSize || undefined,
limitClaimsPerChannel: limitClaims,
releaseTime: `>${Math.floor(
moment()
.subtract(cat.daysOfContent || 30, 'days')
.startOf('week')
.unix()
)}`,
},
};
};
export function GetLinksData(
2021-07-17 00:20:22 +02:00
all: any, // HomepageData type?
Playlistorder (#7442) * Add horizontal layout (#636) * Test out a horizontal scroll for upcoming (tile only for now) * - add support for list layout - add following label on home page - clan up css and naming conventions * Update header type + show only if scheduled streams are showing * [Playlist] Pull in sorting changes from desktop + Add Drag-n-Drop + Handle unavailable/deleted claims (#641) * Add ordering Icons * Refactor doCollectionEdit - It required claims as parameter, when only uris are used to populate the collection, so that was changed to pass down the uris instead. - There were unused and mostly unnecessary functions inside, for example the parameter claimIds was never used so it would never enter the claimSearch function which again would be used to generate uris, so it's better to just use uris as parameter * Add List Reordering changes * Add toggle button for list editing * Add toggle on content page collection sidebar * Enable drag-n-drop to re-order list items https://www.youtube.com/watch?v=aYZRRyukuIw * Allow removing all unavailable claims from a List * Fix <g> on icons * Fix section buttons positioning * Move preventDefault and stopPropagation to buttons div instead of each button, preventing clicking even if disabled opening the claim * Change dragging cursor * Fix sizing * Fix dragging component * Restrict dragging to vertical axis * Ignore shuffle state for ordering * Fix console errors * Mobile fixes * Fix sidebar spacing * Fix grey on mobile after click * cleanup Co-authored-by: Dan Peterson <dan@dan-peterson.ca> Co-authored-by: saltrafael <76502841+saltrafael@users.noreply.github.com>
2022-01-27 16:20:21 +01:00
isLargeScreen: boolean,
isHomepage?: boolean = false,
authenticated?: boolean,
showPersonalizedChannels?: boolean,
showPersonalizedTags?: boolean,
subscribedChannels?: Array<Subscription>,
followedTags?: Array<Tag>,
showIndividualTags?: boolean,
showNsfw?: boolean
) {
function getPageSize(originalSize) {
return isLargeScreen ? originalSize * (3 / 2) : originalSize;
}
// $FlowFixMe
let rowData: Array<RowDataItem> = [];
const individualTagDataItems: Array<RowDataItem> = [];
Selector refactors (#7424) * 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. * Fix and optimize makeSelectIsSubscribed (#273) - It will not return true if the uri provided is canonical, because the compared subscription uri is in permanent form. This was causing certain elements like the Heart to not appear in claim tiles. - It is super slow for large subscriptions not just because of the array size + being a hot selector, but also because it is looking up the claim twice (not memo'd) and also calling `parseURI` to determine if it's a channel, which is unnecessary if you already have the claim. - Optimize the selector to only look up the claim once, and make operations using already-obtained info. * Simplify makeSelectTitleForUri No need to memo given no transformation. * Simplify makeSelectIsUriResolving - Memo not required. `resolvingUris` is very dynamic and is a short array anyways. - Changeg from using `indexOf` to `includes`, which is more concise. * Cost Info selector fixes - no memo required since they are just directly accessing the store. Co-authored-by: infinite-persistence <64950861+infinite-persistence@users.noreply.github.com> Co-authored-by: infinite-persistence <inf.persistence@gmail.com>
2022-01-20 02:46:01 +01:00
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<string>
rowData.push(RECENT_FROM_FOLLOWING);
}
// **************************************************************************
// @if CUSTOM_HOMEPAGE='false'
const YOUTUBER_CHANNEL_IDS = [
'fb364ef587872515f545a5b4b3182b58073f230f',
'589276465a23c589801d874f484cc39f307d7ec7',
'ba79c80788a9e1751e49ad401f5692d86f73a2db',
'b6e207c5f8c58e7c8362cd05a1501bf2f5b694f2',
'c5724e280283cd985186af9a62494aae377daabd',
'243b6f18093ff97c861d0568c7d3379606201a4b',
'5b7c7a202201033d99e1be2930d290c127c0f4fe',
'c9da929d12afe6066acc89eb044b552f0d63782a',
'89985db232ec2a9a31dbd985196de817da223fe6',
'187bf3616318b4bfb85223fc40724c307696f0c6',
'aa3db8d2145340e26597b88fbb6d0e7ff09786be',
'a9d289718f3f14e3d1fa8da7a7fcfdb6f40ae2d7',
'9a5dfcb1a4b29c3a1598392d039744b9938b5a26',
'0b998b98a2b9a88d9519739f99f2c74c95e3fc22',
'46be492ee0f56db11e005991c537c867a8682f77',
'c5cd9b63e2ba0abc191feae48238f464baecb147',
'4b602d7a3e268abb45951f623a109d2a131ab0ba',
'd25ae97a1516f5700fc717152b885f33da47f12b',
'8f4fecfc836ea33798ee3e5cef56926fa54e2cf9',
'8671dfd2f34302c1a4dcb4dd7361568a0bb23eba',
'b9288432bd089c6f332145aab08a56eec155f307',
'87b13b074936b1f42a7c6758c7c2995f58c602e7',
'25f384bd95e218f6ac37fcaca99ed40f36760d8c',
'02c020b2fab7dd1fbd175c3b22947688c0a219e5',
'57dbc8fdc4d062e2824d8550861b380203539099',
'4e17d248adc0128afe969c2e1327e10afd9cb921',
'760da3ba3dd85830a843beaaed543a89b7a367e7',
'5a1b164d0a2e7adf1db08d7363ea1cb06c30cd74',
'c9da929d12afe6066acc89eb044b552f0d63782a',
'113515e893b8186595595e594ecc410bae50c026',
'5fbfcf517d3df749bd032a44c1946b2baa738ecb',
'74333143a3dcc001a5602aa524583fc75a013d75',
'0d4e104ffc0ff0a6c8701e67cf13760f4e0335a8',
'b924ac36b7499591f7929d9c4903de79b07b1cb9',
'13edd7e7e2fbaf845699cf2f8f0b1c095bacb05f',
'7b1c72ba903af4aecdc2595397a9cb91bb7f188d',
'6c0bf1fed2705d675da950a94e4af004ec975a06',
'f33657a2fcbab2dc3ce555d5d6728f8758af7bc7',
'26c9b54d7e47dc8f7dc847821b26fce3009ee1a0',
'1516361918bfd02ddd460489f438e153c918521c',
'd468989b4668bce7452fc3434a6dc7ba7d799378',
'a1c8f84670da9a3371bc5832e86c8d32826b2f2e',
'70e56234217f30317c0e67fd0eede6e82b74aea0',
'7a88e0eabf60af5ac61240fe60f8f08fa3e48ab4',
'2f229d3ac26aa655c5123c29f1f7352403279ca3',
'7ea92a937f5755b40ac3d99ed37c53b40359b0a2',
'96ede5667bc4533ace8cfcbde4f33aa9fe1ae5f5',
'5097b175c4c58c431424ce3b60901de6ae650127',
'32de523ba228dd3f3159eb5a6cc07b6fd51f4dc0',
'cdb6fe516afe08618b91a754f92412e7f98a8a62',
'1e9f582c2df798228e8583fe1101fee551487d4b',
'b032695b52a78e0f5251b8d7f2f32183a5985d19',
'c042155dfcb5c813345248bff18a62d0f585718e',
'294f5c164da5ac9735658b2d58d8fee6745dfc45',
'07e4546674268fc0222b2ca22d31d0549dc217ee',
'1487afc813124abbeb0629d2172be0f01ccec3bf',
'ac471128a5ed05b80365170b29997d860afa33b7',
'c101bac49ec048acca169fd6090e70f7488645b1',
'c9282bbb89d3f9f5f1d972a02f96a5f0f0f40df8',
'9576be30de21b3b755828314d6ccbbaa3334f43a',
'b12e255e9f84d8b4ed86343b27676dccbc8b6d8b',
'50ebba2b06908f93d7963b1c6826cc0fd6104477',
'84342ae85d216d5ffc0ef149a123aae649d5c253',
'80f78c4b8591390758b9e6303eaf9087180444ad',
'086d2bacf441cef45ff15b5afe163d0b03a9f7ea',
'5af39f818f668d8c00943c9326c5201c4fe3c423',
'057053dfb657aaa98553e2c544b06e1a2371557e',
'fd1aee1d4858ec2ef6ccc3e60504c76e9d774386',
'930fc43ca7bae20d4706543e97175d1872b0671f',
'e715c457b4a3e51214b62f49f05303bba4ee5be9',
'ebf5bc6842638cefcf66904522ac96231ea7a9d8',
'1f9bb08bfa2259629f4aaa9ed40f97e9a41b6fa1',
'ac415179241e0cd8a14ed71175b759254d381137',
'8e098d2042ad9b9074f52cc06b89d6d4db5231dd',
'149c4686ff0792b8d68dac1f17b6273a85628d34',
'199eba05b6ecccab919e26a0cb7dacd544f25700',
'6569758308f12a66001e28f5e6056cb84334e69c',
'e50f82e2236274c54af762a9c2b897646477ef62',
'7e1a7afadc8734b33a3e219f5668470715fb063d',
'ff80e24f41a2d706c70df9779542cba4715216c9',
'e8f68563d242f6ac9784dcbc41dd86c28a9391d6',
];
const YOUTUBE_CREATOR_ROW = {
title: __('CableTube Escape Artists'),
link: `/$/${PAGES.DISCOVER}?${CS.CLAIM_TYPE}=${CS.CLAIM_STREAM}&${CS.CHANNEL_IDS_KEY}=${YOUTUBER_CHANNEL_IDS.join(
','
)}`,
options: {
claimType: ['stream'],
2021-12-02 21:18:21 +01:00
orderBy: CS.ORDER_BY_NEW_VALUE,
pageSize: getPageSize(12),
channelIds: YOUTUBER_CHANNEL_IDS,
limitClaimsPerChannel: 1,
releaseTime: `>${Math.floor(moment().subtract(1, 'months').startOf('week').unix())}`,
},
};
const TOP_CONTENT_TODAY = {
title: __('Top Content from Today'),
link: `/$/${PAGES.DISCOVER}?${CS.ORDER_BY_KEY}=${CS.ORDER_BY_TOP}&${CS.FRESH_KEY}=${CS.FRESH_DAY}`,
options: {
pageSize: getPageSize(showPersonalizedChannels || showPersonalizedTags ? 4 : 8),
2021-12-03 03:17:08 +01:00
orderBy: CS.ORDER_BY_TOP_VALUE,
claimType: ['stream'],
limitClaimsPerChannel: 2,
releaseTime: `>${Math.floor(moment().subtract(1, 'day').startOf('day').unix())}`,
},
};
2022-05-23 18:50:59 +02:00
const language = localStorage.getItem('language') || 'en';
const languageName = SUPPORTED_LANGUAGES[language];
const LANGUAGE_CATEGORY = {
title: __('Top content in %language%', { language: languageName }),
link: `/$/${PAGES.DISCOVER}?${CS.ORDER_BY_KEY}=${CS.ORDER_BY_TOP}&${CS.FRESH_KEY}=${CS.FRESH_DAY}&${CS.LANGUAGE_KEY}=${language}`,
options: {
languages: [language],
pageSize: getPageSize(showPersonalizedChannels || showPersonalizedTags ? 4 : 8),
orderBy: CS.ORDER_BY_TOP_VALUE,
claimType: ['stream'],
limitClaimsPerChannel: 2,
releaseTime: `>${Math.floor(moment().subtract(1, 'day').startOf('day').unix())}`,
},
};
const TOP_CHANNELS = {
title: __('Top Channels On LBRY'),
link: `/$/${PAGES.DISCOVER}?claim_type=channel&${CS.ORDER_BY_KEY}=${CS.ORDER_BY_TOP}&${CS.FRESH_KEY}=${CS.FRESH_ALL}`,
options: {
2021-12-02 21:18:21 +01:00
orderBy: CS.ORDER_BY_TOP_VALUE,
claimType: ['channel'],
},
};
const LATEST_FROM_LBRY = {
title: __('Latest From @lbry'),
link: `/@lbry:3f`,
options: {
2021-12-02 21:18:21 +01:00
orderBy: CS.ORDER_BY_NEW_VALUE,
pageSize: getPageSize(4),
channelIds: ['3fda836a92faaceedfe398225fb9b2ee2ed1f01a'],
},
};
if (isHomepage && !CUSTOM_HOMEPAGE) {
if (followedTags) {
const TRENDING_FOR_TAGS = {
title: __('Trending For Your Tags'),
link: `/$/${PAGES.TAGS_FOLLOWING}`,
icon: ICONS.TAG,
options: {
pageSize: getPageSize(4),
tags: followedTags.map((tag) => tag.name),
claimType: ['stream'],
limitClaimsPerChannel: 2,
},
};
followedTags.forEach((tag: Tag) => {
const tagName = `#${toCapitalCase(tag.name)}`;
individualTagDataItems.push({
title: __('Trending for %tagName%', { tagName: tagName }),
link: `/$/${PAGES.DISCOVER}?t=${tag.name}`,
options: {
pageSize: 4,
tags: [tag.name],
claimType: ['stream'],
},
});
});
if (showPersonalizedTags && !showIndividualTags) rowData.push(TRENDING_FOR_TAGS);
if (showPersonalizedTags && showIndividualTags) {
individualTagDataItems.forEach((item: RowDataItem) => {
rowData.push(item);
});
}
}
}
Selector refactors (#7424) * 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. * Fix and optimize makeSelectIsSubscribed (#273) - It will not return true if the uri provided is canonical, because the compared subscription uri is in permanent form. This was causing certain elements like the Heart to not appear in claim tiles. - It is super slow for large subscriptions not just because of the array size + being a hot selector, but also because it is looking up the claim twice (not memo'd) and also calling `parseURI` to determine if it's a channel, which is unnecessary if you already have the claim. - Optimize the selector to only look up the claim once, and make operations using already-obtained info. * Simplify makeSelectTitleForUri No need to memo given no transformation. * Simplify makeSelectIsUriResolving - Memo not required. `resolvingUris` is very dynamic and is a short array anyways. - Changeg from using `indexOf` to `includes`, which is more concise. * Cost Info selector fixes - no memo required since they are just directly accessing the store. Co-authored-by: infinite-persistence <64950861+infinite-persistence@users.noreply.github.com> Co-authored-by: infinite-persistence <inf.persistence@gmail.com>
2022-01-20 02:46:01 +01:00
if (!CUSTOM_HOMEPAGE) {
if (!authenticated) {
rowData.push(YOUTUBE_CREATOR_ROW);
}
rowData.push(TOP_CONTENT_TODAY);
2022-05-23 18:50:59 +02:00
if (language !== 'en') {
rowData.push(LANGUAGE_CATEGORY);
}
rowData.push(LATEST_FROM_LBRY);
if (!showPersonalizedChannels) rowData.push(TOP_CHANNELS);
}
Selector refactors (#7424) * 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. * Fix and optimize makeSelectIsSubscribed (#273) - It will not return true if the uri provided is canonical, because the compared subscription uri is in permanent form. This was causing certain elements like the Heart to not appear in claim tiles. - It is super slow for large subscriptions not just because of the array size + being a hot selector, but also because it is looking up the claim twice (not memo'd) and also calling `parseURI` to determine if it's a channel, which is unnecessary if you already have the claim. - Optimize the selector to only look up the claim once, and make operations using already-obtained info. * Simplify makeSelectTitleForUri No need to memo given no transformation. * Simplify makeSelectIsUriResolving - Memo not required. `resolvingUris` is very dynamic and is a short array anyways. - Changeg from using `indexOf` to `includes`, which is more concise. * Cost Info selector fixes - no memo required since they are just directly accessing the store. Co-authored-by: infinite-persistence <64950861+infinite-persistence@users.noreply.github.com> Co-authored-by: infinite-persistence <inf.persistence@gmail.com>
2022-01-20 02:46:01 +01:00
// @endif
// **************************************************************************
2021-07-23 21:44:16 +02:00
// TODO: provide better method for exempting from homepage
(Object.values(all): any)
.filter((row) => !(isHomepage && row.name === 'news'))
.map((row) => rowData.push(getHomepageRowForCat(row)));
return rowData;
}