diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js
index fa909f90..8ba7ef11 100755
--- a/src/js/bootstrap.js
+++ b/src/js/bootstrap.js
@@ -1,16 +1,24 @@
console.info('Bootstrapping...');
-import { createStore, applyMiddleware } from 'redux'
-import thunk from 'redux-thunk'
-import reducer from './reducers/index'
-import mopidyMiddleware from './services/mopidy/middleware'
+import { createStore, applyMiddleware, combineReducers } from 'redux'
+
+import mopidy from './services/mopidy/reducer'
+import spotify from './services/spotify/reducer'
+
+import thunk from 'redux-thunk'
+import mopidyMiddleware from './services/mopidy/middleware'
+import spotifyMiddleware from './services/spotify/middleware'
+
+let reducers = combineReducers({
+ mopidy,
+ spotify
+});
-// create our global store
let store = createStore(
- reducer,
+ reducers,
{},
- applyMiddleware( thunk, mopidyMiddleware )
+ applyMiddleware( thunk, mopidyMiddleware, spotifyMiddleware )
);
export default store;
diff --git a/src/js/components/Album.js b/src/js/components/Album.js
index d88e0ae9..0d50b570 100755
--- a/src/js/components/Album.js
+++ b/src/js/components/Album.js
@@ -18,19 +18,21 @@ class Album extends React.Component{
// on render
componentDidMount(){
- this.loadAlbum( this.props.params.id );
+ this.loadAlbum( this.props.params.uri );
}
// when props changed
componentWillReceiveProps( nextProps ){
- if( nextProps.params.id != this.props.params.id ){
- this.loadAlbum( nextProps.params.id );
+ if( nextProps.params.uri != this.props.params.uri ){
+ this.loadAlbum( nextProps.params.uri );
}
}
- loadAlbum( id ){
+ loadAlbum( uri ){
let self = this;
+ var id = uri.replace('spotify:album:','');
+
$.ajax({
method: 'GET',
cache: true,
diff --git a/src/js/components/AlbumLink.js b/src/js/components/AlbumLink.js
new file mode 100755
index 00000000..6119ab18
--- /dev/null
+++ b/src/js/components/AlbumLink.js
@@ -0,0 +1,18 @@
+
+import React, { PropTypes } from 'react'
+import FontAwesome from 'react-fontawesome'
+import { Link } from 'react-router'
+
+export default class AlbumLink extends React.Component{
+
+ constructor(props) {
+ super(props);
+ }
+
+ render(){
+ var link = '/album/' + this.props.album.uri;
+ return (
+ { this.props.album.name }
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/js/components/App.js b/src/js/components/App.js
index 30817054..a2e7924c 100755
--- a/src/js/components/App.js
+++ b/src/js/components/App.js
@@ -7,6 +7,8 @@ import { connect } from 'react-redux'
import * as actions from '../actions/index'
import * as mopidyActions from '../services/mopidy/actions'
+import * as spotifyActions from '../services/spotify/actions'
+import SpotifyAuthenticationFrame from './SpotifyAuthenticationFrame'
/**
@@ -28,12 +30,9 @@ class App extends React.Component{
- Now playing
- - 808's and Heartbreak
- - A million
- Library: Albums
- - Album
- - Authorize
+
{this.props.children}
);
@@ -53,7 +52,8 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = (dispatch) => {
return {
actions: bindActionCreators(actions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch)
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch)
}
}
diff --git a/src/js/components/ArtistList.js b/src/js/components/ArtistList.js
new file mode 100755
index 00000000..e4e8a8a1
--- /dev/null
+++ b/src/js/components/ArtistList.js
@@ -0,0 +1,34 @@
+
+import React, { PropTypes } from 'react'
+import FontAwesome from 'react-fontawesome'
+import { Link } from 'react-router'
+
+export default class ArtistList extends React.Component{
+
+ constructor(props) {
+ super(props);
+ }
+
+ render(){
+ return (
+
+ {
+ this.props.artists.map( (artist, index) => {
+ var separator = null;
+ if( index == this.props.artists.length - 2 ){
+ separator = ' and ';
+ }else if( index < this.props.artists.length - 2 ){
+ separator = ', ';
+ }
+ var link = '/artist/' + artist.uri;
+ return (
+
+ { artist.name }{ separator }
+
+ );
+ })
+ }
+
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/js/components/Player.js b/src/js/components/Player.js
index 5d99a1b4..1b72ccca 100755
--- a/src/js/components/Player.js
+++ b/src/js/components/Player.js
@@ -37,8 +37,12 @@ class Player extends React.Component{
return (
{ playButton }
-
this.props.actions.instruct('playback.previous')}>
-
this.props.actions.instruct('playback.next')}>
+
this.props.actions.instruct('playback.previous')}>
+
+
+
this.props.actions.instruct('playback.next')}>
+
+
{ consumeButton }
{ randomButton }
{ repeatButton }
diff --git a/src/js/components/Queue.js b/src/js/components/Queue.js
index bd45dc31..992d0afd 100755
--- a/src/js/components/Queue.js
+++ b/src/js/components/Queue.js
@@ -7,6 +7,8 @@ import FontAwesome from 'react-fontawesome'
import TrackList from '../components/TrackList'
import Track from '../components/Track'
import Player from '../components/Player'
+import ArtistList from '../components/ArtistList'
+import AlbumLink from '../components/AlbumLink'
import * as actions from '../services/mopidy/actions'
class Queue extends React.Component{
@@ -18,7 +20,11 @@ class Queue extends React.Component{
renderTrackInFocus(){
if( this.props.mopidy && this.props.mopidy.trackInFocus ){
return (
-
{ this.props.mopidy.trackInFocus.track.name }
+
+
{ this.props.mopidy.trackInFocus.track.name }
+
+
+
);
}
return null;
diff --git a/src/js/components/SpotifyAuthenticationFrame.js b/src/js/components/SpotifyAuthenticationFrame.js
new file mode 100755
index 00000000..216d09a8
--- /dev/null
+++ b/src/js/components/SpotifyAuthenticationFrame.js
@@ -0,0 +1,43 @@
+
+import React, { PropTypes } from 'react'
+import { connect } from 'react-redux'
+import { createStore, bindActionCreators } from 'redux'
+
+import * as actions from '../services/spotify/actions'
+
+class SpotifyAuthenticationFrame extends React.Component{
+
+ constructor(props) {
+ super(props);
+ }
+
+ handleClick(e){
+ console.log('handling click')
+ this.props.actions.authorize();
+ }
+
+ render(){
+ var src = '//jamesbarnsley.co.nz/spotmop.php?action=frame';
+ if( this.props.spotify.authorizing ){
+ src = '//jamesbarnsley.co.nz/spotmop.php?action=authorize&app='+location.protocol+'//'+window.location.host;
+ }
+ return (
+
+
+
+
+ );
+ }
+}
+
+const mapStateToProps = (state, ownProps) => {
+ return state;
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ actions: bindActionCreators(actions, dispatch)
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(SpotifyAuthenticationFrame)
\ No newline at end of file
diff --git a/src/js/components/Track.js b/src/js/components/Track.js
index df92f06c..daa2e790 100755
--- a/src/js/components/Track.js
+++ b/src/js/components/Track.js
@@ -1,6 +1,8 @@
import React, { PropTypes } from 'react'
import FontAwesome from 'react-fontawesome'
+import ArtistList from './ArtistList'
+import AlbumLink from './AlbumLink'
export default class Track extends React.Component{
@@ -24,9 +26,13 @@ export default class Track extends React.Component{
}
return (
-
this.playTrack(e) }>
-
this.toggleSelected(e) } />
- #{this.props.track.uri}: {this.props.track.name}
+ this.playTrack(e) }>
+
this.toggleSelected(e) } />
+ {this.props.track.name}
+
+ { this.props.track.album ? : null }
);
}
diff --git a/src/js/components/TrackList.js b/src/js/components/TrackList.js
index e500de16..ddf2d3be 100755
--- a/src/js/components/TrackList.js
+++ b/src/js/components/TrackList.js
@@ -24,8 +24,22 @@ class TrackList extends React.Component{
playTrack( index ){
var tracks = this.state.tracks;
- console.log('playTrack', tracks[index].tlid)
- this.props.actions.changeTrack( index )
+ this.props.actions.changeTrack( tracks[index].tlid )
+ }
+
+ deleteSelected(){
+
+ function isSelected( track ){
+ return ( typeof(track.selected) !== 'undefined' && track.selected );
+ }
+
+ var selectedTracks = this.state.tracks.filter(isSelected)
+ var selectedTracksTlids = [];
+ for( var i = 0; i < selectedTracks.length; i++ ){
+ selectedTracksTlids.push( selectedTracks[i].tlid )
+ }
+
+ this.props.actions.removeTracks( selectedTracksTlids )
}
componentWillReceiveProps( nextProps ){
@@ -36,28 +50,31 @@ class TrackList extends React.Component{
let self = this;
if( this.state.tracks ){
return (
-
- {
- this.state.tracks.map(
- (track, index) => {
+
+
+ {
+ this.state.tracks.map(
+ (track, index) => {
- // flatten nested track objects (as in the case of TlTracks)
- if( typeof(track.track) !== 'undefined' ){
- for( var property in track.track ){
- if( track.track.hasOwnProperty(property) ){
- track[property] = track.track[property]
+ // flatten nested track objects (as in the case of TlTracks)
+ if( typeof(track.track) !== 'undefined' ){
+ for( var property in track.track ){
+ if( track.track.hasOwnProperty(property) ){
+ track[property] = track.track[property]
+ }
}
}
+ return
+ )
+ }
+
+
+
);
}
return null;
diff --git a/src/js/index.js b/src/js/index.js
index 3ca212c8..65add352 100755
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -18,7 +18,7 @@ ReactDOM.render(
-
+
diff --git a/src/js/services/MopidyService.js b/src/js/services/MopidyService.js
deleted file mode 100755
index 83663429..00000000
--- a/src/js/services/MopidyService.js
+++ /dev/null
@@ -1,183 +0,0 @@
-
-import Mopidy from 'mopidy'
-import React, { PropTypes } from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-import FontAwesome from 'react-fontawesome'
-
-import * as actions from '../services/mopidy/actions'
-
-
-/**
- * Mopidy service
- *
- * Handles internal requests and passes them on to our connection
- **/
-class MopidyService extends React.Component{
-
- constructor( props ){
- super(props);
-/*
- this.connection = new Mopidy({
- webSocketUrl: "ws://tv.barnsley.nz:6680/mopidy/ws",
- //webSocketUrl: "ws://music.james:6680/mopidy/ws",
- callingConvention: 'by-position-or-by-name'
- });
-
- this.connection.on( (type, data) => this.handleMessage( type, data ) );
- */
- }
-
- componentDidMount(){
-
- this.props.actions.connect();
- }
-
- handleMessage( type, data ){
- switch( type ){
-
- case 'state:online':
- this.props.actions.updateStatus( true );
- this.get( 'playback', 'State' );
- this.get( 'playback', 'Volume' );
- this.get( 'tracklist', 'Consume' );
- this.get( 'tracklist', 'Random' );
- this.get( 'tracklist', 'Repeat' );
- this.get( 'tracklist', 'TlTracks' );
- this.get( 'playback', 'CurrentTlTrack' );
- break;
-
- case 'state:offline':
- this.props.actions.updateStatus( false );
- break;
-
- case 'event:tracklistChanged':
- this.get( 'tracklist', 'TlTracks' );
- break;
-
- //case 'event:trackPlaybackEnded':
- case 'event:playbackStateChanged':
- case 'event:trackPlaybackStarted':
- this.get( 'playback', 'State' );
- this.get( 'playback', 'CurrentTlTrack' );
- break;
-
- case 'event:volumeChanged':
- this.props.actions.updateVolume( data.volume );
- break;
-
- case 'event:optionsChanged':
- this.get( 'tracklist', 'Consume' );
- this.get( 'tracklist', 'Random' );
- this.get( 'tracklist', 'Repeat' );
- break;
-
- default:
- //console.log( 'MopidyService: Unhandled event', type, message );
- }
- }
-
-
- /**
- * Get something from Mopidy
- *
- * Sends request to Mopidy server, and updates our local storage on return
- * @param string model Mopidy model (playback, tracklist, etc)
- * @param string property the property to get (TlTracks, Consume, etc)
- **/
- get( model, property ){
- console.log('MopidyService: '+model+'.get'+property);
- let self = this;
- this.connection[model]['get'+property]()
- .then(
- function( response ){
- self.props.actions['update'+property]( response );
- },
- function( error ){
- console.error( error );
- }
- );
- }
-
-
- /**
- * Set something in Mopidy
- *
- * Sends request to Mopidy server, and updates our local storage on return
- * @param string model Mopidy model (playback, tracklist, etc)
- * @param string property the property to get (TlTracks, Consume, etc)
- * @param mixed value
- **/
- set( model, property, value ){
- console.log('MopidyServie: '+model+'.set'+property, value);
- let self = this;
- this.connection[model]['set'+property]( value )
- .then(
- function( response ){
- self.props.actions['update'+property]( response );
- },
- function( error ){
- console.error( error );
- }
- );
- }
-
- changeTlTrack( tlid ){
- console.log('Changing track to '+ tlid)
- }
-
-
- render(){
- console.log( this.props.mopidy );
- var playButton = this.connection.playback.play()}>
- if( this.props.mopidy.state == 'playing' ){
- playButton = this.connection.playback.pause()}>
- }
-
- var consumeButton = this.set('tracklist', 'Consume', [true])}>Consume
- if( this.props.mopidy.consume ){
- consumeButton = this.set('tracklist', 'Consume', [false])}>Un-Consume
- }
-
- var randomButton = this.set('tracklist', 'Random', [true])}>Random
- if( this.props.mopidy.random ){
- randomButton = this.set('tracklist', 'Random', [false])}>Un-Random
- }
-
- var repeatButton = this.set('tracklist', 'Repeat', [true])}>Repeat
- if( this.props.mopidy.repeat ){
- repeatButton = this.set('tracklist', 'Repeat', [false])}>Un-Repeat
- }
-
- return (
-
- );
- }
-}
-
-
-/**
- * Export our component
- *
- * We also integrate our global store, using connect()
- **/
-
-const mapStateToProps = (state, ownProps) => {
- return state;
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- actions: bindActionCreators(actions, dispatch)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(MopidyService)
\ No newline at end of file
diff --git a/src/js/services/Services.js b/src/js/services/Services.js
deleted file mode 100755
index 5136678b..00000000
--- a/src/js/services/Services.js
+++ /dev/null
@@ -1,11 +0,0 @@
-
-import ServicesContainer from 'kioc';
-
-import MopidyService from './MopidyService';
-import SpotifyService from './SpotifyService';
-
-var Services = new ServicesContainer();
-Services.use(MopidyService, true);
-//Services.use(SpotifyService, true);
-
-export default Services;
\ No newline at end of file
diff --git a/src/js/services/SpotifyService.js b/src/js/services/SpotifyService.js
deleted file mode 100755
index 51f828d3..00000000
--- a/src/js/services/SpotifyService.js
+++ /dev/null
@@ -1,79 +0,0 @@
-
-import React, { PropTypes } from 'react'
-import * as actions from '../actions/spotifyActions'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-
-class SpotifyService extends React.Component{
-
- constructor(props){
- super(props);
- let self = this;
- this.urlBase = 'https://api.spotify.com/v1/';
- console.log('SpotifyProvider > constructor')
-
- // listen for incoming messages from the authorization iframe
- // this is triggered when authentication is granted from the popup
- window.addEventListener('message', function(event){
- if( !/^https?:\/\/jamesbarnsley\.co\.nz/.test(event.origin) ) return false;
- self.handleMessage( event );
- }, false);
- }
-
- handleMessage( event ){
-
- // convert to json
- var data = JSON.parse(event.data);
-
- // fire event
- this.props.actions.authorizeSpotifySuccess( data );
- }
-
- test(){
- console.log('test stuff');
- }
-
- getAlbum( albumid ){
- return $.when(
- $.ajax({
- method: 'GET',
- cache: true,
- url: this.urlBase+'albums/'+albumid
- })
- );
- }
-
- render(){
-
- if( this.props.config.authorizingSpotify ){
- var src = '//jamesbarnsley.co.nz/spotmop.php?action=authorize&app='+location.protocol+'//'+window.location.host;
- return (
-
- Authorizing...
-
-
- );
- }
-
- return null
- }
-}
-
-
-/**
- * Export our component
- *
- * We also integrate our global store, using connect()
- **/
-
-const mapStateToProps = (state, ownProps) => {
- return state;
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- actions: bindActionCreators(actions, dispatch)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(SpotifyService)
\ No newline at end of file
diff --git a/src/js/services/mopidy/actions.js b/src/js/services/mopidy/actions.js
index fd3972c2..b00a8b65 100755
--- a/src/js/services/mopidy/actions.js
+++ b/src/js/services/mopidy/actions.js
@@ -5,19 +5,35 @@
export function connect(){
return {
- type: 'CONNECT'
+ type: 'MOPIDY_CONNECT'
}
}
export function disconnect(){
return {
- type: 'DISCONNECT'
+ type: 'MOPIDY_DISCONNECT'
+ }
+}
+
+export function changeTrack( tlid ){
+ return {
+ type: 'MOPIDY_CHANGE_TRACK',
+ call: 'playback.play',
+ value: { tlid: tlid }
+ }
+}
+
+export function removeTracks( tlids ){
+ return {
+ type: 'MOPIDY_REMOVE_TRACKS',
+ call: 'tracklist.remove',
+ value: { tlid: tlids }
}
}
export function instruct( call, value ){
return {
- type: 'INSTRUCT',
+ type: 'MOPIDY_INSTRUCT',
call: call,
value: value
}
diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js
index ba0ba0ab..74b33c74 100755
--- a/src/js/services/mopidy/middleware.js
+++ b/src/js/services/mopidy/middleware.js
@@ -4,27 +4,15 @@ import actions from './actions'
const MopidyMiddleware = (function(){
+ // container for the actual Mopidy socket
var socket = null;
- const onOpen = (ws, store, token) => evt => {
- console.log('opened')
- //Send a handshake, or authenticate with remote end
-
- //Tell the store we're connected
- //store.dispatch(actions.connected());
- }
-
- const onClose = (ws, store) => evt => {
- //Tell the store we've disconnected
- //store.dispatch(actions.disconnected());
- }
-
+ // handle all manner of socket messages
const handleMessage = (ws, store, type, data) => {
-
switch( type ){
case 'state:online':
- //store.dispatch( actions.updateStatus( true ) );
+ store.dispatch({ type: 'MOPIDY_CONNECTED' });
instruct( ws, store, 'playback.getState' );
instruct( ws, store, 'playback.getVolume' );
instruct( ws, store, 'tracklist.getConsume' );
@@ -35,7 +23,7 @@ const MopidyMiddleware = (function(){
break;
case 'state:offline':
- store.dispatch( actions.updateStatus( false ) );
+ store.dispatch({ type: 'MOPIDY_DISCONNECTED' });
break;
case 'event:tracklistChanged':
@@ -50,7 +38,7 @@ const MopidyMiddleware = (function(){
break;
case 'event:volumeChanged':
- store.dispatch( actions.updateVolume( data.volume ) );
+ store.dispatch({ type: 'MOPIDY_Volume', data: data.volume });
break;
case 'event:optionsChanged':
@@ -60,35 +48,22 @@ const MopidyMiddleware = (function(){
break;
default:
- //console.log( 'MopidyService: Unhandled event', type, message );
+ //console.log( 'MopidyService: Unhandled message', type, message );
}
}
- function doStuff( ws, store ){
- console.log('doing stuff', store);
- ws.playback.getState()
- .then(
- response => {
- store.dispatch({ type: 'STATE', state: response })
- },
- error => {
- console.error( error );
- }
- );
- }
-
-
/**
- * Get something from Mopidy
+ * Call something with Mopidy
*
* Sends request to Mopidy server, and updates our local storage on return
- * @param object ws Websocket
- * @param string model Mopidy model (playback, tracklist, etc)
- * @param string property the property to get (TlTracks, Consume, etc)
+ * @param object ws = Mopidy class that wraps a Websocket
+ * @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
**/
const instruct = ( ws, store, call, value = false ) => {
- console.log('Mopidy: '+call, value);
+
var callParts = call.split('.');
var model = callParts[0];
var method = callParts[1];
@@ -96,30 +71,38 @@ 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 ){
ws[model][method]( value )
.then(
- response => store.dispatch({ type: property, model: model, data: response }),
+ response => store.dispatch({ type: 'MOPIDY_'+property, model: model, data: response }),
error => console.error( error )
);
+
+ // no value, so omit the payload
}else{
ws[model][method]()
.then(
- response => store.dispatch({ type: property, model: model, data: response }),
+ response => store.dispatch({ type: 'MOPIDY_'+property, model: model, data: response }),
error => console.error( error )
);
}
}
+ /**
+ * Middleware
+ *
+ * This behaves like an action interceptor. We listen for specific actions
+ * and handle special functionality. If the action is not in our switch, then
+ * it just proceeds to the next middleware, or default functionality
+ **/
return store => next => action => {
-
switch(action.type) {
- //The user wants us to connect
- case 'CONNECT':
+ case 'MOPIDY_CONNECT':
if(socket != null) socket.close();
- store.dispatch({ type: 'CONNECTING' });
+ store.dispatch({ type: 'MOPIDY_CONNECTING' });
socket = new Mopidy({
webSocketUrl: "ws://tv.barnsley.nz:6680/mopidy/ws",
@@ -130,19 +113,20 @@ const MopidyMiddleware = (function(){
break;
- //The user wants us to disconnect
- case 'DISCONNECT':
+ case 'MOPIDY_DISCONNECT':
if(socket != null) socket.close();
socket = null;
- store.dispatch({ type: 'DISCONNECTED' });
+ store.dispatch({ type: 'MOPIDY_DISCONNECTED' });
break;
- //Send the 'SEND_MESSAGE' action down the websocket to the server
- case 'INSTRUCT':
+ // send an instruction to the websocket
+ case 'MOPIDY_INSTRUCT':
+ case 'MOPIDY_CHANGE_TRACK':
+ case 'MOPIDY_REMOVE_TRACKS':
instruct( socket, store, action.call, action.value )
break;
- //This action is irrelevant to us, pass it on to the next middleware
+ // This action is irrelevant to us, pass it on to the next middleware
default:
return next(action);
}
diff --git a/src/js/services/mopidy/reducer.js b/src/js/services/mopidy/reducer.js
index 8a2cec12..beafffc9 100755
--- a/src/js/services/mopidy/reducer.js
+++ b/src/js/services/mopidy/reducer.js
@@ -2,53 +2,56 @@
export default function reducer(mopidy = {}, action){
switch (action.type) {
- case 'CONNECTING':
+ case 'MOPIDY_CONNECTING':
return Object.assign({}, mopidy, { connected: false, connecting: true });
- case 'CONNECTED':
+ case 'MOPIDY_CONNECTED':
return Object.assign({}, mopidy, { connected: true, connecting: false });
- case 'DISCONNECTED':
+ case 'MOPIDY_DISCONNECTED':
return Object.assign({}, mopidy, { connected: false, connecting: false });
- case 'State':
+ case 'MOPIDY_CHANGE_TRACK':
+ return Object.assign({}, mopidy, {
+ tlid: action.tlid
+ });
+
+ /**
+ * Websocket-initiated actions
+ **/
+ case 'MOPIDY_State':
return Object.assign({}, mopidy, {
state: action.data
});
- case 'Consume':
+ case 'MOPIDY_Consume':
return Object.assign({}, mopidy, {
consume: action.data
});
- case 'Random':
+ case 'MOPIDY_Random':
return Object.assign({}, mopidy, {
random: action.data
});
- case 'Repeat':
+ case 'MOPIDY_Repeat':
return Object.assign({}, mopidy, {
repeat: action.data
});
- case 'TlTracks':
+ case 'MOPIDY_TlTracks':
return Object.assign({}, mopidy, {
- tracks: action.data
+ tracks: action.data
});
- case 'CurrentTlTrack':
+ case 'MOPIDY_CurrentTlTrack':
return Object.assign({}, mopidy, {
- trackInFocus: action.data
+ trackInFocus: action.data
});
- case 'Volume':
+ case 'MOPIDY_Volume':
return Object.assign({}, mopidy, {
- volume: action.volume
- });
-
- case 'CHANGE_TRACK':
- return Object.assign({}, mopidy, {
- tlid: action.tlid
+ volume: action.data
});
default:
diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js
new file mode 100755
index 00000000..8640ac1c
--- /dev/null
+++ b/src/js/services/spotify/actions.js
@@ -0,0 +1,30 @@
+
+/**
+ * Actions and Action Creators
+ **/
+
+export function authorize(){
+ return {
+ type: 'SPOTIFY_AUTHORIZING'
+ }
+}
+
+export function connect(){
+ return {
+ type: 'SPOTIFY_CONNECTING'
+ }
+}
+
+export function disconnect(){
+ return {
+ type: 'SPOTIFY_DISCONNECT'
+ }
+}
+
+export function loadAlbum( uri ){
+ return {
+ type: 'SPOTIFY_LOAD_ALBUM',
+ uri: uri
+ }
+}
+
diff --git a/src/js/services/spotify/middleware.js b/src/js/services/spotify/middleware.js
new file mode 100755
index 00000000..a04eccd1
--- /dev/null
+++ b/src/js/services/spotify/middleware.js
@@ -0,0 +1,28 @@
+
+import actions from './actions'
+
+const SpotifyMiddleware = (function(){
+
+ return store => next => action => {
+
+ switch(action.type) {
+
+ 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);
+ }
+ }
+
+})();
+
+export default SpotifyMiddleware
\ No newline at end of file
diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js
new file mode 100755
index 00000000..736832c8
--- /dev/null
+++ b/src/js/services/spotify/reducer.js
@@ -0,0 +1,23 @@
+
+export default function reducer(spotify = {}, action){
+ switch (action.type) {
+
+ case 'SPOTIFY_CONNECTING':
+ return Object.assign({}, spotify, { connected: false, connecting: true });
+
+ case 'SPOTIFY_AUTHORIZING':
+ return Object.assign({}, spotify, { authorizing: true });
+
+ case 'SPOTIFY_CONNECTED':
+ return Object.assign({}, spotify, { connected: true, connecting: false });
+
+ case 'SPOTIFY_DISCONNECTED':
+ return Object.assign({}, spotify, { connected: false, connecting: false });
+
+ default:
+ return spotify
+ }
+}
+
+
+