In-memory search results cache

- Switching between type and provider now negates need for repeat queries
- Mopidy caching varies, so for some providers this has a huge performance gain (eg YouTube)
- Spotify will requery anyway, but the browser handles query caching
This commit is contained in:
James Barnsley
2023-10-10 20:33:51 +13:00
parent bec0cf95e3
commit 8dfd585a3f
5 changed files with 27 additions and 21 deletions

View File

@ -197,12 +197,12 @@ const CoreMiddleware = (function () {
// Trigger reducer immediately; this will hose out any previous results // Trigger reducer immediately; this will hose out any previous results
next(action); next(action);
if (providers.includes('spotify:')) { if (providers.includes('spotify')) {
store.dispatch(spotifyActions.getSearchResults(query)); store.dispatch(spotifyActions.getSearchResults(query));
} }
store.dispatch(mopidyActions.getSearchResults( store.dispatch(mopidyActions.getSearchResults(
query, query,
providers.filter((i) => i !== 'spotify:'), // Omit Spotify; handled above providers.filter((i) => i !== 'spotify'), // Omit Spotify; handled above
)); ));
break; break;
} }

View File

@ -32,6 +32,7 @@ import {
indexToArray, indexToArray,
} from '../../util/arrays'; } from '../../util/arrays';
import { getProvider, getSortSelector } from '../../util/selectors'; import { getProvider, getSortSelector } from '../../util/selectors';
import { iterate } from 'localforage';
const mopidyActions = require('./actions.js'); const mopidyActions = require('./actions.js');
const coreActions = require('../core/actions.js'); const coreActions = require('../core/actions.js');
@ -268,22 +269,28 @@ const MopidyMiddleware = (function () {
method = 'library.search', method = 'library.search',
data, data,
} = queue.shift(); } = queue.shift();
const resultKey = getSearchResultKey({ provider, type, term });
const processKey = 'MOPIDY_GET_SEARCH_RESULTS'; const processKey = 'MOPIDY_GET_SEARCH_RESULTS';
const processor = store.getState().ui.processes[processKey]; const processor = store.getState().ui.processes[processKey];
if (processor && processor.status === 'cancelling') { if (processor && processor.status === 'cancelling') {
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS')); store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS'));
return; return;
} }
const iterateNext = (store, queue) => {
if (queue.length) {
processSearchQueue(store, queue);
} else {
store.dispatch(uiActions.processFinished(processKey));
}
}
store.dispatch(uiActions.updateProcess( store.dispatch(uiActions.updateProcess(
processKey, processKey,
{ {
content: i18n( content: i18n(
'services.mopidy.searching', 'services.mopidy.searching',
{ {
provider: titleCase(provider.replace(':', '')), provider: titleCase(provider),
type: requestType, type: requestType,
}, },
), ),
@ -291,6 +298,12 @@ const MopidyMiddleware = (function () {
}, },
)); ));
const resultKey = getSearchResultKey({ provider, type, term });
if (resultKey in store.getState().core.search_results) {
iterateNext(store, queue);
return;
}
// Each type has a different method of formatting and destructuring. // Each type has a different method of formatting and destructuring.
const processResults = { const processResults = {
albums: (response) => { albums: (response) => {
@ -377,12 +390,7 @@ const MopidyMiddleware = (function () {
processResults[requestType](response), processResults[requestType](response),
)); ));
} }
iterateNext(store, queue);
if (queue.length) {
processSearchQueue(store, queue);
} else {
store.dispatch(uiActions.processFinished(processKey));
}
}, },
); );
}; };
@ -1239,7 +1247,7 @@ const MopidyMiddleware = (function () {
provider, provider,
requestType: type, requestType: type,
data: { data: {
uris: [provider], uris: [`${provider}:`],
}, },
}; };
switch (type) { switch (type) {

View File

@ -603,8 +603,7 @@ const upgradeSpotifyPlaylistUri = function (uri) {
return upgradeSpotifyPlaylistUris([uri])[0]; return upgradeSpotifyPlaylistUris([uri])[0];
}; };
const getSearchResultKey = ({ provider, type, term }) => const getSearchResultKey = ({ provider, type, term }) => [provider, type, term].join(':');
[provider.replace(':', ''), type, term].join(':');
export { export {
debounce, debounce,

View File

@ -7,11 +7,13 @@ const useSearchQuery = () => {
type = 'all', type = 'all',
providers: rawProviders = 'all', providers: rawProviders = 'all',
} = useParams(); } = useParams();
const allProviders = useSelector((state) => state.mopidy?.uri_schemes || []); const allProviders = useSelector(
({ mopidy: { uri_schemes } }) => uri_schemes || []
).map((str) => str.replace(/:/g,''));
const providers = rawProviders == 'all' const providers = rawProviders == 'all'
? [...allProviders] ? [...allProviders]
: rawProviders.split(',').filter((str) => allProviders.indexOf(str) > -1); : rawProviders.split(',').filter((str) => allProviders.indexOf(str) > -1);
const providersString = providers.join(',').replace(/:/g,''); const providersString = providers.join(',');
return { return {
term, term,

View File

@ -34,16 +34,15 @@ const Search = () => {
useEffect(() => { useEffect(() => {
dispatch(setWindowTitle('Search')); dispatch(setWindowTitle('Search'));
$(document).find('.search-form input').focus(); $(document).find('.search-form input').trigger('focus');
}, []); }, []);
useEffect(() => { useEffect(() => {
if (term) { if (term) {
console.debug('STARTING SEARCH', { term, type, providers })
dispatch(setWindowTitle(i18n('search.title_window', { term: decodeURIComponent(term) }))); dispatch(setWindowTitle(i18n('search.title_window', { term: decodeURIComponent(term) })));
dispatch(startSearch({ term, type, providers })); dispatch(startSearch({ term, type, providers }));
} }
}, []) }, [providersString, type, term])
const onSubmit = (term) => { const onSubmit = (term) => {
updateSearchQuery(term, providers); updateSearchQuery(term, providers);
@ -57,8 +56,6 @@ const Search = () => {
const onReset = () => navigate('/search'); const onReset = () => navigate('/search');
const onProvidersChange = (providers) => { const onProvidersChange = (providers) => {
console.debug(providers)
// ON BLUR then trigger search event
updateSearchQuery(term, providers) updateSearchQuery(term, providers)
dispatch(hideContextMenu()); dispatch(hideContextMenu());
} }