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
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
const selectState = (state) => state.claims || {};
|
2018-01-11 13:12:37 +01:00
|
|
|
|
2018-10-26 14:08:05 -04: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 = {};
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
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,
|
2018-10-26 14:08:05 -04:00
|
|
|
(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
|
|
|
|
2018-10-26 14:08:05 -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
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -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]);
|
|
|
|
});
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const makeSelectPendingByUri = (uri) =>
|
|
|
|
createSelector(selectPendingById, (pendingById) => {
|
2018-10-25 12:57:55 -04:00
|
|
|
const { claimId } = parseURI(uri);
|
|
|
|
return pendingById[claimId];
|
|
|
|
});
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
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
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const selectMyClaimsRaw = createSelector(selectState, (state) => state.myClaims);
|
2018-04-05 03:57:29 +01:00
|
|
|
|
2018-10-26 14:08:05 -04: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
|
2018-10-26 14:08:05 -04:00
|
|
|
.map((claim) => claim.claim_id)
|
|
|
|
.filter((claimId) => Object.keys(abandoningIds).indexOf(claimId) === -1)
|
2018-04-05 03:57:29 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04: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,
|
2018-10-26 14:08:05 -04:00
|
|
|
(state) => state.fetchingChannelClaims || {}
|
2018-04-05 03:57:29 +01:00
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const makeSelectFetchingChannelClaims = (uri) =>
|
|
|
|
createSelector(selectAllFetchingChannelClaims, (fetching) => fetching && fetching[uri]);
|
2018-04-05 03:57:29 +01:00
|
|
|
|
2018-05-25 12:34:12 +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;
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
return claimIds.map((claimId) => byId[claimId]);
|
2018-05-25 12:34:12 +01:00
|
|
|
});
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
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;
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
return claimIds.map((claimId) => byId[claimId]);
|
2018-04-05 03:57:29 +01:00
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2018-10-26 14:08:05 -04: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);
|
|
|
|
});
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const makeSelectTitleForUri = (uri) =>
|
|
|
|
createSelector(makeSelectMetadataForUri(uri), (metadata) => metadata && metadata.title);
|
2018-04-05 03:57:29 +01:00
|
|
|
|
2018-10-26 14:08:05 -04: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,
|
2018-10-26 14:08:05 -04:00
|
|
|
(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 = [];
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
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,
|
2018-10-26 14:08:05 -04:00
|
|
|
(claims) =>
|
|
|
|
new Set(claims && claims.length ? claims.map((claim) => `${claim.txid}:${claim.nout}`) : null)
|
2018-04-05 03:57:29 +01:00
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const selectMyClaimsOutpoints = createSelector(selectMyClaims, (myClaims) => {
|
2018-04-05 03:57:29 +01:00
|
|
|
const outpoints = [];
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
myClaims.forEach((claim) => outpoints.push(`${claim.txid}:${claim.nout}`));
|
2018-04-05 03:57:29 +01:00
|
|
|
|
|
|
|
return outpoints;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectFetchingMyChannels = createSelector(
|
|
|
|
selectState,
|
2018-10-26 14:08:05 -04:00
|
|
|
(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 = [];
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const selectResolvingUris = createSelector(
|
|
|
|
selectState,
|
|
|
|
(state) => state.resolvingUris || []
|
|
|
|
);
|
2018-04-05 03:57:29 +01:00
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const makeSelectIsUriResolving = (uri) =>
|
2018-04-05 03:57:29 +01:00
|
|
|
createSelector(
|
|
|
|
selectResolvingUris,
|
2018-10-26 14:08:05 -04:00
|
|
|
(resolvingUris) => resolvingUris && resolvingUris.indexOf(uri) !== -1
|
2018-04-05 03:57:29 +01:00
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const selectFeaturedUris = createSelector(selectState, (state) => state.featuredUris);
|
2018-04-05 03:57:29 +01:00
|
|
|
|
|
|
|
export const selectFetchingFeaturedUris = createSelector(
|
|
|
|
selectState,
|
2018-10-26 14:08:05 -04:00
|
|
|
(state) => state.fetchingFeaturedContent
|
2018-04-05 03:57:29 +01:00
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const selectTrendingUris = createSelector(selectState, (state) => state.trendingUris);
|
2018-06-06 01:24:01 +01:00
|
|
|
|
|
|
|
export const selectFetchingTrendingUris = createSelector(
|
|
|
|
selectState,
|
2018-10-26 14:08:05 -04:00
|
|
|
(state) => state.fetchingTrendingContent
|
2018-06-06 01:24:01 +01:00
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const selectPlayingUri = createSelector(selectState, (state) => state.playingUri);
|
2018-04-05 03:57:29 +01:00
|
|
|
|
|
|
|
export const selectChannelClaimCounts = createSelector(
|
|
|
|
selectState,
|
2018-10-26 14:08:05 -04:00
|
|
|
(state) => state.channelClaimCounts || {}
|
2018-04-05 03:57:29 +01:00
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const makeSelectTotalItemsForChannel = (uri) =>
|
|
|
|
createSelector(selectChannelClaimCounts, (byUri) => byUri && byUri[uri]);
|
2018-04-05 03:57:29 +01:00
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const makeSelectTotalPagesForChannel = (uri) =>
|
2018-04-05 03:57:29 +01:00
|
|
|
createSelector(
|
|
|
|
selectChannelClaimCounts,
|
2018-10-26 14:08:05 -04:00
|
|
|
(byUri) => byUri && byUri[uri] && Math.ceil(byUri[uri] / 10)
|
2018-04-05 03:57:29 +01:00
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04: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)
|
|
|
|
);
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
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
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
export const makeSelectRecommendedContentForUri = (uri) =>
|
2018-08-01 23:31:51 -04:00
|
|
|
createSelector(
|
|
|
|
makeSelectClaimForUri(uri),
|
|
|
|
selectSearchUrisByQuery,
|
|
|
|
(claim, searchUrisByQuery) => {
|
2018-08-26 22:43:25 -04:00
|
|
|
const atVanityURI = !uri.includes('#');
|
2018-08-01 23:31:51 -04:00
|
|
|
|
2018-08-26 22:43:25 -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) {
|
2018-08-26 22:43:25 -04:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2018-10-26 14:08:05 -04:00
|
|
|
searchUris = searchUris.filter((searchUri) => searchUri !== uri);
|
2018-08-01 23:31:51 -04:00
|
|
|
recommendedContent = searchUris;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return recommendedContent;
|
|
|
|
}
|
|
|
|
);
|
2018-10-18 13:46:31 -04:00
|
|
|
|
|
|
|
// Returns the associated channel uri for a given claim uri
|
|
|
|
export const makeSelectChannelForClaimUri = (uri, includePrefix = false) =>
|
2018-10-26 14:08:05 -04:00
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
2018-10-18 13:46:31 -04:00
|
|
|
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;
|
|
|
|
});
|