lbry-desktop/ui/redux/selectors/content.js

265 lines
9.2 KiB
JavaScript
Raw Permalink Normal View History

2019-03-05 05:46:57 +01:00
// @flow
import { createSelector } from 'reselect';
2019-08-02 08:28:14 +02:00
import {
makeSelectClaimForUri,
selectClaimsByUri,
makeSelectClaimsInChannelForCurrentPageState,
makeSelectClaimIsNsfw,
makeSelectClaimIsMine,
makeSelectMediaTypeForUri,
selectBalance,
parseURI,
makeSelectContentTypeForUri,
makeSelectFileNameForUri,
selectClaimIdsByUri,
2019-08-02 08:28:14 +02:00
} from 'lbry-redux';
2020-07-27 22:04:12 +02:00
import { makeSelectRecommendedContentForUri } from 'redux/selectors/search';
import { selectMutedChannels } from 'redux/selectors/blocked';
import { selectAllCostInfoByUri, makeSelectCostInfoForUri } from 'lbryinc';
2019-08-02 08:28:14 +02:00
import { selectShowMatureContent } from 'redux/selectors/settings';
import * as RENDER_MODES from 'constants/file_render_modes';
import path from 'path';
import { FORCE_CONTENT_TYPE_PLAYER, FORCE_CONTENT_TYPE_COMIC } from 'constants/claim';
2019-04-01 01:04:01 +02:00
const RECENT_HISTORY_AMOUNT = 10;
const HISTORY_ITEMS_PER_PAGE = 50;
2019-03-05 05:46:57 +01:00
export const selectState = (state: any) => state.content || {};
export const selectPlayingUri = createSelector(selectState, (state) => state.playingUri);
export const selectPrimaryUri = createSelector(selectState, (state) => state.primaryUri);
2019-03-05 05:46:57 +01:00
export const makeSelectIsPlaying = (uri: string) =>
createSelector(selectPrimaryUri, (primaryUri) => primaryUri === uri);
2019-08-02 08:28:14 +02:00
export const makeSelectIsPlayerFloating = (location: UrlLocation) =>
createSelector(selectPrimaryUri, selectPlayingUri, selectClaimsByUri, (primaryUri, playingUri, claimsByUri) => {
const isInlineSecondaryPlayer =
playingUri &&
playingUri.uri !== primaryUri &&
location.pathname === playingUri.pathname &&
(playingUri.source === 'comment' || playingUri.source === 'markdown');
if ((playingUri && playingUri.uri === primaryUri) || isInlineSecondaryPlayer) {
return false;
}
return true;
2020-04-14 01:48:11 +02:00
});
2019-03-05 05:46:57 +01:00
export const makeSelectContentPositionForUri = (uri: string) =>
createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => {
if (!claim) {
return null;
2019-03-05 05:46:57 +01:00
}
const outpoint = `${claim.txid}:${claim.nout}`;
const id = claim.claim_id;
return state.positions[id] ? state.positions[id][outpoint] : null;
});
2019-03-05 05:46:57 +01:00
export const selectHistory = createSelector(selectState, (state) => state.history || []);
2019-04-01 01:04:01 +02:00
export const selectHistoryPageCount = createSelector(selectHistory, (history) =>
Math.ceil(history.length / HISTORY_ITEMS_PER_PAGE)
2019-03-05 05:46:57 +01:00
);
export const makeSelectHistoryForPage = (page: number) =>
createSelector(selectHistory, selectClaimsByUri, (history, claimsByUri) => {
const left = page * HISTORY_ITEMS_PER_PAGE;
const historyItemsForPage = history.slice(left, left + HISTORY_ITEMS_PER_PAGE);
return historyItemsForPage;
});
2019-03-05 05:46:57 +01:00
export const makeSelectHistoryForUri = (uri: string) =>
createSelector(selectHistory, (history) => history.find((i) => i.uri === uri));
2019-03-05 05:46:57 +01:00
2019-07-11 20:06:25 +02:00
export const makeSelectHasVisitedUri = (uri: string) =>
createSelector(makeSelectHistoryForUri(uri), (history) => Boolean(history));
2019-07-11 20:06:25 +02:00
2019-09-09 19:31:00 +02:00
export const makeSelectNextUnplayedRecommended = (uri: string) =>
createSelector(
makeSelectRecommendedContentForUri(uri),
selectHistory,
selectClaimsByUri,
selectAllCostInfoByUri,
selectMutedChannels,
(
recommendedForUri: Array<string>,
history: Array<{ uri: string }>,
claimsByUri: { [string]: ?Claim },
costInfoByUri: { [string]: { cost: 0 | string } },
blockedChannels: Array<string>
) => {
if (recommendedForUri) {
// Make sure we don't autoplay paid content, channels, or content from blocked channels
for (let i = 0; i < recommendedForUri.length; i++) {
const recommendedUri = recommendedForUri[i];
2020-02-05 16:07:48 +01:00
const claim = claimsByUri[recommendedUri];
if (!claim) {
continue;
}
const { isChannel } = parseURI(recommendedUri);
if (isChannel) {
continue;
}
const costInfo = costInfoByUri[recommendedUri];
if (!costInfo || costInfo.cost !== 0) {
continue;
}
2020-02-05 16:07:48 +01:00
// We already check if it's a channel above
// $FlowFixMe
const isVideo = claim.value && claim.value.stream_type === 'video';
2020-02-05 21:46:44 +01:00
// $FlowFixMe
const isAudio = claim.value && claim.value.stream_type === 'audio';
2020-02-07 07:22:48 +01:00
if (!isVideo && !isAudio) {
2020-02-05 16:07:48 +01:00
continue;
}
const channel = claim && claim.signing_channel;
if (channel && blockedChannels.some((blockedUri) => blockedUri === channel.permanent_url)) {
continue;
}
const recommendedUriInfo = parseURI(recommendedUri);
const recommendedUriShort = recommendedUriInfo.claimName + '#' + recommendedUriInfo.claimId.substring(0, 1);
if (claimsByUri[uri] && claimsByUri[uri].claim_id === recommendedUriInfo.claimId) {
// Skip myself (same claim ID)
continue;
}
if (
!history.some((h) => {
const directMatch = h.uri === recommendedForUri[i];
const shortUriMatch = h.uri.includes(recommendedUriShort);
const idMatch = claimsByUri[h.uri] && claimsByUri[h.uri].claim_id === recommendedUriInfo.claimId;
return directMatch || shortUriMatch || idMatch;
})
) {
return recommendedForUri[i];
2019-09-09 19:31:00 +02:00
}
}
}
}
);
export const selectRecentHistory = createSelector(selectHistory, (history) => {
return history.slice(0, RECENT_HISTORY_AMOUNT);
});
2019-04-01 01:04:01 +02:00
2019-03-05 05:46:57 +01:00
export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) =>
createSelector(makeSelectClaimsInChannelForCurrentPageState(channel), (channelClaims) => {
if (uris) return uris;
2019-03-05 05:46:57 +01:00
if (channelClaims) {
const CATEGORY_LIST_SIZE = 10;
return channelClaims.slice(0, CATEGORY_LIST_SIZE).map(({ name, claim_id: claimId }) => `${name}#${claimId}`);
2019-03-05 05:46:57 +01:00
}
2019-08-02 08:28:14 +02:00
return null;
});
export const makeSelectShouldObscurePreview = (uri: string) =>
createSelector(selectShowMatureContent, makeSelectClaimIsNsfw(uri), (showMatureContent, isClaimMature) => {
return isClaimMature && !showMatureContent;
});
// should probably be in lbry-redux, yarn link was fighting me
export const makeSelectFileExtensionForUri = (uri: string) =>
createSelector(makeSelectFileNameForUri(uri), (fileName) => {
return fileName && path.extname(fileName).substring(1);
});
export const makeSelectFileRenderModeForUri = (uri: string) =>
createSelector(
makeSelectContentTypeForUri(uri),
makeSelectMediaTypeForUri(uri),
makeSelectFileExtensionForUri(uri),
(contentType, mediaType, extension) => {
if (mediaType === 'video' || FORCE_CONTENT_TYPE_PLAYER.includes(contentType)) {
return RENDER_MODES.VIDEO;
}
2020-04-03 16:18:07 +02:00
if (mediaType === 'audio') {
return RENDER_MODES.AUDIO;
}
if (mediaType === 'image') {
return RENDER_MODES.IMAGE;
}
if (['md', 'markdown'].includes(extension) || ['text/md', 'text/markdown'].includes(contentType)) {
return RENDER_MODES.MARKDOWN;
}
if (contentType === 'application/pdf') {
return RENDER_MODES.PDF;
}
if (['text/htm', 'text/html'].includes(contentType)) {
return RENDER_MODES.HTML;
}
if (['text', 'document', 'script'].includes(mediaType)) {
return RENDER_MODES.DOCUMENT;
}
if (extension === 'docx') {
return RENDER_MODES.DOCX;
}
// when writing this my local copy of Lbry.getMediaType had '3D-file', but I was receiving model...'
if (['3D-file', 'model'].includes(mediaType)) {
return RENDER_MODES.CAD;
}
// Force content type for fallback support of older claims
if (mediaType === 'comic-book' || FORCE_CONTENT_TYPE_COMIC.includes(contentType)) {
return RENDER_MODES.COMIC;
}
if (
[
'application/zip',
'application/x-gzip',
'application/x-gtar',
'application/x-tgz',
'application/vnd.rar',
'application/x-7z-compressed',
].includes(contentType)
) {
return RENDER_MODES.DOWNLOAD;
}
if (mediaType === 'application') {
return RENDER_MODES.APPLICATION;
}
return RENDER_MODES.UNSUPPORTED;
}
);
2020-01-06 21:57:49 +01:00
export const makeSelectInsufficientCreditsForUri = (uri: string) =>
2020-01-06 21:57:49 +01:00
createSelector(
makeSelectClaimIsMine(uri),
makeSelectCostInfoForUri(uri),
selectBalance,
(isMine, costInfo, balance) => {
return !isMine && costInfo && costInfo.cost > 0 && costInfo.cost > balance;
2020-01-06 21:57:49 +01:00
}
);
2021-06-11 22:49:18 +02:00
export const makeSelectRecommendationId = (claimId: string) =>
createSelector(selectState, (state) => state.recommendationId[claimId]);
export const makeSelectRecommendationParentId = (claimId: string) =>
createSelector(selectState, (state) => state.recommendationParentId[claimId]);
export const makeSelectRecommendedClaimIds = (claimId: string) =>
createSelector(selectState, selectClaimIdsByUri, (state, claimIdsByUri) => {
const recommendationUrls = state.recommendationUrls[claimId];
if (recommendationUrls) {
return recommendationUrls.map((url) => claimIdsByUri[url]);
}
return undefined;
});
2021-06-11 22:49:18 +02:00
export const makeSelectRecommendationClicks = (claimId: string) =>
createSelector(selectState, (state) => state.recommendationClicks[claimId]);