2016-10-16 12:37:37 +13:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Actions and Action Creators
|
|
|
|
|
**/
|
|
|
|
|
|
2016-10-18 21:57:29 +13:00
|
|
|
export function setConfig( config ){
|
|
|
|
|
return {
|
|
|
|
|
type: 'SPOTIFY_SET_CONFIG',
|
|
|
|
|
config: config
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
export function connect(){
|
2016-10-16 12:37:37 +13:00
|
|
|
return {
|
2016-10-20 21:38:01 +13:00
|
|
|
type: 'SPOTIFY_CONNECTING'
|
2016-10-17 10:39:11 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
export function disconnect(){
|
2016-10-17 10:39:11 +13:00
|
|
|
return {
|
2016-10-20 21:38:01 +13:00
|
|
|
type: 'SPOTIFY_DISCONNECT'
|
2016-10-17 10:39:11 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send an ajax request to the Spotify API
|
|
|
|
|
*
|
2016-10-22 09:53:36 +13:00
|
|
|
* @param dispatch obj
|
|
|
|
|
* @param getState obj
|
2016-10-20 21:38:01 +13:00
|
|
|
* @param endpoint string = the url to query (ie /albums/:uri)
|
|
|
|
|
* @param method string
|
|
|
|
|
* @param data mixed = request payload
|
2016-10-22 09:53:36 +13:00
|
|
|
* @return Promise
|
2016-10-20 21:38:01 +13:00
|
|
|
**/
|
2016-10-22 09:53:36 +13:00
|
|
|
const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false) => {
|
|
|
|
|
return new Promise( (resolve, reject) => {
|
2016-10-23 23:48:06 +13:00
|
|
|
getToken( dispatch, getState )
|
|
|
|
|
.then( response => {
|
|
|
|
|
$.ajax({
|
|
|
|
|
method: method,
|
|
|
|
|
cache: true,
|
|
|
|
|
url: 'https://api.spotify.com/v1/'+endpoint,
|
|
|
|
|
headers: {
|
|
|
|
|
Authorization: 'Bearer '+ response
|
|
|
|
|
},
|
|
|
|
|
data: data
|
|
|
|
|
}).then(
|
2016-10-22 09:53:36 +13:00
|
|
|
response => resolve(response),
|
|
|
|
|
error => {
|
2016-10-24 21:26:01 +13:00
|
|
|
console.error('Could not send request to '+endpoint, error, data)
|
2016-10-22 09:53:36 +13:00
|
|
|
reject(error)
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
});
|
2016-10-20 21:38:01 +13:00
|
|
|
}
|
2016-10-22 09:53:36 +13:00
|
|
|
);
|
2016-10-20 21:38:01 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle authorization process
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
export function startAuthorization(){
|
|
|
|
|
return { type: 'SPOTIFY_START_AUTHORIZATION' }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function authorizationGranted( data ){
|
2016-10-21 16:34:16 +13:00
|
|
|
data.token_expiry = new Date().getTime() + data.expires_in;
|
2016-10-20 21:38:01 +13:00
|
|
|
return { type: 'SPOTIFY_AUTHORIZATION_GRANTED', data: data }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function removeAuthorization(){
|
|
|
|
|
return { type: 'SPOTIFY_REMOVE_AUTHORIZATION' }
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 09:56:07 +13:00
|
|
|
|
2016-10-21 16:34:16 +13:00
|
|
|
/**
|
|
|
|
|
* Check an access token validity
|
|
|
|
|
*
|
|
|
|
|
* @return Promise
|
|
|
|
|
**/
|
2016-10-23 23:48:06 +13:00
|
|
|
function getToken( dispatch, getState ){
|
2016-10-21 16:34:16 +13:00
|
|
|
return new Promise( (resolve, reject) => {
|
|
|
|
|
|
2016-10-23 23:48:06 +13:00
|
|
|
// token is okay for now, so just resolve with the current token
|
2016-10-21 16:34:16 +13:00
|
|
|
if( new Date().getTime() < getState().spotify.token_expiry ){
|
2016-10-23 23:48:06 +13:00
|
|
|
resolve(getState().spotify.access_token);
|
2016-10-21 16:34:16 +13:00
|
|
|
return
|
|
|
|
|
}
|
2016-10-24 21:26:01 +13:00
|
|
|
|
2016-10-23 23:48:06 +13:00
|
|
|
// token is expiring/expired, so go get a new one and resolve that
|
|
|
|
|
refreshToken( dispatch, getState )
|
2016-10-21 16:34:16 +13:00
|
|
|
.then(
|
2016-10-24 21:26:01 +13:00
|
|
|
response => resolve(response.access_token),
|
|
|
|
|
error => reject(error)
|
2016-10-21 16:34:16 +13:00
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2016-10-21 09:56:07 +13:00
|
|
|
|
2016-10-23 23:48:06 +13:00
|
|
|
function refreshToken( dispatch, getState ){
|
2016-10-21 16:34:16 +13:00
|
|
|
return new Promise( (resolve, reject) => {
|
2016-10-21 09:56:07 +13:00
|
|
|
$.ajax({
|
|
|
|
|
method: 'GET',
|
|
|
|
|
url: '//jamesbarnsley.co.nz/spotmop.php?action=refresh&refresh_token='+getState().spotify.refresh_token,
|
|
|
|
|
dataType: "json",
|
|
|
|
|
timeout: 10000
|
|
|
|
|
})
|
2016-10-21 16:34:16 +13:00
|
|
|
.then(
|
|
|
|
|
response => {
|
2016-10-22 09:53:36 +13:00
|
|
|
response.token_expiry = new Date().getTime() + ( response.expires_in * 1000 );
|
2016-10-21 16:34:16 +13:00
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_TOKEN_REFRESHED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
2016-10-23 23:48:06 +13:00
|
|
|
resolve(response);
|
2016-10-21 16:34:16 +13:00
|
|
|
},
|
2016-10-23 23:48:06 +13:00
|
|
|
error => {
|
2016-10-24 21:26:01 +13:00
|
|
|
console.error('Could not refresh token', error)
|
2016-10-23 23:48:06 +13:00
|
|
|
reject(error)
|
|
|
|
|
}
|
2016-10-21 16:34:16 +13:00
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
}
|
2016-10-21 09:56:07 +13:00
|
|
|
|
2016-10-24 21:26:01 +13:00
|
|
|
export function refreshingToken(){
|
2016-10-21 16:34:16 +13:00
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
dispatch({ type: 'SPOTIFY_TOKEN_REFRESHING' });
|
2016-10-24 21:26:01 +13:00
|
|
|
refreshToken( dispatch, getState );
|
2016-10-21 09:56:07 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get current user
|
|
|
|
|
**/
|
|
|
|
|
export function getMe(){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
|
|
|
|
// flush out the previous store value
|
|
|
|
|
dispatch({ type: 'SPOTIFY_ME_LOADED', data: false });
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'me' )
|
2016-10-21 09:56:07 +13:00
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_ME_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
|
2016-10-24 21:26:01 +13:00
|
|
|
/**
|
|
|
|
|
* Get a single track
|
|
|
|
|
*
|
|
|
|
|
* @param uri string
|
|
|
|
|
**/
|
|
|
|
|
export function getTrack( uri ){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
|
|
|
|
// flush out the previous store value
|
|
|
|
|
dispatch({ type: 'SPOTIFY_TRACK_LOADED', data: false });
|
|
|
|
|
|
|
|
|
|
sendRequest( dispatch, getState, 'tracks/'+ getFromUri('trackid', uri) )
|
|
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_TRACK_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
/**
|
|
|
|
|
* Get a single artist
|
|
|
|
|
*
|
|
|
|
|
* @param uri string
|
|
|
|
|
**/
|
|
|
|
|
export function getArtist( uri ){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
|
|
|
|
// flush out the previous store value
|
|
|
|
|
dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: false });
|
|
|
|
|
|
|
|
|
|
var artist = {};
|
|
|
|
|
|
|
|
|
|
// while we're fiddling about, go get the albums
|
|
|
|
|
dispatch(getArtistAlbums(uri));
|
|
|
|
|
|
|
|
|
|
// get both the artist and the top tracks
|
|
|
|
|
$.when(
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'artists/'+ getFromUri('artistid', uri) )
|
2016-10-20 21:38:01 +13:00
|
|
|
.then( response => {
|
|
|
|
|
Object.assign(artist, response);
|
|
|
|
|
}),
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'artists/'+ getFromUri('artistid', uri) +'/top-tracks?country='+getState().spotify.country )
|
2016-10-20 21:38:01 +13:00
|
|
|
.then( response => {
|
|
|
|
|
Object.assign(artist, response);
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
).then( () => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_ARTIST_LOADED',
|
|
|
|
|
data: artist
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-10-16 12:37:37 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
export function getArtistAlbums( uri ){
|
2016-10-22 09:53:36 +13:00
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
sendRequest( dispatch, getState, 'artists/'+ getFromUri('artistid', uri) +'/albums' )
|
2016-10-20 21:38:01 +13:00
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_ARTIST_ALBUMS_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-10-16 12:37:37 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
/**
|
|
|
|
|
* Single album
|
|
|
|
|
*
|
|
|
|
|
* @oaram uri string
|
|
|
|
|
**/
|
|
|
|
|
export function getAlbum( uri ){
|
2016-10-22 09:53:36 +13:00
|
|
|
return (dispatch, getState) => {
|
2016-10-20 21:38:01 +13:00
|
|
|
|
2016-10-21 09:56:07 +13:00
|
|
|
// flush out the previous store value
|
2016-10-20 21:38:01 +13:00
|
|
|
dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: false });
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'albums/'+ getFromUri('albumid', uri) )
|
2016-10-20 21:38:01 +13:00
|
|
|
.then( response => {
|
|
|
|
|
|
2016-10-21 09:56:07 +13:00
|
|
|
// inject the parent album object into each track for consistent track objects
|
2016-10-20 21:38:01 +13:00
|
|
|
for( var i = 0; i < response.tracks.items.length; i++ ){
|
|
|
|
|
response.tracks.items[i].album = {
|
|
|
|
|
name: response.name,
|
|
|
|
|
uri: response.uri
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dispatch({
|
2016-10-21 09:56:07 +13:00
|
|
|
type: 'SPOTIFY_ALBUM_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Single playlist
|
|
|
|
|
*
|
|
|
|
|
* @oaram uri string
|
|
|
|
|
**/
|
|
|
|
|
export function getPlaylist( uri ){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
|
|
|
|
// flush out the previous store value
|
|
|
|
|
dispatch({ type: 'SPOTIFY_PLAYLIST_LOADED', data: false });
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'users/'+ getFromUri('userid',uri) +'/playlists/'+ getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
|
2016-10-21 09:56:07 +13:00
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_PLAYLIST_LOADED',
|
2016-10-20 21:38:01 +13:00
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-10-16 12:37:37 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
|
2016-10-21 09:56:07 +13:00
|
|
|
export function getLibraryPlaylists(){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
|
|
|
|
dispatch({ type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED', data: false });
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'me/playlists' )
|
2016-10-21 09:56:07 +13:00
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
export function getLibraryArtists(){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
|
|
|
|
dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: false });
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'me/following?type=artist' )
|
2016-10-20 21:38:01 +13:00
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-10-17 10:39:11 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
|
|
|
|
|
export function getLibraryAlbums(){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
|
|
|
|
dispatch({ type: 'SPOTIFY_LIBRARY_ALBUMS_LOADED', data: false });
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'me/albums' )
|
2016-10-20 21:38:01 +13:00
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_LIBRARY_ALBUMS_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-10-17 14:27:48 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 21:38:01 +13:00
|
|
|
export function getLibraryTracks(){
|
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
dispatch({ type: 'SPOTIFY_LIBRARY_TRACKS_LOADED', data: false });
|
2016-10-20 21:38:01 +13:00
|
|
|
|
2016-10-22 09:53:36 +13:00
|
|
|
sendRequest( dispatch, getState, 'me/tracks?limit=50' )
|
|
|
|
|
.then( response => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SPOTIFY_LIBRARY_TRACKS_LOADED',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
2016-10-20 21:38:01 +13:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-21 09:56:07 +13:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get an element from a URI
|
|
|
|
|
* @param element = string, the element we wish to extract
|
|
|
|
|
* @param uri = string
|
|
|
|
|
**/
|
|
|
|
|
function getFromUri( element, uri ){
|
|
|
|
|
var exploded = uri.split(':');
|
|
|
|
|
if( element == 'userid' && exploded[1] == 'user' )
|
|
|
|
|
return exploded[2];
|
|
|
|
|
if( element == 'playlistid' && exploded[3] == 'playlist' )
|
|
|
|
|
return exploded[4];
|
|
|
|
|
if( element == 'artistid' && exploded[1] == 'artist' )
|
|
|
|
|
return exploded[2];
|
|
|
|
|
if( element == 'albumid' && exploded[1] == 'album' )
|
|
|
|
|
return exploded[2];
|
|
|
|
|
if( element == 'trackid' && exploded[1] == 'track' )
|
|
|
|
|
return exploded[2];
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Identify what kind of asset a URI is (playlist, album, etc)
|
|
|
|
|
* @param uri = string
|
|
|
|
|
* @return string
|
|
|
|
|
**/
|
|
|
|
|
function uriType( uri ){
|
|
|
|
|
var exploded = uri.split(':');
|
|
|
|
|
if( exploded[0] == 'spotify' && exploded[1] == 'track' )
|
|
|
|
|
return 'track';
|
|
|
|
|
if( exploded[0] == 'spotify' && exploded[1] == 'artist' )
|
|
|
|
|
return 'artist';
|
|
|
|
|
if( exploded[0] == 'spotify' && exploded[1] == 'album' )
|
|
|
|
|
return 'album';
|
|
|
|
|
if( exploded[0] == 'spotify' && exploded[1] == 'user' && exploded[3] == 'playlist' )
|
|
|
|
|
return 'playlist';
|
|
|
|
|
if( exploded[0] == 'spotify' && exploded[1] == 'user' && exploded.length == 3 )
|
|
|
|
|
return 'user';
|
|
|
|
|
return null;
|
|
|
|
|
}
|