From 667efba1f7078444bc9070c7a452d9ae5227d307 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 21 Oct 2016 16:34:16 +1300 Subject: [PATCH] Spotify checkToken before any critical request --- src/js/components/TrackList.js | 2 +- src/js/services/localstorage/middleware.js | 19 ++++-- src/js/services/mopidy/middleware.js | 3 + src/js/services/mopidy/reducer.js | 1 + src/js/services/spotify/actions.js | 74 ++++++++++++++++------ src/js/services/spotify/reducer.js | 12 ++-- src/js/views/Queue.js | 2 +- 7 files changed, 83 insertions(+), 30 deletions(-) diff --git a/src/js/components/TrackList.js b/src/js/components/TrackList.js index 0d111c6f..2f78158a 100755 --- a/src/js/components/TrackList.js +++ b/src/js/components/TrackList.js @@ -83,7 +83,7 @@ class TrackList extends React.Component{ playTrack( track ){ if( typeof(this.props.playTrack) !== 'undefined' ){ - return this.props.playTrack( this.selectedTracks() ); + return this.props.playTrack( track ); } var uris = [track.uri]; diff --git a/src/js/services/localstorage/middleware.js b/src/js/services/localstorage/middleware.js index 0b82f463..074b25d9 100755 --- a/src/js/services/localstorage/middleware.js +++ b/src/js/services/localstorage/middleware.js @@ -30,16 +30,27 @@ const localstorageMiddleware = (function(){ localStorage.setItem('spotify', JSON.stringify(spotify)); break; - case 'SPOTIFY_AUTHORIZATION_COMPLETE': + case 'SPOTIFY_AUTHORIZATION_GRANTED': var spotify = JSON.parse( localStorage.getItem('spotify') ); if( !spotify ) spotify = {}; - console.log(spotify) Object.assign( spotify,{ authorized: true, access_token: action.data.access_token, - refresh_token: action.data.refresh_token, - me: action.data.me + refresh_token: action.data.refresh_token, + token_expiry: action.data.token_expiry + } + ); + localStorage.setItem('spotify', JSON.stringify(spotify)); + break; + + case 'SPOTIFY_TOKEN_REFRESHED': + var spotify = JSON.parse( localStorage.getItem('spotify') ); + if( !spotify ) spotify = {}; + Object.assign( + spotify,{ + access_token: action.data.access_token, + token_expiry: action.data.token_expiry } ); localStorage.setItem('spotify', JSON.stringify(spotify)); diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index 503fcc58..fec128a2 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -143,6 +143,9 @@ const MopidyMiddleware = (function(){ // play it store.dispatch( actions.changeTrack( response[0].tlid ) ); + // TODO: perhaps force update of currentTlTrack before we proceed? + // this will make the UI feel snappier... + // add the rest of our uris (if any) action.uris.shift(); if( action.uris.length > 0 ){ diff --git a/src/js/services/mopidy/reducer.js b/src/js/services/mopidy/reducer.js index c47e1025..f44660c3 100755 --- a/src/js/services/mopidy/reducer.js +++ b/src/js/services/mopidy/reducer.js @@ -20,6 +20,7 @@ export default function reducer(mopidy = {}, action){ }); case 'MOPIDY_HIGHLIGHT_CURRENT_TLTRACK': + if( !action.data ) return mopidy; for( var i = 0; i < mopidy.tracks.length; i++ ){ if( mopidy.tracks[i].tlid == action.data.tlid ){ action.data.track.playing = true; diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js index b6eff556..43515cf9 100755 --- a/src/js/services/spotify/actions.js +++ b/src/js/services/spotify/actions.js @@ -30,7 +30,6 @@ export function loadAlbum( uri ){ } - /** * Send an ajax request to the Spotify API * @@ -67,6 +66,7 @@ export function startAuthorization(){ } export function authorizationGranted( data ){ + data.token_expiry = new Date().getTime() + data.expires_in; return { type: 'SPOTIFY_AUTHORIZATION_GRANTED', data: data } } @@ -74,26 +74,58 @@ export function removeAuthorization(){ return { type: 'SPOTIFY_REMOVE_AUTHORIZATION' } } -export function refreshToken(){ - return (dispatch, getState) => { - dispatch({ type: 'SPOTIFY_TOKEN_REFRESHING' }); +/** +* Check an access token validity +* +* @return Promise +**/ +function checkToken( dispatch, getState ){ + return new Promise( (resolve, reject) => { + // is our token_expiry still in the future? + if( new Date().getTime() < getState().spotify.token_expiry ){ + resolve(); + return + } + + // token is expiring/expired + doRefreshToken( dispatch, getState ) + .then( + response => { + resolve(); + }, + error => reject(error) + ); + }); +} + +function doRefreshToken( dispatch, getState ){ + return new Promise( (resolve, reject) => { $.ajax({ method: 'GET', url: '//jamesbarnsley.co.nz/spotmop.php?action=refresh&refresh_token='+getState().spotify.refresh_token, dataType: "json", timeout: 10000 }) - .then( response => { + .then( + response => { + response.token_expiry = new Date().getTime() + response.expires_in; + dispatch({ + type: 'SPOTIFY_TOKEN_REFRESHED', + data: response + }); + resolve(); + }, + error => reject(error) + ); + }) +} - response.expires = new Date().getTime() + 3600000; - - dispatch({ - type: 'SPOTIFY_TOKEN_REFRESHED', - data: response - }); - }); +export function refreshToken(){ + return (dispatch, getState) => { + dispatch({ type: 'SPOTIFY_TOKEN_REFRESHING' }); + doRefreshToken( dispatch, getState ); } } @@ -270,14 +302,18 @@ export function getLibraryAlbums(){ export function getLibraryTracks(){ return (dispatch, getState) => { - dispatch({ type: 'SPOTIFY_LIBRARY_TRACKS_LOADED', data: false }); + checkToken( dispatch, getState ) + .then( () => { - sendRequest( getState().spotify.access_token, 'me/tracks?limit=50' ) - .then( response => { - dispatch({ - type: 'SPOTIFY_LIBRARY_TRACKS_LOADED', - data: response - }); + dispatch({ type: 'SPOTIFY_LIBRARY_TRACKS_LOADED', data: false }); + + sendRequest( getState().spotify.access_token, 'me/tracks?limit=50' ) + .then( response => { + dispatch({ + type: 'SPOTIFY_LIBRARY_TRACKS_LOADED', + data: response + }); + }); }); } } diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js index d5f2144e..32517f8d 100755 --- a/src/js/services/spotify/reducer.js +++ b/src/js/services/spotify/reducer.js @@ -5,12 +5,16 @@ export default function reducer(spotify = {}, action){ case 'SPOTIFY_CONNECTING': return Object.assign({}, spotify, { connected: false, connecting: true }); + case 'SPOTIFY_CONNECTED': + return Object.assign({}, spotify, { connected: true, connecting: false }); + case 'SPOTIFY_AUTHORIZATION_GRANTED': return Object.assign({}, spotify, { authorizing: false, authorized: true, authorization: action.data, - access_token: action.data.access_token + access_token: action.data.access_token, + token_expiry: action.data.token_expiry }); case 'SPOTIFY_REMOVE_AUTHORIZATION': @@ -22,9 +26,6 @@ export default function reducer(spotify = {}, action){ me: false }); - case 'SPOTIFY_CONNECTED': - return Object.assign({}, spotify, { connected: true, connecting: false }); - case 'SPOTIFY_TOKEN_REFRESHING': return Object.assign({}, spotify, { refreshing_token: true }); @@ -32,7 +33,8 @@ export default function reducer(spotify = {}, action){ return Object.assign({}, spotify, { refreshing_token: false, authorization: action.data, - access_token: action.data.access_token + access_token: action.data.access_token, + token_expiry: action.data.token_expiry }); case 'SPOTIFY_DISCONNECTED': diff --git a/src/js/views/Queue.js b/src/js/views/Queue.js index 52ab375e..bcdacc7b 100755 --- a/src/js/views/Queue.js +++ b/src/js/views/Queue.js @@ -52,7 +52,7 @@ class Queue extends React.Component{ this.props.actions.removeTracks( tlids ) } - playTrack( track ){ + playTrack( track ){ this.props.actions.changeTrack( track.tlid ) }