Artist and Playlist

This commit is contained in:
James Barnsley
2016-11-09 21:13:40 +13:00
parent b18b1fa2b7
commit 52d95fd74b
10 changed files with 286 additions and 320 deletions

View File

@ -918,7 +918,6 @@
exports.getTrack = getTrack; exports.getTrack = getTrack;
exports.getArtist = getArtist; exports.getArtist = getArtist;
exports.getArtists = getArtists; exports.getArtists = getArtists;
exports.getArtistAlbums = getArtistAlbums;
exports.getAlbum = getAlbum; exports.getAlbum = getAlbum;
exports.getPlaylist = getPlaylist; exports.getPlaylist = getPlaylist;
exports.getLibraryPlaylists = getLibraryPlaylists; exports.getLibraryPlaylists = getLibraryPlaylists;
@ -1143,9 +1142,6 @@
var artist = {}; var artist = {};
// while we're fiddling about, go get the albums
dispatch(getArtistAlbums(uri));
// get both the artist and the top tracks // get both the artist and the top tracks
$.when(sendRequest(dispatch, getState, 'artists/' + helpers.getFromUri('artistid', uri)).then(function (response) { $.when(sendRequest(dispatch, getState, 'artists/' + helpers.getFromUri('artistid', uri)).then(function (response) {
Object.assign(artist, response); Object.assign(artist, response);
@ -1153,6 +1149,8 @@
Object.assign(artist, response); Object.assign(artist, response);
}), sendRequest(dispatch, getState, 'artists/' + helpers.getFromUri('artistid', uri) + '/related-artists').then(function (response) { }), sendRequest(dispatch, getState, 'artists/' + helpers.getFromUri('artistid', uri) + '/related-artists').then(function (response) {
Object.assign(artist, { related_artists: response.artists }); Object.assign(artist, { related_artists: response.artists });
}), sendRequest(dispatch, getState, 'artists/' + helpers.getFromUri('artistid', uri) + '/albums').then(function (response) {
Object.assign(artist, { albums: response.items, albums_more: response.next });
})).then(function () { })).then(function () {
dispatch({ dispatch({
type: 'SPOTIFY_ARTIST_LOADED', type: 'SPOTIFY_ARTIST_LOADED',
@ -1184,17 +1182,6 @@
}; };
} }
function getArtistAlbums(uri) {
return function (dispatch, getState) {
sendRequest(dispatch, getState, 'artists/' + helpers.getFromUri('artistid', uri) + '/albums').then(function (response) {
dispatch({
type: 'SPOTIFY_ARTIST_ALBUMS_LOADED',
data: response
});
});
};
}
/** /**
* Single album * Single album
* *
@ -19841,7 +19828,7 @@
/* 172 */ /* 172 */
/***/ function(module, exports) { /***/ function(module, exports) {
'use strict'; "use strict";
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
@ -19853,12 +19840,6 @@
switch (action.type) { switch (action.type) {
case 'LASTFM_ARTIST_LOADED':
return Object.assign({}, lastfm, { artist: action.data });
case 'LASTFM_TRACK_LOADED':
return Object.assign({}, lastfm, { track: action.data });
default: default:
return lastfm; return lastfm;
} }
@ -20201,15 +20182,16 @@
case 'MOPIDY_PLAYLIST': case 'MOPIDY_PLAYLIST':
store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: false }); store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: false });
instruct(socket, store, 'playlists.lookup', action.data).then(function (response) { instruct(socket, store, 'playlists.lookup', action.data).then(function (response) {
var playlist = response; var playlist = Object.assign({}, {
playlist.tracks = { images: []
items: response.tracks, }, response, {
total: response.tracks.length tracks: response.tracks,
}; total_tracks: response.tracks.length
});
var uris = []; var uris = [];
for (var i = 0; i < playlist.tracks.items.length; i++) { for (var i = 0; i < playlist.tracks.length; i++) {
uris.push(playlist.tracks.items[i].uri); uris.push(playlist.tracks[i].uri);
} }
instruct(socket, store, 'library.lookup', { uris: uris }).then(function (response) { instruct(socket, store, 'library.lookup', { uris: uris }).then(function (response) {
@ -20223,12 +20205,12 @@
}; };
var track = response[uri][0]; var track = response[uri][0];
var trackReferences = playlist.tracks.items.filter(getByURI); var trackReferences = playlist.tracks.filter(getByURI);
// there could be multiple instances of this track, so accommodate this // there could be multiple instances of this track, so accommodate this
for (var j = 0; j < trackReferences.length; j++) { for (var j = 0; j < trackReferences.length; j++) {
var key = playlist.tracks.items.indexOf(trackReferences[j]); var key = playlist.tracks.indexOf(trackReferences[j]);
playlist.tracks.items[key] = track; playlist.tracks[key] = track;
} }
} }
} }
@ -20456,11 +20438,6 @@
playlist: action.data playlist: action.data
}); });
case 'MOPIDY_ARTIST_LOADED':
return Object.assign({}, mopidy, {
artist: action.data
});
case 'MOPIDY_ARTISTS_LOADED': case 'MOPIDY_ARTISTS_LOADED':
return Object.assign({}, mopidy, { return Object.assign({}, mopidy, {
artists: action.data artists: action.data
@ -20799,36 +20776,9 @@
case 'SPOTIFY_ME_LOADED': case 'SPOTIFY_ME_LOADED':
return Object.assign({}, spotify, { me: action.data }); return Object.assign({}, spotify, { me: action.data });
case 'SPOTIFY_PLAYLIST_LOADED':
return Object.assign({}, spotify, { playlist: action.data });
case 'SPOTIFY_PLAYLIST_LOADED_MORE':
var playlist = spotify.playlist;
Object.assign(playlist, { tracks: {
href: action.data.href,
next: action.data.next,
previous: action.data.previous,
items: [].concat(_toConsumableArray(spotify.playlist.tracks.items), _toConsumableArray(action.data.items))
} });
return Object.assign({}, spotify, { playlist: playlist });
case 'SPOTIFY_ARTIST_LOADED':
return Object.assign({}, spotify, { artist: action.data });
case 'SPOTIFY_ARTISTS_LOADED': case 'SPOTIFY_ARTISTS_LOADED':
return Object.assign({}, spotify, { artists: action.data }); return Object.assign({}, spotify, { artists: action.data });
case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
return Object.assign({}, spotify, { artist_albums: action.data });
case 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE':
return Object.assign({}, spotify, { artist_albums: {
href: action.data.href,
next: action.data.next,
previous: action.data.previous,
items: [].concat(_toConsumableArray(spotify.artist_albums.items), _toConsumableArray(action.data.items))
} });
case 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED': case 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED':
return Object.assign({}, spotify, { library_playlists: action.data }); return Object.assign({}, spotify, { library_playlists: action.data });
@ -20933,11 +20883,11 @@
return Object.assign({}, ui, { context_menu: { show: false } }); return Object.assign({}, ui, { context_menu: { show: false } });
/** /**
* General assets * Albums
* Playlists/albums/etc
**/ **/
case 'MOPIDY_ALBUM_LOADED': case 'MOPIDY_ALBUM_LOADED':
if (!action.data) return Object.assign({}, ui, { album: false });
return Object.assign({}, ui, { album: action.data }); return Object.assign({}, ui, { album: action.data });
case 'LASTFM_ALBUM_LOADED': case 'LASTFM_ALBUM_LOADED':
@ -20949,7 +20899,6 @@
case 'SPOTIFY_ALBUM_LOADED': case 'SPOTIFY_ALBUM_LOADED':
if (!action.data) return Object.assign({}, ui, { album: false }); if (!action.data) return Object.assign({}, ui, { album: false });
console.log(action.data);
var album = Object.assign({}, { images: [] }, action.data, { var album = Object.assign({}, { images: [] }, action.data, {
tracks: action.data.tracks.items, tracks: action.data.tracks.items,
tracks_total: action.data.tracks.total, tracks_total: action.data.tracks.total,
@ -20964,6 +20913,72 @@
}); });
return Object.assign({}, ui, { album: album }); return Object.assign({}, ui, { album: album });
/**
* Artists
**/
case 'MOPIDY_ARTIST_LOADED':
if (!action.data) return Object.assign({}, ui, { artist: false });
return Object.assign({}, ui, { artist: action.data });
case 'LASTFM_ARTIST_LOADED':
if (!action.data.image) return ui;
var artist = Object.assign({}, ui.artist, { images: action.data.image, bio: action.data.bio });
return Object.assign({}, ui, { artist: artist });
case 'SPOTIFY_ARTIST_LOADED':
if (!action.data) return Object.assign({}, ui, { artist: false });
return Object.assign({}, ui, { artist: action.data });
case 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE':
var artist = Object.assign({}, ui.artist, {
albums: [].concat(_toConsumableArray(ui.artist.albums), _toConsumableArray(action.data.items)),
albums_more: action.data.next
});
return Object.assign({}, ui, { artist: artist });
/**
* 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 });
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: [].concat(_toConsumableArray(ui.playlist.tracks), _toConsumableArray(tracks)),
tracks_more: action.data.next
});
return Object.assign({}, ui, { playlist: playlist });
/** /**
* Current track and tracklist * Current track and tracklist
**/ **/
@ -21558,7 +21573,7 @@
value: function componentWillReceiveProps(nextProps) { value: function componentWillReceiveProps(nextProps) {
if (nextProps.params.uri != this.props.params.uri) { if (nextProps.params.uri != this.props.params.uri) {
this.loadArtist(nextProps); this.loadArtist(nextProps);
} else if (!this.props.mopidy.connected && nextProps.mopidy.connected) { } else if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
if (helpers.uriSource(this.props.params.uri) == 'local') { if (helpers.uriSource(this.props.params.uri) == 'local') {
this.loadArtist(nextProps); this.loadArtist(nextProps);
} }
@ -21572,59 +21587,70 @@
var source = helpers.uriSource(props.params.uri); var source = helpers.uriSource(props.params.uri);
if (source == 'spotify') { if (source == 'spotify') {
this.props.spotifyActions.getArtist(props.params.uri); this.props.spotifyActions.getArtist(props.params.uri);
} else if (source == 'local' && props.mopidy.connected) { } else if (source == 'local' && props.mopidy_connected) {
this.props.mopidyActions.getArtist(props.params.uri); this.props.mopidyActions.getArtist(props.params.uri);
} }
} }
}, { }, {
key: 'loadMore', key: 'loadMore',
value: function loadMore() { value: function loadMore() {
if (!this.props.spotify.artist_albums || !this.props.spotify.artist_albums.next) return; if (!this.props.artist.albums_more) return;
this.props.spotifyActions.getURL(this.props.spotify.artist_albums.next, 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE'); this.props.spotifyActions.getURL(this.props.artist.albums_more, 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE');
} }
}, { }, {
key: 'renderSpotifyArtist', key: 'render',
value: function renderSpotifyArtist() { value: function render() {
var _this2 = this; var _this2 = this;
if (!this.props.spotify.artist) return null; if (!this.props.artist) return null;
var artist = this.props.spotify.artist; var scheme = helpers.uriSource(this.props.params.uri);
var albums = this.props.spotify.artist_albums;
return _react2.default.createElement( return _react2.default.createElement(
'div', 'div',
{ className: 'view artist-view' }, { className: 'view artist-view' },
_react2.default.createElement(_Parallax2.default, { images: artist.images }), _react2.default.createElement(_Parallax2.default, { images: this.props.artist.images }),
_react2.default.createElement( _react2.default.createElement(
'div', 'div',
{ className: 'intro' }, { className: 'intro' },
_react2.default.createElement(_Thumbnail2.default, { size: 'huge', images: artist.images }), _react2.default.createElement(_Thumbnail2.default, { size: 'huge', images: this.props.artist.images }),
_react2.default.createElement( _react2.default.createElement(
'h1', 'h1',
null, null,
artist.name this.props.artist.name
), ),
_react2.default.createElement( _react2.default.createElement(
'ul', 'ul',
{ className: 'details' }, { className: 'details' },
_react2.default.createElement( this.props.artist.followers ? _react2.default.createElement(
'li', 'li',
null, null,
artist.followers.total.toLocaleString(), this.props.artist.followers.total.toLocaleString(),
' followers' ' followers'
), ) : null,
artist.popularity ? _react2.default.createElement( this.props.artist.popularity ? _react2.default.createElement(
'li', 'li',
null, null,
artist.popularity, this.props.artist.popularity,
'% popularity' '% popularity'
) : null, ) : null,
_react2.default.createElement( _react2.default.createElement(
'li',
null,
this.props.artist.albums.length.toLocaleString(),
' albums'
),
scheme == 'spotify' ? _react2.default.createElement(
'li', 'li',
null, null,
_react2.default.createElement(_reactFontawesome2.default, { name: 'spotify' }), _react2.default.createElement(_reactFontawesome2.default, { name: 'spotify' }),
' Spotify artist' ' Spotify artist'
) ) : null,
scheme == 'local' ? _react2.default.createElement(
'li',
null,
_react2.default.createElement(_reactFontawesome2.default, { name: 'folder' }),
' Local artist'
) : null
) )
), ),
_react2.default.createElement( _react2.default.createElement(
@ -21635,7 +21661,7 @@
{ className: 'left-padding' }, { className: 'left-padding' },
'Top tracks' 'Top tracks'
), ),
artist.tracks ? _react2.default.createElement(_TrackList2.default, { tracks: artist.tracks }) : null this.props.artist.tracks ? _react2.default.createElement(_TrackList2.default, { tracks: this.props.artist.tracks }) : null
), ),
_react2.default.createElement('div', { className: 'col w5' }), _react2.default.createElement('div', { className: 'col w5' }),
_react2.default.createElement( _react2.default.createElement(
@ -21646,7 +21672,7 @@
null, null,
'Related artists' 'Related artists'
), ),
artist.related_artists ? _react2.default.createElement(_ArtistList2.default, { artists: artist.related_artists.slice(0, 6) }) : null this.props.artist.related_artists ? _react2.default.createElement(_ArtistList2.default, { artists: this.props.artist.related_artists.slice(0, 6) }) : null
), ),
_react2.default.createElement('div', { className: 'cf' }), _react2.default.createElement('div', { className: 'cf' }),
_react2.default.createElement( _react2.default.createElement(
@ -21657,76 +21683,13 @@
_react2.default.createElement( _react2.default.createElement(
'section', 'section',
{ className: 'grid-wrapper no-top-padding' }, { className: 'grid-wrapper no-top-padding' },
albums ? _react2.default.createElement(_AlbumGrid2.default, { albums: albums.items }) : null, this.props.artist.albums ? _react2.default.createElement(_AlbumGrid2.default, { albums: this.props.artist.albums }) : null,
_react2.default.createElement(_LazyLoadListener2.default, { loadMore: function loadMore() { _react2.default.createElement(_LazyLoadListener2.default, { loadMore: function loadMore() {
return _this2.loadMore(); return _this2.loadMore();
} }) } })
) )
); );
} }
}, {
key: 'renderMopidyArtist',
value: function renderMopidyArtist() {
if (!this.props.mopidy.artist) return null;
var artist = this.props.mopidy.artist;
if (this.props.lastfm.artist.image && this.props.lastfm.artist.name == artist.name) artist.images = this.props.lastfm.artist.image;
return _react2.default.createElement(
'div',
{ className: 'view artist-view' },
_react2.default.createElement(_Parallax2.default, { images: artist.images }),
_react2.default.createElement(
'div',
{ className: 'intro' },
_react2.default.createElement(_Thumbnail2.default, { size: 'huge', images: artist.images }),
_react2.default.createElement(
'h1',
null,
artist.name
),
_react2.default.createElement(
'ul',
{ className: 'details' },
_react2.default.createElement(
'li',
null,
artist.albums.length.toLocaleString(),
' albums'
),
_react2.default.createElement(
'li',
null,
_react2.default.createElement(_reactFontawesome2.default, { name: 'folder' }),
' Local artist'
)
)
),
_react2.default.createElement(
'h4',
{ className: 'left-padding' },
'Top tracks'
),
artist.tracks ? _react2.default.createElement(_TrackList2.default, { tracks: artist.tracks }) : null,
_react2.default.createElement(
'h4',
{ className: 'left-padding' },
'Albums'
),
_react2.default.createElement(
'section',
{ className: 'grid-wrapper no-top-padding' },
artist.albums ? _react2.default.createElement(_AlbumGrid2.default, { albums: artist.albums }) : null
)
);
}
}, {
key: 'render',
value: function render() {
var source = helpers.uriSource(this.props.params.uri);
if (source == 'spotify') return this.renderSpotifyArtist();
if (source == 'local') return this.renderMopidyArtist();
}
}]); }]);
return Artist; return Artist;
@ -21739,7 +21702,10 @@
**/ **/
var mapStateToProps = function mapStateToProps(state, ownProps) { var mapStateToProps = function mapStateToProps(state, ownProps) {
return state; return {
mopidy_connected: state.mopidy.connected,
artist: state.ui.artist
};
}; };
var mapDispatchToProps = function mapDispatchToProps(dispatch) { var mapDispatchToProps = function mapDispatchToProps(dispatch) {
@ -21831,7 +21797,7 @@
value: function componentWillReceiveProps(nextProps) { value: function componentWillReceiveProps(nextProps) {
if (nextProps.params.uri != this.props.params.uri) { if (nextProps.params.uri != this.props.params.uri) {
this.loadPlaylist(nextProps); this.loadPlaylist(nextProps);
} else if (!this.props.mopidy.connected && nextProps.mopidy.connected) { } else if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
if (helpers.uriSource(this.props.params.uri) == 'm3u') { if (helpers.uriSource(this.props.params.uri) == 'm3u') {
this.loadPlaylist(nextProps); this.loadPlaylist(nextProps);
} }
@ -21845,30 +21811,23 @@
var source = helpers.uriSource(props.params.uri); var source = helpers.uriSource(props.params.uri);
if (source == 'spotify') { if (source == 'spotify') {
this.props.spotifyActions.getPlaylist(props.params.uri); this.props.spotifyActions.getPlaylist(props.params.uri);
} else if (source == 'm3u' && props.mopidy.connected) { } else if (source == 'm3u' && props.mopidy_connected) {
this.props.mopidyActions.getPlaylist(props.params.uri); this.props.mopidyActions.getPlaylist(props.params.uri);
} }
} }
}, { }, {
key: 'loadMore', key: 'loadMore',
value: function loadMore() { value: function loadMore() {
if (!this.props.spotify.playlist || !this.props.spotify.playlist.tracks.next) return; if (!this.props.playlist.tracks_more) return;
this.props.spotifyActions.getURL(this.props.spotify.playlist.tracks.next, 'SPOTIFY_PLAYLIST_LOADED_MORE'); this.props.spotifyActions.getURL(this.props.playlist.tracks_more, 'SPOTIFY_PLAYLIST_LOADED_MORE');
} }
}, { }, {
key: 'render', key: 'render',
value: function render() { value: function render() {
var _this2 = this; var _this2 = this;
var source = helpers.uriSource(this.props.params.uri); if (!this.props.playlist) return null;
var source_name = source; var scheme = helpers.uriSource(this.props.params.uri);
if (source == 'spotify') {
var playlist = this.props.spotify.playlist;
} else if (source == 'm3u') {
var playlist = this.props.mopidy.playlist;
source_name = 'local';
}
if (!playlist) return null;
return _react2.default.createElement( return _react2.default.createElement(
'div', 'div',
@ -21876,32 +21835,36 @@
_react2.default.createElement( _react2.default.createElement(
'div', 'div',
{ className: 'intro' }, { className: 'intro' },
playlist.images ? _react2.default.createElement(_Thumbnail2.default, { size: 'large', images: playlist.images }) : null, _react2.default.createElement(_Thumbnail2.default, { size: 'large', images: this.props.playlist.images }),
_react2.default.createElement( _react2.default.createElement(
'ul', 'ul',
{ className: 'details' }, { className: 'details' },
_react2.default.createElement( _react2.default.createElement(
'li', 'li',
null, null,
playlist.tracks.total, this.props.playlist.tracks_total,
' tracks, ', ' tracks, ',
_react2.default.createElement(_Dater2.default, { type: 'total-time', data: playlist.tracks.items }) _react2.default.createElement(_Dater2.default, { type: 'total-time', data: this.props.playlist.tracks })
), ),
playlist.last_modified ? _react2.default.createElement( this.props.playlist.last_modified ? _react2.default.createElement(
'li', 'li',
null, null,
'Updated ', 'Updated ',
_react2.default.createElement(_Dater2.default, { type: 'ago', data: playlist.last_modified }), _react2.default.createElement(_Dater2.default, { type: 'ago', data: this.props.playlist.last_modified }),
' ago' ' ago'
) : null, ) : null,
_react2.default.createElement( scheme == 'spotify' ? _react2.default.createElement(
'li', 'li',
null, null,
_react2.default.createElement(_reactFontawesome2.default, { name: helpers.sourceIcon(this.props.params.uri) }), _react2.default.createElement(_reactFontawesome2.default, { name: 'spotify' }),
' ', ' Spotify playlist'
source_name, ) : null,
' playlist' scheme == 'm3u' ? _react2.default.createElement(
) 'li',
null,
_react2.default.createElement(_reactFontawesome2.default, { name: 'folder' }),
' Local playlist'
) : null
) )
), ),
_react2.default.createElement( _react2.default.createElement(
@ -21913,13 +21876,13 @@
_react2.default.createElement( _react2.default.createElement(
'h1', 'h1',
null, null,
playlist.name this.props.playlist.name
) )
), ),
_react2.default.createElement( _react2.default.createElement(
'section', 'section',
{ className: 'list-wrapper' }, { className: 'list-wrapper' },
_react2.default.createElement(_TrackList2.default, { tracks: playlist.tracks.items }), _react2.default.createElement(_TrackList2.default, { tracks: this.props.playlist.tracks }),
_react2.default.createElement(_LazyLoadListener2.default, { loadMore: function loadMore() { _react2.default.createElement(_LazyLoadListener2.default, { loadMore: function loadMore() {
return _this2.loadMore(); return _this2.loadMore();
} }) } })
@ -21939,7 +21902,10 @@
**/ **/
var mapStateToProps = function mapStateToProps(state, ownProps) { var mapStateToProps = function mapStateToProps(state, ownProps) {
return state; return {
playlist: state.ui.playlist,
mopidy_connected: state.mopidy.connected
};
}; };
var mapDispatchToProps = function mapDispatchToProps(dispatch) { var mapDispatchToProps = function mapDispatchToProps(dispatch) {

File diff suppressed because one or more lines are too long

View File

@ -2,12 +2,6 @@
export default function reducer(lastfm = {}, action){ export default function reducer(lastfm = {}, action){
switch (action.type) { switch (action.type) {
case 'LASTFM_ARTIST_LOADED':
return Object.assign({}, lastfm, { artist: action.data });
case 'LASTFM_TRACK_LOADED':
return Object.assign({}, lastfm, { track: action.data });
default: default:
return lastfm return lastfm
} }

View File

@ -198,15 +198,21 @@ const MopidyMiddleware = (function(){
store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: false }); store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: false });
instruct( socket, store, 'playlists.lookup', action.data ) instruct( socket, store, 'playlists.lookup', action.data )
.then( response => { .then( response => {
var playlist = response; var playlist = Object.assign(
playlist.tracks = { {},
items: response.tracks, {
total: response.tracks.length images: []
} },
response,
{
tracks: response.tracks,
total_tracks: response.tracks.length
}
)
var uris = []; var uris = [];
for( var i = 0; i < playlist.tracks.items.length; i++ ){ for( var i = 0; i < playlist.tracks.length; i++ ){
uris.push( playlist.tracks.items[i].uri ); uris.push( playlist.tracks[i].uri );
} }
instruct( socket, store, 'library.lookup', { uris: uris } ) instruct( socket, store, 'library.lookup', { uris: uris } )
@ -221,12 +227,12 @@ const MopidyMiddleware = (function(){
function getByURI( trackReference ){ function getByURI( trackReference ){
return track.uri == trackReference.uri return track.uri == trackReference.uri
} }
var trackReferences = playlist.tracks.items.filter(getByURI); var trackReferences = playlist.tracks.filter(getByURI);
// there could be multiple instances of this track, so accommodate this // there could be multiple instances of this track, so accommodate this
for( var j = 0; j < trackReferences.length; j++){ for( var j = 0; j < trackReferences.length; j++){
var key = playlist.tracks.items.indexOf( trackReferences[j] ); var key = playlist.tracks.indexOf( trackReferences[j] );
playlist.tracks.items[ key ] = track; playlist.tracks[ key ] = track;
} }
} }
} }

View File

@ -81,11 +81,6 @@ export default function reducer(mopidy = {}, action){
playlist: action.data playlist: action.data
}); });
case 'MOPIDY_ARTIST_LOADED':
return Object.assign({}, mopidy, {
artist: action.data
});
case 'MOPIDY_ARTISTS_LOADED': case 'MOPIDY_ARTISTS_LOADED':
return Object.assign({}, mopidy, { return Object.assign({}, mopidy, {
artists: action.data artists: action.data

View File

@ -231,9 +231,6 @@ export function getArtist( uri ){
var artist = {}; var artist = {};
// while we're fiddling about, go get the albums
dispatch(getArtistAlbums(uri));
// get both the artist and the top tracks // get both the artist and the top tracks
$.when( $.when(
@ -250,6 +247,11 @@ export function getArtist( uri ){
sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/related-artists' ) sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/related-artists' )
.then( response => { .then( response => {
Object.assign(artist, { related_artists: response.artists }); 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 });
}) })
).then( () => { ).then( () => {
@ -284,18 +286,6 @@ export function getArtists( uris ){
} }
} }
export function getArtistAlbums( uri ){
return (dispatch, getState) => {
sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/albums' )
.then( response => {
dispatch({
type: 'SPOTIFY_ARTIST_ALBUMS_LOADED',
data: response
});
});
}
}
/** /**
* Single album * Single album
* *

View File

@ -55,36 +55,9 @@ export default function reducer(spotify = {}, action){
case 'SPOTIFY_ME_LOADED': case 'SPOTIFY_ME_LOADED':
return Object.assign({}, spotify, { me: action.data }); return Object.assign({}, spotify, { me: action.data });
case 'SPOTIFY_PLAYLIST_LOADED':
return Object.assign({}, spotify, { playlist: action.data });
case 'SPOTIFY_PLAYLIST_LOADED_MORE':
var playlist = spotify.playlist
Object.assign(playlist, { tracks: {
href: action.data.href,
next: action.data.next,
previous: action.data.previous,
items: [ ...spotify.playlist.tracks.items, ...action.data.items ]
}})
return Object.assign({}, spotify, { playlist: playlist });
case 'SPOTIFY_ARTIST_LOADED':
return Object.assign({}, spotify, { artist: action.data });
case 'SPOTIFY_ARTISTS_LOADED': case 'SPOTIFY_ARTISTS_LOADED':
return Object.assign({}, spotify, { artists: action.data }); return Object.assign({}, spotify, { artists: action.data });
case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
return Object.assign({}, spotify, { artist_albums: action.data });
case 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE':
return Object.assign({}, spotify, { artist_albums: {
href: action.data.href,
next: action.data.next,
previous: action.data.previous,
items: [ ...spotify.artist_albums.items, ...action.data.items ]
}});
case 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED': case 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED':
return Object.assign({}, spotify, { library_playlists: action.data }); return Object.assign({}, spotify, { library_playlists: action.data });

View File

@ -24,11 +24,11 @@ export default function reducer(ui = {}, action){
/** /**
* General assets * Albums
* Playlists/albums/etc
**/ **/
case 'MOPIDY_ALBUM_LOADED': case 'MOPIDY_ALBUM_LOADED':
if( !action.data ) return Object.assign({}, ui, { album: false })
return Object.assign({}, ui, { album: action.data }); return Object.assign({}, ui, { album: action.data });
case 'LASTFM_ALBUM_LOADED': case 'LASTFM_ALBUM_LOADED':
@ -40,7 +40,6 @@ export default function reducer(ui = {}, action){
case 'SPOTIFY_ALBUM_LOADED': case 'SPOTIFY_ALBUM_LOADED':
if( !action.data ) return Object.assign({}, ui, { album: false }) if( !action.data ) return Object.assign({}, ui, { album: false })
console.log(action.data)
var album = Object.assign({}, { images: [] }, action.data, { var album = Object.assign({}, { images: [] }, action.data, {
tracks: action.data.tracks.items, tracks: action.data.tracks.items,
tracks_total: action.data.tracks.total, tracks_total: action.data.tracks.total,
@ -56,6 +55,84 @@ export default function reducer(ui = {}, action){
return Object.assign({}, ui, { album: album }); return Object.assign({}, ui, { album: album });
/**
* Artists
**/
case 'MOPIDY_ARTIST_LOADED':
if( !action.data ) return Object.assign({}, ui, { artist: false })
return Object.assign({}, ui, { artist: action.data })
case 'LASTFM_ARTIST_LOADED':
if( !action.data.image ) return ui
var artist = Object.assign({}, ui.artist, { images: action.data.image, bio: action.data.bio })
return Object.assign({}, ui, { artist: artist });
case 'SPOTIFY_ARTIST_LOADED':
if( !action.data ) return Object.assign({}, ui, { artist: false })
return Object.assign({}, ui, { artist: action.data })
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 });
/**
* 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 })
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 });
/** /**
* Current track and tracklist * Current track and tracklist
**/ **/

View File

@ -30,7 +30,7 @@ class Artist extends React.Component{
componentWillReceiveProps( nextProps ){ componentWillReceiveProps( nextProps ){
if( nextProps.params.uri != this.props.params.uri ){ if( nextProps.params.uri != this.props.params.uri ){
this.loadArtist( nextProps ) this.loadArtist( nextProps )
}else if( !this.props.mopidy.connected && nextProps.mopidy.connected ){ }else if( !this.props.mopidy_connected && nextProps.mopidy_connected ){
if( helpers.uriSource( this.props.params.uri ) == 'local' ){ if( helpers.uriSource( this.props.params.uri ) == 'local' ){
this.loadArtist( nextProps ) this.loadArtist( nextProps )
} }
@ -41,93 +41,58 @@ class Artist extends React.Component{
var source = helpers.uriSource( props.params.uri ); var source = helpers.uriSource( props.params.uri );
if( source == 'spotify' ){ if( source == 'spotify' ){
this.props.spotifyActions.getArtist( props.params.uri ); this.props.spotifyActions.getArtist( props.params.uri );
}else if( source == 'local' && props.mopidy.connected ){ }else if( source == 'local' && props.mopidy_connected ){
this.props.mopidyActions.getArtist( props.params.uri ); this.props.mopidyActions.getArtist( props.params.uri );
} }
} }
loadMore(){ loadMore(){
if( !this.props.spotify.artist_albums || !this.props.spotify.artist_albums.next ) return if( !this.props.artist.albums_more ) return
this.props.spotifyActions.getURL( this.props.spotify.artist_albums.next, 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE' ); this.props.spotifyActions.getURL( this.props.artist.albums_more, 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE' );
} }
renderSpotifyArtist(){ render(){
if( !this.props.spotify.artist ) return null if( !this.props.artist ) return null
var artist = this.props.spotify.artist var scheme = helpers.uriSource( this.props.params.uri );
var albums = this.props.spotify.artist_albums
return ( return (
<div className="view artist-view"> <div className="view artist-view">
<Parallax images={artist.images} /> <Parallax images={this.props.artist.images} />
<div className="intro"> <div className="intro">
<Thumbnail size="huge" images={ artist.images } /> <Thumbnail size="huge" images={ this.props.artist.images } />
<h1>{ artist.name }</h1> <h1>{ this.props.artist.name }</h1>
<ul className="details"> <ul className="details">
<li>{ artist.followers.total.toLocaleString() } followers</li> { this.props.artist.followers ? <li>{ this.props.artist.followers.total.toLocaleString() } followers</li> : null }
{ artist.popularity ? <li>{ artist.popularity }% popularity</li> : null } { this.props.artist.popularity ? <li>{ this.props.artist.popularity }% popularity</li> : null }
<li><FontAwesome name='spotify' /> Spotify artist</li> <li>{ this.props.artist.albums.length.toLocaleString() } albums</li>
{ scheme == 'spotify' ? <li><FontAwesome name='spotify' /> Spotify artist</li> : null }
{ scheme == 'local' ? <li><FontAwesome name='folder' /> Local artist</li> : null }
</ul> </ul>
</div> </div>
<div className="col w70"> <div className="col w70">
<h4 className="left-padding">Top tracks</h4> <h4 className="left-padding">Top tracks</h4>
{ artist.tracks ? <TrackList tracks={ artist.tracks } /> : null } { this.props.artist.tracks ? <TrackList tracks={ this.props.artist.tracks } /> : null }
</div> </div>
<div className="col w5"></div> <div className="col w5"></div>
<div className="col w25"> <div className="col w25">
<h4>Related artists</h4> <h4>Related artists</h4>
{ artist.related_artists ? <ArtistList artists={ artist.related_artists.slice(0,6) } /> : null } { this.props.artist.related_artists ? <ArtistList artists={ this.props.artist.related_artists.slice(0,6) } /> : null }
</div> </div>
<div className="cf"></div> <div className="cf"></div>
<h4 className="left-padding">Albums</h4> <h4 className="left-padding">Albums</h4>
<section className="grid-wrapper no-top-padding"> <section className="grid-wrapper no-top-padding">
{ albums ? <AlbumGrid albums={ albums.items } /> : null } { this.props.artist.albums ? <AlbumGrid albums={ this.props.artist.albums } /> : null }
<LazyLoadListener loadMore={ () => this.loadMore() }/> <LazyLoadListener loadMore={ () => this.loadMore() }/>
</section> </section>
</div> </div>
); );
} }
renderMopidyArtist(){
if( !this.props.mopidy.artist ) return null
var artist = this.props.mopidy.artist
if( this.props.lastfm.artist.image && this.props.lastfm.artist.name == artist.name ) artist.images = this.props.lastfm.artist.image
return (
<div className="view artist-view">
<Parallax images={ artist.images } />
<div className="intro">
<Thumbnail size="huge" images={ artist.images } />
<h1>{ artist.name }</h1>
<ul className="details">
<li>{ artist.albums.length.toLocaleString() } albums</li>
<li><FontAwesome name='folder' /> Local artist</li>
</ul>
</div>
<h4 className="left-padding">Top tracks</h4>
{ artist.tracks ? <TrackList tracks={ artist.tracks } /> : null }
<h4 className="left-padding">Albums</h4>
<section className="grid-wrapper no-top-padding">
{ artist.albums ? <AlbumGrid albums={ artist.albums } /> : null }
</section>
</div>
);
}
render(){
var source = helpers.uriSource( this.props.params.uri );
if( source == 'spotify' ) return this.renderSpotifyArtist()
if( source == 'local' ) return this.renderMopidyArtist()
}
} }
@ -138,7 +103,10 @@ class Artist extends React.Component{
**/ **/
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
return state; return {
mopidy_connected: state.mopidy.connected,
artist: state.ui.artist
}
} }
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {

View File

@ -26,7 +26,7 @@ class Playlist extends React.Component{
componentWillReceiveProps( nextProps ){ componentWillReceiveProps( nextProps ){
if( nextProps.params.uri != this.props.params.uri ){ if( nextProps.params.uri != this.props.params.uri ){
this.loadPlaylist( nextProps ) this.loadPlaylist( nextProps )
}else if( !this.props.mopidy.connected && nextProps.mopidy.connected ){ }else if( !this.props.mopidy_connected && nextProps.mopidy_connected ){
if( helpers.uriSource( this.props.params.uri ) == 'm3u' ){ if( helpers.uriSource( this.props.params.uri ) == 'm3u' ){
this.loadPlaylist( nextProps ) this.loadPlaylist( nextProps )
} }
@ -37,45 +37,39 @@ class Playlist extends React.Component{
var source = helpers.uriSource( props.params.uri ); var source = helpers.uriSource( props.params.uri );
if( source == 'spotify' ){ if( source == 'spotify' ){
this.props.spotifyActions.getPlaylist( props.params.uri ); this.props.spotifyActions.getPlaylist( props.params.uri );
}else if( source == 'm3u' && props.mopidy.connected ){ }else if( source == 'm3u' && props.mopidy_connected ){
this.props.mopidyActions.getPlaylist( props.params.uri ); this.props.mopidyActions.getPlaylist( props.params.uri );
} }
} }
loadMore(){ loadMore(){
if( !this.props.spotify.playlist || !this.props.spotify.playlist.tracks.next ) return if( !this.props.playlist.tracks_more ) return
this.props.spotifyActions.getURL( this.props.spotify.playlist.tracks.next, 'SPOTIFY_PLAYLIST_LOADED_MORE' ); this.props.spotifyActions.getURL( this.props.playlist.tracks_more, 'SPOTIFY_PLAYLIST_LOADED_MORE' );
} }
render(){ render(){
var source = helpers.uriSource( this.props.params.uri ); if( !this.props.playlist ) return null;
var source_name = source var scheme = helpers.uriSource( this.props.params.uri );
if( source == 'spotify' ){
var playlist = this.props.spotify.playlist
}else if( source == 'm3u' ){
var playlist = this.props.mopidy.playlist
source_name = 'local'
}
if( !playlist ) return null;
return ( return (
<div className="view playlist-view"> <div className="view playlist-view">
<div className="intro"> <div className="intro">
{ playlist.images ? <Thumbnail size="large" images={ playlist.images } /> : null } <Thumbnail size="large" images={ this.props.playlist.images } />
<ul className="details"> <ul className="details">
<li>{ playlist.tracks.total } tracks, <Dater type="total-time" data={playlist.tracks.items} /></li> <li>{ this.props.playlist.tracks_total } tracks, <Dater type="total-time" data={this.props.playlist.tracks} /></li>
{ playlist.last_modified ? <li>Updated <Dater type="ago" data={playlist.last_modified} /> ago</li> : null } { this.props.playlist.last_modified ? <li>Updated <Dater type="ago" data={this.props.playlist.last_modified} /> ago</li> : null }
<li><FontAwesome name={helpers.sourceIcon( this.props.params.uri )} /> {source_name} playlist</li> { scheme == 'spotify' ? <li><FontAwesome name="spotify" /> Spotify playlist</li> : null }
{ scheme == 'm3u' ? <li><FontAwesome name="folder" /> Local playlist</li> : null }
</ul> </ul>
</div> </div>
<div className="main"> <div className="main">
<div className="title"> <div className="title">
<h1>{ playlist.name }</h1> <h1>{ this.props.playlist.name }</h1>
</div> </div>
<section className="list-wrapper"> <section className="list-wrapper">
<TrackList tracks={ playlist.tracks.items } /> <TrackList tracks={ this.props.playlist.tracks } />
<LazyLoadListener loadMore={ () => this.loadMore() }/> <LazyLoadListener loadMore={ () => this.loadMore() }/>
</section> </section>
@ -93,7 +87,10 @@ class Playlist extends React.Component{
**/ **/
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
return state; return {
playlist: state.ui.playlist,
mopidy_connected: state.mopidy.connected
}
} }
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {