send recsys powered-by #6875
6 changed files with 62 additions and 19 deletions
3
flow-typed/search.js
vendored
3
flow-typed/search.js
vendored
|
@ -28,7 +28,7 @@ declare type SearchOptions = {
|
||||||
|
|
||||||
declare type SearchState = {
|
declare type SearchState = {
|
||||||
options: SearchOptions,
|
options: SearchOptions,
|
||||||
urisByQuery: {},
|
resultsByQuery: {},
|
||||||
hasReachedMaxResultsLength: {},
|
hasReachedMaxResultsLength: {},
|
||||||
searching: boolean,
|
searching: boolean,
|
||||||
};
|
};
|
||||||
|
@ -40,6 +40,7 @@ declare type SearchSuccess = {
|
||||||
from: number,
|
from: number,
|
||||||
size: number,
|
size: number,
|
||||||
uris: Array<string>,
|
uris: Array<string>,
|
||||||
|
recsys: string,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
makeSelectRecommendedClaimIds,
|
makeSelectRecommendedClaimIds,
|
||||||
makeSelectRecommendationClicks,
|
makeSelectRecommendationClicks,
|
||||||
} from 'redux/selectors/content';
|
} from 'redux/selectors/content';
|
||||||
|
import { makeSelectRecommendedRecsysIdForClaimId } from 'redux/selectors/search';
|
||||||
|
|
||||||
const VERSION = '0.0.1';
|
const VERSION = '0.0.1';
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ function createRecsys(claimId, userId, events, loadedAt, isEmbed) {
|
||||||
claimId: claimId,
|
claimId: claimId,
|
||||||
pageLoadedAt: pageLoadedAt,
|
pageLoadedAt: pageLoadedAt,
|
||||||
pageExitedAt: pageExitedAt,
|
pageExitedAt: pageExitedAt,
|
||||||
recsysId: recsysId,
|
recsysId: makeSelectRecommendedRecsysIdForClaimId(claimId)(state) || recsysId,
|
||||||
recClaimIds: makeSelectRecommendedClaimIds(claimId)(state),
|
recClaimIds: makeSelectRecommendedClaimIds(claimId)(state),
|
||||||
recClickedVideoIdx: makeSelectRecommendationClicks(claimId)(state),
|
recClickedVideoIdx: makeSelectRecommendationClicks(claimId)(state),
|
||||||
events: events,
|
events: events,
|
||||||
|
|
|
@ -61,13 +61,14 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => (
|
||||||
|
|
||||||
lighthouse
|
lighthouse
|
||||||
.search(queryWithOptions)
|
.search(queryWithOptions)
|
||||||
.then((data: Array<{ name: string, claimId: string }>) => {
|
.then((data: { body: Array<{ name: string, claimId: string }>, poweredBy: string }) => {
|
||||||
|
const { body: result, poweredBy } = data;
|
||||||
const uris = [];
|
const uris = [];
|
||||||
const actions = [];
|
const actions = [];
|
||||||
|
|
||||||
data.forEach((result) => {
|
result.forEach((item) => {
|
||||||
if (result) {
|
if (item) {
|
||||||
const { name, claimId } = result;
|
const { name, claimId } = item;
|
||||||
const urlObj: LbryUrlObj = {};
|
const urlObj: LbryUrlObj = {};
|
||||||
|
|
||||||
if (name.startsWith('@')) {
|
if (name.startsWith('@')) {
|
||||||
|
@ -94,6 +95,7 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => (
|
||||||
from: from,
|
from: from,
|
||||||
size: size,
|
size: size,
|
||||||
uris,
|
uris,
|
||||||
|
recsys: poweredBy,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dispatch(batchActions(...actions));
|
dispatch(batchActions(...actions));
|
||||||
|
|
|
@ -17,7 +17,7 @@ const defaultState: SearchState = {
|
||||||
[SEARCH_OPTIONS.MEDIA_IMAGE]: defaultSearchTypes.includes(SEARCH_OPTIONS.MEDIA_IMAGE),
|
[SEARCH_OPTIONS.MEDIA_IMAGE]: defaultSearchTypes.includes(SEARCH_OPTIONS.MEDIA_IMAGE),
|
||||||
[SEARCH_OPTIONS.MEDIA_APPLICATION]: defaultSearchTypes.includes(SEARCH_OPTIONS.MEDIA_APPLICATION),
|
[SEARCH_OPTIONS.MEDIA_APPLICATION]: defaultSearchTypes.includes(SEARCH_OPTIONS.MEDIA_APPLICATION),
|
||||||
},
|
},
|
||||||
urisByQuery: {},
|
resultsByQuery: {},
|
||||||
hasReachedMaxResultsLength: {},
|
hasReachedMaxResultsLength: {},
|
||||||
searching: false,
|
searching: false,
|
||||||
};
|
};
|
||||||
|
@ -29,21 +29,23 @@ export default handleActions(
|
||||||
searching: true,
|
searching: true,
|
||||||
}),
|
}),
|
||||||
[ACTIONS.SEARCH_SUCCESS]: (state: SearchState, action: SearchSuccess): SearchState => {
|
[ACTIONS.SEARCH_SUCCESS]: (state: SearchState, action: SearchSuccess): SearchState => {
|
||||||
const { query, uris, from, size } = action.data;
|
const { query, uris, from, size, recsys } = action.data;
|
||||||
const normalizedQuery = createNormalizedSearchKey(query);
|
const normalizedQuery = createNormalizedSearchKey(query);
|
||||||
|
const urisForQuery = state.resultsByQuery[normalizedQuery] && state.resultsByQuery[normalizedQuery]['uris'];
|
||||||
|
|
||||||
let newUris = uris;
|
let newUris = uris;
|
||||||
if (from !== 0 && state.urisByQuery[normalizedQuery]) {
|
if (from !== 0 && urisForQuery) {
|
||||||
newUris = Array.from(new Set(state.urisByQuery[normalizedQuery].concat(uris)));
|
newUris = Array.from(new Set(urisForQuery.concat(uris)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The returned number of urls is less than the page size, so we're on the last page
|
// The returned number of urls is less than the page size, so we're on the last page
|
||||||
const noMoreResults = size && uris.length < size;
|
const noMoreResults = size && uris.length < size;
|
||||||
|
|
||||||
|
const results = { uris: newUris, recsys };
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
searching: false,
|
searching: false,
|
||||||
urisByQuery: Object.assign({}, state.urisByQuery, { [normalizedQuery]: newUris }),
|
resultsByQuery: Object.assign({}, state.resultsByQuery, { [normalizedQuery]: results }),
|
||||||
hasReachedMaxResultsLength: Object.assign({}, state.hasReachedMaxResultsLength, {
|
hasReachedMaxResultsLength: Object.assign({}, state.hasReachedMaxResultsLength, {
|
||||||
[normalizedQuery]: noMoreResults,
|
[normalizedQuery]: noMoreResults,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { selectShowMatureContent } from 'redux/selectors/settings';
|
||||||
import {
|
import {
|
||||||
parseURI,
|
parseURI,
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
|
makeSelectClaimForClaimId,
|
||||||
makeSelectClaimIsNsfw,
|
makeSelectClaimIsNsfw,
|
||||||
buildURI,
|
buildURI,
|
||||||
isClaimNsfw,
|
isClaimNsfw,
|
||||||
|
@ -28,7 +29,7 @@ export const selectIsSearching: (state: State) => boolean = createSelector(selec
|
||||||
|
|
||||||
export const selectSearchUrisByQuery: (state: State) => { [string]: Array<string> } = createSelector(
|
export const selectSearchUrisByQuery: (state: State) => { [string]: Array<string> } = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
(state) => state.urisByQuery
|
(state) => state.resultsByQuery
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectHasReachedMaxResultsLength: (state: State) => { [boolean]: Array<boolean> } = createSelector(
|
export const selectHasReachedMaxResultsLength: (state: State) => { [boolean]: Array<boolean> } = createSelector(
|
||||||
|
@ -42,9 +43,9 @@ export const makeSelectSearchUris = (query: string): ((state: State) => Array<st
|
||||||
if (query) {
|
if (query) {
|
||||||
query = query.replace(/^lbry:\/\//i, '').replace(/\//, ' ');
|
query = query.replace(/^lbry:\/\//i, '').replace(/\//, ' ');
|
||||||
const normalizedQuery = createNormalizedSearchKey(query);
|
const normalizedQuery = createNormalizedSearchKey(query);
|
||||||
return byQuery[normalizedQuery];
|
return byQuery[normalizedQuery] && byQuery[normalizedQuery]['uris'];
|
||||||
}
|
}
|
||||||
return byQuery[query];
|
return byQuery[query] && byQuery[query]['uris'];
|
||||||
});
|
});
|
||||||
|
|
||||||
export const makeSelectHasReachedMaxResultsLength = (query: string): ((state: State) => boolean) =>
|
export const makeSelectHasReachedMaxResultsLength = (query: string): ((state: State) => boolean) =>
|
||||||
|
@ -84,16 +85,47 @@ export const makeSelectRecommendedContentForUri = (uri: string) =>
|
||||||
const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options);
|
const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options);
|
||||||
const normalizedSearchQuery = createNormalizedSearchKey(searchQuery);
|
const normalizedSearchQuery = createNormalizedSearchKey(searchQuery);
|
||||||
|
|
||||||
let searchUris = searchUrisByQuery[normalizedSearchQuery];
|
let searchResult = searchUrisByQuery[normalizedSearchQuery];
|
||||||
if (searchUris) {
|
if (searchResult) {
|
||||||
searchUris = searchUris.filter((searchUri) => searchUri !== currentUri);
|
recommendedContent = searchResult['uris'].filter((searchUri) => searchUri !== currentUri);
|
||||||
recommendedContent = searchUris;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return recommendedContent;
|
return recommendedContent;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const makeSelectRecommendedRecsysIdForClaimId = (claimId: string) =>
|
||||||
|
createSelector(makeSelectClaimForClaimId(claimId), selectSearchUrisByQuery, (claim, searchUrisByQuery) => {
|
||||||
|
// TODO: DRY this out.
|
||||||
|
let poweredBy;
|
||||||
|
if (claim) {
|
||||||
|
const isMature = isClaimNsfw(claim);
|
||||||
|
const { title } = claim.value;
|
||||||
|
|
||||||
|
if (!title) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: {
|
||||||
|
related_to?: string,
|
||||||
|
nsfw?: boolean,
|
||||||
|
isBackgroundSearch?: boolean,
|
||||||
|
} = { related_to: claim.claim_id, isBackgroundSearch: true };
|
||||||
|
|
||||||
|
options['nsfw'] = isMature;
|
||||||
|
const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options);
|
||||||
|
const normalizedSearchQuery = createNormalizedSearchKey(searchQuery);
|
||||||
|
|
||||||
|
let searchResult = searchUrisByQuery[normalizedSearchQuery];
|
||||||
|
if (searchResult) {
|
||||||
|
poweredBy = searchResult.recsys;
|
||||||
|
} else {
|
||||||
|
return normalizedSearchQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return poweredBy;
|
||||||
|
});
|
||||||
|
|
||||||
export const makeSelectWinningUriForQuery = (query: string) => {
|
export const makeSelectWinningUriForQuery = (query: string) => {
|
||||||
const uriFromQuery = `lbry://${query}`;
|
const uriFromQuery = `lbry://${query}`;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
export default function handleFetchResponse(response: Response): Promise<any> {
|
export default function handleFetchResponse(response: Response): Promise<any> {
|
||||||
return response.status === 200 ? Promise.resolve(response.json()) : Promise.reject(new Error(response.statusText));
|
const headers = response.headers;
|
||||||
|
const poweredBy = headers.get('x-powered-by');
|
||||||
|
|
||||||
|
return response.status === 200
|
||||||
|
? response.json().then((body) => ({ body, poweredBy }))
|
||||||
|
: Promise.reject(new Error(response.statusText));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue