2021-10-17 10:36:14 +02:00
|
|
|
// @flow
|
|
|
|
import { normalizeURI, parseURI, isURIValid } from 'util/lbryURI';
|
|
|
|
import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
|
|
|
|
import { createSelector } from 'reselect';
|
2021-10-08 03:57:48 +02:00
|
|
|
import { createCachedSelector } from 're-reselect';
|
2021-10-17 10:36:14 +02:00
|
|
|
import { isClaimNsfw, filterClaims } from 'util/claim';
|
|
|
|
import * as CLAIM from 'constants/claim';
|
|
|
|
|
2021-10-08 03:57:48 +02:00
|
|
|
type State = { claims: any };
|
2021-10-17 10:36:14 +02:00
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
const selectState = (state: State) => state.claims || {};
|
2021-10-17 10:36:14 +02:00
|
|
|
|
2021-10-08 03:57:48 +02:00
|
|
|
export const selectById = (state: State) => selectState(state).byId || {};
|
|
|
|
export const selectPendingClaimsById = (state: State) => selectState(state).pendingById || {};
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const selectClaimsById = createSelector(selectById, selectPendingClaimsById, (byId, pendingById) => {
|
|
|
|
return Object.assign(byId, pendingById); // do I need merged to keep metadata?
|
|
|
|
});
|
|
|
|
|
2021-10-08 03:57:48 +02:00
|
|
|
export const selectClaimIdsByUri = (state: State) => selectState(state).claimsByUri || {};
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectCurrentChannelPage = (state: State) => selectState(state).currentChannelPage || 1;
|
|
|
|
export const selectCreatingChannel = (state: State) => selectState(state).creatingChannel;
|
|
|
|
export const selectCreateChannelError = (state: State) => selectState(state).createChannelError;
|
|
|
|
export const selectRepostLoading = (state: State) => selectState(state).repostLoading;
|
|
|
|
export const selectRepostError = (state: State) => selectState(state).repostError;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const selectClaimsByUri = createSelector(selectClaimIdsByUri, selectClaimsById, (byUri, byId) => {
|
|
|
|
const claims = {};
|
|
|
|
|
|
|
|
Object.keys(byUri).forEach((uri) => {
|
|
|
|
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;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectAllClaimsByChannel = createSelector(selectState, (state) => state.paginatedClaimsByChannel || {});
|
|
|
|
|
|
|
|
export const selectPendingIds = createSelector(selectState, (state) => Object.keys(state.pendingById) || []);
|
|
|
|
|
|
|
|
export const selectPendingClaims = createSelector(selectPendingClaimsById, (pendingById) => Object.values(pendingById));
|
|
|
|
|
|
|
|
export const makeSelectClaimIsPending = (uri: string) =>
|
|
|
|
createSelector(selectClaimIdsByUri, selectPendingClaimsById, (idsByUri, pendingById) => {
|
|
|
|
const claimId = idsByUri[normalizeURI(uri)];
|
|
|
|
|
|
|
|
if (claimId) {
|
|
|
|
return Boolean(pendingById[claimId]);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectClaimIdIsPending = (claimId: string) =>
|
|
|
|
createSelector(selectPendingClaimsById, (pendingById) => {
|
|
|
|
return Boolean(pendingById[claimId]);
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectClaimIdForUri = (uri: string) =>
|
|
|
|
createSelector(selectClaimIdsByUri, (claimIds) => claimIds[uri]);
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectReflectingById = (state: State) => selectState(state).reflectingById;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const makeSelectClaimForClaimId = (claimId: string) => createSelector(selectClaimsById, (byId) => byId[claimId]);
|
|
|
|
|
2021-10-08 03:57:48 +02:00
|
|
|
export const selectClaimForUri = createCachedSelector(
|
|
|
|
selectClaimIdsByUri,
|
|
|
|
selectClaimsById,
|
|
|
|
(state, uri) => uri,
|
|
|
|
(state, uri, returnRepost = true) => returnRepost,
|
|
|
|
(byUri, byId, uri, returnRepost) => {
|
|
|
|
const validUri = isURIValid(uri);
|
|
|
|
|
|
|
|
if (validUri && byUri) {
|
|
|
|
const claimId = uri && byUri[normalizeURI(uri)];
|
|
|
|
const claim = byId[claimId];
|
|
|
|
|
|
|
|
// Make sure to return the claim as is so apps can check if it's been resolved before (null) or still needs to be resolved (undefined)
|
|
|
|
if (claimId === null) {
|
|
|
|
return null;
|
|
|
|
} else if (claimId === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
const repostedClaim = claim && claim.reposted_claim;
|
|
|
|
if (repostedClaim && returnRepost) {
|
|
|
|
const channelUrl =
|
|
|
|
claim.signing_channel && (claim.signing_channel.canonical_url || claim.signing_channel.permanent_url);
|
|
|
|
|
|
|
|
return {
|
|
|
|
...repostedClaim,
|
|
|
|
repost_url: normalizeURI(uri),
|
|
|
|
repost_channel_url: channelUrl,
|
|
|
|
repost_bid_amount: claim && claim.meta && claim.meta.effective_amount,
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return claim;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-25 06:58:34 +02:00
|
|
|
)((state, uri, returnRepost = true) => `${String(uri)}:${returnRepost ? '1' : '0'}`);
|
2021-10-08 03:57:48 +02:00
|
|
|
|
2021-10-17 10:36:14 +02:00
|
|
|
export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true) =>
|
|
|
|
createSelector(selectClaimIdsByUri, selectClaimsById, (byUri, byId) => {
|
|
|
|
const validUri = isURIValid(uri);
|
|
|
|
|
|
|
|
if (validUri && byUri) {
|
|
|
|
const claimId = uri && byUri[normalizeURI(uri)];
|
|
|
|
const claim = byId[claimId];
|
|
|
|
|
|
|
|
// Make sure to return the claim as is so apps can check if it's been resolved before (null) or still needs to be resolved (undefined)
|
|
|
|
if (claimId === null) {
|
|
|
|
return null;
|
|
|
|
} else if (claimId === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
const repostedClaim = claim && claim.reposted_claim;
|
|
|
|
if (repostedClaim && returnRepost) {
|
|
|
|
const channelUrl =
|
|
|
|
claim.signing_channel && (claim.signing_channel.canonical_url || claim.signing_channel.permanent_url);
|
|
|
|
|
|
|
|
return {
|
|
|
|
...repostedClaim,
|
|
|
|
repost_url: normalizeURI(uri),
|
|
|
|
repost_channel_url: channelUrl,
|
|
|
|
repost_bid_amount: claim && claim.meta && claim.meta.effective_amount,
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return claim;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectMyClaimsRaw = createSelector(selectState, selectClaimsById, (state, byId) => {
|
|
|
|
const ids = state.myClaims;
|
|
|
|
if (!ids) {
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
const claims = [];
|
|
|
|
ids.forEach((id) => {
|
|
|
|
if (byId[id]) {
|
|
|
|
// 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
|
|
|
|
claims.push(byId[id]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return claims;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectAbandoningIds = createSelector(selectState, (state) => Object.keys(state.abandoningById || {}));
|
|
|
|
|
|
|
|
export const makeSelectAbandoningClaimById = (claimId: string) =>
|
|
|
|
createSelector(selectAbandoningIds, (ids) => ids.includes(claimId));
|
|
|
|
|
|
|
|
export const makeSelectIsAbandoningClaimForUri = (uri: string) =>
|
|
|
|
createSelector(selectClaimIdsByUri, selectAbandoningIds, (claimIdsByUri, abandoningById) => {
|
|
|
|
const claimId = claimIdsByUri[normalizeURI(uri)];
|
|
|
|
return abandoningById.indexOf(claimId) >= 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
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)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
export const makeSelectClaimIsMine = (rawUri: string) => {
|
|
|
|
let uri;
|
|
|
|
try {
|
|
|
|
uri = normalizeURI(rawUri);
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
|
|
return createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => {
|
|
|
|
if (!isURIValid(uri)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
claims &&
|
|
|
|
claims[uri] &&
|
|
|
|
(claims[uri].is_my_output || (claims[uri].claim_id && myClaims.has(claims[uri].claim_id)))
|
|
|
|
);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectMyPurchases = (state: State) => selectState(state).myPurchases;
|
|
|
|
export const selectPurchaseUriSuccess = (state: State) => selectState(state).purchaseUriSuccess;
|
|
|
|
export const selectMyPurchasesCount = (state: State) => selectState(state).myPurchasesPageTotalResults;
|
|
|
|
export const selectIsFetchingMyPurchases = (state: State) => selectState(state).fetchingMyPurchases;
|
|
|
|
export const selectFetchingMyPurchasesError = (state: State) => selectState(state).fetchingMyPurchasesError;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const makeSelectMyPurchasesForPage = (query: ?string, page: number = 1) =>
|
|
|
|
createSelector(
|
|
|
|
selectMyPurchases,
|
|
|
|
selectClaimsByUri,
|
|
|
|
(myPurchases: Array<string>, claimsByUri: { [string]: Claim }) => {
|
|
|
|
if (!myPurchases) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!query) {
|
|
|
|
// ensure no duplicates from double purchase bugs
|
|
|
|
// return [...new Set(myPurchases)];
|
|
|
|
return Array.from(new Set(myPurchases));
|
|
|
|
}
|
|
|
|
|
|
|
|
const fileInfos = myPurchases.map((uri) => claimsByUri[uri]);
|
|
|
|
const matchingFileInfos = filterClaims(fileInfos, query);
|
|
|
|
const start = (Number(page) - 1) * Number(CLAIM.PAGE_SIZE);
|
|
|
|
const end = Number(page) * Number(CLAIM.PAGE_SIZE);
|
|
|
|
return matchingFileInfos && matchingFileInfos.length
|
|
|
|
? matchingFileInfos.slice(start, end).map((fileInfo) => fileInfo.canonical_url || fileInfo.permanent_url)
|
|
|
|
: [];
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
export const makeSelectClaimWasPurchased = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
return claim && claim.purchase_receipt !== undefined;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectAllFetchingChannelClaims = createSelector(selectState, (state) => state.fetchingChannelClaims || {});
|
|
|
|
|
|
|
|
export const makeSelectFetchingChannelClaims = (uri: string) =>
|
|
|
|
createSelector(selectAllFetchingChannelClaims, (fetching) => fetching && fetching[uri]);
|
|
|
|
|
|
|
|
export const makeSelectClaimsInChannelForPage = (uri: string, page?: number) =>
|
|
|
|
createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => {
|
|
|
|
const byChannel = allClaims[uri] || {};
|
|
|
|
const claimIds = byChannel[page || 1];
|
|
|
|
|
|
|
|
if (!claimIds) return claimIds;
|
|
|
|
|
|
|
|
return claimIds.map((claimId) => byId[claimId]);
|
|
|
|
});
|
|
|
|
|
|
|
|
// THIS IS LEFT OVER FROM ONE TAB CHANNEL_CONTENT
|
|
|
|
export const makeSelectTotalClaimsInChannelSearch = (uri: string) =>
|
|
|
|
createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => {
|
|
|
|
const byChannel = allClaims[uri] || {};
|
|
|
|
return byChannel['itemCount'];
|
|
|
|
});
|
|
|
|
|
|
|
|
// THIS IS LEFT OVER FROM ONE_TAB CHANNEL CONTENT
|
|
|
|
export const makeSelectTotalPagesInChannelSearch = (uri: string) =>
|
|
|
|
createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => {
|
|
|
|
const byChannel = allClaims[uri] || {};
|
|
|
|
return byChannel['pageCount'];
|
|
|
|
});
|
|
|
|
|
2021-10-08 07:52:30 +02:00
|
|
|
export const selectMetadataForUri = createCachedSelector(selectClaimForUri, (claim, uri) => {
|
|
|
|
const metadata = claim && claim.value;
|
|
|
|
return metadata || (claim === undefined ? undefined : null);
|
2021-10-25 06:58:34 +02:00
|
|
|
})((state, uri) => String(uri));
|
2021-10-08 07:52:30 +02:00
|
|
|
|
2021-10-17 10:36:14 +02:00
|
|
|
export const makeSelectMetadataForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
const metadata = claim && claim.value;
|
|
|
|
return metadata || (claim === undefined ? undefined : null);
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectMetadataItemForUri = (uri: string, key: string) =>
|
|
|
|
createSelector(makeSelectMetadataForUri(uri), (metadata: ChannelMetadata | StreamMetadata) => {
|
|
|
|
return metadata ? metadata[key] : undefined;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectTitleForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectMetadataForUri(uri), (metadata) => metadata && metadata.title);
|
|
|
|
|
2021-10-08 03:57:48 +02:00
|
|
|
export const selectDateForUri = createCachedSelector(
|
|
|
|
selectClaimForUri, // input: (state, uri, ?returnRepost)
|
|
|
|
(claim) => {
|
2021-10-17 10:36:14 +02:00
|
|
|
const timestamp =
|
|
|
|
claim &&
|
|
|
|
claim.value &&
|
|
|
|
(claim.value.release_time
|
|
|
|
? claim.value.release_time * 1000
|
|
|
|
: claim.meta && claim.meta.creation_timestamp
|
|
|
|
? claim.meta.creation_timestamp * 1000
|
|
|
|
: null);
|
|
|
|
if (!timestamp) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
const dateObj = new Date(timestamp);
|
|
|
|
return dateObj;
|
2021-10-08 03:57:48 +02:00
|
|
|
}
|
2021-10-25 06:58:34 +02:00
|
|
|
)((state, uri) => String(uri));
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const makeSelectAmountForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
return claim && claim.amount;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectEffectiveAmountForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri, false), (claim) => {
|
|
|
|
return (
|
|
|
|
claim && claim.meta && typeof claim.meta.effective_amount === 'string' && Number(claim.meta.effective_amount)
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectContentTypeForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
const source = claim && claim.value && claim.value.source;
|
|
|
|
return source ? source.media_type : undefined;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectThumbnailForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
const thumbnail = claim && claim.value && claim.value.thumbnail;
|
|
|
|
return thumbnail && thumbnail.url ? thumbnail.url.trim().replace(/^http:\/\//i, 'https://') : undefined;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectCoverForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
const cover = claim && claim.value && claim.value.cover;
|
|
|
|
return cover && cover.url ? cover.url.trim().replace(/^http:\/\//i, 'https://') : undefined;
|
|
|
|
});
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectIsFetchingClaimListMine = (state: State) => selectState(state).isFetchingClaimListMine;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const selectMyClaimsPage = createSelector(selectState, (state) => state.myClaimsPageResults || []);
|
|
|
|
|
|
|
|
export const selectMyClaimsPageNumber = createSelector(
|
|
|
|
selectState,
|
|
|
|
(state) => (state.claimListMinePage && state.claimListMinePage.items) || [],
|
|
|
|
|
|
|
|
(state) => (state.txoPage && state.txoPage.page) || 1
|
|
|
|
);
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectMyClaimsPageItemCount = (state: State) => selectState(state).myClaimsPageTotalResults || 1;
|
|
|
|
export const selectFetchingMyClaimsPageError = (state: State) => selectState(state).fetchingClaimListMinePageError;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const selectMyClaims = createSelector(
|
|
|
|
selectMyActiveClaims,
|
|
|
|
selectClaimsById,
|
|
|
|
selectAbandoningIds,
|
|
|
|
(myClaimIds, byId, abandoningIds) => {
|
|
|
|
const claims = [];
|
|
|
|
|
|
|
|
myClaimIds.forEach((id) => {
|
|
|
|
const claim = byId[id];
|
|
|
|
|
|
|
|
if (claim && abandoningIds.indexOf(id) === -1) claims.push(claim);
|
|
|
|
});
|
|
|
|
|
|
|
|
return [...claims];
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectMyClaimsWithoutChannels = createSelector(selectMyClaims, (myClaims) =>
|
|
|
|
myClaims.filter((claim) => claim && !claim.name.match(/^@/)).sort((a, b) => a.timestamp - b.timestamp)
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectMyClaimUrisWithoutChannels = createSelector(selectMyClaimsWithoutChannels, (myClaims) => {
|
|
|
|
return myClaims
|
|
|
|
.sort((a, b) => {
|
|
|
|
if (a.height < 1) {
|
|
|
|
return -1;
|
|
|
|
} else if (b.height < 1) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return b.timestamp - a.timestamp;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.map((claim) => {
|
|
|
|
return claim.canonical_url || claim.permanent_url;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectAllMyClaimsByOutpoint = createSelector(
|
|
|
|
selectMyClaimsRaw,
|
|
|
|
(claims) => new Set(claims && claims.length ? claims.map((claim) => `${claim.txid}:${claim.nout}`) : null)
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectMyClaimsOutpoints = createSelector(selectMyClaims, (myClaims) => {
|
|
|
|
const outpoints = [];
|
|
|
|
|
|
|
|
myClaims.forEach((claim) => outpoints.push(`${claim.txid}:${claim.nout}`));
|
|
|
|
|
|
|
|
return outpoints;
|
|
|
|
});
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectFetchingMyChannels = (state: State) => selectState(state).fetchingMyChannels;
|
|
|
|
export const selectFetchingMyCollections = (state: State) => selectState(state).fetchingMyCollections;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const selectMyChannelClaims = createSelector(selectState, selectClaimsById, (state, byId) => {
|
|
|
|
const ids = state.myChannelClaims;
|
|
|
|
if (!ids) {
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
const claims = [];
|
|
|
|
ids.forEach((id) => {
|
|
|
|
if (byId[id]) {
|
|
|
|
// 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
|
|
|
|
claims.push(byId[id]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return claims;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectMyChannelUrls = createSelector(selectMyChannelClaims, (claims) =>
|
|
|
|
claims ? claims.map((claim) => claim.canonical_url || claim.permanent_url) : undefined
|
|
|
|
);
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectMyCollectionIds = (state: State) => selectState(state).myCollectionClaims;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const selectResolvingUris = createSelector(selectState, (state) => state.resolvingUris || []);
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectChannelImportPending = (state: State) => selectState(state).pendingChannelImport;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const makeSelectIsUriResolving = (uri: string) =>
|
|
|
|
createSelector(selectResolvingUris, (resolvingUris) => resolvingUris && resolvingUris.indexOf(uri) !== -1);
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectPlayingUri = (state: State) => selectState(state).playingUri;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const selectChannelClaimCounts = createSelector(selectState, (state) => state.channelClaimCounts || {});
|
|
|
|
|
|
|
|
export const makeSelectPendingClaimForUri = (uri: string) =>
|
|
|
|
createSelector(selectPendingClaimsById, (pendingById) => {
|
|
|
|
let uriStreamName;
|
|
|
|
let uriChannelName;
|
|
|
|
try {
|
|
|
|
({ streamName: uriStreamName, channelName: uriChannelName } = parseURI(uri));
|
|
|
|
} catch (e) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const pendingClaims = (Object.values(pendingById): any);
|
|
|
|
const matchingClaim = pendingClaims.find((claim: GenericClaim) => {
|
|
|
|
return claim.normalized_name === uriChannelName || claim.normalized_name === uriStreamName;
|
|
|
|
});
|
|
|
|
return matchingClaim || null;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectTotalItemsForChannel = (uri: string) =>
|
|
|
|
createSelector(selectChannelClaimCounts, (byUri) => byUri && byUri[normalizeURI(uri)]);
|
|
|
|
|
|
|
|
export const makeSelectTotalPagesForChannel = (uri: string, pageSize: number = 10) =>
|
|
|
|
createSelector(
|
|
|
|
selectChannelClaimCounts,
|
|
|
|
(byUri) => byUri && byUri[uri] && Math.ceil(byUri[normalizeURI(uri)] / pageSize)
|
|
|
|
);
|
|
|
|
|
|
|
|
export const makeSelectNsfwCountFromUris = (uris: Array<string>) =>
|
|
|
|
createSelector(selectClaimsByUri, (claims) =>
|
|
|
|
uris.reduce((acc, uri) => {
|
|
|
|
const claim = claims[uri];
|
|
|
|
if (claim && isClaimNsfw(claim)) {
|
|
|
|
return acc + 1;
|
|
|
|
}
|
|
|
|
return acc;
|
|
|
|
}, 0)
|
|
|
|
);
|
|
|
|
|
|
|
|
export const makeSelectOmittedCountForChannel = (uri: string) =>
|
|
|
|
createSelector(
|
|
|
|
makeSelectTotalItemsForChannel(uri),
|
|
|
|
makeSelectTotalClaimsInChannelSearch(uri),
|
|
|
|
(claimsInChannel, claimsInSearch) => {
|
|
|
|
if (claimsInChannel && typeof claimsInSearch === 'number' && claimsInSearch >= 0) {
|
|
|
|
return claimsInChannel - claimsInSearch;
|
|
|
|
} else return 0;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
export const makeSelectClaimIsNsfw = (uri: string) =>
|
|
|
|
createSelector(
|
|
|
|
makeSelectClaimForUri(uri),
|
|
|
|
// Eventually these will come from some list of tags that are considered adult
|
|
|
|
// Or possibly come from users settings of what tags they want to hide
|
|
|
|
// For now, there is just a hard coded list of tags inside `isClaimNsfw`
|
|
|
|
// selectNaughtyTags(),
|
|
|
|
(claim: Claim) => {
|
|
|
|
if (!claim) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return isClaimNsfw(claim);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Returns the associated channel uri for a given claim uri
|
|
|
|
// accepts a regular claim uri lbry://something
|
|
|
|
// returns the channel uri that created this claim lbry://@channel
|
|
|
|
export const makeSelectChannelForClaimUri = (uri: string, includePrefix: boolean = false) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim: ?Claim) => {
|
|
|
|
if (!claim || !claim.signing_channel || !claim.is_channel_signature_valid) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { canonical_url: canonicalUrl, permanent_url: permanentUrl } = claim.signing_channel;
|
|
|
|
|
|
|
|
if (canonicalUrl) {
|
|
|
|
return includePrefix ? canonicalUrl : canonicalUrl.slice('lbry://'.length);
|
|
|
|
} else {
|
|
|
|
return includePrefix ? permanentUrl : permanentUrl.slice('lbry://'.length);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectChannelPermUrlForClaimUri = (uri: string, includePrefix: boolean = false) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim: ?Claim) => {
|
|
|
|
if (claim && claim.value_type === 'channel') {
|
|
|
|
return claim.permanent_url;
|
|
|
|
}
|
|
|
|
if (!claim || !claim.signing_channel || !claim.is_channel_signature_valid) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return claim.signing_channel.permanent_url;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectMyChannelPermUrlForName = (name: string) =>
|
|
|
|
createSelector(selectMyChannelClaims, (claims) => {
|
|
|
|
const matchingClaim = claims && claims.find((claim) => claim.name === name);
|
|
|
|
return matchingClaim ? matchingClaim.permanent_url : null;
|
|
|
|
});
|
|
|
|
|
2021-10-08 07:52:30 +02:00
|
|
|
export const selectTagsForUri = createCachedSelector(selectMetadataForUri, (metadata: ?GenericMetadata) => {
|
|
|
|
return (metadata && metadata.tags) || [];
|
2021-10-25 06:58:34 +02:00
|
|
|
})((state, uri) => String(uri));
|
2021-10-08 07:52:30 +02:00
|
|
|
|
2021-10-17 10:36:14 +02:00
|
|
|
export const makeSelectTagsForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectMetadataForUri(uri), (metadata: ?GenericMetadata) => {
|
|
|
|
return (metadata && metadata.tags) || [];
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectFetchingClaimSearchByQuery = createSelector(
|
|
|
|
selectState,
|
|
|
|
(state) => state.fetchingClaimSearchByQuery || {}
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectFetchingClaimSearch = createSelector(
|
|
|
|
selectFetchingClaimSearchByQuery,
|
|
|
|
(fetchingClaimSearchByQuery) => Boolean(Object.keys(fetchingClaimSearchByQuery).length)
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectClaimSearchByQuery = createSelector(selectState, (state) => state.claimSearchByQuery || {});
|
|
|
|
|
|
|
|
export const selectClaimSearchByQueryLastPageReached = createSelector(
|
|
|
|
selectState,
|
|
|
|
(state) => state.claimSearchByQueryLastPageReached || {}
|
|
|
|
);
|
|
|
|
|
|
|
|
export const makeSelectShortUrlForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => claim && claim.short_url);
|
|
|
|
|
|
|
|
export const makeSelectCanonicalUrlForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => claim && claim.canonical_url);
|
|
|
|
|
|
|
|
export const makeSelectPermanentUrlForUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => claim && claim.permanent_url);
|
|
|
|
|
|
|
|
export const makeSelectSupportsForUri = (uri: string) =>
|
|
|
|
createSelector(selectSupportsByOutpoint, makeSelectClaimForUri(uri), (byOutpoint, claim: ?StreamClaim) => {
|
|
|
|
if (!claim || !claim.is_my_output) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { claim_id: claimId } = claim;
|
|
|
|
let total = 0;
|
|
|
|
|
|
|
|
Object.values(byOutpoint).forEach((support) => {
|
|
|
|
// $FlowFixMe
|
|
|
|
const { claim_id, amount } = support;
|
|
|
|
total = claim_id === claimId && amount ? total + parseFloat(amount) : total;
|
|
|
|
});
|
|
|
|
|
|
|
|
return total;
|
|
|
|
});
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectUpdatingChannel = (state: State) => selectState(state).updatingChannel;
|
|
|
|
export const selectUpdateChannelError = (state: State) => selectState(state).updateChannelError;
|
2021-10-17 10:36:14 +02:00
|
|
|
|
|
|
|
export const makeSelectReflectingClaimForUri = (uri: string) =>
|
|
|
|
createSelector(selectClaimIdsByUri, selectReflectingById, (claimIdsByUri, reflectingById) => {
|
|
|
|
const claimId = claimIdsByUri[normalizeURI(uri)];
|
|
|
|
return reflectingById[claimId];
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectMyStreamUrlsForPage = (page: number = 1) =>
|
|
|
|
createSelector(selectMyClaimUrisWithoutChannels, (urls) => {
|
|
|
|
const start = (Number(page) - 1) * Number(CLAIM.PAGE_SIZE);
|
|
|
|
const end = Number(page) * Number(CLAIM.PAGE_SIZE);
|
|
|
|
|
|
|
|
return urls && urls.length ? urls.slice(start, end) : [];
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectMyStreamUrlsCount = createSelector(selectMyClaimUrisWithoutChannels, (channels) => channels.length);
|
|
|
|
|
|
|
|
export const makeSelectTagInClaimOrChannelForUri = (uri: string, tag: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
const claimTags = (claim && claim.value && claim.value.tags) || [];
|
|
|
|
const channelTags =
|
|
|
|
(claim && claim.signing_channel && claim.signing_channel.value && claim.signing_channel.value.tags) || [];
|
|
|
|
return claimTags.includes(tag) || channelTags.includes(tag);
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectClaimHasSource = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
if (!claim) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Boolean(claim.value.source);
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectClaimIsStreamPlaceholder = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
if (!claim) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Boolean(claim.value_type === 'stream' && !claim.value.source);
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectTotalStakedAmountForChannelUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectClaimForUri(uri), (claim) => {
|
|
|
|
if (!claim || !claim.amount || !claim.meta || !claim.meta.support_amount) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parseFloat(claim.amount) + parseFloat(claim.meta.support_amount) || 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectStakedLevelForChannelUri = (uri: string) =>
|
|
|
|
createSelector(makeSelectTotalStakedAmountForChannelUri(uri), (amount) => {
|
|
|
|
let level = 1;
|
|
|
|
switch (true) {
|
|
|
|
case amount >= CLAIM.LEVEL_2_STAKED_AMOUNT && amount < CLAIM.LEVEL_3_STAKED_AMOUNT:
|
|
|
|
level = 2;
|
|
|
|
break;
|
|
|
|
case amount >= CLAIM.LEVEL_3_STAKED_AMOUNT && amount < CLAIM.LEVEL_4_STAKED_AMOUNT:
|
|
|
|
level = 3;
|
|
|
|
break;
|
|
|
|
case amount >= CLAIM.LEVEL_4_STAKED_AMOUNT && amount < CLAIM.LEVEL_5_STAKED_AMOUNT:
|
|
|
|
level = 4;
|
|
|
|
break;
|
|
|
|
case amount >= CLAIM.LEVEL_5_STAKED_AMOUNT:
|
|
|
|
level = 5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return level;
|
|
|
|
});
|
|
|
|
|
2021-10-23 04:41:43 +02:00
|
|
|
export const selectUpdatingCollection = (state: State) => selectState(state).updatingCollection;
|
|
|
|
export const selectUpdateCollectionError = (state: State) => selectState(state).updateCollectionError;
|
|
|
|
export const selectCreatingCollection = (state: State) => selectState(state).creatingCollection;
|
|
|
|
export const selectCreateCollectionError = (state: State) => selectState(state).createCollectionError;
|