Standardizing of search_results (overhaul of Mopidy search process, can improve other processes this way)
This commit is contained in:
@ -91,13 +91,21 @@ const SearchResults = ({
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const searchResultsSelector = makeSearchResultsSelector();
|
||||
const { query: { term }, type } = ownProps;
|
||||
const {
|
||||
ui: {
|
||||
uri_schemes_priority = [],
|
||||
search_results_sort: sort = 'name',
|
||||
search_results_sort_reverse: sort_reverse = false,
|
||||
},
|
||||
} = state;
|
||||
const searchResultsSelector = makeSearchResultsSelector(term, type);
|
||||
|
||||
return {
|
||||
uri_schemes_priority: state.ui.uri_schemes_priority || [],
|
||||
results: searchResultsSelector(state, ownProps),
|
||||
sort: state.ui.search_results_sort,
|
||||
sort_reverse: state.ui.search_results_sort_reverse,
|
||||
results: searchResultsSelector(state),
|
||||
uri_schemes_priority,
|
||||
sort,
|
||||
sort_reverse,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -116,6 +116,7 @@ services:
|
||||
title: Mopidy
|
||||
local: Local
|
||||
adding_uris: 'Adding %{count} URI(s)'
|
||||
searching: 'Searching %{provider} %{type}'
|
||||
searching_providers: 'Searching %{count} Mopidy providers'
|
||||
loading_albums: 'Loading %{count} local albums'
|
||||
spotify:
|
||||
|
||||
@ -5,15 +5,6 @@ import { uriSource } from '../../util/helpers';
|
||||
const spotifyActions = require('../../services/spotify/actions');
|
||||
const mopidyActions = require('../../services/mopidy/actions');
|
||||
|
||||
export function startSearch(search_type, query, only_mopidy = false) {
|
||||
return {
|
||||
type: 'SEARCH_STARTED',
|
||||
search_type,
|
||||
query,
|
||||
only_mopidy,
|
||||
};
|
||||
}
|
||||
|
||||
export function handleException(message, data = {}, description = null, show_notification = true) {
|
||||
if (!message) {
|
||||
if (data.message) {
|
||||
@ -92,6 +83,26 @@ export function updateColdStore(items) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Search results
|
||||
*/
|
||||
|
||||
export function startSearch(query) {
|
||||
return {
|
||||
type: 'START_SEARCH',
|
||||
query,
|
||||
};
|
||||
}
|
||||
|
||||
export function searchResultsLoaded(query, resultType, results) {
|
||||
return {
|
||||
type: 'SEARCH_RESULTS_LOADED',
|
||||
query,
|
||||
resultType,
|
||||
results,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record getters
|
||||
|
||||
@ -264,33 +264,89 @@ const CoreMiddleware = (function () {
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'SEARCH_STARTED':
|
||||
if (ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Search', action: 'Started', label: `${action.type}: ${action.query}` });
|
||||
case 'START_SEARCH': {
|
||||
const { query } = action;
|
||||
const {
|
||||
ui: {
|
||||
allow_reporting,
|
||||
uri_schemes_search_enabled = [],
|
||||
search_settings,
|
||||
},
|
||||
} = store.getState();
|
||||
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({
|
||||
category: 'Search',
|
||||
action: 'Started',
|
||||
label: `${query.type}: ${query.term}`,
|
||||
});
|
||||
}
|
||||
|
||||
console.info(`Searching for ${query.type} matching "${query.term}"`);
|
||||
|
||||
// Trigger reducer immediately; this will hose out any previous results
|
||||
next(action);
|
||||
|
||||
// backends that can handle more than just track results
|
||||
// make sure they are available and respect our settings
|
||||
const uri_schemes = ui.search_uri_schemes || mopidy.uri_schemes;
|
||||
const available_full_uri_schemes = ['local:', 'file:', 'gmusic:'];
|
||||
const full_uri_schemes = available_full_uri_schemes.filter(
|
||||
(full_uri_scheme) => uri_schemes.indexOf(full_uri_scheme) > -1
|
||||
);
|
||||
|
||||
// initiate spotify searching
|
||||
if (!action.only_mopidy) {
|
||||
if (!ui.search_settings || ui.search_settings.spotify) {
|
||||
store.dispatch(spotifyActions.getSearchResults(action.query));
|
||||
if (uri_schemes_search_enabled.includes('spotify:')) {
|
||||
if (!search_settings || search_settings.spotify) {
|
||||
store.dispatch(spotifyActions.getSearchResults(query));
|
||||
}
|
||||
}
|
||||
|
||||
// backend searching (mopidy)
|
||||
store.dispatch(
|
||||
mopidyActions.getSearchResults(action.search_type, action.query, 100, full_uri_schemes),
|
||||
);
|
||||
|
||||
store.dispatch(mopidyActions.getSearchResults(
|
||||
query,
|
||||
100,
|
||||
uri_schemes_search_enabled.filter((i) => i !== 'spotify:'), // Omit Spotify; handled above
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'SEARCH_RESULTS_LOADED': {
|
||||
const {
|
||||
query: {
|
||||
term,
|
||||
type,
|
||||
},
|
||||
resultType,
|
||||
results,
|
||||
} = action;
|
||||
const {
|
||||
core: {
|
||||
search_results: {
|
||||
query: {
|
||||
term: prevTerm,
|
||||
type: prevType,
|
||||
} = {},
|
||||
...allResults
|
||||
} = {},
|
||||
} = {},
|
||||
} = store.getState();
|
||||
|
||||
// Add to our existing results, so long as the search term is the same
|
||||
const search_results = {
|
||||
query: { term, type },
|
||||
...(term === prevTerm && type === prevType ? allResults : {}),
|
||||
};
|
||||
|
||||
console.log({
|
||||
term,
|
||||
type,
|
||||
prevTerm,
|
||||
prevType,
|
||||
allResults,
|
||||
});
|
||||
|
||||
// Merge our new results with the existing (if any)
|
||||
search_results[resultType] = [
|
||||
...(search_results[resultType] || []),
|
||||
...results,
|
||||
];
|
||||
|
||||
next({
|
||||
...action,
|
||||
search_results,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'RESTART':
|
||||
location.reload();
|
||||
|
||||
@ -167,9 +167,9 @@ export default function reducer(core = {}, action) {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Genres
|
||||
* */
|
||||
/**
|
||||
* Genres
|
||||
* */
|
||||
|
||||
case 'SPOTIFY_GENRES_LOADED':
|
||||
return { ...core, genres: action.genres };
|
||||
@ -183,92 +183,28 @@ export default function reducer(core = {}, action) {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Search results
|
||||
* */
|
||||
|
||||
case 'SEARCH_STARTED':
|
||||
/**
|
||||
* Search results
|
||||
* */
|
||||
case 'START_SEARCH':
|
||||
return {
|
||||
...core,
|
||||
search_results: {
|
||||
artists_uris: [],
|
||||
albums_uris: [],
|
||||
playlists_uris: [],
|
||||
query: action.query,
|
||||
artists: [],
|
||||
albums: [],
|
||||
playlists: [],
|
||||
tracks: [],
|
||||
},
|
||||
};
|
||||
|
||||
case 'SEARCH_RESULTS_LOADED':
|
||||
|
||||
// artists
|
||||
if (core.search_results && core.search_results.artists_uris) {
|
||||
var { artists_uris } = core.search_results;
|
||||
} else {
|
||||
var artists_uris = [];
|
||||
}
|
||||
if (action.artists_uris) artists_uris = [...artists_uris, ...action.artists_uris];
|
||||
|
||||
// more tracks
|
||||
if (typeof (action.artists_more) !== 'undefined') var { artists_more } = action;
|
||||
else if (core.search_results && core.search_results.artists_more) var { artists_more } = core.search_results;
|
||||
else var artists_more = null;
|
||||
|
||||
|
||||
// albums
|
||||
if (core.search_results && core.search_results.albums_uris) {
|
||||
var { albums_uris } = core.search_results;
|
||||
} else {
|
||||
var albums_uris = [];
|
||||
}
|
||||
if (action.albums_uris) albums_uris = [...albums_uris, ...action.albums_uris];
|
||||
|
||||
// more tracks
|
||||
if (typeof (action.albums_more) !== 'undefined') var { albums_more } = action;
|
||||
else if (core.search_results && core.search_results.albums_more) var { albums_more } = core.search_results;
|
||||
else var albums_more = null;
|
||||
|
||||
|
||||
// playlists
|
||||
if (core.search_results && core.search_results.playlists_uris) {
|
||||
var { playlists_uris } = core.search_results;
|
||||
} else {
|
||||
var playlists_uris = [];
|
||||
}
|
||||
if (action.playlists_uris) playlists_uris = [...playlists_uris, ...action.playlists_uris];
|
||||
|
||||
// more tracks
|
||||
if (typeof (action.playlists_more) !== 'undefined') var { playlists_more } = action;
|
||||
else if (core.search_results && core.search_results.playlists_more) var { playlists_more } = core.search_results;
|
||||
else var playlists_more = null;
|
||||
|
||||
|
||||
// tracks
|
||||
if (core.search_results && core.search_results.tracks) {
|
||||
var { tracks } = core.search_results;
|
||||
} else {
|
||||
var tracks = [];
|
||||
}
|
||||
if (action.tracks) tracks = [...tracks, ...formatTracks(action.tracks)];
|
||||
|
||||
// more tracks
|
||||
if (typeof (action.tracks_more) !== 'undefined') var { tracks_more } = action;
|
||||
else if (core.search_results && core.search_results.tracks_more) var { tracks_more } = core.search_results;
|
||||
else var tracks_more = null;
|
||||
|
||||
case 'SEARCH_RESULTS_LOADED': {
|
||||
const { search_results } = action;
|
||||
return {
|
||||
...core,
|
||||
search_results: {
|
||||
artists_more,
|
||||
artists_uris: removeDuplicates(artists_uris),
|
||||
albums_more,
|
||||
albums_uris: removeDuplicates(albums_uris),
|
||||
playlists_more,
|
||||
playlists_uris: removeDuplicates(playlists_uris),
|
||||
tracks,
|
||||
tracks_more,
|
||||
},
|
||||
search_results,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return core;
|
||||
|
||||
@ -546,11 +546,12 @@ export function clearSearchResults() {
|
||||
};
|
||||
}
|
||||
|
||||
export function getSearchResults(type, term, limit = 100) {
|
||||
export function getSearchResults(query, limit = 100, uri_schemes) {
|
||||
return {
|
||||
type: 'MOPIDY_GET_SEARCH_RESULTS',
|
||||
query: { type, term },
|
||||
query,
|
||||
limit,
|
||||
uri_schemes,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -2,12 +2,13 @@
|
||||
import ReactGA from 'react-ga';
|
||||
import Mopidy from 'mopidy';
|
||||
import { sha256 } from 'js-sha256';
|
||||
import { sampleSize } from 'lodash';
|
||||
import { sampleSize, uniqBy } from 'lodash';
|
||||
import { i18n } from '../../locale';
|
||||
import {
|
||||
generateGuid,
|
||||
uriSource,
|
||||
setFavicon,
|
||||
titleCase,
|
||||
} from '../../util/helpers';
|
||||
import {
|
||||
digestMopidyImages,
|
||||
@ -239,14 +240,140 @@ const MopidyMiddleware = (function () {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Process our search queries queue. We process one item in the queue and then
|
||||
* reiterate if there are any items remaining.
|
||||
*
|
||||
* @param {Object} store
|
||||
* @param {Array} queries
|
||||
*/
|
||||
const processSearchQueue = (store, queue) => {
|
||||
const {
|
||||
type,
|
||||
term,
|
||||
requestType,
|
||||
uri_scheme,
|
||||
method = 'library.search',
|
||||
data,
|
||||
} = queue.shift();
|
||||
const processor = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS;
|
||||
|
||||
if (processor && processor.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS',
|
||||
i18n(
|
||||
'services.mopidy.searching',
|
||||
{
|
||||
provider: titleCase(uri_scheme.replace(':', '')),
|
||||
type: requestType,
|
||||
},
|
||||
),
|
||||
{
|
||||
remaining: queue.length,
|
||||
},
|
||||
));
|
||||
|
||||
/**
|
||||
* Process our results. Each type has a different method of formatting and destructuring.
|
||||
*/
|
||||
const processResults = {
|
||||
albums: (response) => {
|
||||
const result = response[0];
|
||||
const albums = {};
|
||||
if (result.albums) {
|
||||
result.albums.forEach((album) => {
|
||||
if (album.uri) {
|
||||
albums[album.uri] = {
|
||||
...albums[album.uri],
|
||||
...formatAlbum(album),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
if (result.tracks) {
|
||||
result.tracks.forEach((track) => {
|
||||
if (track.album && track.album.uri) {
|
||||
albums[track.album.uri] = {
|
||||
...albums[track.album.uri],
|
||||
...formatAlbum(track.album),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
return indexToArray(albums);
|
||||
},
|
||||
artists: (response) => {
|
||||
const result = response[0];
|
||||
const artists = {};
|
||||
if (result.artists) {
|
||||
result.artists.forEach((artist) => {
|
||||
if (artist.uri) {
|
||||
artists[artist.uri] = {
|
||||
...artists[artist.uri],
|
||||
...formatArtist(artist),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
if (result.tracks) {
|
||||
result.tracks.forEach((track) => {
|
||||
if (track.artists) {
|
||||
track.artists.forEach((artist) => {
|
||||
if (artist && artist.uri) {
|
||||
artists[artist.uri] = {
|
||||
...artists[artist.uri],
|
||||
...formatArtist(artist),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return indexToArray(artists);
|
||||
},
|
||||
playlists: () => {},
|
||||
tracks: (response) => {
|
||||
const { tracks = [] } = response[0];
|
||||
return tracks;
|
||||
},
|
||||
};
|
||||
|
||||
request(
|
||||
store,
|
||||
method,
|
||||
data,
|
||||
).then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
store.dispatch(coreActions.searchResultsLoaded(
|
||||
{ term, type },
|
||||
requestType,
|
||||
processResults[requestType](response),
|
||||
));
|
||||
}
|
||||
|
||||
if (queue.length) {
|
||||
processSearchQueue(store, queue);
|
||||
} else {
|
||||
store.dispatch(uiActions.processFinished(
|
||||
'MOPIDY_GET_SEARCH_RESULTS',
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Middleware
|
||||
*
|
||||
* This behaves like an action interceptor. We listen for specific actions
|
||||
* and handle special functionality. If the action is not in our switch, then
|
||||
* it just proceeds to the next middleware, or default functionality
|
||||
* */
|
||||
* Middleware
|
||||
*
|
||||
* This behaves like an action interceptor. We listen for specific actions
|
||||
* and handle special functionality. If the action is not in our switch, then
|
||||
* it just proceeds to the next middleware, or default functionality
|
||||
* */
|
||||
return (store) => (next) => (action) => {
|
||||
switch (action.type) {
|
||||
case 'MOPIDY_CONNECT':
|
||||
@ -992,559 +1119,61 @@ const MopidyMiddleware = (function () {
|
||||
* */
|
||||
|
||||
|
||||
case 'MOPIDY_GET_SEARCH_RESULTS':
|
||||
case 'MOPIDY_GET_SEARCH_RESULTS': {
|
||||
const {
|
||||
uri_schemes = [],
|
||||
query = {},
|
||||
} = action;
|
||||
const types = query.type === 'all'
|
||||
? ['artists', 'albums', 'tracks']
|
||||
: [query.type];
|
||||
|
||||
// Flush out our previous results
|
||||
store.dispatch({ type: 'MOPIDY_CLEAR_SEARCH_RESULTS' });
|
||||
const queue = [];
|
||||
uri_schemes.forEach(
|
||||
(uri_scheme) => types.forEach(
|
||||
(type) => {
|
||||
const item = {
|
||||
type: query.type,
|
||||
term: query.term,
|
||||
requestType: type,
|
||||
uri_scheme,
|
||||
};
|
||||
switch (type) {
|
||||
case 'tracks':
|
||||
item.data = { query: { track_name: [query.term] }, uris: [uri_scheme] };
|
||||
break;
|
||||
case 'artists':
|
||||
item.data = { query: { artist: [query.term] }, uris: [uri_scheme] };
|
||||
break;
|
||||
case 'albums':
|
||||
item.data = { query: { album: [query.term] }, uris: [uri_scheme] };
|
||||
break;
|
||||
case 'playlistsXX': // Once we have the result handler, uncomment this
|
||||
item.method = 'playlists.asList';
|
||||
item.data = {};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
queue.push(item);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
var uri_schemes_to_ignore = ['spotify:'];
|
||||
var uri_schemes = Object.assign([], store.getState().ui.uri_schemes_search_enabled);
|
||||
for (var i = 0; i < uri_schemes.length; i++) {
|
||||
if (uri_schemes_to_ignore.includes(uri_schemes[i])) {
|
||||
uri_schemes.splice(i, 1);
|
||||
}
|
||||
}
|
||||
var uri_schemes_total = uri_schemes.length;
|
||||
var uri_scheme = uri_schemes.shift();
|
||||
|
||||
if (uri_schemes_total <= 0) {
|
||||
store.dispatch(uiActions.createNotification({ content: 'No sources selected', level: 'warning' }));
|
||||
} else {
|
||||
if (queue.length) {
|
||||
store.dispatch(uiActions.startProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
i18n('services.mopidy.searching_providers', { count: uri_schemes_total }),
|
||||
'MOPIDY_GET_SEARCH_RESULTS',
|
||||
i18n('services.mopidy.searching'),
|
||||
{
|
||||
query: action.query,
|
||||
limit: action.limit,
|
||||
total: uri_schemes_total,
|
||||
remaining: uri_schemes.length,
|
||||
uri_scheme,
|
||||
uri_schemes,
|
||||
total: queue.length,
|
||||
remaining: queue.length,
|
||||
},
|
||||
));
|
||||
|
||||
processSearchQueue(store, queue);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR':
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
|
||||
// Cancelling
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
|
||||
// No more schemes, so we're done!
|
||||
} if (!action.data.uri_scheme) {
|
||||
store.dispatch(uiActions.processFinished('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct our next batch's task
|
||||
var next_uri_schemes = Object.assign([], action.data.uri_schemes);
|
||||
var next_uri_scheme = next_uri_schemes.shift();
|
||||
|
||||
// Update UI for this round
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')}`,
|
||||
{
|
||||
remaining: action.data.uri_schemes.length,
|
||||
},
|
||||
));
|
||||
|
||||
switch (action.data.query.type) {
|
||||
case 'albums':
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')}`,
|
||||
));
|
||||
|
||||
var continue_process = () => {
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
uri_schemes: next_uri_schemes,
|
||||
},
|
||||
));
|
||||
};
|
||||
|
||||
request(store, 'library.search', { query: { album: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
let albums = [];
|
||||
|
||||
// Merge our proper album response container
|
||||
if (response[0].albums) {
|
||||
albums = [...response[0].albums, ...albums];
|
||||
}
|
||||
|
||||
// Pull the Album objects from our track responses
|
||||
if (response[0].tracks) {
|
||||
for (let i = 0; i < response[0].tracks.length; i++) {
|
||||
if (response[0].tracks[i].album !== undefined && response[0].tracks[i].album.uri !== undefined) {
|
||||
albums.push(response[0].tracks[i].album);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.itemsLoaded(albums));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
results: albums_uris,
|
||||
context: 'albums',
|
||||
});
|
||||
}
|
||||
|
||||
continue_process();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
continue_process();
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case 'artists':
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')}`,
|
||||
));
|
||||
|
||||
var continue_process = () => {
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
uri_schemes: next_uri_schemes,
|
||||
},
|
||||
));
|
||||
};
|
||||
|
||||
request(store, 'library.search', { query: { artist: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
let artists_uris = [];
|
||||
|
||||
// Pull actual artist objects
|
||||
if (response[0].artists) {
|
||||
for (var i = 0; i < response[0].artists.length; i++) {
|
||||
artists_uris.push(response[0].artists.uri);
|
||||
}
|
||||
}
|
||||
|
||||
// Digest track artists into actual artist results
|
||||
if (response[0].tracks) {
|
||||
for (var i = 0; i < response[0].tracks.length; i++) {
|
||||
if (response[0].tracks[i].artists) {
|
||||
for (let j = 0; j < response[0].tracks[i].artists.length; j++) {
|
||||
const artist = response[0].tracks[i].artists[j];
|
||||
if (artist.uri) {
|
||||
artists_uris.push(artist.uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
artists_uris = removeDuplicates(artists_uris);
|
||||
store.dispatch(coreActions.loadItems(artists_uris));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: 'artists',
|
||||
results: artists_uris,
|
||||
});
|
||||
}
|
||||
|
||||
continue_process();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
continue_process();
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case 'playlists':
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
'Searching playlists',
|
||||
));
|
||||
|
||||
var continue_process = () => {
|
||||
store.dispatch(uiActions.processFinished('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
};
|
||||
|
||||
request(store, 'playlists.asList')
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
const playlists_uris = [];
|
||||
|
||||
for (var i = 0; i < response.length; i++) {
|
||||
const playlist = response[i];
|
||||
if (playlist.name.includes(action.data.query) && action.data.uri_schemes.includes(`${uriSource(playlist.uri)}:`)) {
|
||||
playlists_uris.push(playlist.uri);
|
||||
}
|
||||
}
|
||||
|
||||
// load each playlist
|
||||
for (var i = 0; i < playlists_uris.length; i++) {
|
||||
store.dispatch(mopidyActions.getPlaylist(playlists_uris[i]));
|
||||
}
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: 'playlists',
|
||||
results: playlists_uris,
|
||||
});
|
||||
}
|
||||
continue_process();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
continue_process();
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case 'tracks':
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')}`,
|
||||
));
|
||||
|
||||
var continue_process = () => {
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
uri_schemes: next_uri_schemes,
|
||||
},
|
||||
));
|
||||
};
|
||||
|
||||
request(store, 'library.search', { query: { any: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0 && response[0].tracks !== undefined) {
|
||||
const { tracks } = response[0];
|
||||
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: 'tracks',
|
||||
results: formatTracks(tracks),
|
||||
});
|
||||
}
|
||||
continue_process();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
continue_process();
|
||||
},
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'all':
|
||||
default:
|
||||
var process_tracks = () => {
|
||||
const last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')} tracks`,
|
||||
{
|
||||
remaining: (action.data.uri_schemes.length) + 1,
|
||||
},
|
||||
));
|
||||
request(store, 'library.search', { query: { any: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0 && response[0].tracks !== undefined) {
|
||||
const { tracks } = response[0];
|
||||
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: 'tracks',
|
||||
results: formatTracks(tracks),
|
||||
});
|
||||
}
|
||||
|
||||
process_albums();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
process_albums();
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
var process_albums = () => {
|
||||
// Quick check to see if we should be cancelling
|
||||
const last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')} albums`,
|
||||
{
|
||||
remaining: (action.data.uri_schemes.length) + 0.75,
|
||||
},
|
||||
));
|
||||
request(store, 'library.search', { query: { album: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
let albums = [];
|
||||
|
||||
// Merge actual album responses first
|
||||
if (response[0].albums) {
|
||||
albums = [...response[0].albums, ...albums];
|
||||
}
|
||||
|
||||
// Then digest tracks albums
|
||||
if (response[0].tracks) {
|
||||
for (let i = 0; i < response[0].tracks.length; i++) {
|
||||
if (response[0].tracks[i].album !== undefined && response[0].tracks[i].album.uri !== undefined) {
|
||||
albums.push(response[0].tracks[i].album);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let albums_uris = arrayOf('uri', albums);
|
||||
albums_uris = removeDuplicates(albums_uris);
|
||||
|
||||
store.dispatch(coreActions.itemsLoaded(formatAlbums(albums)));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: 'albums',
|
||||
results: albums_uris,
|
||||
});
|
||||
}
|
||||
|
||||
process_artists();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
process_artists();
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
var process_artists = () => {
|
||||
// Quick check to see if we should be cancelling
|
||||
const last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')} artists`,
|
||||
{
|
||||
remaining: (action.data.uri_schemes.length) + 0.5,
|
||||
},
|
||||
));
|
||||
request(store, 'library.search', { query: { artist: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
let artists_uris = [];
|
||||
|
||||
// Pull our actual artists objects
|
||||
if (response[0].artists) {
|
||||
for (var i = 0; i < response[0].artists.length; i++) {
|
||||
artists_uris.push(response[0].artists.uri);
|
||||
}
|
||||
}
|
||||
|
||||
// Digest tracks artists
|
||||
if (response[0].tracks) {
|
||||
for (var i = 0; i < response[0].tracks.length; i++) {
|
||||
if (response[0].tracks[i].artists) {
|
||||
for (let j = 0; j < response[0].tracks[i].artists.length; j++) {
|
||||
const artist = response[0].tracks[i].artists[j];
|
||||
if (artist.uri) {
|
||||
artists_uris.push(artist.uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
artists_uris = removeDuplicates(artists_uris);
|
||||
store.dispatch(coreActions.loadItems(artists_uris));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: 'artists',
|
||||
results: artists_uris,
|
||||
});
|
||||
}
|
||||
|
||||
process_playlists();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
process_playlists();
|
||||
},
|
||||
);
|
||||
};
|
||||
var process_playlists = () => {
|
||||
// Quick check to see if we should be cancelling
|
||||
const last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (action.data.uri_scheme == 'm3u:') {
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${action.data.uri_scheme.replace(':', '')} playlists`,
|
||||
{
|
||||
remaining: (action.data.uri_schemes.length) + 0.25,
|
||||
},
|
||||
));
|
||||
request(store, 'playlists.asList')
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
let playlists_uris = [];
|
||||
for (var i = 0; i < response.length; i++) {
|
||||
const playlist = response[i];
|
||||
if (playlist.name.includes(action.data.query.term) && action.data.uri_schemes.includes(`${uriSource(playlist.uri)}:`)) {
|
||||
playlists_uris.push(playlist.uri);
|
||||
}
|
||||
}
|
||||
|
||||
playlists_uris = playlists_uris;
|
||||
|
||||
// load each playlist
|
||||
for (var i = 0; i < playlists_uris.length; i++) {
|
||||
store.dispatch(mopidyActions.getPlaylist(playlists_uris[i]));
|
||||
}
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: 'playlists',
|
||||
results: playlists_uris,
|
||||
});
|
||||
}
|
||||
|
||||
finished();
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
`Mopidy: ${error.message ? error.message : 'Search failed'}`,
|
||||
error,
|
||||
));
|
||||
finished();
|
||||
},
|
||||
);
|
||||
} else {
|
||||
finished();
|
||||
}
|
||||
};
|
||||
|
||||
var finished = () => {
|
||||
// We're finally done searching for types on this provider
|
||||
// On to the next scheme!
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
uri_schemes: next_uri_schemes,
|
||||
remaining: action.data.uri_schemes.length,
|
||||
},
|
||||
));
|
||||
};
|
||||
|
||||
// Kick things off with the tracks
|
||||
process_tracks();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'MOPIDY_GET_PLAYLIST':
|
||||
request(store, 'playlists.lookup', { uri: action.uri })
|
||||
|
||||
@ -563,13 +563,7 @@ export function getMore(url, core_action = null, custom_action = null, extra_dat
|
||||
};
|
||||
}
|
||||
|
||||
export function clearSearchResults() {
|
||||
return {
|
||||
type: 'SPOTIFY_CLEAR_SEARCH_RESULTS',
|
||||
};
|
||||
}
|
||||
|
||||
export function getSearchResults(type, term, limit = 50, offset = 0) {
|
||||
export function getSearchResults({ type, term }, limit = 50, offset = 0) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(uiActions.startProcess('SPOTIFY_GET_SEARCH_RESULTS_PROCESSOR', 'Searching Spotify'));
|
||||
|
||||
@ -588,54 +582,39 @@ export function getSearchResults(type, term, limit = 50, offset = 0) {
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.tracks !== undefined) {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'tracks',
|
||||
query: { type, term },
|
||||
results: formatTracks(response.tracks.items),
|
||||
more: response.tracks.next,
|
||||
});
|
||||
dispatch(coreActions.searchResultsLoaded(
|
||||
{ term, type },
|
||||
'tracks',
|
||||
formatTracks(response.tracks.items),
|
||||
));
|
||||
}
|
||||
|
||||
if (response.artists !== undefined) {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'artists',
|
||||
query: { type, term },
|
||||
results: arrayOf('uri', response.artists.items),
|
||||
more: response.artists.next,
|
||||
});
|
||||
// TODO: Loading items into index causes massive performance issue
|
||||
// Not the formatter, not coldstorage (async) and not building new index
|
||||
dispatch(coreActions.itemsLoaded(formatArtists(response.artists.items)));
|
||||
dispatch(coreActions.searchResultsLoaded(
|
||||
{ term, type },
|
||||
'artists',
|
||||
formatArtists(response.artists.items),
|
||||
));
|
||||
}
|
||||
|
||||
if (response.albums !== undefined) {
|
||||
dispatch(coreActions.itemsLoaded(formatAlbums(response.albums.items)));
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'albums',
|
||||
query: { type, term },
|
||||
results: arrayOf('uri', response.albums.items),
|
||||
more: response.albums.next,
|
||||
});
|
||||
dispatch(coreActions.searchResultsLoaded(
|
||||
{ term, type },
|
||||
'albums',
|
||||
formatAlbums(response.albums.items),
|
||||
));
|
||||
}
|
||||
|
||||
if (response.playlists !== undefined) {
|
||||
const playlists = response.playlists.items.map((item) => ({
|
||||
...formatPlaylist(item),
|
||||
can_edit: (getState().spotify.me && item.owner.id === getState().spotify.me.id),
|
||||
tracks_total: item.tracks.total,
|
||||
}));
|
||||
dispatch(coreActions.itemsLoaded(playlists));
|
||||
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'playlists',
|
||||
query: { type, term },
|
||||
results: arrayOf('uri', playlists),
|
||||
more: response.playlists.next,
|
||||
});
|
||||
dispatch(coreActions.searchResultsLoaded(
|
||||
{ term, type },
|
||||
'playlists',
|
||||
playlists,
|
||||
));
|
||||
}
|
||||
|
||||
dispatch(uiActions.processFinished('SPOTIFY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
|
||||
@ -327,83 +327,6 @@ const SpotifyMiddleware = (function () {
|
||||
next(action);
|
||||
break;
|
||||
|
||||
|
||||
/**
|
||||
* Searching
|
||||
* More results are lazy-loaded on demand, based on the _more URL
|
||||
* */
|
||||
|
||||
case 'SEARCH_STARTED':
|
||||
store.dispatch({
|
||||
type: 'SPOTIFY_CLEAR_SEARCH_RESULTS',
|
||||
});
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_TRACKS':
|
||||
store.dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'tracks',
|
||||
results: formatTracks(action.data.tracks.items),
|
||||
more: action.data.tracks.next,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_ARTISTS':
|
||||
|
||||
store.dispatch({
|
||||
type: 'ARTISTS_LOADED',
|
||||
artists: action.data.artists.items,
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'artists',
|
||||
results: arrayOf('uri', action.data.playlists.items),
|
||||
more: action.data.playlists.next,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_ALBUMS':
|
||||
|
||||
store.dispatch({
|
||||
type: 'ALBUMS_LOADED',
|
||||
albums: action.data.albums.items,
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'playlists',
|
||||
results: arrayOf('uri', action.data.albums.items),
|
||||
more: action.data.albums.next,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_PLAYLISTS':
|
||||
|
||||
var playlists = [];
|
||||
for (var i = 0; i < action.data.playlists.items.length; i++) {
|
||||
playlists.push({
|
||||
|
||||
...action.data.playlists.items[i],
|
||||
tracks_total: action.data.playlists.items[i].tracks.total,
|
||||
});
|
||||
}
|
||||
|
||||
store.dispatch({
|
||||
type: 'PLAYLISTS_LOADED',
|
||||
playlists,
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'playlists',
|
||||
results: arrayOf('uri', action.data.playlists.items),
|
||||
more: action.data.playlists.next,
|
||||
});
|
||||
break;
|
||||
|
||||
|
||||
case 'SPOTIFY_ME_LOADED':
|
||||
var me = { ...formatUser(action.me) };
|
||||
|
||||
|
||||
@ -184,36 +184,6 @@ export default function reducer(spotify = {}, action) {
|
||||
library_tracks_more: action.data.next,
|
||||
};
|
||||
|
||||
case 'SPOTIFY_CLEAR_SEARCH_RESULTS':
|
||||
return { ...spotify, search_results: {} };
|
||||
|
||||
case 'SPOTIFY_SEARCH_RESULTS_LOADED':
|
||||
|
||||
// Fetch or create our container
|
||||
if (spotify.search_results) {
|
||||
var search_results = { ...spotify.search_results };
|
||||
} else {
|
||||
var search_results = {};
|
||||
}
|
||||
|
||||
search_results = {
|
||||
...search_results,
|
||||
query: action.query,
|
||||
};
|
||||
|
||||
if (search_results.results) {
|
||||
search_results[action.context] = [...search_results[action.context], ...action.results];
|
||||
} else {
|
||||
search_results[action.context] = action.results;
|
||||
}
|
||||
|
||||
if (action.more) {
|
||||
search_results[`${action.context}_more`] = action.more;
|
||||
} else {
|
||||
search_results[`${action.context}_more`] = null;
|
||||
}
|
||||
return { ...spotify, search_results };
|
||||
|
||||
default:
|
||||
return spotify;
|
||||
}
|
||||
|
||||
@ -162,6 +162,7 @@ const corePersistConfig = {
|
||||
'albums',
|
||||
'artists',
|
||||
'playlists',
|
||||
'search_results',
|
||||
'users',
|
||||
'tracks',
|
||||
'libraries', // We manually hydrate this, so we can handle the rehydration of library items
|
||||
@ -252,7 +253,6 @@ const store = createStore(
|
||||
state,
|
||||
applyMiddleware(
|
||||
thunk,
|
||||
localstorageMiddleware,
|
||||
coreMiddleware,
|
||||
uiMiddleware,
|
||||
mopidyMiddleware,
|
||||
|
||||
@ -7,6 +7,7 @@ const getItems = (state) => state.core.items;
|
||||
const getLoadQueue = (state) => state.ui.load_queue;
|
||||
const getLibrary = (state, uri) => state.core.libraries[uri];
|
||||
const getLibraries = (state) => state.core.libraries;
|
||||
const getSearchResults = (state) => state.core.search_results;
|
||||
|
||||
const makeItemSelector = (uri) => createSelector(
|
||||
[getItems],
|
||||
@ -42,20 +43,11 @@ const makeLibrarySelector = (uris) => createSelector(
|
||||
},
|
||||
);
|
||||
|
||||
const getMopidySearchResults = (state, props) => (
|
||||
state.mopidy.search_results && state.mopidy.search_results[props.type]
|
||||
);
|
||||
const getSpotifySearchResults = (state, props) => (
|
||||
state.spotify.search_results && state.spotify.search_results[props.type]
|
||||
);
|
||||
const makeSearchResultsSelector = () => createSelector(
|
||||
[getMopidySearchResults, getSpotifySearchResults, getItems],
|
||||
(mopidySearchResults, spotifySearchResults, items) => {
|
||||
const uris = [
|
||||
...mopidySearchResults || [],
|
||||
...spotifySearchResults || [],
|
||||
];
|
||||
return indexToArray(items, uris);
|
||||
const makeSearchResultsSelector = (term, type) => createSelector(
|
||||
[getSearchResults],
|
||||
(searchResults) => {
|
||||
if (!searchResults || searchResults.query.term !== term) return [];
|
||||
return searchResults[type] || [];
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -96,8 +96,6 @@ class Search extends React.Component {
|
||||
}
|
||||
|
||||
onSourceClose = () => {
|
||||
spotifyActions.clearSearchResults();
|
||||
mopidyActions.clearSearchResults();
|
||||
this.search();
|
||||
};
|
||||
|
||||
@ -118,59 +116,44 @@ class Search extends React.Component {
|
||||
|
||||
clearSearch = () => {
|
||||
const {
|
||||
spotifyActions,
|
||||
mopidyActions,
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
spotifyActions.clearSearchResults();
|
||||
mopidyActions.clearSearchResults();
|
||||
setWindowTitle(i18n('search.title'));
|
||||
this.setState({ term: '' });
|
||||
}
|
||||
|
||||
search = () => {
|
||||
const {
|
||||
coreActions: {
|
||||
startSearch,
|
||||
},
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
uri_schemes_search_enabled,
|
||||
mopidyActions,
|
||||
spotifyActions,
|
||||
mopidy_search_results: {
|
||||
query: {
|
||||
term: mopidyTerm,
|
||||
type: mopidyType,
|
||||
} = {},
|
||||
},
|
||||
spotify_search_results: {
|
||||
query: {
|
||||
term: spotifyTerm,
|
||||
type: spotifyType,
|
||||
} = {},
|
||||
},
|
||||
} = this.props;
|
||||
const {
|
||||
type,
|
||||
term,
|
||||
} = this.state;
|
||||
|
||||
console.info(`Searching for ${type} matching "${term}"`);
|
||||
|
||||
setWindowTitle(i18n('search.title_window', { term: decodeURIComponent(term) }));
|
||||
|
||||
if (type && term) {
|
||||
if (mopidyTerm !== term || mopidyType !== type) {
|
||||
mopidyActions.clearSearchResults();
|
||||
mopidyActions.getSearchResults(type, term);
|
||||
}
|
||||
/**
|
||||
* TODO: Searches are being triggered when navigating to type subviews, despite already having
|
||||
* results. This might be a consequence of having providers merging their results into one array
|
||||
*/
|
||||
|
||||
if ((spotifyTerm !== term || spotifyType !== type) && uri_schemes_search_enabled.includes('spotify:')) {
|
||||
spotifyActions.clearSearchResults();
|
||||
if (type && term) {
|
||||
startSearch({ type, term });
|
||||
/*
|
||||
mopidyActions.getSearchResults(type, term);
|
||||
|
||||
if (uri_schemes_search_enabled.includes('spotify:')) {
|
||||
spotifyActions.getSearchResults(type, term);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,11 +294,9 @@ class Search extends React.Component {
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
type: ownProps.match.params.type,
|
||||
term: ownProps.match.params.term,
|
||||
uri_schemes_search_enabled: (state.ui.uri_schemes_search_enabled ? state.ui.uri_schemes_search_enabled : []),
|
||||
uri_schemes: (state.mopidy.uri_schemes ? state.mopidy.uri_schemes : []),
|
||||
mopidy_search_results: (state.mopidy.search_results ? state.mopidy.search_results : {}),
|
||||
spotify_search_results: (state.spotify.search_results ? state.spotify.search_results : {}),
|
||||
sort: (state.ui.search_results_sort ? state.ui.search_results_sort : 'followers.total'),
|
||||
uri_schemes_search_enabled: state.ui.uri_schemes_search_enabled || [],
|
||||
uri_schemes: state.mopidy.uri_schemes || [],
|
||||
sort: state.ui.search_results_sort || 'followers.total',
|
||||
sort_reverse: (!!state.ui.search_results_sort_reverse),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user