lbry-desktop/ui/redux/selectors/content.js
Thomas Zarebczan 7d3f35b0c5 improve pop up not identifying your own content in some cases
edit option

delete option

analytics for channel claim

support option

follow option

fix

revert

subscription actions

block actions

mute actions

block and mute buttons

mute menu option

lint

handle edit channel

fix comment mute

logic

analytics

handle delete channel

fix claimismine

fix rebase
2021-06-08 16:08:53 -04:00

266 lines
9.1 KiB
JavaScript

// @flow
import { createSelector } from 'reselect';
import {
makeSelectClaimForUri,
selectClaimsByUri,
makeSelectClaimsInChannelForCurrentPageState,
makeSelectClaimIsNsfw,
makeSelectClaimIsMine,
makeSelectMediaTypeForUri,
selectBalance,
parseURI,
makeSelectContentTypeForUri,
makeSelectFileNameForUri,
normalizeURI,
selectMyActiveClaims,
} from 'lbry-redux';
import { makeSelectRecommendedContentForUri } from 'redux/selectors/search';
import { selectMutedChannels } from 'redux/selectors/blocked';
import { selectAllCostInfoByUri, makeSelectCostInfoForUri } from 'lbryinc';
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';
const RECENT_HISTORY_AMOUNT = 10;
const HISTORY_ITEMS_PER_PAGE = 50;
export const selectState = (state: any) => state.content || {};
export const selectPlayingUri = createSelector(selectState, (state) => state.playingUri);
export const selectPrimaryUri = createSelector(selectState, (state) => state.primaryUri);
export const makeSelectIsPlaying = (uri: string) =>
createSelector(selectPrimaryUri, (primaryUri) => primaryUri === uri);
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;
});
export const makeSelectContentPositionForUri = (uri: string) =>
createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => {
if (!claim) {
return null;
}
const outpoint = `${claim.txid}:${claim.nout}`;
const id = claim.claim_id;
return state.positions[id] ? state.positions[id][outpoint] : null;
});
export const selectHistory = createSelector(selectState, (state) => state.history || []);
export const selectHistoryPageCount = createSelector(selectHistory, (history) =>
Math.ceil(history.length / HISTORY_ITEMS_PER_PAGE)
);
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;
});
export const makeSelectHistoryForUri = (uri: string) =>
createSelector(selectHistory, (history) => history.find((i) => i.uri === uri));
export const makeSelectHasVisitedUri = (uri: string) =>
createSelector(makeSelectHistoryForUri(uri), (history) => Boolean(history));
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];
const claim = claimsByUri[recommendedUri];
if (!claim) {
continue;
}
const { isChannel } = parseURI(recommendedUri);
if (isChannel) {
continue;
}
const costInfo = costInfoByUri[recommendedUri];
if (!costInfo || costInfo.cost !== 0) {
continue;
}
// We already check if it's a channel above
// $FlowFixMe
const isVideo = claim.value && claim.value.stream_type === 'video';
// $FlowFixMe
const isAudio = claim.value && claim.value.stream_type === 'audio';
if (!isVideo && !isAudio) {
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];
}
}
}
}
);
export const selectRecentHistory = createSelector(selectHistory, (history) => {
return history.slice(0, RECENT_HISTORY_AMOUNT);
});
export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) =>
createSelector(makeSelectClaimsInChannelForCurrentPageState(channel), (channelClaims) => {
if (uris) return uris;
if (channelClaims) {
const CATEGORY_LIST_SIZE = 10;
return channelClaims.slice(0, CATEGORY_LIST_SIZE).map(({ name, claim_id: claimId }) => `${name}#${claimId}`);
}
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;
}
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;
}
);
export const makeSelectInsufficientCreditsForUri = (uri: string) =>
createSelector(
makeSelectClaimIsMine(uri),
makeSelectCostInfoForUri(uri),
selectBalance,
(isMine, costInfo, balance) => {
return !isMine && costInfo && costInfo.cost > 0 && costInfo.cost > balance;
}
);
export const makeSelectSigningIsMine = (rawUri: string) => {
let uri;
try {
uri = normalizeURI(rawUri);
} catch (e) { }
return createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => {
try {
parseURI(uri);
} catch (e) {
return false;
}
const repostedChannel = claims && claims[uri] && claims[uri].reposted_claim && (claims[uri].reposted_claim.signing_channel || claims[uri].reposted_claim);
const signingChannel = claims && claims[uri] && (repostedChannel || claims[uri].signing_channel || claims[uri]);
return signingChannel && myClaims.has(signingChannel.claim_id);
});
};