2019-03-05 05:46:57 +01:00
|
|
|
// @flow
|
|
|
|
import { createSelector } from 'reselect';
|
2019-08-02 08:28:14 +02:00
|
|
|
import {
|
|
|
|
selectClaimsByUri,
|
2021-11-16 02:10:03 +01:00
|
|
|
selectClaimIsNsfwForUri,
|
2021-11-19 03:40:01 +01:00
|
|
|
selectClaimIsMineForUri,
|
2020-04-01 20:43:50 +02:00
|
|
|
makeSelectContentTypeForUri,
|
2022-04-01 10:18:51 +02:00
|
|
|
selectClaimForUri,
|
2021-10-17 10:36:14 +02:00
|
|
|
} from 'redux/selectors/claims';
|
|
|
|
import { makeSelectMediaTypeForUri, makeSelectFileNameForUri } from 'redux/selectors/file_info';
|
|
|
|
import { selectBalance } from 'redux/selectors/wallet';
|
2021-11-19 03:40:01 +01:00
|
|
|
import { selectCostInfoForUri } from 'lbryinc';
|
2019-08-02 08:28:14 +02:00
|
|
|
import { selectShowMatureContent } from 'redux/selectors/settings';
|
2020-04-01 20:43:50 +02:00
|
|
|
import * as RENDER_MODES from 'constants/file_render_modes';
|
|
|
|
import path from 'path';
|
2020-05-09 05:24:02 +02:00
|
|
|
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
|
|
|
|
2022-05-18 08:31:49 +02:00
|
|
|
type State = { claims: any, content: ContentState, user: UserState };
|
2019-03-05 05:46:57 +01:00
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectState = (state: State) => state.content || {};
|
2019-03-05 05:46:57 +01:00
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectPlayingUri = (state: State) => selectState(state).playingUri;
|
|
|
|
export const selectPrimaryUri = (state: State) => selectState(state).primaryUri;
|
|
|
|
export const selectListLoop = (state: State) => selectState(state).loopList;
|
|
|
|
export const selectListShuffle = (state: State) => selectState(state).shuffleList;
|
2022-05-18 11:01:25 +02:00
|
|
|
export const selectLastViewedAnnouncement = (state: State) => selectState(state).lastViewedAnnouncement;
|
2022-05-24 14:24:04 +02:00
|
|
|
export const selectRecsysEntries = (state: State) => selectState(state).recsysEntries;
|
2021-09-02 22:05:32 +02:00
|
|
|
|
2021-02-25 07:23:23 +01:00
|
|
|
export const makeSelectIsPlaying = (uri: string) =>
|
2021-04-02 10:53:28 +02:00
|
|
|
createSelector(selectPrimaryUri, (primaryUri) => primaryUri === uri);
|
2019-08-02 08:28:14 +02:00
|
|
|
|
2022-04-29 15:54:14 +02:00
|
|
|
export const selectIsUriCurrentlyPlaying = createSelector(
|
|
|
|
(state, uri) => uri,
|
|
|
|
selectPlayingUri,
|
|
|
|
(uri, playingUri) => Boolean(playingUri.uri === uri)
|
|
|
|
);
|
2022-02-08 13:15:22 +01:00
|
|
|
|
2020-04-29 22:50:06 +02:00
|
|
|
export const makeSelectIsPlayerFloating = (location: UrlLocation) =>
|
2021-09-13 17:24:35 +02:00
|
|
|
createSelector(selectPrimaryUri, selectPlayingUri, (primaryUri, playingUri) => {
|
2022-03-15 17:28:55 +01:00
|
|
|
if (!playingUri.uri) return false;
|
2021-09-24 17:53:17 +02:00
|
|
|
|
|
|
|
const { pathname, search } = location;
|
|
|
|
const hasSecondarySource = Boolean(playingUri.source);
|
|
|
|
const isComment = playingUri.source === 'comment';
|
2020-10-20 19:10:02 +02:00
|
|
|
const isInlineSecondaryPlayer =
|
2021-09-24 17:53:17 +02:00
|
|
|
hasSecondarySource && playingUri.uri !== primaryUri && pathname === playingUri.pathname;
|
|
|
|
|
|
|
|
if (isComment && isInlineSecondaryPlayer && search && search !== '?view=discussion') return true;
|
2020-04-29 22:50:06 +02:00
|
|
|
|
2021-09-16 22:00:44 +02:00
|
|
|
if (
|
2021-09-24 17:53:17 +02:00
|
|
|
isInlineSecondaryPlayer ||
|
|
|
|
(hasSecondarySource && !isComment ? playingUri.primaryUri === primaryUri : playingUri.uri === primaryUri)
|
2021-09-16 22:00:44 +02:00
|
|
|
) {
|
2020-10-20 19:10:02 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-04-29 22:50:06 +02:00
|
|
|
|
2020-10-20 19:10:02 +02:00
|
|
|
return true;
|
2020-04-14 01:48:11 +02:00
|
|
|
});
|
|
|
|
|
2022-04-01 10:18:51 +02:00
|
|
|
export const selectContentPositionForUri = (state: State, uri: string) => {
|
|
|
|
const claim = selectClaimForUri(state, uri);
|
|
|
|
if (claim) {
|
2020-04-01 20:43:50 +02:00
|
|
|
const outpoint = `${claim.txid}:${claim.nout}`;
|
|
|
|
const id = claim.claim_id;
|
2022-04-01 10:18:51 +02:00
|
|
|
const positions = selectState(state).positions;
|
|
|
|
return positions[id] ? positions[id][outpoint] : null;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
2019-03-05 05:46:57 +01:00
|
|
|
|
2022-05-16 08:44:01 +02:00
|
|
|
export const selectHistory = (state: State) => selectState(state).history || [];
|
2019-04-01 01:04:01 +02:00
|
|
|
|
2021-02-25 07:23:23 +01:00
|
|
|
export const selectHistoryPageCount = createSelector(selectHistory, (history) =>
|
2020-04-01 20:43:50 +02:00
|
|
|
Math.ceil(history.length / HISTORY_ITEMS_PER_PAGE)
|
2019-03-05 05:46:57 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
export const makeSelectHistoryForPage = (page: number) =>
|
2020-04-01 20:43:50 +02:00
|
|
|
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) =>
|
2021-02-25 07:23:23 +01:00
|
|
|
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) =>
|
2021-02-25 07:23:23 +01:00
|
|
|
createSelector(makeSelectHistoryForUri(uri), (history) => Boolean(history));
|
2019-07-11 20:06:25 +02:00
|
|
|
|
2021-02-25 07:23:23 +01:00
|
|
|
export const selectRecentHistory = createSelector(selectHistory, (history) => {
|
2020-04-01 20:43:50 +02:00
|
|
|
return history.slice(0, RECENT_HISTORY_AMOUNT);
|
|
|
|
});
|
2019-04-01 01:04:01 +02:00
|
|
|
|
2022-05-16 08:44:01 +02:00
|
|
|
export const selectWatchHistoryUris = createSelector(selectHistory, (history) => {
|
|
|
|
const uris = [];
|
|
|
|
for (let entry of history) {
|
|
|
|
if (entry.uri.indexOf('@') !== -1) {
|
|
|
|
uris.push(entry.uri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return uris;
|
|
|
|
});
|
|
|
|
|
2021-11-16 02:10:03 +01:00
|
|
|
export const selectShouldObscurePreviewForUri = (state: State, uri: string) => {
|
|
|
|
const showMatureContent = selectShowMatureContent(state);
|
|
|
|
const isClaimMature = selectClaimIsNsfwForUri(state, uri);
|
|
|
|
return isClaimMature && !showMatureContent;
|
|
|
|
};
|
2020-04-01 20:43:50 +02:00
|
|
|
|
|
|
|
// should probably be in lbry-redux, yarn link was fighting me
|
|
|
|
export const makeSelectFileExtensionForUri = (uri: string) =>
|
2021-02-25 07:23:23 +01:00
|
|
|
createSelector(makeSelectFileNameForUri(uri), (fileName) => {
|
2020-04-01 20:43:50 +02:00
|
|
|
return fileName && path.extname(fileName).substring(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectFileRenderModeForUri = (uri: string) =>
|
2019-12-10 20:45:41 +01:00
|
|
|
createSelector(
|
2020-04-01 20:43:50 +02:00
|
|
|
makeSelectContentTypeForUri(uri),
|
2019-12-10 20:45:41 +01:00
|
|
|
makeSelectMediaTypeForUri(uri),
|
2020-04-01 20:43:50 +02:00
|
|
|
makeSelectFileExtensionForUri(uri),
|
|
|
|
(contentType, mediaType, extension) => {
|
2022-03-15 17:18:08 +01:00
|
|
|
if (mediaType === 'video' || FORCE_CONTENT_TYPE_PLAYER.includes(contentType) || mediaType === 'livestream') {
|
2020-04-01 20:43:50 +02:00
|
|
|
return RENDER_MODES.VIDEO;
|
|
|
|
}
|
2020-04-03 16:18:07 +02:00
|
|
|
if (mediaType === 'audio') {
|
|
|
|
return RENDER_MODES.AUDIO;
|
|
|
|
}
|
2020-04-01 20:43:50 +02:00
|
|
|
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;
|
|
|
|
}
|
2020-05-09 05:24:02 +02:00
|
|
|
// Force content type for fallback support of older claims
|
|
|
|
if (mediaType === 'comic-book' || FORCE_CONTENT_TYPE_COMIC.includes(contentType)) {
|
2020-04-01 20:43:50 +02:00
|
|
|
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;
|
2019-12-10 20:45:41 +01:00
|
|
|
}
|
|
|
|
);
|
2020-01-06 21:57:49 +01:00
|
|
|
|
2021-11-19 03:40:01 +01:00
|
|
|
export const selectInsufficientCreditsForUri = (state: State, uri: string) => {
|
|
|
|
const isMine = selectClaimIsMineForUri(state, uri);
|
|
|
|
const costInfo = selectCostInfoForUri(state, uri);
|
|
|
|
const balance = selectBalance(state);
|
|
|
|
return !isMine && costInfo && costInfo.cost > 0 && costInfo.cost > balance;
|
|
|
|
};
|