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