Merge pull request #166 from lbryio/cache

cache claim search results by query
This commit is contained in:
Sean Yesmunt 2019-07-31 15:04:14 -04:00 committed by GitHub
commit 469d3b70cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 182 additions and 345 deletions

198
dist/bundle.es.js vendored
View file

@ -902,7 +902,7 @@ const channelNameMinLength = 1;
const claimIdMaxLength = 40; const claimIdMaxLength = 40;
// see https://spec.lbry.com/#urls // see https://spec.lbry.com/#urls
const regexInvalidURI = /[ =&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/gu; const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
/** /**
@ -1228,6 +1228,8 @@ function doDismissError() {
var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
const matureTagMap = MATURE_TAGS.reduce((acc, tag) => _extends$2({}, acc, { [tag]: true }), {}); const matureTagMap = MATURE_TAGS.reduce((acc, tag) => _extends$2({}, acc, { [tag]: true }), {});
const isClaimNsfw = claim => { const isClaimNsfw = claim => {
@ -1250,9 +1252,13 @@ const isClaimNsfw = claim => {
return false; return false;
}; };
const createNormalizedTagKey = tags => { function createNormalizedClaimSearchKey(options) {
return tags ? tags.sort().join(',') : ''; // Ignore page because we don't care what the last page searched was, we want everything
}; // Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567"
const rest = _objectWithoutProperties(options, ['page', 'release_time']);
const query = JSON.stringify(rest);
return query;
}
// //
@ -1308,12 +1314,14 @@ const makeSelectClaimForUri = uri => reselect.createSelector(selectClaimsByUri,
// Check if a claim is pending first // Check if a claim is pending first
// It won't be in claimsByUri because resolving it will return nothing // It won't be in claimsByUri because resolving it will return nothing
let valid;
let claimId; let claimId;
try { try {
({ claimId } = parseURI(uri)); ({ claimId } = parseURI(uri));
valid = true;
} catch (e) {} } catch (e) {}
if (claimId) { if (valid) {
const pendingClaim = pendingById[claimId]; const pendingClaim = pendingById[claimId];
if (pendingClaim) { if (pendingClaim) {
@ -1400,7 +1408,11 @@ const makeSelectContentTypeForUri = uri => reselect.createSelector(makeSelectCla
const makeSelectThumbnailForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { const makeSelectThumbnailForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => {
const thumbnail = claim && claim.value && claim.value.thumbnail; const thumbnail = claim && claim.value && claim.value.thumbnail;
return thumbnail && thumbnail.url && thumbnail.url.trim().length > 0 ? thumbnail.url : undefined; if (!thumbnail || !thumbnail.url) {
return null;
}
return thumbnail.url.trim();
}); });
const makeSelectCoverForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { const makeSelectCoverForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => {
@ -1549,20 +1561,14 @@ const makeSelectTagsForUri = uri => reselect.createSelector(makeSelectMetadataFo
return metadata && metadata.tags || []; return metadata && metadata.tags || [];
}); });
const selectFetchingClaimSearch = reselect.createSelector(selectState$1, state => state.fetchingClaimSearch); const selectfetchingClaimSearchByQuery = reselect.createSelector(selectState$1, state => state.fetchingClaimSearchByQuery || {});
const selectLastClaimSearchUris = reselect.createSelector(selectState$1, state => state.lastClaimSearchUris); const selectFetchingClaimSearch = reselect.createSelector(selectfetchingClaimSearchByQuery, fetchingClaimSearchByQuery => Boolean(Object.keys(fetchingClaimSearchByQuery).length));
const selectClaimSearchByQuery = reselect.createSelector(selectState$1, state => state.claimSearchByQuery || {});
const makeSelectShortUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.short_url); const makeSelectShortUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.short_url);
const selectFetchingClaimSearchByTags = reselect.createSelector(selectState$1, state => state.fetchingClaimSearchByTags);
const selectClaimSearchUrisByTags = reselect.createSelector(selectState$1, state => state.claimSearchUrisByTags);
const makeSelectFetchingClaimSearchForTags = tags => reselect.createSelector(selectFetchingClaimSearchByTags, byTags => byTags[createNormalizedTagKey(tags)]);
const makeSelectClaimSearchUrisForTags = tags => reselect.createSelector(selectClaimSearchUrisByTags, byTags => byTags[createNormalizedTagKey(tags)]);
const selectState$2 = state => state.wallet || {}; const selectState$2 = state => state.wallet || {};
const selectWalletState = selectState$2; const selectWalletState = selectState$2;
@ -2084,6 +2090,14 @@ function doUpdateBlockHeight() {
}); });
} }
// https://github.com/reactjs/redux/issues/911
function batchActions(...actions) {
return {
type: 'BATCH_ACTIONS',
actions
};
}
var _extends$3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _extends$3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function doResolveUris(uris, returnCachedClaims = false) { function doResolveUris(uris, returnCachedClaims = false) {
@ -2366,10 +2380,14 @@ function doFetchChannelListMine() {
}; };
} }
function doClaimSearch(options = {}) { function doClaimSearch(options = {
page_size: 10
}) {
const query = createNormalizedClaimSearchKey(options);
return dispatch => { return dispatch => {
dispatch({ dispatch({
type: CLAIM_SEARCH_STARTED type: CLAIM_SEARCH_STARTED,
data: { query: query }
}); });
const success = data => { const success = data => {
@ -2382,56 +2400,19 @@ function doClaimSearch(options = {}) {
dispatch({ dispatch({
type: CLAIM_SEARCH_COMPLETED, type: CLAIM_SEARCH_COMPLETED,
data: { resolveInfo, uris, append: options.page && options.page !== 1 } data: { query, resolveInfo, uris, append: options.page && options.page !== 1 }
}); });
}; };
const failure = err => { const failure = err => {
dispatch({ dispatch({
type: CLAIM_SEARCH_FAILED, type: CLAIM_SEARCH_FAILED,
data: { query },
error: err error: err
}); });
}; };
lbryProxy.claim_search(_extends$3({}, options)).then(success, failure); lbryProxy.claim_search(options).then(success, failure);
};
}
// tags can be one or many (comma separated)
function doClaimSearchByTags(tags, amount = 10, options = {}) {
return dispatch => {
const tagList = createNormalizedTagKey(tags);
dispatch({
type: CLAIM_SEARCH_BY_TAGS_STARTED,
data: { tags: tagList }
});
const success = data => {
const resolveInfo = {};
const uris = [];
data.items.forEach(stream => {
resolveInfo[stream.permanent_url] = { stream };
uris.push(stream.permanent_url);
});
dispatch({
type: CLAIM_SEARCH_BY_TAGS_COMPLETED,
data: { tags: tagList, resolveInfo, uris, append: options.page && options.page !== 1 }
});
};
const failure = err => {
dispatch({
type: CLAIM_SEARCH_BY_TAGS_FAILED,
data: { tags: tagList },
error: err
});
};
lbryProxy.claim_search(_extends$3({
page_size: amount,
any_tags: tags
}, options)).then(success, failure);
}; };
} }
@ -2780,20 +2761,12 @@ function doSetFileListSort(page, value) {
}; };
} }
// https://github.com/reactjs/redux/issues/911 function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function batchActions(...actions) {
return {
type: 'BATCH_ACTIONS',
actions
};
}
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
const selectState$5 = state => state.publish || {}; const selectState$5 = state => state.publish || {};
const selectPublishFormValues = reselect.createSelector(selectState$5, state => { const selectPublishFormValues = reselect.createSelector(selectState$5, state => {
const formValues = _objectWithoutProperties(state, ['pendingPublish']); const formValues = _objectWithoutProperties$1(state, ['pendingPublish']);
return formValues; return formValues;
}); });
const makeSelectPublishFormValue = item => reselect.createSelector(selectState$5, state => state[item]); const makeSelectPublishFormValue = item => reselect.createSelector(selectState$5, state => state[item]);
@ -3475,10 +3448,9 @@ const defaultState = {
fetchingMyChannels: false, fetchingMyChannels: false,
abandoningById: {}, abandoningById: {},
pendingById: {}, pendingById: {},
fetchingClaimSearch: false, claimSearchError: false,
claimSearchUrisByTags: {}, claimSearchByQuery: {},
fetchingClaimSearchByTags: {}, fetchingClaimSearchByQuery: {}
lastClaimSearchUris: []
}; };
function handleClaimAction(state, action) { function handleClaimAction(state, action) {
@ -3707,64 +3679,41 @@ reducers[RESOLVE_URIS_STARTED] = (state, action) => {
}); });
}; };
reducers[CLAIM_SEARCH_STARTED] = state => { reducers[CLAIM_SEARCH_STARTED] = (state, action) => {
const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
fetchingClaimSearchByQuery[action.data.query] = true;
return Object.assign({}, state, { return Object.assign({}, state, {
fetchingClaimSearch: true fetchingClaimSearchByQuery
}); });
}; };
reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => { reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => {
const { lastClaimSearchUris } = state; const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery);
const { append, query, uris } = action.data;
let newClaimSearchUris = []; if (append) {
if (action.data.append) {
newClaimSearchUris = lastClaimSearchUris.concat(action.data.uris);
} else {
newClaimSearchUris = action.data.uris;
}
return _extends$5({}, handleClaimAction(state, action), {
fetchingClaimSearch: false,
lastClaimSearchUris: newClaimSearchUris
});
};
reducers[CLAIM_SEARCH_FAILED] = state => {
return Object.assign({}, state, {
fetchingClaimSearch: false
});
};
reducers[CLAIM_SEARCH_BY_TAGS_STARTED] = (state, action) => {
const fetchingClaimSearchByTags = Object.assign({}, state.fetchingClaimSearchByTags);
fetchingClaimSearchByTags[action.data.tags] = true;
return Object.assign({}, state, {
fetchingClaimSearchByTags
});
};
reducers[CLAIM_SEARCH_BY_TAGS_COMPLETED] = (state, action) => {
const fetchingClaimSearchByTags = Object.assign({}, state.fetchingClaimSearchByTags);
const claimSearchUrisByTags = Object.assign({}, state.claimSearchUrisByTags);
const { append, tags, uris } = action.data;
if (action.data.append) {
// todo: check for duplicate uris when concatenating? // todo: check for duplicate uris when concatenating?
claimSearchUrisByTags[tags] = claimSearchUrisByTags[tags] && claimSearchUrisByTags[tags].length ? claimSearchUrisByTags[tags].concat(uris) : uris; claimSearchByQuery[query] = claimSearchByQuery[query] && claimSearchByQuery[query].length ? claimSearchByQuery[query].concat(uris) : uris;
} else { } else {
claimSearchUrisByTags[tags] = uris; claimSearchByQuery[query] = uris;
} }
fetchingClaimSearchByTags[tags] = false; // or delete the key instead?
return Object.assign({}, state, { delete fetchingClaimSearchByQuery[query];
claimSearchUrisByTags,
fetchingClaimSearchByTags return Object.assign({}, state, _extends$5({}, handleClaimAction(state, action), {
}); claimSearchByQuery,
fetchingClaimSearchByQuery
}));
}; };
reducers[CLAIM_SEARCH_BY_TAGS_FAILED] = (state, action) => {
const fetchingClaimSearchByTags = Object.assign({}, state.fetchingClaimSearchByTags); reducers[CLAIM_SEARCH_FAILED] = (state, action) => {
fetchingClaimSearchByTags[action.data.tags] = false; const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
fetchingClaimSearchByQuery[action.data.tags] = false;
return Object.assign({}, state, { return Object.assign({}, state, {
fetchingClaimSearchByTags fetchingClaimSearchByQuery
}); });
}; };
@ -4209,7 +4158,7 @@ const notificationsReducer = handleActions({
var _extends$b = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _extends$b = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _objectWithoutProperties$2(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
const defaultState$6 = { const defaultState$6 = {
editingURI: undefined, editingURI: undefined,
@ -4259,7 +4208,7 @@ const publishReducer = handleActions({
publishSuccess: true publishSuccess: true
}), }),
[DO_PREPARE_EDIT]: (state, action) => { [DO_PREPARE_EDIT]: (state, action) => {
const publishData = _objectWithoutProperties$1(action.data, []); const publishData = _objectWithoutProperties$2(action.data, []);
const { channel, name, uri } = publishData; const { channel, name, uri } = publishData;
// The short uri is what is presented to the user // The short uri is what is presented to the user
@ -4766,6 +4715,7 @@ exports.claimsReducer = claimsReducer;
exports.commentReducer = commentReducer; exports.commentReducer = commentReducer;
exports.contentReducer = contentReducer; exports.contentReducer = contentReducer;
exports.convertToShareLink = convertToShareLink; exports.convertToShareLink = convertToShareLink;
exports.createNormalizedClaimSearchKey = createNormalizedClaimSearchKey;
exports.creditsToString = creditsToString; exports.creditsToString = creditsToString;
exports.doAbandonClaim = doAbandonClaim; exports.doAbandonClaim = doAbandonClaim;
exports.doAddTag = doAddTag; exports.doAddTag = doAddTag;
@ -4774,7 +4724,6 @@ exports.doBlurSearchInput = doBlurSearchInput;
exports.doCheckAddressIsMine = doCheckAddressIsMine; exports.doCheckAddressIsMine = doCheckAddressIsMine;
exports.doCheckPendingPublishes = doCheckPendingPublishes; exports.doCheckPendingPublishes = doCheckPendingPublishes;
exports.doClaimSearch = doClaimSearch; exports.doClaimSearch = doClaimSearch;
exports.doClaimSearchByTags = doClaimSearchByTags;
exports.doClearPublish = doClearPublish; exports.doClearPublish = doClearPublish;
exports.doCommentCreate = doCommentCreate; exports.doCommentCreate = doCommentCreate;
exports.doCommentList = doCommentList; exports.doCommentList = doCommentList;
@ -4836,7 +4785,6 @@ exports.makeSelectClaimForUri = makeSelectClaimForUri;
exports.makeSelectClaimIsMine = makeSelectClaimIsMine; exports.makeSelectClaimIsMine = makeSelectClaimIsMine;
exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw; exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw;
exports.makeSelectClaimIsPending = makeSelectClaimIsPending; exports.makeSelectClaimIsPending = makeSelectClaimIsPending;
exports.makeSelectClaimSearchUrisForTags = makeSelectClaimSearchUrisForTags;
exports.makeSelectClaimsInChannelForCurrentPageState = makeSelectClaimsInChannelForCurrentPageState; exports.makeSelectClaimsInChannelForCurrentPageState = makeSelectClaimsInChannelForCurrentPageState;
exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage; exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage;
exports.makeSelectCommentsForUri = makeSelectCommentsForUri; exports.makeSelectCommentsForUri = makeSelectCommentsForUri;
@ -4846,7 +4794,6 @@ exports.makeSelectCoverForUri = makeSelectCoverForUri;
exports.makeSelectDateForUri = makeSelectDateForUri; exports.makeSelectDateForUri = makeSelectDateForUri;
exports.makeSelectDownloadingForUri = makeSelectDownloadingForUri; exports.makeSelectDownloadingForUri = makeSelectDownloadingForUri;
exports.makeSelectFetchingChannelClaims = makeSelectFetchingChannelClaims; exports.makeSelectFetchingChannelClaims = makeSelectFetchingChannelClaims;
exports.makeSelectFetchingClaimSearchForTags = makeSelectFetchingClaimSearchForTags;
exports.makeSelectFileInfoForUri = makeSelectFileInfoForUri; exports.makeSelectFileInfoForUri = makeSelectFileInfoForUri;
exports.makeSelectFirstRecommendedFileForUri = makeSelectFirstRecommendedFileForUri; exports.makeSelectFirstRecommendedFileForUri = makeSelectFirstRecommendedFileForUri;
exports.makeSelectIsUriResolving = makeSelectIsUriResolving; exports.makeSelectIsUriResolving = makeSelectIsUriResolving;
@ -4883,7 +4830,7 @@ exports.selectAllMyClaimsByOutpoint = selectAllMyClaimsByOutpoint;
exports.selectBalance = selectBalance; exports.selectBalance = selectBalance;
exports.selectBlocks = selectBlocks; exports.selectBlocks = selectBlocks;
exports.selectChannelClaimCounts = selectChannelClaimCounts; exports.selectChannelClaimCounts = selectChannelClaimCounts;
exports.selectClaimSearchUrisByTags = selectClaimSearchUrisByTags; exports.selectClaimSearchByQuery = selectClaimSearchByQuery;
exports.selectClaimsById = selectClaimsById; exports.selectClaimsById = selectClaimsById;
exports.selectClaimsByUri = selectClaimsByUri; exports.selectClaimsByUri = selectClaimsByUri;
exports.selectCurrentChannelPage = selectCurrentChannelPage; exports.selectCurrentChannelPage = selectCurrentChannelPage;
@ -4897,7 +4844,6 @@ exports.selectDraftTransactionError = selectDraftTransactionError;
exports.selectError = selectError; exports.selectError = selectError;
exports.selectFailedPurchaseUris = selectFailedPurchaseUris; exports.selectFailedPurchaseUris = selectFailedPurchaseUris;
exports.selectFetchingClaimSearch = selectFetchingClaimSearch; exports.selectFetchingClaimSearch = selectFetchingClaimSearch;
exports.selectFetchingClaimSearchByTags = selectFetchingClaimSearchByTags;
exports.selectFetchingMyChannels = selectFetchingMyChannels; exports.selectFetchingMyChannels = selectFetchingMyChannels;
exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint; exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint;
exports.selectFileInfosDownloaded = selectFileInfosDownloaded; exports.selectFileInfosDownloaded = selectFileInfosDownloaded;
@ -4914,7 +4860,6 @@ exports.selectIsResolvingPublishUris = selectIsResolvingPublishUris;
exports.selectIsSearching = selectIsSearching; exports.selectIsSearching = selectIsSearching;
exports.selectIsSendingSupport = selectIsSendingSupport; exports.selectIsSendingSupport = selectIsSendingSupport;
exports.selectIsStillEditing = selectIsStillEditing; exports.selectIsStillEditing = selectIsStillEditing;
exports.selectLastClaimSearchUris = selectLastClaimSearchUris;
exports.selectLastPurchasedUri = selectLastPurchasedUri; exports.selectLastPurchasedUri = selectLastPurchasedUri;
exports.selectMyActiveClaims = selectMyActiveClaims; exports.selectMyActiveClaims = selectMyActiveClaims;
exports.selectMyChannelClaims = selectMyChannelClaims; exports.selectMyChannelClaims = selectMyChannelClaims;
@ -4962,6 +4907,7 @@ exports.selectWalletState = selectWalletState;
exports.selectWalletUnlockPending = selectWalletUnlockPending; exports.selectWalletUnlockPending = selectWalletUnlockPending;
exports.selectWalletUnlockResult = selectWalletUnlockResult; exports.selectWalletUnlockResult = selectWalletUnlockResult;
exports.selectWalletUnlockSucceeded = selectWalletUnlockSucceeded; exports.selectWalletUnlockSucceeded = selectWalletUnlockSucceeded;
exports.selectfetchingClaimSearchByQuery = selectfetchingClaimSearchByQuery;
exports.setSearchApi = setSearchApi; exports.setSearchApi = setSearchApi;
exports.tagsReducer = tagsReducer; exports.tagsReducer = tagsReducer;
exports.toQueryString = toQueryString; exports.toQueryString = toQueryString;

View file

@ -55,7 +55,6 @@ export {
doCreateChannel, doCreateChannel,
doUpdateChannel, doUpdateChannel,
doClaimSearch, doClaimSearch,
doClaimSearchByTags,
} from 'redux/actions/claims'; } from 'redux/actions/claims';
export { doDeletePurchasedUri, doPurchaseUri, doFileGet } from 'redux/actions/file'; export { doDeletePurchasedUri, doPurchaseUri, doFileGet } from 'redux/actions/file';
@ -113,10 +112,10 @@ export { doToggleTagFollow, doAddTag, doDeleteTag } from 'redux/actions/tags';
export { doCommentList, doCommentCreate } from 'redux/actions/comments'; export { doCommentList, doCommentCreate } from 'redux/actions/comments';
// utils // utils
export { batchActions } from 'util/batchActions'; export { batchActions } from 'util/batch-actions';
export { parseQueryParams, toQueryString } from 'util/query_params'; export { parseQueryParams, toQueryString } from 'util/query-params';
export { formatCredits, formatFullPrice, creditsToString } from 'util/formatCredits'; export { formatCredits, formatFullPrice, creditsToString } from 'util/format-credits';
export { isClaimNsfw } from 'util/claim'; export { isClaimNsfw, createNormalizedClaimSearchKey } from 'util/claim';
// reducers // reducers
export { claimsReducer } from 'redux/reducers/claims'; export { claimsReducer } from 'redux/reducers/claims';
@ -193,11 +192,8 @@ export {
selectChannelClaimCounts, selectChannelClaimCounts,
selectCurrentChannelPage, selectCurrentChannelPage,
selectFetchingClaimSearch, selectFetchingClaimSearch,
selectLastClaimSearchUris, selectfetchingClaimSearchByQuery,
selectFetchingClaimSearchByTags, selectClaimSearchByQuery,
selectClaimSearchUrisByTags,
makeSelectFetchingClaimSearchForTags,
makeSelectClaimSearchUrisForTags,
} from 'redux/selectors/claims'; } from 'redux/selectors/claims';
export { makeSelectCommentsForUri } from 'redux/selectors/comments'; export { makeSelectCommentsForUri } from 'redux/selectors/comments';

View file

@ -2,7 +2,7 @@ const channelNameMinLength = 1;
const claimIdMaxLength = 40; const claimIdMaxLength = 40;
// see https://spec.lbry.com/#urls // see https://spec.lbry.com/#urls
export const regexInvalidURI = /[ =&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/gu; export const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
/** /**

View file

@ -6,9 +6,9 @@ import { doToast } from 'redux/actions/notifications';
import { selectMyClaimsRaw, selectResolvingUris, selectClaimsByUri } from 'redux/selectors/claims'; import { selectMyClaimsRaw, selectResolvingUris, selectClaimsByUri } from 'redux/selectors/claims';
import { doFetchTransactions } from 'redux/actions/wallet'; import { doFetchTransactions } from 'redux/actions/wallet';
import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
import { creditsToString } from 'util/formatCredits'; import { creditsToString } from 'util/format-credits';
import { batchActions } from 'util/batchActions'; import { batchActions } from 'util/batch-actions';
import { createNormalizedTagKey } from 'util/claim'; import { createNormalizedClaimSearchKey } from 'util/claim';
export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean = false) { export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean = false) {
return (dispatch: Dispatch, getState: GetState) => { return (dispatch: Dispatch, getState: GetState) => {
@ -314,10 +314,16 @@ export function doFetchChannelListMine() {
}; };
} }
export function doClaimSearch(options: { page_size?: number, page?: number } = {}) { export function doClaimSearch(
options: { tags?: Array<string>, page?: number, page_size?: number, release_time?: string } = {
page_size: 10,
}
) {
const query = createNormalizedClaimSearchKey(options);
return (dispatch: Dispatch) => { return (dispatch: Dispatch) => {
dispatch({ dispatch({
type: ACTIONS.CLAIM_SEARCH_STARTED, type: ACTIONS.CLAIM_SEARCH_STARTED,
data: { query: query },
}); });
const success = (data: ClaimSearchResponse) => { const success = (data: ClaimSearchResponse) => {
@ -330,62 +336,18 @@ export function doClaimSearch(options: { page_size?: number, page?: number } = {
dispatch({ dispatch({
type: ACTIONS.CLAIM_SEARCH_COMPLETED, type: ACTIONS.CLAIM_SEARCH_COMPLETED,
data: { resolveInfo, uris, append: options.page && options.page !== 1 }, data: { query, resolveInfo, uris, append: options.page && options.page !== 1 },
}); });
}; };
const failure = err => { const failure = err => {
dispatch({ dispatch({
type: ACTIONS.CLAIM_SEARCH_FAILED, type: ACTIONS.CLAIM_SEARCH_FAILED,
data: { query },
error: err, error: err,
}); });
}; };
Lbry.claim_search({ Lbry.claim_search(options).then(success, failure);
...options,
}).then(success, failure);
};
}
// tags can be one or many (comma separated)
export function doClaimSearchByTags(
tags: Array<string>,
amount: number = 10,
options: { page?: number } = {}
) {
return (dispatch: Dispatch) => {
const tagList = createNormalizedTagKey(tags);
dispatch({
type: ACTIONS.CLAIM_SEARCH_BY_TAGS_STARTED,
data: { tags: tagList },
});
const success = (data: ClaimSearchResponse) => {
const resolveInfo = {};
const uris = [];
data.items.forEach((stream: Claim) => {
resolveInfo[stream.permanent_url] = { stream };
uris.push(stream.permanent_url);
});
dispatch({
type: ACTIONS.CLAIM_SEARCH_BY_TAGS_COMPLETED,
data: { tags: tagList, resolveInfo, uris, append: options.page && options.page !== 1 },
});
};
const failure = err => {
dispatch({
type: ACTIONS.CLAIM_SEARCH_BY_TAGS_FAILED,
data: { tags: tagList },
error: err,
});
};
Lbry.claim_search({
page_size: amount,
any_tags: tags,
...options,
}).then(success, failure);
}; };
} }

View file

@ -3,8 +3,8 @@ import { CC_LICENSES, COPYRIGHT, OTHER, NONE, PUBLIC_DOMAIN } from 'constants/li
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses'; import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
import Lbry from 'lbry'; import Lbry from 'lbry';
import { batchActions } from 'util/batchActions'; import { batchActions } from 'util/batch-actions';
import { creditsToString } from 'util/formatCredits'; import { creditsToString } from 'util/format-credits';
import { doError } from 'redux/actions/notifications'; import { doError } from 'redux/actions/notifications';
import { isClaimNsfw } from 'util/claim'; import { isClaimNsfw } from 'util/claim';
import { import {

View file

@ -8,7 +8,7 @@ import {
makeSelectQueryWithOptions, makeSelectQueryWithOptions,
selectSearchValue, selectSearchValue,
} from 'redux/selectors/search'; } from 'redux/selectors/search';
import { batchActions } from 'util/batchActions'; import { batchActions } from 'util/batch-actions';
import debounce from 'util/debounce'; import debounce from 'util/debounce';
import handleFetchResponse from 'util/handle-fetch'; import handleFetchResponse from 'util/handle-fetch';

View file

@ -2,7 +2,7 @@ import * as ACTIONS from 'constants/action_types';
import Lbry from 'lbry'; import Lbry from 'lbry';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import { selectBalance } from 'redux/selectors/wallet'; import { selectBalance } from 'redux/selectors/wallet';
import { creditsToString } from 'util/formatCredits'; import { creditsToString } from 'util/format-credits';
import { selectMyClaimsRaw } from 'redux/selectors/claims'; import { selectMyClaimsRaw } from 'redux/selectors/claims';
export function doUpdateBalance() { export function doUpdateBalance() {
@ -230,7 +230,9 @@ export function doSendTip(amount, claimId, successCallback, errorCallback) {
const success = () => { const success = () => {
dispatch( dispatch(
doToast({ doToast({
message: isSupport ? __(`You deposited ${amount} LBC as a support!`) : __(`You sent ${amount} LBC as a tip, Mahalo!`), message: isSupport
? __(`You deposited ${amount} LBC as a support!`)
: __(`You sent ${amount} LBC as a tip, Mahalo!`),
linkText: __('History'), linkText: __('History'),
linkTarget: __('/wallet'), linkTarget: __('/wallet'),
}) })

View file

@ -21,9 +21,8 @@ type State = {
abandoningById: { [string]: boolean }, abandoningById: { [string]: boolean },
fetchingChannelClaims: { [string]: number }, fetchingChannelClaims: { [string]: number },
fetchingMyChannels: boolean, fetchingMyChannels: boolean,
lastClaimSearchUris: Array<string>, fetchingClaimSearchByQuery: { [string]: boolean },
fetchingClaimSearchByTags: { [string]: boolean }, claimSearchByQuery: { [string]: Array<string> },
claimSearchUrisByTags: { [string]: { all: Array<string> } },
claimsByChannel: { claimsByChannel: {
[string]: { [string]: {
all: Array<string>, all: Array<string>,
@ -46,10 +45,9 @@ const defaultState = {
fetchingMyChannels: false, fetchingMyChannels: false,
abandoningById: {}, abandoningById: {},
pendingById: {}, pendingById: {},
fetchingClaimSearch: false, claimSearchError: false,
claimSearchUrisByTags: {}, claimSearchByQuery: {},
fetchingClaimSearchByTags: {}, fetchingClaimSearchByQuery: {},
lastClaimSearchUris: [],
}; };
function handleClaimAction(state: State, action: any): State { function handleClaimAction(state: State, action: any): State {
@ -289,66 +287,45 @@ reducers[ACTIONS.RESOLVE_URIS_STARTED] = (state: State, action: any): State => {
}); });
}; };
reducers[ACTIONS.CLAIM_SEARCH_STARTED] = (state: State): State => { reducers[ACTIONS.CLAIM_SEARCH_STARTED] = (state: State, action: any): State => {
const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
fetchingClaimSearchByQuery[action.data.query] = true;
return Object.assign({}, state, { return Object.assign({}, state, {
fetchingClaimSearch: true, fetchingClaimSearchByQuery,
}); });
}; };
reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => { reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => {
const { lastClaimSearchUris } = state; const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery);
const { append, query, uris } = action.data;
let newClaimSearchUris = []; if (append) {
if (action.data.append) {
newClaimSearchUris = lastClaimSearchUris.concat(action.data.uris);
} else {
newClaimSearchUris = action.data.uris;
}
return {
...handleClaimAction(state, action),
fetchingClaimSearch: false,
lastClaimSearchUris: newClaimSearchUris,
};
};
reducers[ACTIONS.CLAIM_SEARCH_FAILED] = (state: State): State => {
return Object.assign({}, state, {
fetchingClaimSearch: false,
});
};
reducers[ACTIONS.CLAIM_SEARCH_BY_TAGS_STARTED] = (state: State, action: any): State => {
const fetchingClaimSearchByTags = Object.assign({}, state.fetchingClaimSearchByTags);
fetchingClaimSearchByTags[action.data.tags] = true;
return Object.assign({}, state, {
fetchingClaimSearchByTags
});
};
reducers[ACTIONS.CLAIM_SEARCH_BY_TAGS_COMPLETED] = (state: State, action: any): State => {
const fetchingClaimSearchByTags = Object.assign({}, state.fetchingClaimSearchByTags);
const claimSearchUrisByTags = Object.assign({}, state.claimSearchUrisByTags);
const { append, tags, uris } = action.data;
if (action.data.append) {
// todo: check for duplicate uris when concatenating? // todo: check for duplicate uris when concatenating?
claimSearchUrisByTags[tags] = claimSearchUrisByTags[tags] && claimSearchUrisByTags[tags].length ? claimSearchByQuery[query] =
claimSearchUrisByTags[tags].concat(uris) : uris; claimSearchByQuery[query] && claimSearchByQuery[query].length
? claimSearchByQuery[query].concat(uris)
: uris;
} else { } else {
claimSearchUrisByTags[tags] = uris; claimSearchByQuery[query] = uris;
} }
fetchingClaimSearchByTags[tags] = false; // or delete the key instead?
delete fetchingClaimSearchByQuery[query];
return Object.assign({}, state, { return Object.assign({}, state, {
claimSearchUrisByTags, ...handleClaimAction(state, action),
fetchingClaimSearchByTags, claimSearchByQuery,
fetchingClaimSearchByQuery,
}); });
}; };
reducers[ACTIONS.CLAIM_SEARCH_BY_TAGS_FAILED] = (state: State, action: any): State => {
const fetchingClaimSearchByTags = Object.assign({}, state.fetchingClaimSearchByTags); reducers[ACTIONS.CLAIM_SEARCH_FAILED] = (state: State, action: any): State => {
fetchingClaimSearchByTags[action.data.tags] = false; const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
fetchingClaimSearchByQuery[action.data.tags] = false;
return Object.assign({}, state, { return Object.assign({}, state, {
fetchingClaimSearchByTags, fetchingClaimSearchByQuery,
}); });
}; };

View file

@ -2,8 +2,8 @@
import { normalizeURI, buildURI, parseURI } from 'lbryURI'; import { normalizeURI, buildURI, parseURI } from 'lbryURI';
import { selectSearchUrisByQuery } from 'redux/selectors/search'; import { selectSearchUrisByQuery } from 'redux/selectors/search';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { isClaimNsfw, createNormalizedTagKey } from 'util/claim'; import { isClaimNsfw, createNormalizedClaimSearchKey } from 'util/claim';
import { getSearchQueryString } from 'util/query_params'; import { getSearchQueryString } from 'util/query-params';
const selectState = state => state.claims || {}; const selectState = state => state.claims || {};
@ -88,12 +88,14 @@ export const makeSelectClaimForUri = (uri: string) =>
// Check if a claim is pending first // Check if a claim is pending first
// It won't be in claimsByUri because resolving it will return nothing // It won't be in claimsByUri because resolving it will return nothing
let valid;
let claimId; let claimId;
try { try {
({ claimId } = parseURI(uri)); ({ claimId } = parseURI(uri));
valid = true;
} catch (e) {} } catch (e) {}
if (claimId) { if (valid) {
const pendingClaim = pendingById[claimId]; const pendingClaim = pendingById[claimId];
if (pendingClaim) { if (pendingClaim) {
@ -253,7 +255,11 @@ export const makeSelectThumbnailForUri = (uri: string) =>
makeSelectClaimForUri(uri), makeSelectClaimForUri(uri),
claim => { claim => {
const thumbnail = claim && claim.value && claim.value.thumbnail; const thumbnail = claim && claim.value && claim.value.thumbnail;
return thumbnail && thumbnail.url && thumbnail.url.trim().length > 0 ? thumbnail.url : undefined; if (!thumbnail || !thumbnail.url) {
return null;
}
return thumbnail.url.trim();
} }
); );
@ -494,40 +500,34 @@ export const makeSelectTagsForUri = (uri: string) =>
} }
); );
export const selectFetchingClaimSearch = createSelector( export const selectfetchingClaimSearchByQuery = createSelector(
selectState, selectState,
state => state.fetchingClaimSearch state => state.fetchingClaimSearchByQuery || {}
); );
export const selectLastClaimSearchUris = createSelector( export const selectFetchingClaimSearch = createSelector(
selectState, selectfetchingClaimSearchByQuery,
state => state.lastClaimSearchUris fetchingClaimSearchByQuery => Boolean(Object.keys(fetchingClaimSearchByQuery).length)
); );
export const selectClaimSearchByQuery = createSelector(
selectState,
state => state.claimSearchByQuery || {}
);
export const makeSelectClaimSearchUrisByOptions = (options: {}) =>
createSelector(
selectClaimSearchByQuery,
byQuery => {
// We don't care what options are passed to this selector. Just forward them.
// $FlowFixMe
const query = createNormalizedClaimSearchKey(options);
return byQuery[query];
}
);
export const makeSelectShortUrlForUri = (uri: string) => export const makeSelectShortUrlForUri = (uri: string) =>
createSelector( createSelector(
makeSelectClaimForUri(uri), makeSelectClaimForUri(uri),
claim => claim && claim.short_url claim => claim && claim.short_url
); );
export const selectFetchingClaimSearchByTags = createSelector(
selectState,
state => state.fetchingClaimSearchByTags
);
export const selectClaimSearchUrisByTags = createSelector(
selectState,
state => state.claimSearchUrisByTags
);
export const makeSelectFetchingClaimSearchForTags = (tags: Array<string>) =>
createSelector(
selectFetchingClaimSearchByTags,
byTags => byTags[createNormalizedTagKey(tags)]
);
export const makeSelectClaimSearchUrisForTags = (tags: Array<string>) =>
createSelector(
selectClaimSearchUrisByTags,
byTags => byTags[createNormalizedTagKey(tags)]
);

View file

@ -1,50 +0,0 @@
import { createSelector } from 'reselect';
import { parseQueryParams } from 'util/query_params';
export const selectState = state => state.navigation || {};
export const selectCurrentPath = createSelector(selectState, state => state.currentPath);
export const computePageFromPath = path => (path ? path.replace(/^\//, '').split('?')[0] : '');
export const selectCurrentPage = createSelector(selectCurrentPath, path =>
computePageFromPath(path)
);
export const selectCurrentParams = createSelector(selectCurrentPath, path => {
if (path === undefined) return {};
if (!path.match(/\?/)) return {};
return parseQueryParams(path.split('?')[1]);
});
export const makeSelectCurrentParam = param =>
createSelector(selectCurrentParams, params => (params ? params[param] : undefined));
export const selectPathAfterAuth = createSelector(selectState, state => state.pathAfterAuth);
export const selectIsBackDisabled = createSelector(selectState, state => state.index === 0);
export const selectIsForwardDisabled = createSelector(
selectState,
state => state.index === state.stack.length - 1
);
export const selectIsHome = createSelector(selectCurrentPage, page => page === 'discover');
export const selectHistoryIndex = createSelector(selectState, state => state.index);
export const selectHistoryStack = createSelector(selectState, state => state.stack);
// returns current page attributes (scrollY, path)
export const selectActiveHistoryEntry = createSelector(
selectState,
state => state.stack[state.index]
);
export const selectPageTitle = createSelector(selectCurrentPage, page => {
switch (page) {
default:
return '';
}
});

View file

@ -1,6 +1,6 @@
// @flow // @flow
import { SEARCH_TYPES, SEARCH_OPTIONS } from 'constants/search'; import { SEARCH_TYPES, SEARCH_OPTIONS } from 'constants/search';
import { getSearchQueryString } from 'util/query_params'; import { getSearchQueryString } from 'util/query-params';
import { normalizeURI, parseURI } from 'lbryURI'; import { normalizeURI, parseURI } from 'lbryURI';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';

View file

@ -23,6 +23,10 @@ export const isClaimNsfw = (claim: Claim): boolean => {
return false; return false;
}; };
export const createNormalizedTagKey = (tags: Array<string>): string => { export function createNormalizedClaimSearchKey(options: { page?: number, release_time?: string }) {
return tags ? tags.sort().join(',') : ''; // Ignore page because we don't care what the last page searched was, we want everything
}; // Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567"
const { page: optionToIgnoreForQuery, release_time: anotherToIgnore, ...rest } = options;
const query = JSON.stringify(rest);
return query;
}