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

335 lines
9.6 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';
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
);
2018-10-26 18:40:53 -04: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) =>
2018-04-05 03:57:29 +01:00
createSelector(
selectChannelClaimCounts,
(byUri) => byUri && byUri[uri] && Math.ceil(byUri[uri] / 10)
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) {
const {
value: {
stream: {
metadata: { title },
},
},
} = claim;
2018-08-22 16:02:20 -04:00
let searchUris = searchUrisByQuery[title.replace(/\//, ' ')];
2018-08-01 23:31:51 -04:00
if (searchUris) {
// If we are at a vanity uri, we can't do a uri match
// The first search result _should_ be the same as the claim a user is on
if (atVanityURI) {
searchUris = searchUris.slice(1);
}
searchUris = searchUris.filter((searchUri) => searchUri !== uri);
2018-08-01 23:31:51 -04:00
recommendedContent = searchUris;
}
}
return recommendedContent;
}
);
// 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;
});