Merge pull request #38 from jaedb/feature/playlist-pool
Asset index storage
This commit is contained in:
2
build.sh
2
build.sh
@ -20,5 +20,7 @@ CACHEBUSTER=$(date | md5sum | cut -f1 -d' ')
|
||||
echo -e Cachebusting js/css URLs $CACHEBUSTER
|
||||
sed -i 's/app.js/app.min.js?'$CACHEBUSTER'/g' mopidy_iris/static/index.html
|
||||
sed -i 's/app.css/app.min.css?'$CACHEBUSTER'/g' mopidy_iris/static/index.html
|
||||
sed -i 's/app.js/app.js?'$CACHEBUSTER'/g' mopidy_iris/static/test.html
|
||||
sed -i 's/app.css/app.css?'$CACHEBUSTER'/g' mopidy_iris/static/test.html
|
||||
|
||||
echo -e "\x1b[32;01m"Done!"\x1b[39;49;00m"
|
||||
1
src/js/bootstrap.js
vendored
1
src/js/bootstrap.js
vendored
@ -65,6 +65,7 @@ var initialState = {
|
||||
playlists: [],
|
||||
tracks: []
|
||||
},
|
||||
library_playlists: [],
|
||||
playlists: [],
|
||||
notifications: []
|
||||
}
|
||||
|
||||
@ -16,14 +16,16 @@ export default class ArtistSentence extends React.Component{
|
||||
<span className={ this.props.className ? this.props.className+" artist-sentence" : "artist-sentence" }>
|
||||
{
|
||||
this.props.artists.map( (artist, index) => {
|
||||
if (!artist) return <span>-</span>
|
||||
var separator = null;
|
||||
if( index == this.props.artists.length - 2 ){
|
||||
separator = ' and ';
|
||||
}else if( index < this.props.artists.length - 2 ){
|
||||
separator = ', ';
|
||||
}
|
||||
if( !artist.name ) artist.name = '-'
|
||||
if( artist.uri ){
|
||||
if (!artist.name){
|
||||
var content = <span>-</span>
|
||||
} else if (artist.uri){
|
||||
var content = <Link className="artist" to={global.baseURL+'artist/'+artist.uri}>{ artist.name }</Link>
|
||||
}else{
|
||||
var content = <span>{ artist.name }</span>
|
||||
|
||||
@ -30,9 +30,8 @@ class FollowButton extends React.Component{
|
||||
|
||||
render(){
|
||||
if( !this.props.spotify_authorized || !this.props.uri ) return false
|
||||
var item = this.props[helpers.uriType( this.props.uri )]
|
||||
|
||||
if( item.following === true ){
|
||||
if( this.props.is_following === true ){
|
||||
return <button className="tertiary large" onClick={ () => this.remove() }>{ this.props.removeText }</button>
|
||||
}else{
|
||||
return <button className="tertiary large" onClick={ () => this.add() }>{ this.props.addText }</button>
|
||||
@ -42,11 +41,7 @@ class FollowButton extends React.Component{
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
spotify_authorized: state.spotify.authorized,
|
||||
artist: state.ui.artist,
|
||||
user: state.ui.user,
|
||||
album: state.ui.album,
|
||||
playlist: state.ui.playlist
|
||||
spotify_authorized: state.spotify.authorized
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,32 @@ export default class GridItem extends React.Component{
|
||||
return <Thumbnail size="medium" images={[]} />
|
||||
}
|
||||
|
||||
renderSecondary(item){
|
||||
var output = ''
|
||||
|
||||
switch (item.type){
|
||||
|
||||
case 'playlist':
|
||||
return (
|
||||
<span>
|
||||
{ item.tracks_total ? item.tracks_total+' tracks' : null }
|
||||
{ item.can_edit ? <FontAwesome name="edit" /> : null }
|
||||
</span>
|
||||
)
|
||||
break
|
||||
|
||||
default:
|
||||
return (
|
||||
<span>
|
||||
{ item.artists ? <ArtistSentence artists={ item.artists } /> : null }
|
||||
{ item.followers ? item.followers.total.toLocaleString()+' followers' : null }
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.item ) return null
|
||||
|
||||
@ -37,10 +63,7 @@ export default class GridItem extends React.Component{
|
||||
{ this.renderThumbnail() }
|
||||
<div className="name">{ item.name }</div>
|
||||
<div className="secondary">
|
||||
{ item.artists ? <ArtistSentence artists={ item.artists } /> : null }
|
||||
{ item.type == 'playlist' && item.tracks ? item.tracks.total+' tracks' : null }
|
||||
{ item.followers ? item.followers.total.toLocaleString()+' followers' : null }
|
||||
{ item.type == 'playlist' && item.can_edit ? <FontAwesome name="edit" /> : null }
|
||||
{ this.renderSecondary(item) }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -18,7 +18,7 @@ export default class List extends React.Component{
|
||||
|
||||
// make sure we haven't clicked a nested link (ie Artist name)
|
||||
if( e.target.tagName.toLowerCase() !== 'a' ){
|
||||
hashHistory.push( this.props.link_prefix + encodeURIComponent(uri) );
|
||||
hashHistory.push( this.props.link_prefix + uri );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,12 +13,7 @@ export default class Thumbnail extends React.Component{
|
||||
shouldComponentUpdate(nextProps, nextState){
|
||||
|
||||
// no images at all, and we already know it
|
||||
if(
|
||||
typeof(nextProps.image) == 'undefined' &&
|
||||
typeof(this.props.image) == 'undefined' &&
|
||||
typeof(nextProps.images) == 'undefined' &&
|
||||
typeof(this.props.images) == 'undefined'
|
||||
) return false
|
||||
if (!nextProps.image && !this.props.image && !nextProps.images && !this.props.images) return false
|
||||
|
||||
// image changed
|
||||
if( !this.props.image && nextProps.image ) return true
|
||||
|
||||
@ -245,7 +245,7 @@ class TrackList extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.state.tracks ) return null
|
||||
if( !this.state.tracks || Object.prototype.toString.call(this.state.tracks) !== '[object Array]' ) return null
|
||||
|
||||
let self = this;
|
||||
return (
|
||||
|
||||
@ -93,6 +93,28 @@ export let getTrackIcon = function( track = false ){
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a track's icon
|
||||
* @param track object
|
||||
* @return string
|
||||
**/
|
||||
export let flattenTracks = function( tracks ){
|
||||
var flattened = []
|
||||
for( var i = 0; i < tracks.length; i++ ){
|
||||
flattened.push( Object.assign(
|
||||
{},
|
||||
tracks[i].track,
|
||||
{
|
||||
added_by: tracks[i].added_by,
|
||||
added_at: tracks[i].added_at
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
return flattened
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -174,6 +196,18 @@ export let uriType = function( uri ){
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a raw URI into a object index-friendly format. Primarily used for loading local playlists
|
||||
* @param $uri = string
|
||||
* @return string
|
||||
**/
|
||||
export let indexFriendlyUri = function (uri){
|
||||
var output = encodeURI(uri)
|
||||
output = output.replace("'",'%27')
|
||||
return output
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Digest an array of objects, and pull into simple array of uris
|
||||
*
|
||||
|
||||
@ -27,11 +27,8 @@ const sendRequest = ( dispatch, getState, params ) => {
|
||||
})
|
||||
}
|
||||
|
||||
export function getArtist( artist, mbid = false ){
|
||||
export function getArtist( uri, artist, mbid = false ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'LASTFM_ARTIST_LOADED', data: false });
|
||||
|
||||
if( mbid ){
|
||||
var params = 'method=artist.getInfo&mbid='+mbid
|
||||
}else{
|
||||
@ -43,8 +40,12 @@ export function getArtist( artist, mbid = false ){
|
||||
response => {
|
||||
if( response.artist ){
|
||||
dispatch({
|
||||
type: 'LASTFM_ARTIST_LOADED',
|
||||
data: response.artist
|
||||
type: 'ARTIST_LOADED',
|
||||
uri: uri,
|
||||
artist: {
|
||||
images: response.artist.image,
|
||||
bio: response.artist.bio
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,47 +157,47 @@ export function deletePlaylist( uri ){
|
||||
}
|
||||
}
|
||||
|
||||
export function getPlaylists(){
|
||||
return { type: 'MOPIDY_PLAYLISTS' }
|
||||
export function getLibraryPlaylists(){
|
||||
return { type: 'MOPIDY_GET_LIBRARY_PLAYLISTS' }
|
||||
}
|
||||
|
||||
export function getPlaylist( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_PLAYLIST',
|
||||
type: 'MOPIDY_GET_PLAYLIST',
|
||||
data: { uri: uri }
|
||||
}
|
||||
}
|
||||
|
||||
export function getDirectory( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_DIRECTORY',
|
||||
data: { uri: uri }
|
||||
}
|
||||
}
|
||||
|
||||
export function getAlbum( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_ALBUM',
|
||||
type: 'MOPIDY_GET_DIRECTORY',
|
||||
data: { uri: uri }
|
||||
}
|
||||
}
|
||||
|
||||
export function getArtist( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_ARTIST',
|
||||
type: 'MOPIDY_GET_ARTIST',
|
||||
data: { uri: uri }
|
||||
}
|
||||
}
|
||||
|
||||
export function getArtists(){
|
||||
return {
|
||||
type: 'MOPIDY_ARTISTS'
|
||||
type: 'MOPIDY_GET_ARTISTS'
|
||||
}
|
||||
}
|
||||
|
||||
export function getAlbum( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_GET_ALBUM',
|
||||
data: { uri: uri }
|
||||
}
|
||||
}
|
||||
|
||||
export function getAlbums(){
|
||||
return {
|
||||
type: 'MOPIDY_ALBUMS'
|
||||
type: 'MOPIDY_GET_ALBUMS'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -282,57 +282,75 @@ const MopidyMiddleware = (function(){
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_PLAYLISTS':
|
||||
|
||||
/**
|
||||
* =============================================================== PLAYLIST(S) ==========
|
||||
* ======================================================================================
|
||||
**/
|
||||
|
||||
case 'MOPIDY_GET_LIBRARY_PLAYLISTS':
|
||||
instruct( socket, store, 'playlists.asList' )
|
||||
.then( response => {
|
||||
for( var i = 0; i < response.length; i++ ){
|
||||
if( response[i].uri.startsWith('m3u:')) response[i] = Object.assign({}, response[i], { can_edit: true })
|
||||
}
|
||||
store.dispatch({ type: 'MOPIDY_PLAYLISTS_LOADED', data: response });
|
||||
|
||||
// TODO: dispatch an action to fetch extra data for each playlist
|
||||
// this will then trigger an PLAYLIST_REFRESHED action to update a specific store item
|
||||
// drop in our URI list
|
||||
var playlist_uris = helpers.asURIs(response)
|
||||
|
||||
store.dispatch({ type: 'LIBRARY_PLAYLISTS_LOADED', uris: playlist_uris });
|
||||
|
||||
// get the full playlist objects
|
||||
for (var i = 0; i < response.length; i++ ){
|
||||
instruct( socket, store, 'playlists.lookup', { uri: response[i].uri })
|
||||
.then( response => {
|
||||
var playlist = Object.assign(
|
||||
{},
|
||||
{
|
||||
type: 'playlist',
|
||||
name: response.name,
|
||||
uri: response.uri,
|
||||
last_modified: response.last_modified,
|
||||
can_edit: (response.uri.startsWith('m3u:')),
|
||||
tracks_total: ( response.tracks ? response.tracks.length : 0 )
|
||||
}
|
||||
)
|
||||
|
||||
store.dispatch({
|
||||
type: 'PLAYLIST_LOADED',
|
||||
uri: playlist.uri,
|
||||
playlist: playlist
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_CREATE_PLAYLIST':
|
||||
instruct( socket, store, 'playlists.create', { name: action.name, uri_scheme: action.scheme })
|
||||
.then( response => {
|
||||
|
||||
// re-load our global playlists
|
||||
store.dispatch({ type: 'MOPIDY_PLAYLISTS' });
|
||||
});
|
||||
break
|
||||
|
||||
case 'MOPIDY_PLAYLIST':
|
||||
case 'MOPIDY_GET_PLAYLIST':
|
||||
store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: false });
|
||||
instruct( socket, store, 'playlists.lookup', action.data )
|
||||
.then( response => {
|
||||
var playlist = Object.assign(
|
||||
{},
|
||||
{
|
||||
images: []
|
||||
},
|
||||
response,
|
||||
{
|
||||
tracks: ( response.tracks ? response.tracks : [] ),
|
||||
tracks_total: ( response.tracks ? response.tracks.length : 0 )
|
||||
type: 'playlist',
|
||||
tracks: ( response.tracks ? response.tracks : null ),
|
||||
tracks_total: ( response.tracks ? response.tracks.length : null )
|
||||
}
|
||||
)
|
||||
|
||||
// tracks? get the full track objects
|
||||
if( playlist.tracks.length > 0 ) store.dispatch({ type: 'MOPIDY_PLAYLIST_TRACKS', tracks: playlist.tracks })
|
||||
if( playlist.tracks.length > 0 ) store.dispatch({ type: 'MOPIDY_RESOLVE_PLAYLIST_TRACKS', tracks: playlist.tracks, uri: response.uri })
|
||||
|
||||
store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: playlist })
|
||||
store.dispatch({
|
||||
type: 'PLAYLIST_LOADED',
|
||||
uri: playlist.uri,
|
||||
playlist: playlist
|
||||
})
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_PLAYLIST_TRACKS':
|
||||
case 'MOPIDY_RESOLVE_PLAYLIST_TRACKS':
|
||||
var tracks = Object.assign([], action.tracks)
|
||||
var uris = [];
|
||||
for( var i = 0; i < tracks.length; i++ ){
|
||||
uris.push( tracks[i].uri );
|
||||
}
|
||||
var uris = helpers.asURIs(tracks)
|
||||
|
||||
instruct( socket, store, 'library.lookup', { uris: uris } )
|
||||
.then( response => {
|
||||
@ -357,13 +375,17 @@ const MopidyMiddleware = (function(){
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch({ type: 'PLAYLIST_TRACKS_LOADED', tracks: tracks })
|
||||
store.dispatch({
|
||||
type: 'PLAYLIST_TRACKS',
|
||||
tracks: tracks,
|
||||
uri: action.uri
|
||||
})
|
||||
})
|
||||
break
|
||||
|
||||
case 'MOPIDY_ADD_PLAYLIST_TRACKS':
|
||||
|
||||
instruct( socket, store, 'playlists.lookup', { uri: action.playlist_uri })
|
||||
instruct( socket, store, 'playlists.lookup', { uri: action.uri })
|
||||
.then( response => {
|
||||
var tracks = [];
|
||||
for( var i = 0; i < action.tracks_uris.length; i++ ){
|
||||
@ -382,7 +404,7 @@ const MopidyMiddleware = (function(){
|
||||
|
||||
instruct( socket, store, 'playlists.save', { playlist: playlist } )
|
||||
.then( response => {
|
||||
store.dispatch({ type: 'PLAYLIST_TRACKS_ADDED', tracks_uris: action.tracks_uris });
|
||||
store.dispatch({ type: 'PLAYLIST_TRACKS_ADDED', uri: action.uri, tracks_uris: action.tracks_uris });
|
||||
})
|
||||
});
|
||||
break
|
||||
@ -396,7 +418,7 @@ const MopidyMiddleware = (function(){
|
||||
var indexes = Object.assign([], action.tracks_indexes)
|
||||
indexes.sort(descending);
|
||||
|
||||
instruct( socket, store, 'playlists.lookup', { uri: action.playlist_uri })
|
||||
instruct( socket, store, 'playlists.lookup', { uri: action.uri })
|
||||
.then( response => {
|
||||
var playlist = Object.assign({}, response)
|
||||
for( var i = 0; i < indexes.length; i++ ){
|
||||
@ -404,7 +426,7 @@ const MopidyMiddleware = (function(){
|
||||
}
|
||||
instruct( socket, store, 'playlists.save', { playlist: playlist } )
|
||||
.then( response => {
|
||||
store.dispatch({ type: 'PLAYLIST_TRACKS_REMOVED', tracks_indexes: action.tracks_indexes });
|
||||
store.dispatch({ type: 'PLAYLIST_TRACKS_REMOVED', uri: action.uri, tracks_indexes: action.tracks_indexes });
|
||||
})
|
||||
});
|
||||
break
|
||||
@ -415,7 +437,11 @@ const MopidyMiddleware = (function(){
|
||||
var playlist = Object.assign({}, response, { name: action.name })
|
||||
instruct( socket, store, 'playlists.save', { playlist: playlist } )
|
||||
.then( response => {
|
||||
store.dispatch({ type: 'PLAYLIST_UPDATED', playlist: playlist })
|
||||
store.dispatch({
|
||||
type: 'PLAYLIST_UPDATED',
|
||||
uri: action.uri,
|
||||
playlist: playlist
|
||||
})
|
||||
})
|
||||
});
|
||||
break
|
||||
@ -454,23 +480,50 @@ const MopidyMiddleware = (function(){
|
||||
instruct( socket, store, 'playlists.save', { playlist: playlist } )
|
||||
.then( response => {
|
||||
|
||||
// and now re-render our full track references
|
||||
store.dispatch({ type: 'MOPIDY_PLAYLIST_TRACKS', tracks: playlist.tracks })
|
||||
store.dispatch({ type: 'MOPIDY_RESOLVE_PLAYLIST_TRACKS', tracks: playlist.tracks, uri: playlist.uri })
|
||||
})
|
||||
});
|
||||
break
|
||||
|
||||
case 'MOPIDY_CREATE_PLAYLIST':
|
||||
instruct( socket, store, 'playlists.create', { name: action.name, uri_scheme: action.scheme })
|
||||
.then( response => {
|
||||
|
||||
// re-load our global playlists
|
||||
//store.dispatch({ type: 'MOPIDY_GET_PLAYLISTS' });
|
||||
});
|
||||
break
|
||||
|
||||
case 'MOPIDY_DELETE_PLAYLIST':
|
||||
instruct( socket, store, 'playlists.delete', { uri: action.uri })
|
||||
.then( response => {
|
||||
|
||||
// re-load our global playlists
|
||||
store.dispatch({ type: 'MOPIDY_PLAYLISTS' });
|
||||
// store.dispatch({ type: 'MOPIDY_PLAYLISTS' });
|
||||
});
|
||||
break
|
||||
|
||||
|
||||
case 'MOPIDY_ALBUM':
|
||||
//store.dispatch({ type: 'MOPIDY_ALBUM_LOADED', data: false });
|
||||
/**
|
||||
* =============================================================== ALBUM(S) =============
|
||||
* ======================================================================================
|
||||
**/
|
||||
|
||||
case 'MOPIDY_GET_ALBUMS':
|
||||
instruct( socket, store, 'library.browse', { uri: 'local:directory?type=album' } )
|
||||
.then( response => {
|
||||
store.dispatch({
|
||||
type: 'ALBUMS_LOADED',
|
||||
albums: response
|
||||
});
|
||||
store.dispatch({
|
||||
type: 'LOCAL_ALBUMS_LOADED',
|
||||
uris: helpers.asURIs(response)
|
||||
});
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_GET_ALBUM':
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then( response => {
|
||||
var album = Object.assign(
|
||||
@ -522,45 +575,92 @@ const MopidyMiddleware = (function(){
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch({ type: 'MOPIDY_ALBUM_LOADED', data: album });
|
||||
store.dispatch({
|
||||
type: 'ALBUM_LOADED',
|
||||
uri: album.uri,
|
||||
album: album
|
||||
});
|
||||
})
|
||||
})
|
||||
break;
|
||||
|
||||
|
||||
case 'MOPIDY_ARTIST':
|
||||
store.dispatch({ type: 'MOPIDY_ARTIST_LOADED', data: false });
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then( response => {
|
||||
var artist = response[0].artists[0];
|
||||
if( !artist.images ) artist.images = [];
|
||||
if( !artist.albums ) artist.albums = [];
|
||||
artist.tracks = response.slice(0,10);
|
||||
|
||||
for( var i = 0; i < response.length; i++ ){
|
||||
var album = response[i].album;
|
||||
/**
|
||||
* =============================================================== ARTIST(S) ============
|
||||
* ======================================================================================
|
||||
**/
|
||||
|
||||
function getByURI( albumToCheck ){
|
||||
return album.uri == albumToCheck.uri
|
||||
}
|
||||
var existingAlbum = artist.albums.find(getByURI);
|
||||
if( !existingAlbum ){
|
||||
artist.albums.push(album)
|
||||
}
|
||||
}
|
||||
|
||||
// load artwork from LastFM
|
||||
if( artist.images.length <= 0 ){
|
||||
if( artist.musicbrainz_id ){
|
||||
store.dispatch( lastfmActions.getArtist( false, artist.musicbrainz_id ) )
|
||||
}else{
|
||||
store.dispatch( lastfmActions.getArtist( artist.name ) )
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch({ type: 'MOPIDY_ARTIST_LOADED', data: artist });
|
||||
case 'MOPIDY_GET_ARTISTS':
|
||||
store.dispatch({ type: 'LOCAL_ARTISTS_LOADED', data: false });
|
||||
instruct( socket, store, 'library.browse', { uri: 'local:directory?type=artist' } )
|
||||
.then( response => {
|
||||
store.dispatch({
|
||||
type: 'ARTISTS_LOADED',
|
||||
artists: response
|
||||
});
|
||||
store.dispatch({
|
||||
type: 'LOCAL_ARTISTS_LOADED',
|
||||
uris: helpers.asURIs(response)
|
||||
});
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_GET_ARTIST':
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then( response => {
|
||||
|
||||
var albums = []
|
||||
for( var i = 0; i < response.length; i++ ){
|
||||
var album = response[i].album;
|
||||
if (album){
|
||||
function getByURI( albumToCheck ){
|
||||
return album.uri == albumToCheck.uri
|
||||
}
|
||||
var existingAlbum = albums.find(getByURI);
|
||||
if( !existingAlbum ){
|
||||
albums.push(album)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (albums){
|
||||
store.dispatch({
|
||||
type: 'ALBUMS_LOADED',
|
||||
albums: albums
|
||||
})
|
||||
}
|
||||
|
||||
var artist = Object.assign(
|
||||
{},
|
||||
response[0].artists[0],
|
||||
{
|
||||
albums_uris: helpers.asURIs(albums),
|
||||
tracks: response.slice(0,10)
|
||||
}
|
||||
)
|
||||
|
||||
store.dispatch({
|
||||
type: 'ARTIST_LOADED',
|
||||
uri: artist.uri,
|
||||
artist: artist
|
||||
});
|
||||
|
||||
// load artwork from LastFM
|
||||
if( !artist.images || artist.images.length <= 0 ){
|
||||
if( artist.musicbrainz_id ){
|
||||
store.dispatch( lastfmActions.getArtist( artist.uri, false, artist.musicbrainz_id ) )
|
||||
}else{
|
||||
store.dispatch( lastfmActions.getArtist( artist.uri, artist.name.replace('&','and') ) )
|
||||
}
|
||||
}
|
||||
})
|
||||
break;
|
||||
|
||||
|
||||
/**
|
||||
* =============================================================== LOCAL ================
|
||||
* ======================================================================================
|
||||
**/
|
||||
|
||||
case 'MOPIDY_DIRECTORY':
|
||||
store.dispatch({ type: 'MOPIDY_DIRECTORY_LOADED', data: false });
|
||||
instruct( socket, store, 'library.browse', action.data )
|
||||
@ -569,22 +669,6 @@ const MopidyMiddleware = (function(){
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_ARTISTS':
|
||||
store.dispatch({ type: 'MOPIDY_ARTISTS_LOADED', data: false });
|
||||
instruct( socket, store, 'library.browse', { uri: 'local:directory?type=artist' } )
|
||||
.then( response => {
|
||||
store.dispatch({ type: 'MOPIDY_ARTISTS_LOADED', data: response });
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_ALBUMS':
|
||||
store.dispatch({ type: 'MOPIDY_ALBUMS_LOADED', data: false });
|
||||
instruct( socket, store, 'library.browse', { uri: 'local:directory?type=album' } )
|
||||
.then( response => {
|
||||
store.dispatch({ type: 'MOPIDY_ALBUMS_LOADED', data: response });
|
||||
})
|
||||
break;
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
|
||||
@ -262,9 +262,29 @@ export function getFeaturedPlaylists(){
|
||||
|
||||
sendRequest( dispatch, getState, 'browse/featured-playlists?timestamp='+timestamp+'&country='+getState().spotify.country+'&limit=50&locale='+getState().spotify.locale )
|
||||
.then( response => {
|
||||
|
||||
var playlists = []
|
||||
for (var i = 0; i < response.playlists.items.length; i++){
|
||||
playlists.push(Object.assign(
|
||||
{},
|
||||
response.playlists.items[i],
|
||||
{
|
||||
can_edit: (getState().spotify.me && response.playlists.items[i].owner.id == getState().spotify.me.id),
|
||||
tracks_total: response.playlists.items[i].tracks.total
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'PLAYLISTS_LOADED',
|
||||
playlists: playlists
|
||||
});
|
||||
dispatch({
|
||||
type: 'SPOTIFY_FEATURED_PLAYLISTS_LOADED',
|
||||
data: response
|
||||
data: {
|
||||
message: response.message,
|
||||
playlists: helpers.asURIs(response.playlists.items)
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -290,52 +310,69 @@ export function getCategory( id ){
|
||||
|
||||
dispatch({ type: 'SPOTIFY_CATEGORY_LOADED', data: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'browse/categories/'+id+'?country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
$.when(
|
||||
|
||||
sendRequest( dispatch, getState, 'browse/categories/'+id+'?country='+getState().spotify.country+'&locale='+getState().spotify.locale ),
|
||||
sendRequest( dispatch, getState, 'browse/categories/'+id+'/playlists?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
|
||||
).then( ( category_response, playlists_response ) => {
|
||||
|
||||
for (var i = 0; i < playlists_response.playlists.items.length; i++){
|
||||
|
||||
var playlist = Object.assign(
|
||||
{},
|
||||
playlists_response.playlists.items[i],
|
||||
{
|
||||
tracks: null,
|
||||
tracks_more: null,
|
||||
tracks_total: playlists_response.playlists.items[i].tracks.total
|
||||
}
|
||||
)
|
||||
|
||||
dispatch({
|
||||
type: 'PLAYLIST_LOADED',
|
||||
playlist: playlist
|
||||
});
|
||||
}
|
||||
|
||||
var category = Object.assign(
|
||||
{},
|
||||
category_response,
|
||||
{
|
||||
items: false,
|
||||
playlists: helpers.asURIs(playlists_response.playlists.items),
|
||||
playlists_more: playlists_response.playlists.next,
|
||||
playlists_total: playlists_response.playlists.total
|
||||
}
|
||||
)
|
||||
|
||||
dispatch({
|
||||
type: 'SPOTIFY_CATEGORY_LOADED',
|
||||
data: category
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getNewReleases(){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest( dispatch, getState, 'browse/new-releases?country='+getState().spotify.country+'&limit=50' )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_CATEGORY_LOADED',
|
||||
type: 'SPOTIFY_NEW_RELEASES_LOADED',
|
||||
data: response
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getCategoryPlaylists( id ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED', data: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'browse/categories/'+id+'/playlists?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED',
|
||||
data: response.playlists
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getNewReleases(){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_NEW_RELEASES_LOADED', data: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'browse/new-releases?country='+getState().spotify.country+'&limit=50' )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_NEW_RELEASES_LOADED',
|
||||
data: response.albums
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getURL( url, action_name ){
|
||||
export function getURL( url, action_name, uri = false ){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest( dispatch, getState, url )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: action_name,
|
||||
uri: uri,
|
||||
data: response
|
||||
});
|
||||
});
|
||||
@ -366,8 +403,6 @@ export function getSearchResults( query, type = 'album,artist,playlist,track', l
|
||||
export function following(uri, method = 'GET'){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'FOLLOWING_LOADING' });
|
||||
|
||||
if( method == 'PUT' ) var is_following = true
|
||||
if( method == 'DELETE' ) var is_following = false
|
||||
|
||||
@ -411,7 +446,8 @@ export function following(uri, method = 'GET'){
|
||||
if( response ) is_following = response
|
||||
if( typeof(is_following) === 'object' ) is_following = is_following[0]
|
||||
dispatch({
|
||||
type: asset_name.toUpperCase()+'_FOLLOWING_LOADED',
|
||||
type: 'SPOTIFY_'+asset_name.toUpperCase()+'_FOLLOWING_LOADED',
|
||||
uri: uri,
|
||||
is_following: is_following
|
||||
});
|
||||
});
|
||||
@ -547,9 +583,6 @@ export function getDiscover(){
|
||||
export function getArtist( uri ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// flush out the previous store value
|
||||
dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: false });
|
||||
|
||||
var artist = {};
|
||||
|
||||
// get both the artist and the top tracks
|
||||
@ -567,19 +600,29 @@ export function getArtist( uri ){
|
||||
|
||||
sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/related-artists' )
|
||||
.then( response => {
|
||||
Object.assign(artist, { related_artists: response.artists });
|
||||
}),
|
||||
|
||||
sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/albums' )
|
||||
.then( response => {
|
||||
Object.assign(artist, { albums: response.items, albums_more: response.next });
|
||||
dispatch({
|
||||
type: 'ARTISTS_LOADED',
|
||||
artists: response.artists
|
||||
});
|
||||
Object.assign(artist, { related_artists_uris: helpers.asURIs(response.artists) });
|
||||
})
|
||||
|
||||
).then( () => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_ARTIST_LOADED',
|
||||
data: artist
|
||||
type: 'ARTIST_LOADED',
|
||||
uri: artist.uri,
|
||||
artist: artist
|
||||
});
|
||||
|
||||
// now go get our artist albums
|
||||
sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/albums' )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_ARTIST_ALBUMS_LOADED',
|
||||
data: response,
|
||||
uri: uri
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -587,9 +630,6 @@ export function getArtist( uri ){
|
||||
export function getArtists( uris ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// flush out the previous store value
|
||||
dispatch({ type: 'SPOTIFY_ARTISTS_LOADED', data: false });
|
||||
|
||||
// now get all the artists for this album (full objects)
|
||||
var ids = '';
|
||||
for( var i = 0; i < uris.length; i++ ){
|
||||
@ -599,10 +639,21 @@ export function getArtists( uris ){
|
||||
|
||||
sendRequest( dispatch, getState, 'artists/?ids='+ids )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_ARTISTS_LOADED',
|
||||
data: response
|
||||
});
|
||||
for (var i = i; i < response.length; i++){
|
||||
var artist = response
|
||||
for (var i = 0; i < artist.albums.length; i++){
|
||||
dispatch({
|
||||
type: 'ALBUM_LOADED',
|
||||
album: artist.albums[i]
|
||||
});
|
||||
}
|
||||
artist.albums = helpers.asURIs(artist.albums)
|
||||
artist.albums_more = artist.albums.next
|
||||
dispatch({
|
||||
type: 'ARTIST_LOADED',
|
||||
artist: artist
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -610,15 +661,12 @@ export function getArtists( uris ){
|
||||
|
||||
export function getLibraryArtists(){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'me/following?type=artist&limit=50' )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED',
|
||||
data: response
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -675,29 +723,54 @@ export function getUser( uri ){
|
||||
export function getAlbum( uri ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// flush out the previous store value
|
||||
dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: false });
|
||||
|
||||
// get the album
|
||||
sendRequest( dispatch, getState, 'albums/'+ helpers.getFromUri('albumid', uri) )
|
||||
.then( response => {
|
||||
|
||||
var album = response
|
||||
// dispatch our loaded artists (simple objects)
|
||||
dispatch({
|
||||
type: 'ARTISTS_LOADED',
|
||||
artists: response.artists
|
||||
});
|
||||
|
||||
var album = Object.assign(
|
||||
{},
|
||||
response,
|
||||
{
|
||||
artists_uris: helpers.asURIs(response.artists),
|
||||
tracks: response.tracks.items,
|
||||
tracks_more: response.tracks.next,
|
||||
tracks_total: response.tracks.total
|
||||
}
|
||||
)
|
||||
|
||||
// add our album to all the tracks
|
||||
for (var i = 0; i < album.tracks.length; i++){
|
||||
album.tracks[i].album = {
|
||||
name: album.name,
|
||||
uri: album.uri
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'ALBUM_LOADED',
|
||||
uri: album.uri,
|
||||
album: album
|
||||
});
|
||||
|
||||
// now get all the artists for this album (full objects)
|
||||
// we do this to get the artist artwork
|
||||
var artist_ids = [];
|
||||
for( var i = 0; i < album.artists.length; i++ ){
|
||||
artist_ids.push( helpers.getFromUri( 'artistid', album.artists[i].uri ) )
|
||||
for( var i = 0; i < response.artists.length; i++ ){
|
||||
artist_ids.push( helpers.getFromUri( 'artistid', response.artists[i].uri ) )
|
||||
}
|
||||
|
||||
// get all album artists
|
||||
// get all album artists as full objects
|
||||
sendRequest( dispatch, getState, 'artists/?ids='+artist_ids )
|
||||
.then( response => {
|
||||
Object.assign(album, { artists: response.artists })
|
||||
dispatch({
|
||||
type: 'SPOTIFY_ALBUM_LOADED',
|
||||
data: album
|
||||
type: 'ARTISTS_LOADED',
|
||||
artists: response.artists
|
||||
});
|
||||
});
|
||||
|
||||
@ -708,14 +781,14 @@ export function getAlbum( uri ){
|
||||
export function getLibraryAlbums(){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_LIBRARY_ALBUMS_LOADED', data: false });
|
||||
dispatch({ type: 'LIBRARY_ALBUMS_LOADED', uris: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'me/albums?limit=40' )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_ALBUMS_LOADED',
|
||||
data: response
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -774,15 +847,25 @@ export function savePlaylist( uri, name, is_public ){
|
||||
export function getPlaylist( uri ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// flush out the previous store value
|
||||
dispatch({ type: 'SPOTIFY_PLAYLIST_LOADED', data: false });
|
||||
|
||||
// get the main playlist object
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
|
||||
.then( response => {
|
||||
|
||||
var playlist = Object.assign(
|
||||
{},
|
||||
response,
|
||||
{
|
||||
can_edit: (getState().spotify.me && response.owner.id == getState().spotify.me.id),
|
||||
tracks: helpers.flattenTracks(response.tracks.items),
|
||||
tracks_more: response.tracks.next,
|
||||
tracks_total: response.tracks.total
|
||||
}
|
||||
)
|
||||
|
||||
dispatch({
|
||||
type: 'SPOTIFY_PLAYLIST_LOADED',
|
||||
data: response
|
||||
type: 'PLAYLIST_LOADED',
|
||||
uri: playlist.uri,
|
||||
playlist: playlist
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -796,29 +879,15 @@ function loadNextPlaylistsBatch( dispatch, getState, playlists, lastResponse ){
|
||||
loadNextPlaylistsBatch( dispatch, getState, playlists, response )
|
||||
});
|
||||
}else{
|
||||
|
||||
// check our editability of each playlist
|
||||
// used to define what we can add tracks to
|
||||
if( getState().spotify.authorized ){
|
||||
for( var i = 0; i < playlists.length; i++ ){
|
||||
if( playlists[i].owner.id == getState().spotify.me.id ){
|
||||
playlists[i] = Object.assign({}, playlists[i], { can_edit: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED',
|
||||
data: playlists
|
||||
playlists: playlists
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getAllLibraryPlaylists(){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED', data: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'me/playlists?limit=50' )
|
||||
.then( response => {
|
||||
loadNextPlaylistsBatch( dispatch, getState, response.items, response )
|
||||
@ -842,12 +911,13 @@ export function toggleFollowingPlaylist( uri, method ){
|
||||
}
|
||||
}
|
||||
|
||||
export function addTracksToPlaylist( playlist_uri, tracks_uris ){
|
||||
export function addTracksToPlaylist( uri, tracks_uris ){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',playlist_uri) + '/playlists/'+ helpers.getFromUri('playlistid',playlist_uri) + '/tracks', 'POST', { uris: tracks_uris } )
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) + '/playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'POST', { uris: tracks_uris } )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'PLAYLIST_TRACKS_ADDED',
|
||||
uri: uri,
|
||||
tracks_uris: tracks_uris,
|
||||
snapshot_id: response.snapshot_id
|
||||
});
|
||||
@ -861,6 +931,7 @@ export function deleteTracksFromPlaylist( uri, snapshot_id, tracks_indexes ){
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'PLAYLIST_TRACKS_REMOVED',
|
||||
uri: uri,
|
||||
tracks_indexes: tracks_indexes,
|
||||
snapshot_id: response.snapshot_id
|
||||
});
|
||||
@ -874,6 +945,7 @@ export function reorderPlaylistTracks( uri, range_start, range_length, insert_be
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'PLAYLIST_TRACKS_REORDERED',
|
||||
uri: uri,
|
||||
range_start: range_start,
|
||||
range_length: range_length,
|
||||
insert_before: insert_before,
|
||||
|
||||
@ -18,8 +18,6 @@ const SpotifyMiddleware = (function(){
|
||||
break
|
||||
|
||||
case 'SPOTIFY_CREATE_PLAYLIST':
|
||||
var playlist = state.ui.playlist
|
||||
|
||||
if( !store.getState().spotify.authorized ){
|
||||
store.dispatch( uiActions.createNotification( "Must be logged in to Spotify to do that", 'bad' ) )
|
||||
return
|
||||
@ -28,7 +26,7 @@ const SpotifyMiddleware = (function(){
|
||||
break
|
||||
|
||||
case 'SPOTIFY_REMOVE_PLAYLIST_TRACKS':
|
||||
var playlist = state.ui.playlist
|
||||
var playlist = state.ui.playlists[action.uri]
|
||||
|
||||
if( !store.getState().spotify.authorized ){
|
||||
store.dispatch( uiActions.createNotification( "Must be logged in to Spotify to do that", 'bad' ) )
|
||||
@ -95,6 +93,135 @@ const SpotifyMiddleware = (function(){
|
||||
}
|
||||
break
|
||||
|
||||
case 'SPOTIFY_PLAYLIST_FOLLOWING_LOADED':
|
||||
store.dispatch({
|
||||
type: 'PLAYLIST_LOADED',
|
||||
uri: action.uri,
|
||||
playlist: {
|
||||
is_following: action.is_following
|
||||
}
|
||||
});
|
||||
break
|
||||
|
||||
case 'SPOTIFY_ALBUM_FOLLOWING_LOADED':
|
||||
store.dispatch({
|
||||
type: 'ALBUM_LOADED',
|
||||
uri: action.uri,
|
||||
album: {
|
||||
is_following: action.is_following
|
||||
}
|
||||
});
|
||||
break
|
||||
|
||||
case 'SPOTIFY_ARTIST_FOLLOWING_LOADED':
|
||||
store.dispatch({
|
||||
type: 'ARTIST_LOADED',
|
||||
uri: action.uri,
|
||||
artist: {
|
||||
is_following: action.is_following
|
||||
}
|
||||
});
|
||||
break
|
||||
|
||||
case 'SPOTIFY_NEW_RELEASES_LOADED':
|
||||
store.dispatch({
|
||||
type: 'ALBUMS_LOADED',
|
||||
albums: action.data.albums.items
|
||||
});
|
||||
store.dispatch({
|
||||
type: 'NEW_RELEASES_LOADED',
|
||||
uris: helpers.asURIs(action.data.albums.items),
|
||||
more: action.data.albums.next,
|
||||
total: action.data.albums.total
|
||||
});
|
||||
break
|
||||
|
||||
case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
|
||||
store.dispatch({
|
||||
type: 'ALBUMS_LOADED',
|
||||
albums: action.data.items
|
||||
});
|
||||
store.dispatch({
|
||||
type: 'ARTIST_ALBUMS_LOADED',
|
||||
uri: action.uri,
|
||||
uris: helpers.asURIs(action.data.items),
|
||||
more: action.data.next,
|
||||
total: action.data.total
|
||||
});
|
||||
break
|
||||
|
||||
case 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED':
|
||||
var playlists = []
|
||||
for( var i = 0; i < action.playlists.length; i++ ){
|
||||
var playlist = Object.assign(
|
||||
{},
|
||||
action.playlists[i],
|
||||
{
|
||||
can_edit: (store.getState().spotify.authorized && store.getState().spotify.me && action.playlists[i].owner.id == store.getState().spotify.me.id),
|
||||
tracks_total: action.playlists[i].tracks.total
|
||||
}
|
||||
)
|
||||
|
||||
// remove our tracklist. It'll overwrite any full records otherwise
|
||||
delete playlist.tracks
|
||||
|
||||
playlists.push(playlist)
|
||||
}
|
||||
|
||||
store.dispatch({
|
||||
type: 'PLAYLISTS_LOADED',
|
||||
playlists: playlists
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'LIBRARY_PLAYLISTS_LOADED',
|
||||
uris: helpers.asURIs(playlists)
|
||||
});
|
||||
break
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED':
|
||||
store.dispatch({
|
||||
type: 'ARTISTS_LOADED',
|
||||
artists: action.data.artists.items
|
||||
});
|
||||
store.dispatch({
|
||||
type: 'LIBRARY_ARTISTS_LOADED',
|
||||
uris: helpers.asURIs(action.data.artists.items),
|
||||
more: action.data.artists.next,
|
||||
total: action.data.artists.total
|
||||
});
|
||||
break
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED':
|
||||
var albums = []
|
||||
for (var i = 0; i < action.data.items.length; i++){
|
||||
albums.push(
|
||||
Object.assign(
|
||||
{},
|
||||
action.data.items[i].album,
|
||||
{
|
||||
added_at: action.data.items[i].added_at,
|
||||
tracks: action.data.items[i].album.tracks.items,
|
||||
tracks_next: action.data.items[i].album.tracks.tracks_next,
|
||||
tracks_total: action.data.items[i].album.tracks.tracks_total
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
store.dispatch({
|
||||
type: 'ALBUMS_LOADED',
|
||||
albums: albums
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'LIBRARY_ALBUMS_LOADED',
|
||||
uris: helpers.asURIs(albums),
|
||||
more: action.data.next,
|
||||
total: action.data.total
|
||||
});
|
||||
break
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
|
||||
@ -60,7 +60,7 @@ export default function reducer(spotify = {}, action){
|
||||
|
||||
case 'SPOTIFY_ME_LOADED':
|
||||
return Object.assign({}, spotify, { me: action.data })
|
||||
|
||||
/*
|
||||
case 'SPOTIFY_ARTISTS_LOADED':
|
||||
if( !action.data ) return Object.assign({}, spotify)
|
||||
return Object.assign({}, spotify, {
|
||||
@ -79,7 +79,7 @@ export default function reducer(spotify = {}, action){
|
||||
return Object.assign({}, spotify, {
|
||||
library_artists: [ ...spotify.library_artists, ...action.data.artists.items ],
|
||||
library_artists_more: action.data.artists.next
|
||||
})
|
||||
})*/
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED':
|
||||
if( !action.data ) return Object.assign({}, spotify)
|
||||
@ -156,9 +156,7 @@ export default function reducer(spotify = {}, action){
|
||||
case 'SPOTIFY_CATEGORY_LOADED':
|
||||
return Object.assign({}, spotify, { category: action.data })
|
||||
|
||||
case 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED':
|
||||
return Object.assign({}, spotify, { category_playlists: action.data })
|
||||
|
||||
// TODO: update this
|
||||
case 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED_MORE':
|
||||
return Object.assign({}, spotify, { category_playlists: {
|
||||
href: action.data.href,
|
||||
|
||||
@ -147,39 +147,39 @@ export function createPlaylist( scheme, name, is_public = false ){
|
||||
return false
|
||||
}
|
||||
|
||||
export function removeTracksFromPlaylist( playlist_uri, tracks_indexes ){
|
||||
switch( helpers.uriSource( playlist_uri ) ){
|
||||
export function removeTracksFromPlaylist( uri, tracks_indexes ){
|
||||
switch( helpers.uriSource( uri ) ){
|
||||
|
||||
case 'spotify':
|
||||
return {
|
||||
type: 'SPOTIFY_REMOVE_PLAYLIST_TRACKS',
|
||||
playlist_uri: playlist_uri,
|
||||
uri: uri,
|
||||
tracks_indexes: tracks_indexes
|
||||
}
|
||||
|
||||
case 'm3u':
|
||||
return {
|
||||
type: 'MOPIDY_REMOVE_PLAYLIST_TRACKS',
|
||||
playlist_uri: playlist_uri,
|
||||
uri: uri,
|
||||
tracks_indexes: tracks_indexes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function addTracksToPlaylist( playlist_uri, tracks_uris ){
|
||||
switch( helpers.uriSource( playlist_uri ) ){
|
||||
export function addTracksToPlaylist( uri, tracks_uris ){
|
||||
switch( helpers.uriSource( uri ) ){
|
||||
|
||||
case 'spotify':
|
||||
return {
|
||||
type: 'SPOTIFY_ADD_PLAYLIST_TRACKS',
|
||||
playlist_uri: playlist_uri,
|
||||
uri: uri,
|
||||
tracks_uris: tracks_uris
|
||||
}
|
||||
|
||||
case 'm3u':
|
||||
return {
|
||||
type: 'MOPIDY_ADD_PLAYLIST_TRACKS',
|
||||
playlist_uri: playlist_uri,
|
||||
uri: uri,
|
||||
tracks_uris: tracks_uris
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,9 +114,6 @@ export default function reducer(ui = {}, action){
|
||||
current_track: current_track
|
||||
});
|
||||
|
||||
case 'FOLLOWING_LOADING':
|
||||
return Object.assign({}, ui, { following_loading: true })
|
||||
|
||||
case 'RADIO':
|
||||
case 'START_RADIO':
|
||||
return Object.assign({}, ui, { seeds_resolved: false }, { radio: action.data.radio })
|
||||
@ -132,36 +129,71 @@ export default function reducer(ui = {}, action){
|
||||
* Albums
|
||||
**/
|
||||
|
||||
case 'MOPIDY_ALBUM_LOADED':
|
||||
if( !action.data ) return Object.assign({}, ui, { album: false })
|
||||
return Object.assign({}, ui, { album: action.data });
|
||||
case 'ALBUM_LOADED':
|
||||
var albums = Object.assign([], ui.albums)
|
||||
|
||||
case 'LASTFM_ALBUM_LOADED':
|
||||
if( !action.data.image ) return ui
|
||||
if (albums[action.uri]){
|
||||
var album = Object.assign({}, albums[action.uri], action.album)
|
||||
}else{
|
||||
var album = Object.assign({}, action.album)
|
||||
}
|
||||
|
||||
var album = Object.assign({}, ui.album, { images: action.data.image })
|
||||
return Object.assign({}, ui, { album: album });
|
||||
albums[action.uri] = album
|
||||
return Object.assign({}, ui, { albums: albums });
|
||||
|
||||
case 'SPOTIFY_ALBUM_LOADED':
|
||||
if( !action.data ) return Object.assign({}, ui, { album: false })
|
||||
case 'ALBUMS_LOADED':
|
||||
console.log(action)
|
||||
var albums = Object.assign([], ui.albums)
|
||||
|
||||
var album = Object.assign({}, { images: [] }, action.data, {
|
||||
tracks: action.data.tracks.items,
|
||||
tracks_total: action.data.tracks.total,
|
||||
tracks_more: action.data.tracks.next
|
||||
})
|
||||
return Object.assign({}, ui, { album: album })
|
||||
for (var i = 0; i < action.albums.length; i++){
|
||||
var album = action.albums[i]
|
||||
if (typeof(albums[album.uri]) !== 'undefined'){
|
||||
artist = Object.assign({}, albums[album.uri], album)
|
||||
}
|
||||
albums[album.uri] = album
|
||||
}
|
||||
|
||||
case 'SPOTIFY_ALBUM_LOADED_MORE':
|
||||
var album = Object.assign({}, ui.album, {
|
||||
tracks: [ ...ui.album.tracks, ...action.data.items ],
|
||||
tracks_more: action.data.next
|
||||
})
|
||||
return Object.assign({}, ui, { album: album });
|
||||
return Object.assign({}, ui, { albums: albums });
|
||||
|
||||
case 'ALBUM_FOLLOWING_LOADED':
|
||||
var album = Object.assign({}, ui.album, { following: action.is_following })
|
||||
return Object.assign({}, ui, { album: album, following_loading: false });
|
||||
case 'LIBRARY_ALBUMS_LOADED':
|
||||
if (!action.uris){
|
||||
return Object.assign({}, ui, {
|
||||
library_albums: null,
|
||||
library_albums_more: null,
|
||||
library_albums_total: null
|
||||
});
|
||||
}
|
||||
|
||||
var library_albums = []
|
||||
if (ui.library_albums) library_albums = Object.assign([], ui.library_albums)
|
||||
|
||||
return Object.assign({}, ui, {
|
||||
library_albums: [...library_albums, ...action.uris],
|
||||
library_albums_more: action.more,
|
||||
library_albums_total: action.total
|
||||
});
|
||||
|
||||
case 'LOCAL_ALBUMS_LOADED':
|
||||
if (!action.uris) return Object.assign({}, ui, { local_albums: null });
|
||||
return Object.assign({}, ui, { local_albums: action.uris });
|
||||
|
||||
case 'NEW_RELEASES_LOADED':
|
||||
if (!action.uris){
|
||||
return Object.assign({}, ui, {
|
||||
new_releases: null,
|
||||
new_releases_more: null,
|
||||
new_releases_total: null
|
||||
});
|
||||
}
|
||||
|
||||
var new_releases = []
|
||||
if (ui.new_releases) new_releases = Object.assign([], ui.new_releases)
|
||||
|
||||
return Object.assign({}, ui, {
|
||||
new_releases: [...new_releases, ...action.uris],
|
||||
new_releases_more: action.more,
|
||||
new_releases_total: action.total
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -169,34 +201,73 @@ export default function reducer(ui = {}, action){
|
||||
* Artists
|
||||
**/
|
||||
|
||||
case 'MOPIDY_ARTIST_LOADED':
|
||||
if( !action.data ) return Object.assign({}, ui, { artist: false })
|
||||
return Object.assign({}, ui, { artist: action.data })
|
||||
case 'ARTIST_LOADED':
|
||||
console.log(action)
|
||||
var artists = Object.assign([], ui.artists)
|
||||
|
||||
case 'LASTFM_ARTIST_LOADED':
|
||||
if( !action.data.image ) return ui
|
||||
if (artists[action.uri]){
|
||||
// if we've already got images, delete our new ones
|
||||
// this is to prevent LastFM overwriting Spotify images
|
||||
if (artists[action.uri].images) delete action.artist.images
|
||||
var artist = Object.assign({}, artists[action.uri], action.artist)
|
||||
}else{
|
||||
var artist = Object.assign({}, action.artist)
|
||||
}
|
||||
|
||||
// if we already have images, don't overwrite them
|
||||
var images = ui.artist.images
|
||||
if( images.length <= 0 ) images = action.data.image
|
||||
|
||||
var artist = Object.assign({}, ui.artist, { images: images, bio: action.data.bio, listeners: parseInt(action.data.stats.listeners), on_tour: action.data.ontour }, )
|
||||
return Object.assign({}, ui, { artist: artist });
|
||||
artists[action.uri] = artist
|
||||
return Object.assign({}, ui, { artists: artists });
|
||||
|
||||
case 'SPOTIFY_ARTIST_LOADED':
|
||||
if( !action.data ) return Object.assign({}, ui, { artist: false })
|
||||
return Object.assign({}, ui, { artist: action.data })
|
||||
case 'ARTISTS_LOADED':
|
||||
var artists = Object.assign([], ui.artists)
|
||||
|
||||
case 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE':
|
||||
var artist = Object.assign({}, ui.artist, {
|
||||
albums: [ ...ui.artist.albums, ...action.data.items ],
|
||||
albums_more: action.data.next
|
||||
})
|
||||
return Object.assign({}, ui, { artist: artist });
|
||||
for (var i = 0; i < action.artists.length; i++){
|
||||
var artist = action.artists[i]
|
||||
if (typeof(artists[artist.uri]) !== 'undefined'){
|
||||
artist = Object.assign({}, artists[artist.uri], artist)
|
||||
}
|
||||
artists[artist.uri] = artist
|
||||
}
|
||||
|
||||
case 'ARTIST_FOLLOWING_LOADED':
|
||||
var artist = Object.assign({}, ui.artist, { following: action.is_following })
|
||||
return Object.assign({}, ui, { artist: artist, following_loading: false });
|
||||
return Object.assign({}, ui, { artists: artists });
|
||||
|
||||
case 'ARTIST_ALBUMS_LOADED':
|
||||
var artists = Object.assign([], ui.artists)
|
||||
var albums_uris = []
|
||||
if (artists[action.uri].albums_uris) albums_uris = artists[action.uri].albums_uris
|
||||
|
||||
var artist = Object.assign(
|
||||
{},
|
||||
artists[action.uri],
|
||||
{
|
||||
albums_uris: [...albums_uris, ...action.uris],
|
||||
albums_more: action.more,
|
||||
albums_total: action.total
|
||||
}
|
||||
)
|
||||
artists[action.uri] = artist
|
||||
return Object.assign({}, ui, { artists: artists });
|
||||
|
||||
case 'LIBRARY_ARTISTS_LOADED':
|
||||
if (!action.uris){
|
||||
return Object.assign({}, ui, {
|
||||
library_artists: null,
|
||||
library_artists_more: null,
|
||||
library_artists_total: null
|
||||
});
|
||||
}
|
||||
|
||||
var library_artists = []
|
||||
if (ui.library_artists) library_artists = Object.assign([], ui.library_artists)
|
||||
|
||||
return Object.assign({}, ui, {
|
||||
library_artists: [...library_artists, ...action.uris],
|
||||
library_artists_more: action.more,
|
||||
library_artists_total: action.total
|
||||
});
|
||||
|
||||
case 'LOCAL_ARTISTS_LOADED':
|
||||
if (!action.uris) return Object.assign({}, ui, { local_artists: null });
|
||||
return Object.assign({}, ui, { local_artists: action.uris });
|
||||
|
||||
|
||||
/**
|
||||
@ -223,74 +294,76 @@ export default function reducer(ui = {}, action){
|
||||
* Playlists
|
||||
**/
|
||||
|
||||
case 'PLAYLIST_LOADED':
|
||||
case 'PLAYLIST_UPDATED':
|
||||
var playlist = Object.assign({}, ui.playlist, action.playlist)
|
||||
return Object.assign({}, ui, { playlist: playlist })
|
||||
var playlists = Object.assign([], ui.playlists)
|
||||
|
||||
if (playlists[action.uri]){
|
||||
var playlist = Object.assign({}, playlists[action.uri], action.playlist)
|
||||
}else{
|
||||
var playlist = Object.assign({}, action.playlist)
|
||||
}
|
||||
|
||||
playlists[action.uri] = playlist
|
||||
return Object.assign({}, ui, { playlists: playlists });
|
||||
|
||||
case 'PLAYLISTS_LOADED':
|
||||
var playlists = Object.assign([], ui.playlists)
|
||||
|
||||
for (var i = 0; i < action.playlists.length; i++){
|
||||
var playlist = action.playlists[i]
|
||||
if (typeof(playlists[playlist.uri]) !== 'undefined'){
|
||||
artist = Object.assign({}, playlists[playlist.uri], playlist)
|
||||
}
|
||||
playlists[playlist.uri] = playlist
|
||||
}
|
||||
|
||||
return Object.assign({}, ui, { playlists: playlists });
|
||||
|
||||
case 'MOPIDY_PLAYLIST_LOADED':
|
||||
if( !action.data ) return Object.assign({}, ui, { playlist: false })
|
||||
return Object.assign({}, ui, { playlist: action.data })
|
||||
|
||||
case 'SPOTIFY_PLAYLIST_LOADED':
|
||||
if( !action.data ) return Object.assign({}, ui, { playlist: false })
|
||||
case 'PLAYLIST_LOADED_MORE_TRACKS':
|
||||
var playlists = Object.assign([], ui.playlists)
|
||||
var playlist = Object.assign(
|
||||
{},
|
||||
playlists[action.uri],
|
||||
{
|
||||
tracks: [...playlists[action.uri].tracks, ...helpers.flattenTracks(action.data.items)],
|
||||
tracks_more: action.data.next,
|
||||
tracks_total: action.data.total
|
||||
}
|
||||
)
|
||||
|
||||
var tracks = []
|
||||
for( var i = 0; i < action.data.tracks.items.length; i++ ){
|
||||
tracks.push( Object.assign(
|
||||
{},
|
||||
action.data.tracks.items[i].track,
|
||||
{
|
||||
added_by: action.data.tracks.items[i].added_by,
|
||||
added_at: action.data.tracks.items[i].added_at
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
var playlist = Object.assign({}, action.data, {
|
||||
tracks: tracks,
|
||||
tracks_more: action.data.tracks.next,
|
||||
tracks_total: action.data.tracks.total
|
||||
})
|
||||
return Object.assign({}, ui, { playlist: playlist });
|
||||
|
||||
case 'SPOTIFY_PLAYLIST_LOADED_MORE':
|
||||
var tracks = []
|
||||
for( var i = 0; i < action.data.items.length; i++ ){
|
||||
tracks.push( Object.assign(
|
||||
{},
|
||||
action.data.items[i].track,
|
||||
{
|
||||
added_by: action.data.items[i].added_by,
|
||||
added_at: action.data.items[i].added_at
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
var playlist = Object.assign({}, ui.playlist, {
|
||||
tracks: [...ui.playlist.tracks, ...tracks],
|
||||
tracks_more: action.data.next
|
||||
})
|
||||
return Object.assign({}, ui, { playlist: playlist });
|
||||
playlists[action.uri] = playlist
|
||||
return Object.assign({}, ui, { playlists: playlists });
|
||||
|
||||
case 'PLAYLIST_TRACKS_REMOVED':
|
||||
var tracks = Object.assign([], ui.playlist.tracks)
|
||||
var playlists = Object.assign([], ui.playlists)
|
||||
var playlist = Object.assign({}, playlists[action.uri])
|
||||
var tracks = Object.assign([], playlist.tracks)
|
||||
var indexes = action.tracks_indexes.reverse()
|
||||
for( var i = 0; i < indexes.length; i++ ){
|
||||
tracks.splice( indexes[i], 1 )
|
||||
}
|
||||
var snapshot_id = null
|
||||
if( action.snapshot_id ) snapshot_id = action.snapshot_id
|
||||
var playlist = Object.assign({}, ui.playlist, { tracks: tracks, snapshot_id: snapshot_id })
|
||||
return Object.assign({}, ui, { playlist: playlist });
|
||||
Object.assign(playlist, { tracks: tracks, snapshot_id: snapshot_id })
|
||||
playlists[action.uri] = playlist
|
||||
return Object.assign({}, ui, { playlists: playlists });
|
||||
|
||||
case 'PLAYLIST_TRACKS_LOADED':
|
||||
var playlist = Object.assign({}, ui.playlist, { tracks: action.tracks })
|
||||
return Object.assign({}, ui, { playlist: playlist });
|
||||
case 'PLAYLIST_TRACKS':
|
||||
var playlists = Object.assign([], ui.playlists)
|
||||
var playlist = Object.assign({}, playlists[action.uri], { tracks: action.tracks })
|
||||
|
||||
playlists[action.uri] = playlist
|
||||
return Object.assign({}, ui, { playlists: playlists });
|
||||
|
||||
case 'PLAYLIST_TRACKS_REORDERED':
|
||||
var snapshot_id = null
|
||||
if( action.snapshot_id ) snapshot_id = action.snapshot_id
|
||||
var tracks = Object.assign([], ui.playlist.tracks)
|
||||
var playlists = Object.assign([], ui.playlists)
|
||||
var playlist = Object.assign({}, playlists[action.uri])
|
||||
var tracks = Object.assign([], playlist.tracks)
|
||||
|
||||
// handle insert_before offset if we're moving BENEATH where we're slicing tracks
|
||||
var insert_before = action.insert_before
|
||||
@ -304,26 +377,25 @@ export default function reducer(ui = {}, action){
|
||||
tracks.splice(insert_before, 0, tracks_to_move[i])
|
||||
}
|
||||
|
||||
var playlist = Object.assign({}, ui.playlist, { snapshot_id: snapshot_id, tracks: tracks })
|
||||
return Object.assign({}, ui, { playlist: playlist });
|
||||
var snapshot_id = null
|
||||
if( action.snapshot_id ) snapshot_id = action.snapshot_id
|
||||
Object.assign(playlist, { tracks: tracks, snapshot_id: snapshot_id })
|
||||
playlists[action.uri] = playlist
|
||||
return Object.assign({}, ui, { playlists: playlists });
|
||||
|
||||
case 'PLAYLIST_FOLLOWING_LOADED':
|
||||
var playlist = Object.assign({}, ui.playlist, { following: action.is_following })
|
||||
return Object.assign({}, ui, { playlist: playlist, following_loading: false });
|
||||
var playlists = Object.assign([], ui.playlists)
|
||||
var playlist = Object.assign({}, playlists[action.uri], { following: action.is_following })
|
||||
|
||||
playlists[action.uri] = playlist
|
||||
return Object.assign({}, ui, { playlists: playlists });
|
||||
|
||||
/**
|
||||
* Library Playlists
|
||||
**/
|
||||
case 'LIBRARY_PLAYLISTS_LOADED':
|
||||
var library_playlists = []
|
||||
if (ui.library_playlists) library_playlists = ui.library_playlists
|
||||
|
||||
case 'MOPIDY_PLAYLISTS_LOADED':
|
||||
case 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED':
|
||||
if( !action.data ) return ui
|
||||
var playlists = [...ui.playlists, ...action.data]
|
||||
playlists = helpers.mergeDuplicates(playlists, 'uri')
|
||||
helpers.sortItems(playlists, 'name')
|
||||
return Object.assign({}, ui, {
|
||||
playlists: playlists
|
||||
library_playlists: [...library_playlists, ...action.uris]
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ class Album extends React.Component{
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.loadAlbum();
|
||||
this.loadAlbum()
|
||||
}
|
||||
|
||||
componentWillReceiveProps( nextProps ){
|
||||
@ -46,11 +46,21 @@ class Album extends React.Component{
|
||||
switch( helpers.uriSource( props.params.uri ) ){
|
||||
|
||||
case 'spotify':
|
||||
this.props.spotifyActions.getAlbum( props.params.uri );
|
||||
if (props.album && props.album.tracks && props.album.artists_uris){
|
||||
console.info('Loading album from index')
|
||||
}else{
|
||||
this.props.spotifyActions.getAlbum( props.params.uri );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'local':
|
||||
if( props.mopidy_connected ) this.props.mopidyActions.getAlbum( props.params.uri );
|
||||
if (props.mopidy_connected){
|
||||
if (props.album && props.album.tracks){
|
||||
console.info('Loading album from index')
|
||||
} else {
|
||||
this.props.mopidyActions.getAlbum( props.params.uri );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -68,16 +78,26 @@ class Album extends React.Component{
|
||||
render(){
|
||||
if( !this.props.album ) return null
|
||||
|
||||
var artists = []
|
||||
if (this.props.album.artists_uris && this.props.artists){
|
||||
for (var i = 0; i < this.props.album.artists_uris.length; i++){
|
||||
var uri = this.props.album.artists_uris[i]
|
||||
if (this.props.artists.hasOwnProperty(uri)){
|
||||
artists.push(this.props.artists[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view album-view">
|
||||
<SidebarToggleButton />
|
||||
<div className="intro">
|
||||
<Thumbnail size="large" images={ this.props.album.images } />
|
||||
<ArtistGrid artists={ this.props.album.artists } />
|
||||
<ArtistGrid artists={artists} />
|
||||
|
||||
<div className="actions">
|
||||
<button className="large primary" onClick={ e => this.play() }>Play</button>
|
||||
{ helpers.uriSource(this.props.params.uri) == 'spotify' ? <FollowButton uri={this.props.params.uri} addText="Add to library" removeText="Remove from library" /> : null }
|
||||
{ helpers.uriSource(this.props.params.uri) == 'spotify' ? <FollowButton uri={this.props.params.uri} addText="Add to library" removeText="Remove from library" is_following={this.props.album.is_following} /> : null }
|
||||
</div>
|
||||
|
||||
<ul className="details">
|
||||
@ -93,7 +113,7 @@ class Album extends React.Component{
|
||||
|
||||
<div className="title">
|
||||
<h1>{ this.props.album.name }</h1>
|
||||
<h3><ArtistSentence artists={ this.props.album.artists } /></h3>
|
||||
<h3><ArtistSentence artists={artists} /></h3>
|
||||
</div>
|
||||
|
||||
<section className="list-wrapper">
|
||||
@ -116,7 +136,9 @@ class Album extends React.Component{
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
album: state.ui.album,
|
||||
artists: state.ui.artists,
|
||||
album: (state.ui.albums && typeof(state.ui.albums[ownProps.params.uri]) !== 'undefined' ? state.ui.albums[ownProps.params.uri] : false ),
|
||||
albums: state.ui.albums,
|
||||
spotify_authorized: state.spotify.authorized,
|
||||
mopidy_connected: state.mopidy.connected
|
||||
};
|
||||
|
||||
@ -53,7 +53,7 @@ class App extends React.Component{
|
||||
|
||||
// mopidy comes online
|
||||
if( !this.props.mopidy_connected && nextProps.mopidy_connected ){
|
||||
this.props.mopidyActions.getPlaylists();
|
||||
this.props.mopidyActions.getLibraryPlaylists();
|
||||
}
|
||||
|
||||
// spotify authorized
|
||||
|
||||
@ -49,17 +49,31 @@ class Artist extends React.Component{
|
||||
componentWillUpdate( nextProps, nextState ){
|
||||
if( nextState.sub_view != this.state.sub_view && nextState.sub_view == 'biography' ){
|
||||
if( this.props.artist && !this.props.artist.bio ){
|
||||
this.props.lastfmActions.getArtist( this.props.artist.name.replace('&','and') )
|
||||
this.props.lastfmActions.getArtist( this.props.params.uri, this.props.artist.name.replace('&','and') )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadArtist( props = this.props ){
|
||||
var source = helpers.uriSource( props.params.uri );
|
||||
if( source == 'spotify' ){
|
||||
this.props.spotifyActions.getArtist( props.params.uri );
|
||||
}else if( source == 'local' && props.mopidy_connected ){
|
||||
this.props.mopidyActions.getArtist( props.params.uri );
|
||||
switch( helpers.uriSource( props.params.uri ) ){
|
||||
|
||||
case 'spotify':
|
||||
if (props.artist && props.artist.albums_uris && props.artist.related_artists_uris){
|
||||
console.info('Loading spotify artist from index')
|
||||
}else{
|
||||
this.props.spotifyActions.getArtist( props.params.uri );
|
||||
}
|
||||
break
|
||||
|
||||
case 'local':
|
||||
if (props.mopidy_connected){
|
||||
if (props.artist && props.artist.images){
|
||||
console.info('Loading local artist from index')
|
||||
} else {
|
||||
this.props.mopidyActions.getArtist( props.params.uri );
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// go back to overview
|
||||
@ -68,7 +82,7 @@ class Artist extends React.Component{
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.artist.albums_more ) return
|
||||
this.props.spotifyActions.getURL( this.props.artist.albums_more, 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE' );
|
||||
this.props.spotifyActions.getURL( this.props.artist.albums_more, 'SPOTIFY_ARTIST_ALBUMS_LOADED', this.props.params.uri );
|
||||
}
|
||||
|
||||
play(){
|
||||
@ -83,9 +97,7 @@ class Artist extends React.Component{
|
||||
<span className={'option '+( this.state.sub_view == 'overview' ? 'active' : null)} onClick={() => this.setState({ sub_view: 'overview' })}>
|
||||
Overview
|
||||
</span>
|
||||
<span className={'option '+( this.state.sub_view == 'related_artists' ? 'active' : null)} onClick={() => this.setState({ sub_view: 'related_artists' })}>
|
||||
Related artists
|
||||
</span>
|
||||
{this.props.artist.related_artists_uris ? <span className={'option '+( this.state.sub_view == 'related_artists' ? 'active' : null)} onClick={() => this.setState({ sub_view: 'related_artists' })}>Related artists</span> : null}
|
||||
<span className={'option '+( this.state.sub_view == 'biography' ? 'active' : null)} onClick={() => this.setState({ sub_view: 'biography' })}>
|
||||
Biography
|
||||
</span>
|
||||
@ -94,13 +106,32 @@ class Artist extends React.Component{
|
||||
}
|
||||
|
||||
renderBody(){
|
||||
var related_artists = []
|
||||
if (this.props.artist.related_artists_uris){
|
||||
for (var i = 0; i < this.props.artist.related_artists_uris.length; i++){
|
||||
var uri = this.props.artist.related_artists_uris[i]
|
||||
if (this.props.artists.hasOwnProperty(uri)){
|
||||
related_artists.push(this.props.artists[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var albums = []
|
||||
if (this.props.artist.albums_uris){
|
||||
for (var i = 0; i < this.props.artist.albums_uris.length; i++){
|
||||
var uri = this.props.artist.albums_uris[i]
|
||||
if (this.props.albums.hasOwnProperty(uri)){
|
||||
albums.push(this.props.albums[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( this.state.sub_view == 'related_artists' ){
|
||||
return (
|
||||
<div className="body related-artists">
|
||||
<h4 className="left-padding">Related artists</h4>
|
||||
<section className="grid-wrapper no-top-padding">
|
||||
{ this.props.artist.related_artists ? <ArtistGrid artists={ this.props.artist.related_artists } /> : null }
|
||||
<ArtistGrid artists={related_artists} />
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
@ -117,26 +148,22 @@ class Artist extends React.Component{
|
||||
)
|
||||
}
|
||||
|
||||
// default body
|
||||
return (
|
||||
<div className="body overview">
|
||||
<div className="col w70">
|
||||
<div className={related_artists.length > 0 ? "col w70" : "col w100"}>
|
||||
<h4 className="left-padding">Top tracks</h4>
|
||||
{ this.props.artist.tracks ? <TrackList tracks={ this.props.artist.tracks } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="col w5"></div>
|
||||
|
||||
<div className="col w25 related-artists">
|
||||
<h4>Related artists</h4>
|
||||
{ this.props.artist.related_artists ? <ArtistList artists={ this.props.artist.related_artists.slice(0,6) } /> : null }
|
||||
</div>
|
||||
{related_artists.length > 0 ? <div className="col w25 related-artists"><h4>Related artists</h4><ArtistList artists={related_artists.slice(0,6)} /></div> : null}
|
||||
|
||||
<div className="cf"></div>
|
||||
|
||||
<h4 className="left-padding">Albums</h4>
|
||||
<section className="grid-wrapper no-top-padding">
|
||||
{ this.props.artist.albums ? <AlbumGrid albums={ this.props.artist.albums } /> : null }
|
||||
<AlbumGrid albums={albums} />
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</section>
|
||||
</div>
|
||||
@ -147,7 +174,7 @@ class Artist extends React.Component{
|
||||
if( !this.props.artist ) return null
|
||||
var scheme = helpers.uriSource( this.props.params.uri );
|
||||
|
||||
var image = false
|
||||
var image = null
|
||||
if( this.props.artist.images ) image = helpers.sizedImages( this.props.artist.images ).huge
|
||||
|
||||
return (
|
||||
@ -171,7 +198,7 @@ class Artist extends React.Component{
|
||||
|
||||
<div className="actions">
|
||||
<button className="large primary" onClick={ e => this.play() }>Start radio</button>
|
||||
{ helpers.uriSource(this.props.params.uri) == 'spotify' ? <FollowButton uri={this.props.params.uri} removeText="Unfollow" addText="Follow" /> : null }
|
||||
{ helpers.uriSource(this.props.params.uri) == 'spotify' ? <FollowButton uri={this.props.params.uri} removeText="Unfollow" addText="Follow" is_following={this.props.artist.is_following} /> : null }
|
||||
</div>
|
||||
|
||||
<ul className="details">
|
||||
@ -203,7 +230,9 @@ class Artist extends React.Component{
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
artist: state.ui.artist,
|
||||
artist: (state.ui.artists && typeof(state.ui.artists[ownProps.params.uri]) !== 'undefined' ? state.ui.artists[ownProps.params.uri] : false ),
|
||||
artists: state.ui.artists,
|
||||
albums: state.ui.albums,
|
||||
spotify_authorized: state.spotify.authorized,
|
||||
mopidy_connected: state.mopidy.connected
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ class Playlist extends React.Component{
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.playlist.tracks_more ) return
|
||||
this.props.spotifyActions.getURL( this.props.playlist.tracks_more, 'SPOTIFY_PLAYLIST_LOADED_MORE' );
|
||||
this.props.spotifyActions.getURL( this.props.playlist.tracks_more, 'PLAYLIST_LOADED_MORE_TRACKS', this.props.playlist.uri );
|
||||
}
|
||||
|
||||
play(){
|
||||
@ -90,19 +90,6 @@ class Playlist extends React.Component{
|
||||
this.props.uiActions.removeTracksFromPlaylist( this.props.playlist.uri, tracks_indexes )
|
||||
}
|
||||
|
||||
isEditable(){
|
||||
if( helpers.uriSource( this.props.playlist.uri ) == 'spotify' ){
|
||||
if( !this.props.spotify_authorized ) return false
|
||||
|
||||
return ( this.props.playlist &&
|
||||
this.props.playlist.owner &&
|
||||
this.props.playlist.owner.id == this.props.spotify_userid
|
||||
)
|
||||
}else{
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
renderExtraButtons(){
|
||||
switch( helpers.uriSource( this.props.playlist.uri ) ){
|
||||
|
||||
@ -115,7 +102,7 @@ class Playlist extends React.Component{
|
||||
)
|
||||
|
||||
case 'spotify':
|
||||
if( this.isEditable() ){
|
||||
if( this.props.playlist.can_edit ){
|
||||
return (
|
||||
<span>
|
||||
<button className="large tertiary" onClick={ e => this.props.uiActions.openModal('edit_playlist', { uri: this.props.playlist.uri, name: this.props.playlist.name, is_public: this.props.playlist.public }) }>Edit</button>
|
||||
@ -123,7 +110,7 @@ class Playlist extends React.Component{
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return <FollowButton uri={this.props.playlist.uri} addText="Add to library" removeText="Remove from library" />
|
||||
return <FollowButton uri={this.props.playlist.uri} addText="Add to library" removeText="Remove from library" is_following={this.props.playlist.is_following} />
|
||||
|
||||
}
|
||||
}
|
||||
@ -167,7 +154,7 @@ class Playlist extends React.Component{
|
||||
</div>
|
||||
|
||||
<section className="list-wrapper">
|
||||
{ this.props.playlist.tracks ? <TrackList context={ this.isEditable() ? 'editable-playlist' : 'playlist'} tracks={ this.props.playlist.tracks } removeTracks={ tracks_indexes => this.removeTracks(tracks_indexes) } reorderTracks={ (indexes, index) => this.reorderTracks(indexes, index) } /> : null }
|
||||
{ this.props.playlist.tracks ? <TrackList context={ this.props.playlist.can_edit ? 'editable-playlist' : 'playlist'} tracks={ this.props.playlist.tracks } removeTracks={ tracks_indexes => this.removeTracks(tracks_indexes) } reorderTracks={ (indexes, index) => this.reorderTracks(indexes, index) } /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</section>
|
||||
|
||||
@ -186,7 +173,7 @@ class Playlist extends React.Component{
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
playlist: state.ui.playlist,
|
||||
playlist: state.ui.playlists[helpers.indexFriendlyUri(ownProps.params.uri)],
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
spotify_authorized: state.spotify.authorized,
|
||||
spotify_userid: state.spotify.me.id
|
||||
|
||||
@ -17,29 +17,35 @@ class DiscoverCategory extends React.Component{
|
||||
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.getCategory( this.props.params.id );
|
||||
this.props.spotifyActions.getCategoryPlaylists( this.props.params.id );
|
||||
}
|
||||
|
||||
componentWillReceiveProps( nextProps ){
|
||||
if( nextProps.params.id != this.props.params.id ){
|
||||
this.props.spotifyActions.getCategory( nextProps.params.id );
|
||||
this.props.spotifyActions.getCategoryPlaylists( nextProps.params.id );
|
||||
}
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.spotify.new_releases || !this.props.spotify.new_releases.next ) return
|
||||
this.props.spotifyActions.getURL( this.props.spotify.new_releases.next, 'SPOTIFY_NEW_RELEASES_LOADED_MORE' );
|
||||
if( !this.props.playlists_next || !this.props.playlists_next ) return
|
||||
this.props.spotifyActions.getURL( this.props.playlists_next, 'SPOTIFY_NEW_RELEASES_LOADED_MORE' );
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.spotify.category ) return null;
|
||||
if (!this.props.category) return null
|
||||
|
||||
var playlists = []
|
||||
for (var i = 0; i < this.props.category.playlists.length; i++){
|
||||
var uri = this.props.category.playlists[i]
|
||||
if (this.props.playlists.hasOwnProperty(uri)){
|
||||
playlists.push(this.props.playlists[uri])
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view discover-categories-view">
|
||||
<Header icon="grid" title={this.props.spotify.category.name} />
|
||||
<Header icon="grid" title={this.props.category.name} />
|
||||
<section className="grid-wrapper">
|
||||
{ this.props.spotify.category_playlists ? <PlaylistGrid playlists={this.props.spotify.category_playlists.items} /> : null }
|
||||
<PlaylistGrid playlists={playlists} />
|
||||
</section>
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
@ -55,7 +61,10 @@ class DiscoverCategory extends React.Component{
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
return {
|
||||
playlists: state.ui.playlists,
|
||||
category: state.spotify.category
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
@ -20,11 +20,22 @@ class DiscoverFeatured extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
var playlists = []
|
||||
if (this.props.featured_playlists){
|
||||
for (var i = 0; i < this.props.featured_playlists.playlists.length; i++){
|
||||
var uri = this.props.featured_playlists.playlists[i]
|
||||
if (this.props.playlists.hasOwnProperty(uri)){
|
||||
playlists.push(this.props.playlists[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view discover-featured-view">
|
||||
<Header icon="star" title="Featured playlists" />
|
||||
<section className="grid-wrapper">
|
||||
{ this.props.spotify.featured_playlists ? <PlaylistGrid playlists={this.props.spotify.featured_playlists.playlists.items} /> : null }
|
||||
{ playlists ? <PlaylistGrid playlists={playlists} /> : null }
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
@ -39,7 +50,10 @@ class DiscoverFeatured extends React.Component{
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
return {
|
||||
featured_playlists: state.spotify.featured_playlists,
|
||||
playlists: state.ui.playlists
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
@ -17,20 +17,31 @@ class DiscoverNewReleases extends React.Component{
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.getNewReleases();
|
||||
if (!this.props.new_releases) this.props.spotifyActions.getNewReleases();
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.spotify.new_releases || !this.props.spotify.new_releases.next ) return
|
||||
this.props.spotifyActions.getURL( this.props.spotify.new_releases.next, 'SPOTIFY_NEW_RELEASES_LOADED_MORE' );
|
||||
if (!this.props.new_releases_more) return
|
||||
this.props.spotifyActions.getURL(this.props.new_releases_more, 'SPOTIFY_NEW_RELEASES_LOADED');
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
var albums = []
|
||||
if (this.props.new_releases){
|
||||
for (var i = 0; i < this.props.new_releases.length; i++){
|
||||
var uri = this.props.new_releases[i]
|
||||
if (this.props.albums.hasOwnProperty(uri)){
|
||||
albums.push(this.props.albums[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view discover-new-releases-view">
|
||||
<Header icon="leaf" title="New Releases" />
|
||||
<section className="grid-wrapper">
|
||||
{ this.props.spotify.new_releases ? <AlbumGrid albums={this.props.spotify.new_releases.items} /> : null }
|
||||
<AlbumGrid albums={albums} />
|
||||
</section>
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
@ -46,7 +57,12 @@ class DiscoverNewReleases extends React.Component{
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
return {
|
||||
albums: state.ui.albums,
|
||||
new_releases: state.ui.new_releases,
|
||||
new_releases_more: state.ui.new_releases_more,
|
||||
new_releases_total: state.ui.new_releases_total
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
@ -24,16 +24,16 @@ class LibraryAlbums extends React.Component{
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.getLibraryAlbums();
|
||||
if (!this.props.library_albums) this.props.spotifyActions.getLibraryAlbums();
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.albums_more ) return
|
||||
this.props.spotifyActions.getURL( this.props.albums_more, 'SPOTIFY_LIBRARY_ALBUMS_LOADED_MORE' );
|
||||
if( !this.props.library_albums_more ) return
|
||||
this.props.spotifyActions.getURL( this.props.library_albums_more, 'SPOTIFY_LIBRARY_ALBUMS_LOADED' );
|
||||
}
|
||||
|
||||
renderView(){
|
||||
if( !this.props.albums ) return null
|
||||
renderView(albums){
|
||||
if (!albums || albums.length <= 0) return null
|
||||
|
||||
if( this.props.view == 'list' ){
|
||||
var columns = [
|
||||
@ -60,20 +60,20 @@ class LibraryAlbums extends React.Component{
|
||||
]
|
||||
return (
|
||||
<section className="list-wrapper">
|
||||
<List rows={this.props.albums} columns={columns} link_prefix={global.baseURL+"album/"} />
|
||||
<List rows={albums} columns={columns} link_prefix={global.baseURL+"album/"} />
|
||||
</section>
|
||||
)
|
||||
}else if( this.props.view == 'thumbnails' ){
|
||||
return (
|
||||
<section className="grid-wrapper">
|
||||
{ this.props.albums ? <AlbumGrid albums={this.props.albums} /> : null }
|
||||
<AlbumGrid albums={albums} />
|
||||
</section>
|
||||
)
|
||||
}else{
|
||||
return (
|
||||
<section className="grid-wrapper albums-detail-subview">
|
||||
{
|
||||
this.props.albums.map( album => {
|
||||
albums.map( album => {
|
||||
return (
|
||||
<div className="album" key={album.uri}>
|
||||
<Link to={global.baseURL+'album/'+album.uri}>
|
||||
@ -85,7 +85,7 @@ class LibraryAlbums extends React.Component{
|
||||
</Link>
|
||||
<h4><ArtistSentence className="grey-text" artists={album.artists} /></h4>
|
||||
</div>
|
||||
<TrackList tracks={album.tracks.items} />
|
||||
<TrackList tracks={album.tracks} />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@ -96,6 +96,16 @@ class LibraryAlbums extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
var albums = []
|
||||
|
||||
if (this.props.library_albums && this.props.albums){
|
||||
for (var i = 0; i < this.props.library_albums.length; i++){
|
||||
var uri = this.props.library_albums[i]
|
||||
if (this.props.albums.hasOwnProperty(uri)){
|
||||
albums.push(this.props.albums[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var view_options = [
|
||||
{
|
||||
@ -119,7 +129,7 @@ class LibraryAlbums extends React.Component{
|
||||
return (
|
||||
<div className="view library-albums-view">
|
||||
<Header icon="cd" title="My albums" actions={actions} />
|
||||
{ this.renderView() }
|
||||
{ this.renderView(albums) }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
@ -136,8 +146,9 @@ class LibraryAlbums extends React.Component{
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
view: state.ui.library_albums_view,
|
||||
albums: state.spotify.library_albums,
|
||||
albums_more: state.spotify.library_albums_more,
|
||||
albums: state.ui.albums,
|
||||
library_albums: state.ui.library_albums,
|
||||
library_albums_more: state.ui.library_albums_more,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,19 +20,16 @@ class LibraryArtists extends React.Component{
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.getLibraryArtists();
|
||||
if (!this.props.library_artists) this.props.spotifyActions.getLibraryArtists();
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.artists_more ) return
|
||||
this.props.spotifyActions.getURL( this.props.artists_more, 'SPOTIFY_LIBRARY_ARTISTS_LOADED_MORE' );
|
||||
if( !this.props.library_artists_more ) return
|
||||
this.props.spotifyActions.getURL( this.props.library_artists_more, 'SPOTIFY_LIBRARY_ARTISTS_LOADED' );
|
||||
}
|
||||
|
||||
renderView(){
|
||||
if( !this.props.artists ) return null
|
||||
|
||||
renderView(artists){
|
||||
if( this.props.view == 'list' ){
|
||||
var columns = [
|
||||
{
|
||||
@ -48,13 +45,13 @@ class LibraryArtists extends React.Component{
|
||||
]
|
||||
return (
|
||||
<section className="list-wrapper">
|
||||
<List rows={this.props.artists} columns={columns} link_prefix={global.baseURL+"artist/"} show_source_icon={true} />
|
||||
<List rows={artists} columns={columns} link_prefix={global.baseURL+"artist/"} show_source_icon={true} />
|
||||
</section>
|
||||
)
|
||||
}else{
|
||||
return (
|
||||
<section className="grid-wrapper">
|
||||
<ArtistGrid artists={this.props.artists} />
|
||||
<ArtistGrid artists={artists} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@ -62,6 +59,16 @@ class LibraryArtists extends React.Component{
|
||||
|
||||
render(){
|
||||
|
||||
var artists = []
|
||||
if (this.props.library_artists && this.props.artists){
|
||||
for (var i = 0; i < this.props.library_artists.length; i++){
|
||||
var uri = this.props.library_artists[i]
|
||||
if (this.props.artists.hasOwnProperty(uri)){
|
||||
artists.push(this.props.artists[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var view_options = [
|
||||
{
|
||||
value: 'thumbnails',
|
||||
@ -80,7 +87,7 @@ class LibraryArtists extends React.Component{
|
||||
return (
|
||||
<div className="view library-artists-view">
|
||||
<Header icon="mic" title="My artists" actions={actions} />
|
||||
{ this.renderView() }
|
||||
{ this.renderView(artists) }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
@ -96,9 +103,10 @@ class LibraryArtists extends React.Component{
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
view: state.ui.library_artists_view,
|
||||
artists: state.spotify.library_artists,
|
||||
artists_more: state.spotify.library_artists_more
|
||||
artists: state.ui.artists,
|
||||
library_artists: state.ui.library_artists,
|
||||
library_artists_more: state.ui.library_artists_more,
|
||||
view: state.ui.library_artists_view
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ class LibraryLocalAlbums extends React.Component{
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.loadAlbums()
|
||||
}
|
||||
@ -33,13 +32,21 @@ class LibraryLocalAlbums extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.albums ) return null
|
||||
var albums = []
|
||||
if (this.props.albums && this.props.local_albums){
|
||||
for (var i = 0; i < this.props.local_albums.length; i++){
|
||||
var uri = this.props.local_albums[i]
|
||||
if (this.props.albums.hasOwnProperty(uri)){
|
||||
albums.push(this.props.albums[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view library-local-view">
|
||||
<Header icon="music" title="Local albums" />
|
||||
<div>
|
||||
<List columns={[{ name: 'name', width: '100'}]} rows={this.props.albums} link_prefix={global.baseURL+"album/"} />
|
||||
<List columns={[{ name: 'name', width: '100'}]} rows={albums} link_prefix={global.baseURL+"album/"} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -56,7 +63,8 @@ class LibraryLocalAlbums extends React.Component{
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
albums: state.mopidy.albums
|
||||
local_albums: state.ui.local_albums,
|
||||
albums: state.ui.albums
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -27,19 +27,27 @@ class LibraryLocalArtists extends React.Component{
|
||||
}
|
||||
|
||||
loadArtists(props = this.props){
|
||||
if( props.mopidy_connected ){
|
||||
if( props.mopidy_connected && !props.local_artists ){
|
||||
this.props.mopidyActions.getArtists();
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.artists ) return null
|
||||
var artists = []
|
||||
if (this.props.artists && this.props.local_artists){
|
||||
for (var i = 0; i < this.props.local_artists.length; i++){
|
||||
var uri = this.props.local_artists[i]
|
||||
if (this.props.artists.hasOwnProperty(uri)){
|
||||
artists.push(this.props.artists[uri])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view library-local-view">
|
||||
<Header icon="music" title="Local artists" />
|
||||
<section className="list-wrapper">
|
||||
<List columns={[{ name: 'name', width: '100'}]} rows={this.props.artists} link_prefix={global.baseURL+"artist/"} />
|
||||
<List columns={[{ name: 'name', width: '100'}]} rows={artists} link_prefix={global.baseURL+"artist/"} />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
@ -56,7 +64,8 @@ class LibraryLocalArtists extends React.Component{
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
artists: state.mopidy.artists
|
||||
local_artists: state.ui.local_artists,
|
||||
artists: state.ui.artists
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,9 +33,16 @@ class LibraryPlaylists extends React.Component{
|
||||
}
|
||||
|
||||
renderView(){
|
||||
if( !this.props.playlists ) return null
|
||||
if( !this.props.library_playlists || !this.props.playlists ) return null
|
||||
|
||||
var playlists = []
|
||||
for (var i = 0; i < this.props.library_playlists.length; i++){
|
||||
var uri = this.props.library_playlists[i]
|
||||
if (this.props.playlists.hasOwnProperty(uri)){
|
||||
playlists.push(this.props.playlists[uri])
|
||||
}
|
||||
}
|
||||
|
||||
var playlists = Object.assign([], this.props.playlists)
|
||||
if( this.props.sort ){
|
||||
playlists = helpers.sortItems(playlists, this.props.sort, this.props.sort_reverse)
|
||||
}
|
||||
@ -60,7 +67,7 @@ class LibraryPlaylists extends React.Component{
|
||||
{
|
||||
width: 10,
|
||||
label: 'Tracks',
|
||||
name: 'tracks.total'
|
||||
name: 'tracks_total'
|
||||
}
|
||||
]
|
||||
return (
|
||||
@ -141,6 +148,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
view: state.ui.library_playlists_view,
|
||||
sort: state.ui.library_playlists_sort,
|
||||
sort_reverse: state.ui.library_playlists_sort_reverse,
|
||||
library_playlists: state.ui.library_playlists,
|
||||
playlists: state.ui.playlists
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user