From 5063cc095cf19d1e6e458fa5c4a4e98265b5ce3c Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Wed, 8 Nov 2017 08:44:56 +1300 Subject: [PATCH] Bringing all tracks into core index; Need to refactor loading all assets --- src/js/components/ContextMenu.js | 109 ++++++++++++++++++++++----- src/js/components/TrackList.js | 2 +- src/js/services/core/middleware.js | 82 +++++++++++++++++++- src/js/services/core/reducer.js | 34 +-------- src/js/services/lastfm/actions.js | 12 ++- src/js/services/lastfm/middleware.js | 9 --- 6 files changed, 183 insertions(+), 65 deletions(-) diff --git a/src/js/components/ContextMenu.js b/src/js/components/ContextMenu.js index 720f7ca9..8dbd58dd 100755 --- a/src/js/components/ContextMenu.js +++ b/src/js/components/ContextMenu.js @@ -10,6 +10,7 @@ import * as coreActions from '../services/core/actions' import * as uiActions from '../services/ui/actions' import * as pusherActions from '../services/pusher/actions' import * as mopidyActions from '../services/mopidy/actions' +import * as lastfmActions from '../services/lastfm/actions' import * as spotifyActions from '../services/spotify/actions' import TrackList from './TrackList' @@ -41,10 +42,10 @@ class ContextMenu extends React.Component{ this.setState({ submenu_expanded: false }) $('body').addClass('context-menu-open') - var context = this.getContext() + var context = this.getContext(nextProps); // if we're able to be in the library, run a check - if (this.props.spotify_authorized && context.source == 'spotify'){ + if (nextProps.spotify_authorized && context.source == 'spotify'){ switch (nextProps.menu.context){ case 'artist': case 'album': @@ -54,6 +55,14 @@ class ContextMenu extends React.Component{ } } + // if we're able to be in the LastFM library, run a check + if (nextProps.lastfm_authorized && context.is_track && context.items_count == 1){ + if (nextProps.menu.items[0].uri && this.props.tracks[nextProps.menu.items[0].uri] !== undefined){ + var track = this.props.tracks[nextProps.menu.items[0].uri]; + this.props.lastfmActions.getTrack(track); + } + } + // we DID have one prior, and now we don't } else if (this.props.menu && !nextProps.menu){ $('body').removeClass('context-menu-open') @@ -73,41 +82,44 @@ class ContextMenu extends React.Component{ } } - getContext(){ + getContext(props = this.props){ var context = { name: null, - nice_name: 'Unknown' + nice_name: 'Unknown', + is_track: false } - if (this.props.menu && this.props.menu.context){ - context.name = this.props.menu.context - context.nice_name = this.props.menu.context + if (props.menu && props.menu.context){ + context.name = props.menu.context; + context.nice_name = props.menu.context; // handle ugly labels - switch (this.props.menu.context){ + switch (props.menu.context){ case 'playlist': case 'editable-playlist': - context.nice_name = 'playlist' + context.nice_name = 'playlist'; break case 'track': case 'queue-track': case 'playlist-track': case 'editable-playlist-track': - context.nice_name = 'track' + context.nice_name = 'track'; + context.is_track = true; break } // Consider the object(s) themselves // We can only really accommodate the first item. The only instances where // there is multiple is tracklists, when they're all of the same source (except search?) - if (this.props.menu.items && this.props.menu.items.length > 0){ - var item = this.props.menu.items[0] - context.item = item - context.items_count = this.props.menu.items.length - context.source = helpers.uriSource(item.uri) - context.type = helpers.uriType(item.uri) - context.in_library = this.inLibrary(item) + if (props.menu.items && props.menu.items.length > 0){ + var item = props.menu.items[0] + context.item = item; + context.items_count = props.menu.items.length; + context.source = helpers.uriSource(item.uri); + context.type = helpers.uriType(item.uri); + context.in_library = this.inLibrary(item); + context.is_loved = this.isLoved(item); } } @@ -133,6 +145,23 @@ class ContextMenu extends React.Component{ return false } + /** + * TODO: Currently the select track keys are the only details available. We need + * the actual track object reference (including name and artists) to getTrack from LastFM + **/ + isLoved(item = null){ + if (!item){ + return false + } + + if (this.props.tracks[item.uri] === undefined){ + return false; + } + var track = this.props.tracks[item.uri]; + + return (track.userloved !== undefined && track.userloved == "1"); + } + canBeInLibrary(){ if (!this.props.spotify_authorized){ return false @@ -190,6 +219,20 @@ class ContextMenu extends React.Component{ this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.menu.uris) } + toggleLoved(e, is_loved){ + this.props.uiActions.hideContextMenu() + if (is_loved){ + this.props.lastfmActions.unloveTrack(this.props.menu.items[0]) + } else { + this.props.lastfmActions.loveTrack(this.props.menu.items[0]) + } + } + + unloveTrack(e){ + this.props.uiActions.hideContextMenu() + this.props.lastfmActions.unloveTrack(this.props.menu.items[0]) + } + removeFromPlaylist(e){ this.props.uiActions.hideContextMenu() this.props.coreActions.removeTracksFromPlaylist(this.props.menu.tracklist_uri, this.props.menu.indexes) @@ -445,6 +488,29 @@ class ContextMenu extends React.Component{ ) + + if (helpers.isLoading(this.props.load_queue,['lastfm_track.getInfo'])){ + var toggle_loved = ( + + + + Love track + + + + ) + } else { + var toggle_loved = ( + + this.toggleLoved(e, context.is_loved)}> + + {context.is_loved ? 'Unlove' : 'Love'} track + + + + ) + } + var go_to_artist = ( this.goToArtist(e)}> @@ -580,6 +646,7 @@ class ContextMenu extends React.Component{ {context.items_count == 1 ? play_queue_item : null} {context.items_count == 1 ?
: null} {add_to_playlist} + {context.items_count == 1 ? toggle_loved : null} {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null} {context.items_count == 1 ? go_to_track : null}
@@ -598,6 +665,7 @@ class ContextMenu extends React.Component{ {context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
{add_to_playlist} + {context.items_count == 1 ? toggle_loved : null} {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null} {context.items_count == 1 ? go_to_track : null}
@@ -616,6 +684,7 @@ class ContextMenu extends React.Component{ {context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
{add_to_playlist} + {context.items_count == 1 ? toggle_loved : null} {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null} {context.items_count == 1 ? go_to_track : null}
@@ -663,6 +732,7 @@ class ContextMenu extends React.Component{ const mapStateToProps = (state, ownProps) => { return { menu: state.ui.context_menu, + load_queue: state.ui.load_queue, processes: state.ui.processes, current_track: state.core.current_track, current_tracklist: state.core.current_tracklist, @@ -675,7 +745,9 @@ const mapStateToProps = (state, ownProps) => { spotify_library_albums: state.spotify.library_albums, mopidy_library_albums: state.mopidy.library_albums, playlists: state.core.playlists, - spotify_authorized: state.spotify.authorization + tracks: state.core.tracks, + spotify_authorized: state.spotify.authorization, + lastfm_authorized: state.lastfm.session } } @@ -685,6 +757,7 @@ const mapDispatchToProps = (dispatch) => { uiActions: bindActionCreators(uiActions, dispatch), pusherActions: bindActionCreators(pusherActions, dispatch), spotifyActions: bindActionCreators(spotifyActions, dispatch), + lastfmActions: bindActionCreators(lastfmActions, dispatch), mopidyActions: bindActionCreators(mopidyActions, dispatch) } } diff --git a/src/js/components/TrackList.js b/src/js/components/TrackList.js index 61a47830..a712fc8f 100755 --- a/src/js/components/TrackList.js +++ b/src/js/components/TrackList.js @@ -202,7 +202,7 @@ class TrackList extends React.Component{ uris: selected_tracks_uris, indexes: selected_tracks_indexes } - this.props.uiActions.showContextMenu(data) + this.props.uiActions.showContextMenu(data); } handleSelection(e,track_key){ diff --git a/src/js/services/core/middleware.js b/src/js/services/core/middleware.js index 3559a18f..820e28c6 100755 --- a/src/js/services/core/middleware.js +++ b/src/js/services/core/middleware.js @@ -119,6 +119,14 @@ const CoreMiddleware = (function(){ action.album.images = helpers.digestMopidyImages(store.getState().mopidy, action.album.images); } + // Load our tracks + if (action.album.tracks){ + store.dispatch({ + type: 'TRACKS_LOADED', + tracks: action.album.tracks + }); + } + next(action) break @@ -129,13 +137,30 @@ const CoreMiddleware = (function(){ if (action.albums[i].images && action.albums[i].images.length > 0){ action.albums[i].images = helpers.digestMopidyImages(store.getState().mopidy, action.albums[i].images); } + + // Load our tracks + if (action.albums[i].tracks){ + store.dispatch({ + type: 'TRACKS_LOADED', + tracks: action.albums[i].tracks + }); + } } next(action) break case 'ARTIST_LOADED': - if (action.data) ReactGA.event({ category: 'Artist', action: 'Load', label: action.artist.uri }) + if (action.data) ReactGA.event({ category: 'Artist', action: 'Load', label: action.artist.uri }); + + // Load our tracks + if (action.artist.tracks){ + store.dispatch({ + type: 'TRACKS_LOADED', + tracks: action.artist.tracks + }); + } + next(action) break @@ -239,9 +264,17 @@ const CoreMiddleware = (function(){ } } + // Load our tracks + if (action.playlist.tracks){ + store.dispatch({ + type: 'TRACKS_LOADED', + tracks: action.playlist.tracks + }); + } + // proceed as usual - action.playlist = playlist - next(action) + action.playlist = playlist; + next(action); break case 'PLAYLISTS_LOADED': @@ -290,6 +323,49 @@ const CoreMiddleware = (function(){ next(action) break + case 'MOPIDY_TLTRACKS': + + var core = store.getState().core; + var tracklist = [] + for (var i = 0; i < action.data.length; i++){ + + var tltrack = helpers.formatTracks(action.data[i]); + + // load our metadata (if we have any for that tlid) + if (core.queue_metadata !== undefined && core.queue_metadata['tlid_'+tltrack.tlid] !== undefined){ + var metadata = core.queue_metadata['tlid_'+tltrack.tlid] + } else { + var metadata = {} + } + + var current_tlid = null; + if (core.current_track && core.tracks && core.tracks[core.current_track] !== undefined && core.tracks[core.current_track].tlid !== undefined){ + current_tlid = core.tracks[core.current_track].tlid; + } + + var track = Object.assign( + {}, + tltrack, + metadata, + { + playing: (tltrack.tlid == current_tlid) + }) + tracklist.push(track) + } + + // Append to our action + tracklist = helpers.formatTracks(tracklist); + action.tracklist = tracklist; + + // Load our tracks into index + store.dispatch({ + type: 'TRACKS_LOADED', + tracks: tracklist + }); + + next(action); + break + // Get assets from all of our providers case 'GET_LIBRARY_PLAYLISTS': if (store.getState().spotify.connected){ diff --git a/src/js/services/core/reducer.js b/src/js/services/core/reducer.js index 87b5f2b2..c258c2f3 100755 --- a/src/js/services/core/reducer.js +++ b/src/js/services/core/reducer.js @@ -12,38 +12,10 @@ export default function reducer(core = {}, action){ **/ case 'MOPIDY_TLTRACKS': - if (!action.data ) return core - - var tracklist = [] - for (var i = 0; i < action.data.length; i++){ - - var tltrack = helpers.formatTracks(action.data[i]); - - // load our metadata (if we have any for that tlid) - if (core.queue_metadata !== undefined && core.queue_metadata['tlid_'+tltrack.tlid] !== undefined){ - var metadata = core.queue_metadata['tlid_'+tltrack.tlid] - } else { - var metadata = {} - } - - var current_tlid = null; - if (core.current_track && core.tracks && core.tracks[core.current_track] !== undefined && core.tracks[core.current_track].tlid !== undefined){ - current_tlid = core.tracks[core.current_track].tlid; - } - - var track = Object.assign( - {}, - tltrack, - metadata, - { - playing: (tltrack.tlid == current_tlid) - }) - tracklist.push(track) + if (!action.tracklist){ + return core; } - - tracklist = helpers.formatTracks(tracklist); - - return Object.assign({}, core, { current_tracklist: tracklist }); + return Object.assign({}, core, { current_tracklist: action.tracklist }); case 'MOPIDY_CURRENTTLTRACK': if (!action.data) return core diff --git a/src/js/services/lastfm/actions.js b/src/js/services/lastfm/actions.js index 36c6bfbf..a65f1546 100755 --- a/src/js/services/lastfm/actions.js +++ b/src/js/services/lastfm/actions.js @@ -15,7 +15,10 @@ const sendRequest = (dispatch, getState, params, signed = false) => { return new Promise((resolve, reject) => { var loader_key = helpers.generateGuid(); - dispatch(uiActions.startLoading(loader_key, 'lastfm_'+params)); + var method = params.substring(params.indexOf("method=")+7, params.length); + method = method.substring(0, method.indexOf("&")); + + dispatch(uiActions.startLoading(loader_key, 'lastfm_'+method)); var config = { method: 'GET', @@ -83,8 +86,11 @@ const sendSignedRequest = (dispatch, getState, params) => { }); } - var loader_key = helpers.generateGuid() - dispatch(uiActions.startLoading(loader_key, 'lastfm_'+params)); + var loader_key = helpers.generateGuid(); + var method = params.substring(params.indexOf("method=")+7, params.length); + method = method.substring(0, method.indexOf("&")); + + dispatch(uiActions.startLoading(loader_key, 'lastfm_'+method)); params += "&sk="+getState().lastfm.session.key; diff --git a/src/js/services/lastfm/middleware.js b/src/js/services/lastfm/middleware.js index 6f0a7e6a..feaac867 100755 --- a/src/js/services/lastfm/middleware.js +++ b/src/js/services/lastfm/middleware.js @@ -32,15 +32,6 @@ const LastfmMiddleware = (function(){ next(action); break; - case 'MOPIDY_CURRENTTLTRACK': - if (action.data && action.data.track){ - if (state.lastfm.session){ - store.dispatch(lastfmActions.scrobble(action.data.track)); - } - } - next(action); - break; - // This action is irrelevant to us, pass it on to the next middleware default: