lbry-redux/src/redux/selectors/claims.js

335 lines
9.8 KiB
JavaScript
Raw Normal View History

2018-10-25 12:57:55 -04:00
import { normalizeURI, buildURI, parseURI } from 'lbryURI';
2018-04-05 03:57:29 +01:00
import { makeSelectCurrentParam } from 'redux/selectors/navigation';
2018-08-01 23:31:51 -04:00
import { selectSearchUrisByQuery } from 'redux/selectors/search';
2018-01-11 13:12:37 +01:00
import { createSelector } from 'reselect';
2018-07-10 19:15:39 -04:00
import { isClaimNsfw } from 'util/claim';
2019-02-18 11:24:18 -05:00
import { getSearchQueryString } from 'util/query_params';
2018-01-11 13:12:37 +01:00
const selectState = state => state.claims || {};
2018-01-11 13:12:37 +01:00
export const selectClaimsById = createSelector(selectState, state => state.byId || {});
2018-01-11 13:12:37 +01:00
export const selectClaimsByUri = createSelector(selectState, selectClaimsById, (state, byId) => {
const byUri = state.claimsByUri || {};
const claims = {};
Object.keys(byUri).forEach(uri => {
2018-01-11 13:12:37 +01:00
const claimId = byUri[uri];
// NOTE returning a null claim allows us to differentiate between an
// undefined (never fetched claim) and one which just doesn't exist. Not
// the cleanest solution but couldn't think of anything better right now
if (claimId === null) {
claims[uri] = null;
} else {
claims[uri] = byId[claimId];
}
});
return claims;
2018-04-05 03:57:29 +01:00
});
export const selectAllClaimsByChannel = createSelector(
selectState,
state => state.claimsByChannel || {}
2018-04-05 03:57:29 +01:00
);
export const selectPendingById = createSelector(selectState, state => state.pendingById || {});
2018-10-25 12:57:55 -04:00
export const selectPendingClaims = createSelector(selectState, state =>
2018-10-26 18:40:53 -04:00
Object.values(state.pendingById || [])
2018-10-25 12:57:55 -04:00
);
export const makeSelectClaimIsPending = uri =>
createSelector(selectPendingById, pendingById => {
2018-10-25 12:57:55 -04:00
const { claimId } = parseURI(uri);
return Boolean(pendingById[claimId]);
});
export const makeSelectPendingByUri = uri =>
createSelector(selectPendingById, pendingById => {
2018-10-25 12:57:55 -04:00
const { claimId } = parseURI(uri);
return pendingById[claimId];
});
export const makeSelectClaimForUri = uri =>
2018-10-25 12:57:55 -04:00
createSelector(selectClaimsByUri, selectPendingById, (byUri, pendingById) => {
// Check if a claim is pending first
// It won't be in claimsByUri because resolving it will return nothing
const { claimId } = parseURI(uri);
const pendingClaim = pendingById[claimId];
if (pendingClaim) {
return pendingClaim;
}
return byUri && byUri[normalizeURI(uri)];
});
2018-04-05 03:57:29 +01:00
export const selectMyClaimsRaw = createSelector(selectState, state => state.myClaims);
2018-04-05 03:57:29 +01:00
export const selectAbandoningIds = createSelector(selectState, state =>
2018-04-05 03:57:29 +01:00
Object.keys(state.abandoningById || {})
);
export const selectMyActiveClaims = createSelector(
selectMyClaimsRaw,
selectAbandoningIds,
(claims, abandoningIds) =>
new Set(
claims &&
claims
.map(claim => claim.claim_id)
.filter(claimId => Object.keys(abandoningIds).indexOf(claimId) === -1)
2018-04-05 03:57:29 +01:00
)
);
export const makeSelectClaimIsMine = rawUri => {
2018-04-05 03:57:29 +01:00
const uri = normalizeURI(rawUri);
return createSelector(
selectClaimsByUri,
selectMyActiveClaims,
(claims, myClaims) =>
claims && claims[uri] && claims[uri].claim_id && myClaims.has(claims[uri].claim_id)
);
};
export const selectAllFetchingChannelClaims = createSelector(
selectState,
state => state.fetchingChannelClaims || {}
2018-04-05 03:57:29 +01:00
);
export const makeSelectFetchingChannelClaims = uri =>
createSelector(selectAllFetchingChannelClaims, fetching => fetching && fetching[uri]);
2018-04-05 03:57:29 +01:00
export const makeSelectClaimsInChannelForPage = (uri, page) =>
createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => {
const byChannel = allClaims[uri] || {};
const claimIds = byChannel[page || 1];
if (!claimIds) return claimIds;
return claimIds.map(claimId => byId[claimId]);
});
export const makeSelectClaimsInChannelForCurrentPage = uri => {
2018-04-05 03:57:29 +01:00
const pageSelector = makeSelectCurrentParam('page');
return createSelector(
selectClaimsById,
selectAllClaimsByChannel,
pageSelector,
(byId, allClaims, page) => {
const byChannel = allClaims[uri] || {};
const claimIds = byChannel[page || 1];
if (!claimIds) return claimIds;
return claimIds.map(claimId => byId[claimId]);
2018-04-05 03:57:29 +01:00
}
);
};
export const makeSelectMetadataForUri = uri =>
createSelector(makeSelectClaimForUri(uri), claim => {
2018-04-05 03:57:29 +01:00
const metadata = claim && claim.value && claim.value.stream && claim.value.stream.metadata;
return metadata || (claim === undefined ? undefined : null);
});
export const makeSelectTitleForUri = uri =>
createSelector(makeSelectMetadataForUri(uri), metadata => metadata && metadata.title);
2018-04-05 03:57:29 +01:00
export const makeSelectContentTypeForUri = uri =>
createSelector(makeSelectClaimForUri(uri), claim => {
2018-04-05 03:57:29 +01:00
const source = claim && claim.value && claim.value.stream && claim.value.stream.source;
return source ? source.contentType : undefined;
});
export const selectIsFetchingClaimListMine = createSelector(
selectState,
state => state.isFetchingClaimListMine
2018-04-05 03:57:29 +01:00
);
export const selectMyClaims = createSelector(
selectMyActiveClaims,
selectClaimsById,
selectAbandoningIds,
selectPendingClaims,
(myClaimIds, byId, abandoningIds, pendingClaims) => {
const claims = [];
myClaimIds.forEach(id => {
2018-04-05 03:57:29 +01:00
const claim = byId[id];
if (claim && abandoningIds.indexOf(id) === -1) claims.push(claim);
});
return [...claims, ...pendingClaims];
}
);
export const selectMyClaimsWithoutChannels = createSelector(selectMyClaims, myClaims =>
myClaims.filter(claim => !claim.name.match(/^@/))
2018-04-05 03:57:29 +01:00
);
export const selectAllMyClaimsByOutpoint = createSelector(
selectMyClaimsRaw,
claims =>
new Set(claims && claims.length ? claims.map(claim => `${claim.txid}:${claim.nout}`) : null)
2018-04-05 03:57:29 +01:00
);
export const selectMyClaimsOutpoints = createSelector(selectMyClaims, myClaims => {
2018-04-05 03:57:29 +01:00
const outpoints = [];
myClaims.forEach(claim => outpoints.push(`${claim.txid}:${claim.nout}`));
2018-04-05 03:57:29 +01:00
return outpoints;
});
export const selectFetchingMyChannels = createSelector(
selectState,
state => state.fetchingMyChannels
2018-04-05 03:57:29 +01:00
);
export const selectMyChannelClaims = createSelector(
selectState,
selectClaimsById,
(state, byId) => {
const ids = state.myChannelClaims || [];
const claims = [];
ids.forEach(id => {
2018-04-05 03:57:29 +01:00
if (byId[id]) {
2018-07-12 16:42:08 -04:00
// I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-desktop/issues/544
2018-04-05 03:57:29 +01:00
claims.push(byId[id]);
}
});
return claims;
}
);
export const selectResolvingUris = createSelector(selectState, state => state.resolvingUris || []);
2018-04-05 03:57:29 +01:00
export const makeSelectIsUriResolving = uri =>
2018-04-05 03:57:29 +01:00
createSelector(
selectResolvingUris,
resolvingUris => resolvingUris && resolvingUris.indexOf(uri) !== -1
2018-04-05 03:57:29 +01:00
);
export const selectFeaturedUris = createSelector(selectState, state => state.featuredUris);
2018-04-05 03:57:29 +01:00
export const selectFetchingFeaturedUris = createSelector(
selectState,
state => state.fetchingFeaturedContent
2018-04-05 03:57:29 +01:00
);
export const selectTrendingUris = createSelector(selectState, state => state.trendingUris);
export const selectFetchingTrendingUris = createSelector(
selectState,
state => state.fetchingTrendingContent
);
export const selectPlayingUri = createSelector(selectState, state => state.playingUri);
2018-04-05 03:57:29 +01:00
export const selectChannelClaimCounts = createSelector(
selectState,
state => state.channelClaimCounts || {}
2018-04-05 03:57:29 +01:00
);
export const makeSelectTotalItemsForChannel = uri =>
createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri]);
2018-04-05 03:57:29 +01:00
export const makeSelectTotalPagesForChannel = (uri, pageSize = 10) =>
2018-04-05 03:57:29 +01:00
createSelector(
selectChannelClaimCounts,
byUri => byUri && byUri[uri] && Math.ceil(byUri[uri] / pageSize)
2018-04-05 03:57:29 +01:00
);
export const makeSelectNsfwCountFromUris = uris =>
createSelector(selectClaimsByUri, claims =>
2018-07-10 19:15:39 -04:00
uris.reduce((acc, uri) => {
const claim = claims[uri];
if (isClaimNsfw(claim)) {
return acc + 1;
}
return acc;
}, 0)
);
export const makeSelectNsfwCountForChannel = uri => {
2018-07-10 19:15:39 -04:00
const pageSelector = makeSelectCurrentParam('page');
return createSelector(
selectClaimsById,
selectAllClaimsByChannel,
pageSelector,
(byId, allClaims, page) => {
const byChannel = allClaims[uri] || {};
const claimIds = byChannel[page || 1];
if (!claimIds) return 0;
return claimIds.reduce((acc, claimId) => {
const claim = byId[claimId];
if (isClaimNsfw(claim)) {
return acc + 1;
}
return acc;
}, 0);
}
);
};
2018-08-01 23:31:51 -04:00
export const makeSelectRecommendedContentForUri = uri =>
2018-08-01 23:31:51 -04:00
createSelector(
makeSelectClaimForUri(uri),
selectSearchUrisByQuery,
(claim, searchUrisByQuery) => {
const atVanityURI = !uri.includes('#');
2018-08-01 23:31:51 -04:00
let recommendedContent;
2018-08-01 23:31:51 -04:00
if (claim) {
// If we are at a vanity uri, build the full uri so we can properly filter
const currentUri = atVanityURI
? buildURI({ claimId: claim.claim_id, claimName: claim.name })
: uri;
const { title } = claim.value.stream.metadata;
2019-02-18 11:24:18 -05:00
const searchQuery = getSearchQueryString(title.replace(/\//, ' '));
let searchUris = searchUrisByQuery[searchQuery];
2018-08-01 23:31:51 -04:00
if (searchUris) {
searchUris = searchUris.filter(searchUri => searchUri !== currentUri);
2018-08-01 23:31:51 -04:00
recommendedContent = searchUris;
}
}
return recommendedContent;
}
);
export const makeSelectFirstRecommendedFileForUri = uri =>
createSelector(
makeSelectRecommendedContentForUri(uri),
recommendedContent => (recommendedContent ? recommendedContent[0] : null)
);
// Returns the associated channel uri for a given claim uri
export const makeSelectChannelForClaimUri = (uri, includePrefix = false) =>
createSelector(makeSelectClaimForUri(uri), claim => {
if (!claim) {
return null;
}
const { channel_name: channelName, value } = claim;
const channelClaimId =
value && value.publisherSignature && value.publisherSignature.certificateId;
return channelName && channelClaimId
? buildURI({ channelName, claimId: channelClaimId }, includePrefix)
: null;
});