add doResolvedSearch actions which returns resolved search results (#258)
* add doResolvedSearch actions which returns resolved search results * add recommended content selector * update ResolvedSearchResult type * support for multiple pages of resolved search results
This commit is contained in:
parent
f0891dd298
commit
17a5260c3f
10 changed files with 388 additions and 15 deletions
154
dist/bundle.es.js
vendored
154
dist/bundle.es.js
vendored
|
@ -15,7 +15,6 @@ const CHANNEL_NEW = 'new';
|
||||||
const PAGE_SIZE = 20;
|
const PAGE_SIZE = 20;
|
||||||
|
|
||||||
var claim = /*#__PURE__*/Object.freeze({
|
var claim = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
MINIMUM_PUBLISH_BID: MINIMUM_PUBLISH_BID,
|
MINIMUM_PUBLISH_BID: MINIMUM_PUBLISH_BID,
|
||||||
CHANNEL_ANONYMOUS: CHANNEL_ANONYMOUS,
|
CHANNEL_ANONYMOUS: CHANNEL_ANONYMOUS,
|
||||||
CHANNEL_NEW: CHANNEL_NEW,
|
CHANNEL_NEW: CHANNEL_NEW,
|
||||||
|
@ -163,6 +162,9 @@ const DELETE_PURCHASED_URI = 'DELETE_PURCHASED_URI';
|
||||||
const SEARCH_START = 'SEARCH_START';
|
const SEARCH_START = 'SEARCH_START';
|
||||||
const SEARCH_SUCCESS = 'SEARCH_SUCCESS';
|
const SEARCH_SUCCESS = 'SEARCH_SUCCESS';
|
||||||
const SEARCH_FAIL = 'SEARCH_FAIL';
|
const SEARCH_FAIL = 'SEARCH_FAIL';
|
||||||
|
const RESOLVED_SEARCH_START = 'RESOLVED_SEARCH_START';
|
||||||
|
const RESOLVED_SEARCH_SUCCESS = 'RESOLVED_SEARCH_SUCCESS';
|
||||||
|
const RESOLVED_SEARCH_FAIL = 'RESOLVED_SEARCH_FAIL';
|
||||||
const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY';
|
const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY';
|
||||||
const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS';
|
const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS';
|
||||||
const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS';
|
const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS';
|
||||||
|
@ -275,7 +277,6 @@ const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL';
|
||||||
const USER_STATE_POPULATE = 'USER_STATE_POPULATE';
|
const USER_STATE_POPULATE = 'USER_STATE_POPULATE';
|
||||||
|
|
||||||
var action_types = /*#__PURE__*/Object.freeze({
|
var action_types = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
WINDOW_FOCUSED: WINDOW_FOCUSED,
|
WINDOW_FOCUSED: WINDOW_FOCUSED,
|
||||||
DAEMON_READY: DAEMON_READY,
|
DAEMON_READY: DAEMON_READY,
|
||||||
DAEMON_VERSION_MATCH: DAEMON_VERSION_MATCH,
|
DAEMON_VERSION_MATCH: DAEMON_VERSION_MATCH,
|
||||||
|
@ -403,6 +404,9 @@ var action_types = /*#__PURE__*/Object.freeze({
|
||||||
SEARCH_START: SEARCH_START,
|
SEARCH_START: SEARCH_START,
|
||||||
SEARCH_SUCCESS: SEARCH_SUCCESS,
|
SEARCH_SUCCESS: SEARCH_SUCCESS,
|
||||||
SEARCH_FAIL: SEARCH_FAIL,
|
SEARCH_FAIL: SEARCH_FAIL,
|
||||||
|
RESOLVED_SEARCH_START: RESOLVED_SEARCH_START,
|
||||||
|
RESOLVED_SEARCH_SUCCESS: RESOLVED_SEARCH_SUCCESS,
|
||||||
|
RESOLVED_SEARCH_FAIL: RESOLVED_SEARCH_FAIL,
|
||||||
UPDATE_SEARCH_QUERY: UPDATE_SEARCH_QUERY,
|
UPDATE_SEARCH_QUERY: UPDATE_SEARCH_QUERY,
|
||||||
UPDATE_SEARCH_OPTIONS: UPDATE_SEARCH_OPTIONS,
|
UPDATE_SEARCH_OPTIONS: UPDATE_SEARCH_OPTIONS,
|
||||||
UPDATE_SEARCH_SUGGESTIONS: UPDATE_SEARCH_SUGGESTIONS,
|
UPDATE_SEARCH_SUGGESTIONS: UPDATE_SEARCH_SUGGESTIONS,
|
||||||
|
@ -518,7 +522,6 @@ const OTHER = 'other';
|
||||||
const COPYRIGHT = 'copyright';
|
const COPYRIGHT = 'copyright';
|
||||||
|
|
||||||
var licenses = /*#__PURE__*/Object.freeze({
|
var licenses = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
CC_LICENSES: CC_LICENSES,
|
CC_LICENSES: CC_LICENSES,
|
||||||
NONE: NONE,
|
NONE: NONE,
|
||||||
PUBLIC_DOMAIN: PUBLIC_DOMAIN,
|
PUBLIC_DOMAIN: PUBLIC_DOMAIN,
|
||||||
|
@ -549,7 +552,6 @@ const HISTORY = 'user_history';
|
||||||
const WALLET = 'wallet';
|
const WALLET = 'wallet';
|
||||||
|
|
||||||
var pages = /*#__PURE__*/Object.freeze({
|
var pages = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
AUTH: AUTH,
|
AUTH: AUTH,
|
||||||
BACKUP: BACKUP,
|
BACKUP: BACKUP,
|
||||||
CHANNEL: CHANNEL,
|
CHANNEL: CHANNEL,
|
||||||
|
@ -599,7 +601,6 @@ const RECEIVE_INTERESTS_NOTIFICATIONS = 'receiveInterestsNotifications';
|
||||||
const RECEIVE_CREATOR_NOTIFICATIONS = 'receiveCreatorNotifications';
|
const RECEIVE_CREATOR_NOTIFICATIONS = 'receiveCreatorNotifications';
|
||||||
|
|
||||||
var settings = /*#__PURE__*/Object.freeze({
|
var settings = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
CREDIT_REQUIRED_ACKNOWLEDGED: CREDIT_REQUIRED_ACKNOWLEDGED,
|
CREDIT_REQUIRED_ACKNOWLEDGED: CREDIT_REQUIRED_ACKNOWLEDGED,
|
||||||
NEW_USER_ACKNOWLEDGED: NEW_USER_ACKNOWLEDGED,
|
NEW_USER_ACKNOWLEDGED: NEW_USER_ACKNOWLEDGED,
|
||||||
EMAIL_COLLECTION_ACKNOWLEDGED: EMAIL_COLLECTION_ACKNOWLEDGED,
|
EMAIL_COLLECTION_ACKNOWLEDGED: EMAIL_COLLECTION_ACKNOWLEDGED,
|
||||||
|
@ -627,7 +628,6 @@ const TITLE = 'title';
|
||||||
const FILENAME = 'filename';
|
const FILENAME = 'filename';
|
||||||
|
|
||||||
var sort_options = /*#__PURE__*/Object.freeze({
|
var sort_options = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
DATE_NEW: DATE_NEW,
|
DATE_NEW: DATE_NEW,
|
||||||
DATE_OLD: DATE_OLD,
|
DATE_OLD: DATE_OLD,
|
||||||
TITLE: TITLE,
|
TITLE: TITLE,
|
||||||
|
@ -641,7 +641,6 @@ const COMPLETE = 'complete';
|
||||||
const MANUAL = 'manual';
|
const MANUAL = 'manual';
|
||||||
|
|
||||||
var thumbnail_upload_statuses = /*#__PURE__*/Object.freeze({
|
var thumbnail_upload_statuses = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
API_DOWN: API_DOWN,
|
API_DOWN: API_DOWN,
|
||||||
READY: READY,
|
READY: READY,
|
||||||
IN_PROGRESS: IN_PROGRESS,
|
IN_PROGRESS: IN_PROGRESS,
|
||||||
|
@ -661,7 +660,6 @@ const UPDATE = 'update';
|
||||||
const ABANDON = 'abandon';
|
const ABANDON = 'abandon';
|
||||||
|
|
||||||
var transaction_types = /*#__PURE__*/Object.freeze({
|
var transaction_types = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
ALL: ALL,
|
ALL: ALL,
|
||||||
SPEND: SPEND,
|
SPEND: SPEND,
|
||||||
RECEIVE: RECEIVE,
|
RECEIVE: RECEIVE,
|
||||||
|
@ -678,7 +676,6 @@ const PAGE_SIZE$1 = 50;
|
||||||
const LATEST_PAGE_SIZE = 20;
|
const LATEST_PAGE_SIZE = 20;
|
||||||
|
|
||||||
var transaction_list = /*#__PURE__*/Object.freeze({
|
var transaction_list = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
PAGE_SIZE: PAGE_SIZE$1,
|
PAGE_SIZE: PAGE_SIZE$1,
|
||||||
LATEST_PAGE_SIZE: LATEST_PAGE_SIZE
|
LATEST_PAGE_SIZE: LATEST_PAGE_SIZE
|
||||||
});
|
});
|
||||||
|
@ -687,7 +684,6 @@ const SPEECH_STATUS = 'https://spee.ch/api/config/site/publishing';
|
||||||
const SPEECH_PUBLISH = 'https://spee.ch/api/claim/publish';
|
const SPEECH_PUBLISH = 'https://spee.ch/api/claim/publish';
|
||||||
|
|
||||||
var speech_urls = /*#__PURE__*/Object.freeze({
|
var speech_urls = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
SPEECH_STATUS: SPEECH_STATUS,
|
SPEECH_STATUS: SPEECH_STATUS,
|
||||||
SPEECH_PUBLISH: SPEECH_PUBLISH
|
SPEECH_PUBLISH: SPEECH_PUBLISH
|
||||||
});
|
});
|
||||||
|
@ -733,7 +729,6 @@ const WALLET_DIR = 'wallet_dir';
|
||||||
const WALLETS = 'wallets';
|
const WALLETS = 'wallets';
|
||||||
|
|
||||||
var daemon_settings = /*#__PURE__*/Object.freeze({
|
var daemon_settings = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
ANNOUNCE_HEAD_AND_SD_ONLY: ANNOUNCE_HEAD_AND_SD_ONLY,
|
ANNOUNCE_HEAD_AND_SD_ONLY: ANNOUNCE_HEAD_AND_SD_ONLY,
|
||||||
API: API,
|
API: API,
|
||||||
BLOB_DOWNLOAD_TIMEOUT: BLOB_DOWNLOAD_TIMEOUT,
|
BLOB_DOWNLOAD_TIMEOUT: BLOB_DOWNLOAD_TIMEOUT,
|
||||||
|
@ -787,7 +782,6 @@ var daemon_settings = /*#__PURE__*/Object.freeze({
|
||||||
const WALLET_SERVERS = LBRYUM_SERVERS;
|
const WALLET_SERVERS = LBRYUM_SERVERS;
|
||||||
|
|
||||||
var shared_preferences = /*#__PURE__*/Object.freeze({
|
var shared_preferences = /*#__PURE__*/Object.freeze({
|
||||||
__proto__: null,
|
|
||||||
WALLET_SERVERS: WALLET_SERVERS
|
WALLET_SERVERS: WALLET_SERVERS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1342,6 +1336,18 @@ const makeSelectSearchUris = query =>
|
||||||
// replace statement below is kind of ugly, and repeated in doSearch action
|
// replace statement below is kind of ugly, and repeated in doSearch action
|
||||||
reselect.createSelector(selectSearchUrisByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]);
|
reselect.createSelector(selectSearchUrisByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]);
|
||||||
|
|
||||||
|
const selectResolvedSearchResultsByQuery = reselect.createSelector(selectState, state => state.resolvedResultsByQuery);
|
||||||
|
|
||||||
|
const selectResolvedSearchResultsByQueryLastPageReached = reselect.createSelector(selectState, state => state.resolvedResultsByQueryLastPageReached);
|
||||||
|
|
||||||
|
const makeSelectResolvedSearchResults = query =>
|
||||||
|
// replace statement below is kind of ugly, and repeated in doSearch action
|
||||||
|
reselect.createSelector(selectResolvedSearchResultsByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]);
|
||||||
|
|
||||||
|
const makeSelectResolvedSearchResultsLastPageReached = query =>
|
||||||
|
// replace statement below is kind of ugly, and repeated in doSearch action
|
||||||
|
reselect.createSelector(selectResolvedSearchResultsByQueryLastPageReached, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]);
|
||||||
|
|
||||||
const selectSearchBarFocused = reselect.createSelector(selectState, state => state.focused);
|
const selectSearchBarFocused = reselect.createSelector(selectState, state => state.focused);
|
||||||
|
|
||||||
const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selectSuggestions, (query, suggestions) => {
|
const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selectSuggestions, (query, suggestions) => {
|
||||||
|
@ -2277,6 +2283,34 @@ const makeSelectMyStreamUrlsForPage = (page = 1) => reselect.createSelector(sele
|
||||||
|
|
||||||
const selectMyStreamUrlsCount = reselect.createSelector(selectMyClaimUrisWithoutChannels, channels => channels.length);
|
const selectMyStreamUrlsCount = reselect.createSelector(selectMyClaimUrisWithoutChannels, channels => channels.length);
|
||||||
|
|
||||||
|
const makeSelectResolvedRecommendedContentForUri = (uri, size) => reselect.createSelector(makeSelectClaimForUri(uri), selectResolvedSearchResultsByQuery, (claim, resolvedResultsByQuery) => {
|
||||||
|
const atVanityURI = !uri.includes('#');
|
||||||
|
|
||||||
|
let recommendedContent;
|
||||||
|
if (claim) {
|
||||||
|
// always grab full URL - this can change once search returns canonical
|
||||||
|
const currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name });
|
||||||
|
|
||||||
|
const { title } = claim.value;
|
||||||
|
|
||||||
|
if (!title) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchQuery = getSearchQueryString(title.replace(/\//, ' '), { size }, undefined, {
|
||||||
|
related_to: claim.claim_id
|
||||||
|
});
|
||||||
|
|
||||||
|
let results = resolvedResultsByQuery[searchQuery];
|
||||||
|
if (results) {
|
||||||
|
results = results.filter(result => buildURI({ streamClaimId: result.claimId, streamName: result.name }) !== currentUri);
|
||||||
|
recommendedContent = results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recommendedContent;
|
||||||
|
});
|
||||||
|
|
||||||
function numberWithCommas(x) {
|
function numberWithCommas(x) {
|
||||||
var parts = x.toString().split('.');
|
var parts = x.toString().split('.');
|
||||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||||
|
@ -4020,6 +4054,63 @@ from, isBackgroundSearch = false, options = {}, resolveResults = true) => (dispa
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const doResolvedSearch = (rawQuery, size, // only pass in if you don't want to use the users setting (ex: related content)
|
||||||
|
from, isBackgroundSearch = false, options = {}) => (dispatch, getState) => {
|
||||||
|
const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' ');
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
dispatch({
|
||||||
|
type: RESOLVED_SEARCH_FAIL
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = getState();
|
||||||
|
let queryWithOptions = makeSelectQueryWithOptions(query, size, from, isBackgroundSearch, options)(state);
|
||||||
|
|
||||||
|
// make from null so that we can maintain a reference to the same query for multiple pages and simply append the found results
|
||||||
|
let queryWithoutFrom = makeSelectQueryWithOptions(query, size, null, isBackgroundSearch, options)(state);
|
||||||
|
|
||||||
|
// If we have already searched for something, we don't need to do anything
|
||||||
|
// TODO: Tweak this check for multiple page results
|
||||||
|
/* const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state);
|
||||||
|
if (resultsForQuery && resultsForQuery.length && resultsForQuery.length > (from * size)) {
|
||||||
|
return;
|
||||||
|
} */
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: RESOLVED_SEARCH_START
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!state.search.searchQuery && !isBackgroundSearch) {
|
||||||
|
dispatch(doUpdateSearchQuery(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`${CONNECTION_STRING}search?resolve=true&${queryWithOptions}`).then(handleFetchResponse).then(data => {
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
data.forEach(result => {
|
||||||
|
if (result) {
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: RESOLVED_SEARCH_SUCCESS,
|
||||||
|
data: {
|
||||||
|
query: queryWithoutFrom,
|
||||||
|
results,
|
||||||
|
pageSize: size,
|
||||||
|
append: parseInt(from, 10) > parseInt(size, 10) - 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(e => {
|
||||||
|
dispatch({
|
||||||
|
type: RESOLVED_SEARCH_FAIL
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const doFocusSearchInput = () => dispatch => dispatch({
|
const doFocusSearchInput = () => dispatch => dispatch({
|
||||||
type: SEARCH_FOCUS
|
type: SEARCH_FOCUS
|
||||||
});
|
});
|
||||||
|
@ -5024,7 +5115,9 @@ const defaultState$7 = {
|
||||||
[SEARCH_OPTIONS.MEDIA_APPLICATION]: true
|
[SEARCH_OPTIONS.MEDIA_APPLICATION]: true
|
||||||
},
|
},
|
||||||
suggestions: {},
|
suggestions: {},
|
||||||
urisByQuery: {}
|
urisByQuery: {},
|
||||||
|
resolvedResultsByQuery: {},
|
||||||
|
resolvedResultsByQueryLastPageReached: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchReducer = handleActions({
|
const searchReducer = handleActions({
|
||||||
|
@ -5044,6 +5137,35 @@ const searchReducer = handleActions({
|
||||||
searching: false
|
searching: false
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
[RESOLVED_SEARCH_START]: state => _extends$d({}, state, {
|
||||||
|
searching: true
|
||||||
|
}),
|
||||||
|
[RESOLVED_SEARCH_SUCCESS]: (state, action) => {
|
||||||
|
const resolvedResultsByQuery = Object.assign({}, state.resolvedResultsByQuery);
|
||||||
|
const resolvedResultsByQueryLastPageReached = Object.assign({}, state.resolvedResultsByQueryLastPageReached);
|
||||||
|
const { append, query, results, pageSize } = action.data;
|
||||||
|
|
||||||
|
if (append) {
|
||||||
|
// todo: check for duplicates when concatenating?
|
||||||
|
resolvedResultsByQuery[query] = resolvedResultsByQuery[query] && resolvedResultsByQuery[query].length ? resolvedResultsByQuery[query].concat(results) : results;
|
||||||
|
} else {
|
||||||
|
resolvedResultsByQuery[query] = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the returned number of urls is less than the page size, so we're on the last page
|
||||||
|
resolvedResultsByQueryLastPageReached[query] = results.length < pageSize;
|
||||||
|
|
||||||
|
return _extends$d({}, state, {
|
||||||
|
searching: false,
|
||||||
|
resolvedResultsByQuery,
|
||||||
|
resolvedResultsByQueryLastPageReached
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
[RESOLVED_SEARCH_FAIL]: state => _extends$d({}, state, {
|
||||||
|
searching: false
|
||||||
|
}),
|
||||||
|
|
||||||
[UPDATE_SEARCH_QUERY]: (state, action) => _extends$d({}, state, {
|
[UPDATE_SEARCH_QUERY]: (state, action) => _extends$d({}, state, {
|
||||||
searchQuery: action.data.query,
|
searchQuery: action.data.query,
|
||||||
isActive: true
|
isActive: true
|
||||||
|
@ -5612,6 +5734,7 @@ exports.doPurchaseUri = doPurchaseUri;
|
||||||
exports.doResetThumbnailStatus = doResetThumbnailStatus;
|
exports.doResetThumbnailStatus = doResetThumbnailStatus;
|
||||||
exports.doResolveUri = doResolveUri;
|
exports.doResolveUri = doResolveUri;
|
||||||
exports.doResolveUris = doResolveUris;
|
exports.doResolveUris = doResolveUris;
|
||||||
|
exports.doResolvedSearch = doResolvedSearch;
|
||||||
exports.doSearch = doSearch;
|
exports.doSearch = doSearch;
|
||||||
exports.doSendDraftTransaction = doSendDraftTransaction;
|
exports.doSendDraftTransaction = doSendDraftTransaction;
|
||||||
exports.doSendTip = doSendTip;
|
exports.doSendTip = doSendTip;
|
||||||
|
@ -5680,6 +5803,9 @@ exports.makeSelectPermanentUrlForUri = makeSelectPermanentUrlForUri;
|
||||||
exports.makeSelectPublishFormValue = makeSelectPublishFormValue;
|
exports.makeSelectPublishFormValue = makeSelectPublishFormValue;
|
||||||
exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions;
|
exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions;
|
||||||
exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri;
|
exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri;
|
||||||
|
exports.makeSelectResolvedRecommendedContentForUri = makeSelectResolvedRecommendedContentForUri;
|
||||||
|
exports.makeSelectResolvedSearchResults = makeSelectResolvedSearchResults;
|
||||||
|
exports.makeSelectResolvedSearchResultsLastPageReached = makeSelectResolvedSearchResultsLastPageReached;
|
||||||
exports.makeSelectSearchDownloadUrlsCount = makeSelectSearchDownloadUrlsCount;
|
exports.makeSelectSearchDownloadUrlsCount = makeSelectSearchDownloadUrlsCount;
|
||||||
exports.makeSelectSearchDownloadUrlsForPage = makeSelectSearchDownloadUrlsForPage;
|
exports.makeSelectSearchDownloadUrlsForPage = makeSelectSearchDownloadUrlsForPage;
|
||||||
exports.makeSelectSearchUris = makeSelectSearchUris;
|
exports.makeSelectSearchUris = makeSelectSearchUris;
|
||||||
|
@ -5772,6 +5898,8 @@ exports.selectPurchasedUris = selectPurchasedUris;
|
||||||
exports.selectReceiveAddress = selectReceiveAddress;
|
exports.selectReceiveAddress = selectReceiveAddress;
|
||||||
exports.selectRecentTransactions = selectRecentTransactions;
|
exports.selectRecentTransactions = selectRecentTransactions;
|
||||||
exports.selectReservedBalance = selectReservedBalance;
|
exports.selectReservedBalance = selectReservedBalance;
|
||||||
|
exports.selectResolvedSearchResultsByQuery = selectResolvedSearchResultsByQuery;
|
||||||
|
exports.selectResolvedSearchResultsByQueryLastPageReached = selectResolvedSearchResultsByQueryLastPageReached;
|
||||||
exports.selectResolvingUris = selectResolvingUris;
|
exports.selectResolvingUris = selectResolvingUris;
|
||||||
exports.selectSearchBarFocused = selectSearchBarFocused;
|
exports.selectSearchBarFocused = selectSearchBarFocused;
|
||||||
exports.selectSearchOptions = selectSearchOptions;
|
exports.selectSearchOptions = selectSearchOptions;
|
||||||
|
|
25
dist/flow-typed/Search.js
vendored
25
dist/flow-typed/Search.js
vendored
|
@ -28,6 +28,8 @@ declare type SearchState = {
|
||||||
options: SearchOptions,
|
options: SearchOptions,
|
||||||
suggestions: { [string]: Array<SearchSuggestion> },
|
suggestions: { [string]: Array<SearchSuggestion> },
|
||||||
urisByQuery: {},
|
urisByQuery: {},
|
||||||
|
resolvedResultsByQuery: {},
|
||||||
|
resolvedResultsByQueryLastPageReached: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type SearchSuccess = {
|
declare type SearchSuccess = {
|
||||||
|
@ -57,3 +59,26 @@ declare type UpdateSearchOptions = {
|
||||||
type: ACTIONS.UPDATE_SEARCH_OPTIONS,
|
type: ACTIONS.UPDATE_SEARCH_OPTIONS,
|
||||||
data: SearchOptions,
|
data: SearchOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare type ResolvedSearchResult = {
|
||||||
|
channel: string,
|
||||||
|
channel_claim_id: string,
|
||||||
|
claimId: string,
|
||||||
|
duration: number,
|
||||||
|
fee: number,
|
||||||
|
name: string,
|
||||||
|
nsfw: boolean,
|
||||||
|
release_time: string,
|
||||||
|
thumbnail_url: string,
|
||||||
|
title: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type ResolvedSearchSuccess = {
|
||||||
|
type: ACTIONS.RESOLVED_SEARCH_SUCCESS,
|
||||||
|
data: {
|
||||||
|
append: boolean,
|
||||||
|
pageSize: number,
|
||||||
|
results: Array<ResolvedSearchResult>,
|
||||||
|
query: string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
25
flow-typed/Search.js
vendored
25
flow-typed/Search.js
vendored
|
@ -28,6 +28,8 @@ declare type SearchState = {
|
||||||
options: SearchOptions,
|
options: SearchOptions,
|
||||||
suggestions: { [string]: Array<SearchSuggestion> },
|
suggestions: { [string]: Array<SearchSuggestion> },
|
||||||
urisByQuery: {},
|
urisByQuery: {},
|
||||||
|
resolvedResultsByQuery: {},
|
||||||
|
resolvedResultsByQueryLastPageReached: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type SearchSuccess = {
|
declare type SearchSuccess = {
|
||||||
|
@ -57,3 +59,26 @@ declare type UpdateSearchOptions = {
|
||||||
type: ACTIONS.UPDATE_SEARCH_OPTIONS,
|
type: ACTIONS.UPDATE_SEARCH_OPTIONS,
|
||||||
data: SearchOptions,
|
data: SearchOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare type ResolvedSearchResult = {
|
||||||
|
channel: string,
|
||||||
|
channel_claim_id: string,
|
||||||
|
claimId: string,
|
||||||
|
duration: number,
|
||||||
|
fee: number,
|
||||||
|
name: string,
|
||||||
|
nsfw: boolean,
|
||||||
|
release_time: string,
|
||||||
|
thumbnail_url: string,
|
||||||
|
title: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type ResolvedSearchSuccess = {
|
||||||
|
type: ACTIONS.RESOLVED_SEARCH_SUCCESS,
|
||||||
|
data: {
|
||||||
|
append: boolean,
|
||||||
|
pageSize: number,
|
||||||
|
results: Array<ResolvedSearchResult>,
|
||||||
|
query: string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -139,6 +139,9 @@ export const DELETE_PURCHASED_URI = 'DELETE_PURCHASED_URI';
|
||||||
export const SEARCH_START = 'SEARCH_START';
|
export const SEARCH_START = 'SEARCH_START';
|
||||||
export const SEARCH_SUCCESS = 'SEARCH_SUCCESS';
|
export const SEARCH_SUCCESS = 'SEARCH_SUCCESS';
|
||||||
export const SEARCH_FAIL = 'SEARCH_FAIL';
|
export const SEARCH_FAIL = 'SEARCH_FAIL';
|
||||||
|
export const RESOLVED_SEARCH_START = 'RESOLVED_SEARCH_START';
|
||||||
|
export const RESOLVED_SEARCH_SUCCESS = 'RESOLVED_SEARCH_SUCCESS';
|
||||||
|
export const RESOLVED_SEARCH_FAIL = 'RESOLVED_SEARCH_FAIL';
|
||||||
export const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY';
|
export const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY';
|
||||||
export const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS';
|
export const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS';
|
||||||
export const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS';
|
export const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS';
|
||||||
|
|
|
@ -510,5 +510,5 @@ export const DEFAULT_KNOWN_TAGS = [
|
||||||
'portugal',
|
'portugal',
|
||||||
'dantdm',
|
'dantdm',
|
||||||
'teaser',
|
'teaser',
|
||||||
'lbry'
|
'lbry',
|
||||||
];
|
];
|
||||||
|
|
|
@ -90,6 +90,7 @@ export {
|
||||||
|
|
||||||
export {
|
export {
|
||||||
doSearch,
|
doSearch,
|
||||||
|
doResolvedSearch,
|
||||||
doUpdateSearchQuery,
|
doUpdateSearchQuery,
|
||||||
doFocusSearchInput,
|
doFocusSearchInput,
|
||||||
doBlurSearchInput,
|
doBlurSearchInput,
|
||||||
|
@ -183,6 +184,7 @@ export {
|
||||||
makeSelectOmittedCountForChannel,
|
makeSelectOmittedCountForChannel,
|
||||||
makeSelectClaimIsNsfw,
|
makeSelectClaimIsNsfw,
|
||||||
makeSelectRecommendedContentForUri,
|
makeSelectRecommendedContentForUri,
|
||||||
|
makeSelectResolvedRecommendedContentForUri,
|
||||||
makeSelectFirstRecommendedFileForUri,
|
makeSelectFirstRecommendedFileForUri,
|
||||||
makeSelectChannelForClaimUri,
|
makeSelectChannelForClaimUri,
|
||||||
makeSelectClaimIsPending,
|
makeSelectClaimIsPending,
|
||||||
|
@ -265,9 +267,13 @@ export {
|
||||||
export { selectSearchState };
|
export { selectSearchState };
|
||||||
export {
|
export {
|
||||||
makeSelectSearchUris,
|
makeSelectSearchUris,
|
||||||
|
makeSelectResolvedSearchResults,
|
||||||
|
makeSelectResolvedSearchResultsLastPageReached,
|
||||||
selectSearchValue,
|
selectSearchValue,
|
||||||
selectSearchOptions,
|
selectSearchOptions,
|
||||||
selectIsSearching,
|
selectIsSearching,
|
||||||
|
selectResolvedSearchResultsByQuery,
|
||||||
|
selectResolvedSearchResultsByQueryLastPageReached,
|
||||||
selectSearchUrisByQuery,
|
selectSearchUrisByQuery,
|
||||||
selectSearchBarFocused,
|
selectSearchBarFocused,
|
||||||
selectSearchSuggestions,
|
selectSearchSuggestions,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { buildURI } from 'lbryURI';
|
||||||
import { doResolveUri } from 'redux/actions/claims';
|
import { doResolveUri } from 'redux/actions/claims';
|
||||||
import {
|
import {
|
||||||
makeSelectSearchUris,
|
makeSelectSearchUris,
|
||||||
|
makeSelectResolvedSearchResults,
|
||||||
selectSuggestions,
|
selectSuggestions,
|
||||||
makeSelectQueryWithOptions,
|
makeSelectQueryWithOptions,
|
||||||
selectSearchValue,
|
selectSearchValue,
|
||||||
|
@ -159,6 +160,77 @@ export const doSearch = (
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const doResolvedSearch = (
|
||||||
|
rawQuery: string,
|
||||||
|
size: ?number, // only pass in if you don't want to use the users setting (ex: related content)
|
||||||
|
from: ?number,
|
||||||
|
isBackgroundSearch: boolean = false,
|
||||||
|
options: {
|
||||||
|
related_to?: string,
|
||||||
|
} = {}
|
||||||
|
) => (dispatch: Dispatch, getState: GetState) => {
|
||||||
|
const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' ');
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.RESOLVED_SEARCH_FAIL,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = getState();
|
||||||
|
let queryWithOptions = makeSelectQueryWithOptions(query, size, from, isBackgroundSearch, options)(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
|
||||||
|
// make from null so that we can maintain a reference to the same query for multiple pages and simply append the found results
|
||||||
|
let queryWithoutFrom = makeSelectQueryWithOptions(query, size, null, isBackgroundSearch, options)(
|
||||||
|
state
|
||||||
|
);
|
||||||
|
|
||||||
|
// If we have already searched for something, we don't need to do anything
|
||||||
|
// TODO: Tweak this check for multiple page results
|
||||||
|
/* const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state);
|
||||||
|
if (resultsForQuery && resultsForQuery.length && resultsForQuery.length > (from * size)) {
|
||||||
|
return;
|
||||||
|
} */
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.RESOLVED_SEARCH_START,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!state.search.searchQuery && !isBackgroundSearch) {
|
||||||
|
dispatch(doUpdateSearchQuery(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`${CONNECTION_STRING}search?resolve=true&${queryWithOptions}`)
|
||||||
|
.then(handleFetchResponse)
|
||||||
|
.then((data: Array<ResolvedSearchResult>) => {
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
data.forEach(result => {
|
||||||
|
if (result) {
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.RESOLVED_SEARCH_SUCCESS,
|
||||||
|
data: {
|
||||||
|
query: queryWithoutFrom,
|
||||||
|
results,
|
||||||
|
pageSize: size,
|
||||||
|
append: parseInt(from, 10) > parseInt(size, 10) - 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.RESOLVED_SEARCH_FAIL,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const doFocusSearchInput = () => (dispatch: Dispatch) =>
|
export const doFocusSearchInput = () => (dispatch: Dispatch) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.SEARCH_FOCUS,
|
type: ACTIONS.SEARCH_FOCUS,
|
||||||
|
|
|
@ -18,6 +18,8 @@ const defaultState = {
|
||||||
},
|
},
|
||||||
suggestions: {},
|
suggestions: {},
|
||||||
urisByQuery: {},
|
urisByQuery: {},
|
||||||
|
resolvedResultsByQuery: {},
|
||||||
|
resolvedResultsByQueryLastPageReached: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const searchReducer = handleActions(
|
export const searchReducer = handleActions(
|
||||||
|
@ -41,6 +43,47 @@ export const searchReducer = handleActions(
|
||||||
searching: false,
|
searching: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
[ACTIONS.RESOLVED_SEARCH_START]: (state: SearchState): SearchState => ({
|
||||||
|
...state,
|
||||||
|
searching: true,
|
||||||
|
}),
|
||||||
|
[ACTIONS.RESOLVED_SEARCH_SUCCESS]: (
|
||||||
|
state: SearchState,
|
||||||
|
action: ResolvedSearchSuccess
|
||||||
|
): SearchState => {
|
||||||
|
const resolvedResultsByQuery = Object.assign({}, state.resolvedResultsByQuery);
|
||||||
|
const resolvedResultsByQueryLastPageReached = Object.assign(
|
||||||
|
{},
|
||||||
|
state.resolvedResultsByQueryLastPageReached
|
||||||
|
);
|
||||||
|
const { append, query, results, pageSize } = action.data;
|
||||||
|
|
||||||
|
if (append) {
|
||||||
|
// todo: check for duplicates when concatenating?
|
||||||
|
resolvedResultsByQuery[query] =
|
||||||
|
resolvedResultsByQuery[query] && resolvedResultsByQuery[query].length
|
||||||
|
? resolvedResultsByQuery[query].concat(results)
|
||||||
|
: results;
|
||||||
|
} else {
|
||||||
|
resolvedResultsByQuery[query] = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the returned number of urls is less than the page size, so we're on the last page
|
||||||
|
resolvedResultsByQueryLastPageReached[query] = results.length < pageSize;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
searching: false,
|
||||||
|
resolvedResultsByQuery,
|
||||||
|
resolvedResultsByQueryLastPageReached,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
[ACTIONS.RESOLVED_SEARCH_FAIL]: (state: SearchState): SearchState => ({
|
||||||
|
...state,
|
||||||
|
searching: false,
|
||||||
|
}),
|
||||||
|
|
||||||
[ACTIONS.UPDATE_SEARCH_QUERY]: (
|
[ACTIONS.UPDATE_SEARCH_QUERY]: (
|
||||||
state: SearchState,
|
state: SearchState,
|
||||||
action: UpdateSearchQuery
|
action: UpdateSearchQuery
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { normalizeURI, buildURI, parseURI } from 'lbryURI';
|
import { normalizeURI, buildURI, parseURI } from 'lbryURI';
|
||||||
import { selectSearchUrisByQuery } from 'redux/selectors/search';
|
import {
|
||||||
|
selectResolvedSearchResultsByQuery,
|
||||||
|
selectSearchUrisByQuery,
|
||||||
|
} from 'redux/selectors/search';
|
||||||
import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
|
import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { isClaimNsfw, createNormalizedClaimSearchKey } from 'util/claim';
|
import { isClaimNsfw, createNormalizedClaimSearchKey } from 'util/claim';
|
||||||
|
@ -639,3 +642,39 @@ export const selectMyStreamUrlsCount = createSelector(
|
||||||
selectMyClaimUrisWithoutChannels,
|
selectMyClaimUrisWithoutChannels,
|
||||||
channels => channels.length
|
channels => channels.length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const makeSelectResolvedRecommendedContentForUri = (uri: string, size: number) =>
|
||||||
|
createSelector(
|
||||||
|
makeSelectClaimForUri(uri),
|
||||||
|
selectResolvedSearchResultsByQuery,
|
||||||
|
(claim, resolvedResultsByQuery) => {
|
||||||
|
const atVanityURI = !uri.includes('#');
|
||||||
|
|
||||||
|
let recommendedContent;
|
||||||
|
if (claim) {
|
||||||
|
// always grab full URL - this can change once search returns canonical
|
||||||
|
const currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name });
|
||||||
|
|
||||||
|
const { title } = claim.value;
|
||||||
|
|
||||||
|
if (!title) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchQuery = getSearchQueryString(title.replace(/\//, ' '), { size }, undefined, {
|
||||||
|
related_to: claim.claim_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
let results = resolvedResultsByQuery[searchQuery];
|
||||||
|
if (results) {
|
||||||
|
results = results.filter(
|
||||||
|
result =>
|
||||||
|
buildURI({ streamClaimId: result.claimId, streamName: result.name }) !== currentUri
|
||||||
|
);
|
||||||
|
recommendedContent = results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recommendedContent;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -44,6 +44,38 @@ export const makeSelectSearchUris = (query: string): ((state: State) => Array<st
|
||||||
byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]
|
byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectResolvedSearchResultsByQuery: (
|
||||||
|
state: State
|
||||||
|
) => { [string]: Array<ResolvedSearchResult> } = createSelector(
|
||||||
|
selectState,
|
||||||
|
state => state.resolvedResultsByQuery
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectResolvedSearchResultsByQueryLastPageReached: (
|
||||||
|
state: State
|
||||||
|
) => { [string]: Array<boolean> } = createSelector(
|
||||||
|
selectState,
|
||||||
|
state => state.resolvedResultsByQueryLastPageReached
|
||||||
|
);
|
||||||
|
|
||||||
|
export const makeSelectResolvedSearchResults = (
|
||||||
|
query: string
|
||||||
|
): ((state: State) => Array<ResolvedSearchResult>) =>
|
||||||
|
// replace statement below is kind of ugly, and repeated in doSearch action
|
||||||
|
createSelector(
|
||||||
|
selectResolvedSearchResultsByQuery,
|
||||||
|
byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const makeSelectResolvedSearchResultsLastPageReached = (
|
||||||
|
query: string
|
||||||
|
): ((state: State) => boolean) =>
|
||||||
|
// replace statement below is kind of ugly, and repeated in doSearch action
|
||||||
|
createSelector(
|
||||||
|
selectResolvedSearchResultsByQueryLastPageReached,
|
||||||
|
byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]
|
||||||
|
);
|
||||||
|
|
||||||
export const selectSearchBarFocused: boolean = createSelector(
|
export const selectSearchBarFocused: boolean = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.focused
|
state => state.focused
|
||||||
|
|
Loading…
Reference in a new issue