From 80077ea01dfd1dd0860181b3824a956f8228f138 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Thu, 31 Aug 2017 21:13:10 +1200 Subject: [PATCH] Moving search results into each provider; #181 --- src/js/helpers.js | 25 +++++++++++ src/js/services/core/middleware.js | 2 +- src/js/services/core/reducer.js | 4 -- src/js/services/mopidy/middleware.js | 32 ++++++++++++-- src/js/services/mopidy/reducer.js | 25 +++++++++++ src/js/services/spotify/actions.js | 34 +++++++++++---- src/js/services/spotify/middleware.js | 42 +++++++++++++----- src/js/services/spotify/reducer.js | 30 +++++++++++++ src/js/views/Search.js | 63 +++++++++++---------------- 9 files changed, 190 insertions(+), 67 deletions(-) diff --git a/src/js/helpers.js b/src/js/helpers.js index 30e72699..d1833a8d 100755 --- a/src/js/helpers.js +++ b/src/js/helpers.js @@ -569,4 +569,29 @@ export let isLoading = function(load_queue = [], keys = []){ } } return false +} + + +/** + * Get indexed record(s) by URI from our asset index + * + * @param store = obj + * @param uris = mixed (array or string) + * @return array + **/ +export let getIndexedRecords = function(index, uris){ + var records = [] + + // Wrap in array, if we've only got one URI + if (!uris instanceof Array){ + uris = [uris] + } + + for (var i = 0; i < uris.length; i++){ + if (index.hasOwnProperty(uris[i])){ + records.push(index[uris[i]]) + } + } + + return records } \ No newline at end of file diff --git a/src/js/services/core/middleware.js b/src/js/services/core/middleware.js index e2e8f129..c16187aa 100755 --- a/src/js/services/core/middleware.js +++ b/src/js/services/core/middleware.js @@ -105,6 +105,7 @@ const CoreMiddleware = (function(){ case 'SEARCH_STARTED': ReactGA.event({ category: 'Search', action: 'Started', label: action.type+': '+action.query }) + next(action) var state = store.getState() if (state.ui.search_settings){ @@ -171,7 +172,6 @@ const CoreMiddleware = (function(){ } } - next(action) break case 'PLAYLIST_TRACKS_ADDED': diff --git a/src/js/services/core/reducer.js b/src/js/services/core/reducer.js index 73f32d1a..9e4a36fd 100755 --- a/src/js/services/core/reducer.js +++ b/src/js/services/core/reducer.js @@ -488,14 +488,10 @@ export default function reducer(core = {}, action){ case 'SEARCH_STARTED': return Object.assign({}, core, { search_results: { - artists_more: null, artists_uris: [], - albums_more: null, albums_uris: [], - playlists_more: null, playlists_uris: [], tracks: [], - tracks_more: null, } }); diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index 89e2118c..de9c628a 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -480,6 +480,14 @@ const MopidyMiddleware = (function(){ **/ + case 'SEARCH_STARTED': + store.dispatch({ + type: 'MOPIDY_CLEAR_SEARCH_RESULTS' + }); + next(action) + break + + case 'MOPIDY_GET_TRACK_SEARCH_RESULTS': instruct( socket, store, 'library.search', {query: {any: [action.query]}, uris: [action.uri_scheme]}) .then( response => { @@ -488,7 +496,11 @@ const MopidyMiddleware = (function(){ var tracks = response[0].tracks.splice(0,action.limit) - store.dispatch({ type: 'SEARCH_RESULTS_LOADED', tracks: tracks }); + store.dispatch({ + type: 'MOPIDY_SEARCH_RESULTS_LOADED', + context: 'tracks', + results: tracks + }); }) break; @@ -520,7 +532,11 @@ const MopidyMiddleware = (function(){ } // and plug in their URIs - store.dispatch({ type: 'SEARCH_RESULTS_LOADED', artists_uris: artists_uris }) + store.dispatch({ + type: 'MOPIDY_SEARCH_RESULTS_LOADED', + context: 'artists', + results: artists_uris + }) }) break; @@ -551,7 +567,11 @@ const MopidyMiddleware = (function(){ } // and plug in their URIs - store.dispatch({ type: 'SEARCH_RESULTS_LOADED', albums_uris: albums_uris }) + store.dispatch({ + type: 'MOPIDY_SEARCH_RESULTS_LOADED', + context: 'albums', + results: albums_uris + }) }) break @@ -576,7 +596,11 @@ const MopidyMiddleware = (function(){ } // and plug in their URIs - store.dispatch({ type: 'SEARCH_RESULTS_LOADED', playlists_uris: playlists_uris }) + store.dispatch({ + type: 'MOPIDY_SEARCH_RESULTS_LOADED', + context: 'playlists', + results: playlists_uris + }) }) break diff --git a/src/js/services/mopidy/reducer.js b/src/js/services/mopidy/reducer.js index 37547fd4..41dd6e91 100755 --- a/src/js/services/mopidy/reducer.js +++ b/src/js/services/mopidy/reducer.js @@ -141,6 +141,31 @@ export default function reducer(mopidy = {}, action){ } return Object.assign({}, mopidy, { library_albums: helpers.removeDuplicates(uris) }) + + /** + * Searching + **/ + + case 'MOPIDY_CLEAR_SEARCH_RESULTS': + return Object.assign({}, mopidy, { search_results: {} }); + + case 'MOPIDY_SEARCH_RESULTS_LOADED': + + // Fetch or create our container + if (mopidy.search_results){ + var search_results = Object.assign({}, mopidy.search_results) + } else { + var search_results = {} + } + + if (search_results.results){ + search_results[action.context] = [...search_results[action.context], ...action.results] + } else { + search_results[action.context] = action.results + } + + return Object.assign({}, mopidy, { search_results: search_results }); + default: return mopidy } diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js index 4613dcdc..60af8c5b 100755 --- a/src/js/services/spotify/actions.js +++ b/src/js/services/spotify/actions.js @@ -482,15 +482,31 @@ export function getSearchResults(query, type = 'album,artist,playlist,track', li }); dispatch({ - type: 'SEARCH_RESULTS_LOADED', - playlists_uris: helpers.arrayOf('uri',playlists), - playlists_more: response.playlists.next, - artists_uris: helpers.arrayOf('uri',response.artists.items), - artists_more: response.artists.next, - albums_uris: helpers.arrayOf('uri',response.albums.items), - albums_more: response.albums.next, - tracks: response.tracks.items, - tracks_more: response.tracks.next + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'playlists', + results: helpers.arrayOf('uri',playlists), + more: response.playlists.next + }); + + dispatch({ + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'artists', + results: helpers.arrayOf('uri',response.artists.items), + more: response.artists.next, + }); + + dispatch({ + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'albums', + results: helpers.arrayOf('uri',response.albums.items), + more: response.albums.next, + }); + + dispatch({ + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'tracks', + results: response.tracks.items, + more: response.tracks.next, }); }); } diff --git a/src/js/services/spotify/middleware.js b/src/js/services/spotify/middleware.js index 6c8e10bc..a2b78b82 100755 --- a/src/js/services/spotify/middleware.js +++ b/src/js/services/spotify/middleware.js @@ -300,11 +300,25 @@ const SpotifyMiddleware = (function(){ }); 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: 'SEARCH_RESULTS_LOADED', - tracks: action.data.tracks.items, - tracks_more: action.data.tracks.next + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'tracks', + results: action.data.tracks.items, + more: action.data.tracks.next }); break @@ -316,9 +330,10 @@ const SpotifyMiddleware = (function(){ }); store.dispatch({ - type: 'SEARCH_RESULTS_LOADED', - playlists_uris: helpers.arrayOf('uri',action.data.playlists.items), - playlists_more: action.data.playlists.next + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'artists', + results: helpers.arrayOf('uri',action.data.playlists.items), + more: action.data.playlists.next }); break @@ -330,9 +345,10 @@ const SpotifyMiddleware = (function(){ }); store.dispatch({ - type: 'SEARCH_RESULTS_LOADED', - albums_uris: helpers.arrayOf('uri',action.data.albums.items), - albums_more: action.data.albums.next + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'playlists', + results: helpers.arrayOf('uri',action.data.albums.items), + more: action.data.albums.next }); break @@ -355,12 +371,14 @@ const SpotifyMiddleware = (function(){ }); store.dispatch({ - type: 'SEARCH_RESULTS_LOADED', - playlists_uris: helpers.arrayOf('uri',action.data.playlists.items), - playlists_more: action.data.playlists.next + type: 'SPOTIFY_SEARCH_RESULTS_LOADED', + context: 'playlists', + results: helpers.arrayOf('uri',action.data.playlists.items), + more: action.data.playlists.next }); break + case 'SPOTIFY_ME_LOADED': // We've loaded 'me' and we are Anonymous currently diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js index c38f0361..5c45f34e 100755 --- a/src/js/services/spotify/reducer.js +++ b/src/js/services/spotify/reducer.js @@ -240,6 +240,36 @@ export default function reducer(spotify = {}, action){ } return Object.assign({}, spotify, { library_playlists: items }); + + /** + * Searching + **/ + + case 'SPOTIFY_CLEAR_SEARCH_RESULTS': + return Object.assign({}, spotify, { search_results: {} }); + + case 'SPOTIFY_SEARCH_RESULTS_LOADED': + + // Fetch or create our container + if (spotify.search_results){ + var search_results = Object.assign({}, spotify.search_results) + } else { + var search_results = {} + } + + 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 Object.assign({}, spotify, { search_results: search_results }); + default: return spotify } diff --git a/src/js/views/Search.js b/src/js/views/Search.js index 7ef34f8b..c6f5bebc 100755 --- a/src/js/views/Search.js +++ b/src/js/views/Search.js @@ -62,42 +62,35 @@ class Search extends React.Component{ var spotify_search_enabled = (this.props.search_settings && this.props.search_settings.spotify) var artists = [] - if (this.props.artists_uris){ - for (var i = 0; i < this.props.artists_uris.length; i++){ - var uri = this.props.artists_uris[i] - if (this.props.artists.hasOwnProperty(uri)){ - artists.push(this.props.artists[uri]) - } - } + if (this.props.spotify_search_results.artists){ + artists = [...artists, ...helpers.getIndexedRecords(this.props.artists,this.props.spotify_search_results.artists)] + } + if (this.props.mopidy_search_results.artists){ + artists = [...artists, ...helpers.getIndexedRecords(this.props.artists,this.props.mopidy_search_results.artists)] } var albums = [] - if (this.props.albums_uris){ - for (var i = 0; i < this.props.albums_uris.length; i++){ - var uri = this.props.albums_uris[i] - if (this.props.albums.hasOwnProperty(uri)){ - albums.push(this.props.albums[uri]) - } - } + if (this.props.spotify_search_results.albums){ + albums = [...albums, ...helpers.getIndexedRecords(this.props.albums,this.props.spotify_search_results.albums)] + } + if (this.props.mopidy_search_results.albums){ + albums = [...albums, ...helpers.getIndexedRecords(this.props.albums,this.props.mopidy_search_results.albums)] } var playlists = [] - if (this.props.playlists_uris){ - for (var i = 0; i < this.props.playlists_uris.length; i++){ - var uri = this.props.playlists_uris[i] - if (this.props.playlists.hasOwnProperty(uri)){ - playlists.push(this.props.playlists[uri]) - } - } + if (this.props.spotify_search_results.playlists){ + playlists = [...playlists, ...helpers.getIndexedRecords(this.props.playlists,this.props.spotify_search_results.playlists)] + } + if (this.props.mopidy_search_results.playlists){ + playlists = [...playlists, ...helpers.getIndexedRecords(this.props.playlists,this.props.mopidy_search_results.playlists)] } var tracks = [] - if (this.props.tracks){ - for (var i = 0; i < this.props.tracks.length; i++){ - if (helpers.uriSource(this.props.tracks[i].uri)){ - tracks.push(this.props.tracks[i]) - } - } + if (this.props.spotify_search_results.tracks){ + tracks = [...tracks, ...this.props.spotify_search_results.tracks] + } + if (this.props.mopidy_search_results.tracks){ + tracks = [...tracks, ...this.props.mopidy_search_results.tracks] } switch (this.props.params.type){ @@ -260,18 +253,14 @@ class Search extends React.Component{ const mapStateToProps = (state, ownProps) => { return { mopidy_connected: state.mopidy.connected, - search_settings: (state.ui.search_settings ? state.ui.search_settings : null), - tracks: (state.core.search_results ? state.core.search_results.tracks : []), - tracks_more: (state.core.search_results && state.core.search_results.tracks_more ? state.core.search_results.tracks_more : null), - artists: (state.core.artists ? state.core.artists : []), - artists_uris: (state.core.search_results ? state.core.search_results.artists_uris : []), - artists_more: (state.core.search_results ? state.core.search_results.artists_more : null), + spotify_connected: state.spotify.connected, albums: (state.core.albums ? state.core.albums : []), - albums_uris: (state.core.search_results ? state.core.search_results.albums_uris : []), - albums_more: (state.core.search_results ? state.core.search_results.albums_more : null), + artists: (state.core.artists ? state.core.artists : []), playlists: (state.core.playlists ? state.core.playlists : []), - playlists_uris: (state.core.search_results ? state.core.search_results.playlists_uris : []), - playlists_more: (state.core.search_results ? state.core.search_results.playlists_more : null) + tracks: (state.core.tracks ? state.core.tracks : []), + search_settings: (state.ui.search_settings ? state.ui.search_settings : {}), + mopidy_search_results: (state.mopidy.search_results ? state.mopidy.search_results : {}), + spotify_search_results: (state.spotify.search_results ? state.spotify.search_results : {}) } }