Fiddling with thunk; More library endpoints

This commit is contained in:
James Barnsley
2016-10-20 21:38:01 +13:00
parent d659eec7ab
commit daab2133df
16 changed files with 413 additions and 163 deletions

View File

@ -33,8 +33,18 @@ export function changeTrack( tlid ){
export function playTracks( uris ){
return {
type: 'MOPIDY_PLAY_TRACKS',
uris: uris
}
}
export function enqueueTracks( uris, at_position = false ){
if( typeof(uris) !== 'array' ) uris = [uris];
var value = { uris: uris };
if( at_position ) value.at_position = at_position;
return {
type: 'MOPIDY_ENQUEUE_TRACKS',
call: 'tracklist.add',
value: { at_position: 0, uris: uris }
value: value
}
}
@ -54,3 +64,18 @@ export function instruct( call, value ){
}
}
export function play(){
return instruct('playback.play');
}
export function pause(){
return instruct('playback.pause');
}
export function next(){
return instruct('playback.next');
}
export function previous(){
return instruct('playback.previous');
}

View File

@ -1,6 +1,6 @@
import Mopidy from 'mopidy'
import actions from './actions'
var actions = require('./actions.js')
const MopidyMiddleware = (function(){
@ -38,7 +38,7 @@ const MopidyMiddleware = (function(){
break;
case 'event:volumeChanged':
store.dispatch({ type: 'MOPIDY_Volume', data: data.volume });
store.dispatch({ type: 'MOPIDY_VOLUME', data: data.volume });
break;
case 'event:optionsChanged':
@ -61,8 +61,9 @@ const MopidyMiddleware = (function(){
* @param string model = which Mopidy model (playback, tracklist, etc)
* @param string property = TlTracks, Consume, etc
* @param string value (optional) = value of the property to pass
* @return promise
**/
const instruct = ( ws, store, call, value = false ) => {
const instruct = ( ws, store, call, value = {} ) => {
var callParts = call.split('.');
var model = callParts[0];
@ -71,22 +72,19 @@ const MopidyMiddleware = (function(){
property = property.replace('get','');
property = property.replace('set','');
// if we have a value, we need to include in our payload
if( value ){
return new Promise( (resolve, reject) => {
ws[model][method]( value )
.then(
response => store.dispatch({ type: 'MOPIDY_'+property, model: model, data: response }),
error => console.error( error )
response => {
store.dispatch({ type: 'MOPIDY_'+property.toUpperCase(), model: model, data: response });
resolve(response);
},
error => {
console.error(error)
reject(error);
}
);
// no value, so omit the payload
}else{
ws[model][method]()
.then(
response => store.dispatch({ type: 'MOPIDY_'+property, model: model, data: response }),
error => console.error( error )
);
}
});
}
/**
@ -97,6 +95,7 @@ const MopidyMiddleware = (function(){
* it just proceeds to the next middleware, or default functionality
**/
return store => next => action => {
switch(action.type) {
case 'MOPIDY_CONNECT':
@ -129,10 +128,20 @@ const MopidyMiddleware = (function(){
break;
case 'MOPIDY_PLAY_TRACKS':
var callback = function(){
store.dispatch({ type: 'MOPIDY_TEST', model: 'yeah', data: {} })
}
instruct( socket, store, action.call, action.value, callback )
// add our first track
instruct( socket, store, 'tracklist.add', { uri: action.uris[0], at_position: 0 } )
.then( response => {
// play it
store.dispatch( actions.changeTrack( response[0].tlid ) );
// add the rest of our uris (if any)
action.uris.shift();
if( action.uris.length > 0 ){
store.dispatch( actions.enqueueTracks( action.uris, 1 ) )
}
})
break;
// This action is irrelevant to us, pass it on to the next middleware

View File

@ -2,9 +2,6 @@
export default function reducer(mopidy = {}, action){
switch (action.type) {
case 'MOPIDY_CONNECTING':
return Object.assign({}, mopidy, { connected: false, connecting: true });
case 'MOPIDY_CONNECTED':
return Object.assign({}, mopidy, { connected: true, connecting: false });
@ -25,37 +22,37 @@ export default function reducer(mopidy = {}, action){
/**
* Websocket-initiated actions
**/
case 'MOPIDY_State':
case 'MOPIDY_STATE':
return Object.assign({}, mopidy, {
state: action.data
});
case 'MOPIDY_Consume':
case 'MOPIDY_CONSUME':
return Object.assign({}, mopidy, {
consume: action.data
});
case 'MOPIDY_Random':
case 'MOPIDY_RANDOM':
return Object.assign({}, mopidy, {
random: action.data
});
case 'MOPIDY_Repeat':
case 'MOPIDY_REPEAT':
return Object.assign({}, mopidy, {
repeat: action.data
});
case 'MOPIDY_TlTracks':
case 'MOPIDY_TLTRACKS':
return Object.assign({}, mopidy, {
tracks: action.data
});
case 'MOPIDY_CurrentTlTrack':
case 'MOPIDY_CURRENTTLTRACK':
return Object.assign({}, mopidy, {
trackInFocus: action.data
});
case 'MOPIDY_Volume':
case 'MOPIDY_VOLUME':
return Object.assign({}, mopidy, {
volume: action.data
});

View File

@ -10,25 +10,6 @@ export function setConfig( config ){
}
}
export function startAuthorization(){
return {
type: 'SPOTIFY_START_AUTHORIZATION'
}
}
export function removeAuthorization(){
return {
type: 'SPOTIFY_REMOVE_AUTHORIZATION'
}
}
export function authorizationGranted( data ){
return {
type: 'SPOTIFY_AUTHORIZATION_GRANTED',
data: data
}
}
export function connect(){
return {
type: 'SPOTIFY_CONNECTING'
@ -48,16 +29,176 @@ export function loadAlbum( uri ){
}
}
export function loadArtist( uri ){
return {
type: 'SPOTIFY_LOAD_ARTIST',
uri: uri
/**
* Send an ajax request to the Spotify API
*
* @param endpoint string = the url to query (ie /albums/:uri)
* @param method string
* @param data mixed = request payload
* @return ajax promise
**/
const sendRequest = (token, endpoint, method = 'GET', data = false) => {
var options = {
method: method,
cache: true,
url: 'https://api.spotify.com/v1/'+endpoint,
data: data
};
if( token ){
options.headers = {
Authorization: 'Bearer '+ token
}
}
return $.ajax( options );
}
/**
* Handle authorization process
**/
export function startAuthorization(){
return { type: 'SPOTIFY_START_AUTHORIZATION' }
}
export function authorizationGranted( data ){
return { type: 'SPOTIFY_AUTHORIZATION_GRANTED', data: data }
}
export function removeAuthorization(){
return { type: 'SPOTIFY_REMOVE_AUTHORIZATION' }
}
/**
* 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 id = uri.replace('spotify:artist:','');
var artist = {};
// while we're fiddling about, go get the albums
dispatch(getArtistAlbums(uri));
// get both the artist and the top tracks
$.when(
sendRequest( false, 'artists/'+id )
.then( response => {
Object.assign(artist, response);
}),
sendRequest( false, 'artists/'+id+'/top-tracks?country='+getState().spotify.country )
.then( response => {
Object.assign(artist, response);
})
).then( () => {
dispatch({
type: 'SPOTIFY_ARTIST_LOADED',
data: artist
});
});
}
}
export function loadLibraryArtists(){
return {
type: 'SPOTIFY_LOAD_LIBRARY_ARTISTS'
export function getArtistAlbums( uri ){
return dispatch => {
sendRequest( false, 'artists/'+ uri.replace('spotify:artist:','') +'/albums' )
.then( response => {
dispatch({
type: 'SPOTIFY_ARTIST_ALBUMS_LOADED',
data: response
});
});
}
}
/**
* Single album
*
* @oaram uri string
**/
export function getAlbum( uri ){
return dispatch => {
// flush out the previous store value
dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: false });
sendRequest( false, 'albums/'+ uri.replace('spotify:album:','') )
.then( response => {
// inject the parent album object into each track for consistent track objects
for( var i = 0; i < response.tracks.items.length; i++ ){
response.tracks.items[i].album = {
name: response.name,
uri: response.uri
}
}
dispatch({
type: 'SPOTIFY_ALBUM_LOADED',
data: response
});
});
}
}
export function getLibraryArtists(){
return (dispatch, getState) => {
dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: false });
sendRequest( getState().spotify.access_token, 'me/following?type=artist' )
.then( response => {
dispatch({
type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED',
data: response
});
});
}
}
export function getLibraryAlbums(){
return (dispatch, getState) => {
dispatch({ type: 'SPOTIFY_LIBRARY_ALBUMS_LOADED', data: false });
sendRequest( getState().spotify.access_token, 'me/albums' )
.then( response => {
dispatch({
type: 'SPOTIFY_LIBRARY_ALBUMS_LOADED',
data: response
});
});
}
}
export function getLibraryTracks(){
return (dispatch, getState) => {
dispatch({ type: 'SPOTIFY_LIBRARY_TRACKS_LOADED', data: false });
sendRequest( getState().spotify.access_token, 'me/tracks' )
.then( response => {
dispatch({
type: 'SPOTIFY_LIBRARY_TRACKS_LOADED',
data: response
});
});
}
}

View File

@ -47,67 +47,6 @@ const SpotifyMiddleware = (function(){
});
break;
case 'SPOTIFY_LOAD_ALBUM':
store.dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: false })
var id = action.uri.replace('spotify:album:','');
sendRequest( false, 'albums/'+id )
.then( (response) => {
for( var i = 0; i < response.tracks.items.length; i++ ){
response.tracks.items[i].album = {
name: response.name,
uri: response.uri
}
}
store.dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: response })
});
break;
case 'SPOTIFY_LOAD_ARTIST':
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: false })
store.dispatch({ type: 'SPOTIFY_ARTIST_ALBUMS_LOADED', data: false })
var id = action.uri.replace('spotify:artist:','');
sendRequest( false, 'artists/'+id )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: response })
});
sendRequest( false, 'artists/'+id+'/albums' )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_ARTIST_ALBUMS_LOADED', data: response })
});
sendRequest( false, 'artists/'+id+'/top-tracks?country='+state.spotify.country )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_ARTIST_TRACKS_LOADED', data: response })
});
break;
case 'SPOTIFY_LOAD_LIBRARY_ARTISTS':
store.dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: false })
sendRequest( state.spotify.access_token, 'me/following?type=artist' )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: response })
});
break;
case 'SPOTIFY_CONNECT':
console.log('Spotify wants to connect')
break;
case 'SPOTIFY_DISCONNECT':
console.log('Spotify wants to DISconnect')
break;
// This action is irrelevant to us, pass it on to the next middleware
default:
return next(action);

View File

@ -41,12 +41,12 @@ export default function reducer(spotify = {}, action){
case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
return Object.assign({}, spotify, { artist_albums: action.data });
case 'SPOTIFY_ARTIST_TRACKS_LOADED':
return Object.assign({}, spotify, { artist_top_tracks: action.data });
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED':
return Object.assign({}, spotify, { libraryArtists: action.data });
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED':
return Object.assign({}, spotify, { libraryAlbums: action.data });
default:
return spotify
}