Playlists tracks going to be a beast

This commit is contained in:
James Barnsley
2017-11-08 21:13:32 +13:00
parent 26503da1a5
commit ec41eb5271
4 changed files with 275 additions and 303 deletions

View File

@ -15,6 +15,7 @@ const CoreMiddleware = (function(){
* The actual middleware inteceptor
**/
return store => next => action => {
var core = store.getState().core;
switch(action.type){
@ -102,68 +103,6 @@ const CoreMiddleware = (function(){
next(action)
break
case 'TRACK_LOADED':
if (action.data) ReactGA.event({ category: 'Track', action: 'Load', label: action.key });
if (action.track.album && action.track.album.images && action.track.album.images.length > 0){
action.track.album.images = helpers.digestMopidyImages(store.getState().mopidy, action.track.album.images);
}
next(action)
break
case 'ALBUM_LOADED':
if (action.data) ReactGA.event({ category: 'Album', action: 'Load', label: action.key })
if (action.album.images && action.album.images.length > 0){
action.album.images = helpers.digestMopidyImages(store.getState().mopidy, action.album.images);
}
// Load our tracks
if (action.album.tracks){
store.dispatch({
type: 'TRACKS_LOADED',
tracks: action.album.tracks
});
}
next(action)
break
case 'ALBUMS_LOADED':
if (action.data) ReactGA.event({ category: 'Albums', action: 'Load', label: action.albums.length+' items' })
for (var i = 0; i < action.albums.length; i++){
if (action.albums[i].images && action.albums[i].images.length > 0){
action.albums[i].images = helpers.digestMopidyImages(store.getState().mopidy, action.albums[i].images);
}
// Load our tracks
if (action.albums[i].tracks){
store.dispatch({
type: 'TRACKS_LOADED',
tracks: action.albums[i].tracks
});
}
}
next(action)
break
case 'ARTIST_LOADED':
if (action.data) ReactGA.event({ category: 'Artist', action: 'Load', label: action.artist.uri });
// Load our tracks
if (action.artist.tracks){
store.dispatch({
type: 'TRACKS_LOADED',
tracks: action.artist.tracks
});
}
next(action)
break
case 'PLAY_PLAYLIST':
ReactGA.event({ category: 'Playlist', action: 'Play', label: action.uri })
next(action)
@ -248,35 +187,6 @@ const CoreMiddleware = (function(){
next(action)
break
case 'PLAYLIST_LOADED':
if (action.data) ReactGA.event({ category: 'Playlist', action: 'Load', label: action.playlist.uri })
var playlist = Object.assign({}, action.playlist)
switch (helpers.uriSource(playlist.uri)){
case 'm3u':
playlist.can_edit = true
break
case 'spotify':
if (store.getState().spotify.authorization && store.getState().spotify.me){
playlist.can_edit = (helpers.getFromUri('playlistowner',playlist.uri) == store.getState().spotify.me.id)
}
}
// Load our tracks
if (action.playlist.tracks){
store.dispatch({
type: 'TRACKS_LOADED',
tracks: action.playlist.tracks
});
}
// proceed as usual
action.playlist = playlist;
next(action);
break
case 'MOPIDY_CURRENTTLTRACK':
if (action.data && action.data.track){
helpers.setWindowTitle(action.data.track, store.getState().mopidy.play_state);
@ -293,8 +203,22 @@ const CoreMiddleware = (function(){
}
}
next(action)
break
var current_tracklist = []
Object.assign(current_tracklist, core.current_tracklist)
for (var i = 0; i < current_tracklist.length; i++){
Object.assign(
current_tracklist[i],
{ playing: (current_tracklist[i].tlid == action.data.tlid) }
)
}
// Update action
action.current_tracklist = current_tracklist;
action.current_track = action.data.track.uri;
next(action);
break;
case 'MOPIDY_TLTRACKS':
@ -376,6 +300,230 @@ const CoreMiddleware = (function(){
location.reload()
break
/**
* Index actions
* These modify our asset indexes, which are used globally
**/
case 'TRACK_LOADED':
if (action.track.album && action.track.album.images && action.track.album.images.length > 0){
action.track.album.images = helpers.digestMopidyImages(store.getState().mopidy, action.track.album.images);
}
var tracks = Object.assign({}, core.tracks)
if (tracks[action.key]){
var track = Object.assign(
{},
tracks[action.key],
helpers.formatTracks(action.track)
);
} else {
var track = Object.assign(
{},
helpers.formatTracks(action.track)
);
}
// Update index
tracks[action.key] = track;
store.dispatch({
type: 'UPDATE_TRACKS_INDEX',
tracks: tracks
});
next(action);
break;
case 'TRACKS_LOADED':
for (var i = 0; i < action.tracks.length; i++){
store.dispatch({
type: 'TRACK_LOADED',
key: action.tracks[i].uri,
track: action.tracks[i]
});
}
next(action);
break;
case 'ALBUM_LOADED':
var albums = Object.assign({}, core.albums)
if (albums[action.key]){
var album = Object.assign({}, albums[action.key], action.album)
} else {
var album = Object.assign({}, action.album)
}
if (action.album.images && action.album.images.length > 0){
action.album.images = helpers.digestMopidyImages(store.getState().mopidy, action.album.images);
}
// Load our tracks
if (album.tracks){
var tracks = helpers.formatTracks(album.tracks);
var tracks_uris = helpers.arrayOf('uri', tracks);
album.tracks_uris = tracks_uris;
delete album.tracks;
store.dispatch({
type: 'TRACKS_LOADED',
tracks: tracks
});
}
// Update index
albums[action.key] = album;
store.dispatch({
type: 'UPDATE_ALBUMS_INDEX',
albums: albums
});
next(action);
break;
case 'ALBUMS_LOADED':
for (var i = 0; i < action.albums.length; i++){
store.dispatch({
type: 'ALBUM_LOADED',
key: action.albums[i].uri,
album: action.albums[i]
});
}
next(action);
break
case 'ARTIST_LOADED':
var artists = Object.assign({}, core.artists)
if (artists[action.key]){
// if we've already got images, remove and add as additional_images
// this is to prevent LastFM overwriting Spotify images
if (artists[action.key].images){
action.artist.images_additional = action.artist.images
delete action.artist.images
}
var artist = Object.assign({}, artists[action.key], action.artist)
if (artist.tracks){
artist.tracks = helpers.formatTracks(artist.tracks);
}
} else {
var artist = Object.assign({}, action.artist)
if (artist.tracks){
artist.tracks = helpers.formatTracks(artist.tracks);
}
}
// Load our tracks
if (artist.tracks){
store.dispatch({
type: 'TRACKS_LOADED',
tracks: artist.tracks
});
}
// Update index
artists[action.key] = artist;
store.dispatch({
type: 'UPDATE_ARTISTS_INDEX',
artists: artists
});
next(action);
break;
case 'ARTISTS_LOADED':
for (var i = 0; i < action.artists.length; i++){
store.dispatch({
type: 'ARTIST_LOADED',
key: action.artists[i].uri,
artist: action.artists[i]
});
}
next(action);
break;
case 'PLAYLIST_LOADED':
var playlist = Object.assign({}, action.playlist);
var playlists = Object.assign({}, core.playlists);
// Detect editability
switch (helpers.uriSource(playlist.uri)){
case 'm3u':
playlist.can_edit = true
break
case 'spotify':
if (store.getState().spotify.authorization && store.getState().spotify.me){
playlist.can_edit = (helpers.getFromUri('playlistowner',playlist.uri) == store.getState().spotify.me.id)
}
}
if (playlists[action.key] !== undefined){
var existing_playlist = playlists[action.key];
if (existing_playlist.tracks && playlist.tracks){
var tracks = [...existing_playlist.tracks, ...playlist.tracks];
} else if (existing_playlist.tracks){
var tracks = existing_playlist.tracks;
} else if (action.playlist.tracks){
var tracks = playlist.tracks;
} else {
var tracks = [];
}
playlist = Object.assign(
{},
existing_playlist,
playlist
)
}
// Load our tracks
if (playlist.tracks){
var tracks = helpers.formatTracks(playlist.tracks);
var tracks_uris = helpers.arrayOf('uri', tracks);
playlist.tracks_uris = tracks_uris;
delete playlist.tracks;
store.dispatch({
type: 'TRACKS_LOADED',
tracks: tracks
});
}
// Update index
playlists[action.key] = playlist;
store.dispatch({
type: 'UPDATE_PLAYLISTS_INDEX',
playlists: playlists
});
next(action);
break;
case 'USER_LOADED':
var users = Object.assign([], core.users)
if (users[action.key]){
var user = Object.assign({}, users[action.key], action.user)
} else {
var user = Object.assign({}, action.user)
}
// Update index
users[action.key] = user;
store.dispatch({
type: 'UPDATE_USERS_INDEX',
users: users
});
next(action);
break;
// This action is irrelevant to us, pass it on to the next middleware
default:
return next(action)

View File

@ -18,60 +18,14 @@ export default function reducer(core = {}, action){
return Object.assign({}, core, { current_tracklist: action.tracklist });
case 'MOPIDY_CURRENTTLTRACK':
if (!action.data) return core
var current_tracklist = []
Object.assign(current_tracklist, core.current_tracklist)
for (var i = 0; i < current_tracklist.length; i++){
Object.assign(
current_tracklist[i],
{ playing: (current_tracklist[i].tlid == action.data.tlid ) }
)
if (!action.data){
return core;
}
return Object.assign({}, core, {
current_tracklist: current_tracklist,
current_track: action.data.track.uri
current_tracklist: action.current_tracklist,
current_track: action.current_track
});
case 'TRACK_LOADED':
if (!action.key || !action.track) return core
var tracks = Object.assign({}, core.tracks)
if (tracks[action.key]){
var track = Object.assign(
{},
tracks[action.key],
helpers.formatTracks(action.track)
);
} else {
var track = Object.assign(
{},
helpers.formatTracks(action.track)
);
}
tracks[action.key] = track
return Object.assign({}, core, { tracks: tracks });
case 'TRACKS_LOADED':
var tracks = Object.assign({}, core.tracks)
for (var i = 0; i < action.tracks.length; i++){
var track = action.tracks[i]
if (tracks[track.uri] !== undefined){
track = Object.assign(
{},
tracks[track.uri],
track
);
}
tracks[track.uri] = helpers.formatTracks(track);
}
return Object.assign({}, core, { tracks: tracks });
case 'PUSHER_QUEUE_METADATA':
case 'PUSHER_QUEUE_METADATA_CHANGED':
var tracklist = Object.assign([], core.current_tracklist)
@ -153,37 +107,27 @@ export default function reducer(core = {}, action){
/**
* Albums
* Index updates
* These actions are only ever called by middleware after we've digested one more many assets
* and appended to their relevant index.
**/
case 'ALBUM_LOADED':
var albums = Object.assign([], core.albums)
case 'UPDATE_TRACKS_INDEX':
return Object.assign({}, core, { tracks: action.tracks });
if (albums[action.key]){
var album = Object.assign({}, albums[action.key], action.album)
} else {
var album = Object.assign({}, action.album)
}
case 'UPDATE_ALBUMS_INDEX':
return Object.assign({}, core, { albums: action.albums });
album.tracks = helpers.formatTracks(album.tracks);
albums[action.key] = album
case 'UPDATE_ARTISTS_INDEX':
return Object.assign({}, core, { artists: action.artists });
return Object.assign({}, core, { albums: albums });
case 'UPDATE_PLAYLISTS_INDEX':
return Object.assign({}, core, { playlists: action.playlists });
case 'ALBUMS_LOADED':
var albums = Object.assign([], core.albums)
case 'UPDATE_USERS_INDEX':
return Object.assign({}, core, { users: action.users });
for (var i = 0; i < action.albums.length; i++){
var album = action.albums[i]
if (albums[album.uri]){
album = Object.assign({}, albums[album.uri], album)
}
album.tracks = helpers.formatTracks(album.tracks);
albums[album.uri] = album
}
return Object.assign({}, core, { albums: albums });
case 'NEW_RELEASES_LOADED':
if (!action.uris){
@ -204,54 +148,6 @@ export default function reducer(core = {}, action){
});
/**
* Artists
**/
case 'ARTIST_LOADED':
var artists = Object.assign([], core.artists)
if (artists[action.key]){
// if we've already got images, remove and add as additional_images
// this is to prevent LastFM overwriting Spotify images
if (artists[action.key].images){
action.artist.images_additional = action.artist.images
delete action.artist.images
}
var artist = Object.assign({}, artists[action.key], action.artist)
if (artist.tracks){
artist.tracks = helpers.formatTracks(artist.tracks);
}
} else {
var artist = Object.assign({}, action.artist)
if (artist.tracks){
artist.tracks = helpers.formatTracks(artist.tracks);
}
}
artists[action.key] = artist
return Object.assign({}, core, { artists: artists });
case 'ARTISTS_LOADED':
var artists = Object.assign([], core.artists)
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)
}
if (artist.tracks){
artist.tracks = helpers.formatTracks(artist.tracks);
}
artists[artist.uri] = artist
}
return Object.assign({}, core, { artists: artists });
case 'ARTIST_ALBUMS_LOADED':
var artists = Object.assign([], core.artists)
var albums_uris = []
@ -270,22 +166,6 @@ export default function reducer(core = {}, action){
return Object.assign({}, core, { artists: artists });
/**
* User profiles
**/
case 'USER_LOADED':
var users = Object.assign([], core.users)
if (users[action.key]){
var user = Object.assign({}, users[action.key], action.user)
} else {
var user = Object.assign({}, action.user)
}
users[action.key] = user
return Object.assign({}, core, { users: users });
case 'USER_PLAYLISTS_LOADED':
var users = Object.assign([], core.users)
var playlists_uris = []
@ -310,38 +190,6 @@ export default function reducer(core = {}, action){
* Playlists
**/
case 'PLAYLIST_LOADED':
case 'PLAYLIST_UPDATED':
var playlists = Object.assign([], core.playlists)
if (typeof(playlists[action.key]) !== 'undefined'){
var existing_playlist = Object.assign({}, playlists[action.key])
if (existing_playlist.tracks && action.playlist.tracks){
var tracks = [...existing_playlist.tracks, ...action.playlist.tracks]
} else if (existing_playlist.tracks){
var tracks = existing_playlist.tracks
} else if (action.playlist.tracks){
var tracks = action.playlist.tracks
} else {
var tracks = []
}
var merged_playlist = Object.assign(
{},
existing_playlist,
action.playlist,
{
tracks: helpers.formatTracks(tracks)
}
)
} else {
var merged_playlist = Object.assign({}, action.playlist)
}
playlists[action.key] = merged_playlist
return Object.assign({}, core, { playlists: playlists })
case 'PLAYLIST_KEY_UPDATED':
var playlists = Object.assign([], core.playlists)
@ -355,43 +203,6 @@ export default function reducer(core = {}, action){
delete playlists[action.key]
playlists[playlist.uri] = playlist
return Object.assign({}, core, { playlists: playlists })
case 'PLAYLISTS_LOADED':
var playlists = Object.assign([], core.playlists)
for (var i = 0; i < action.playlists.length; i++){
var loaded_playlist = action.playlists[i]
if (typeof(playlists[loaded_playlist.uri]) !== 'undefined'){
var existing_playlist = Object.assign({}, playlists[loaded_playlist.uri])
if (existing_playlist.tracks && loaded_playlist.tracks){
var tracks = [...existing_playlist.tracks, ...loaded_playlist.tracks]
} else if (existing_playlist.tracks){
var tracks = existing_playlist.tracks
} else if (loaded_playlist.tracks){
var tracks = loaded_playlist.tracks
} else {
var tracks = []
}
var merged_playlist = Object.assign(
{},
existing_playlist,
loaded_playlist,
{
tracks: helpers.formatTracks(tracks)
}
)
} else {
var merged_playlist = loaded_playlist
}
playlists[merged_playlist.uri] = merged_playlist
}
return Object.assign({}, core, { playlists: playlists });
case 'PLAYLIST_LOADED_MORE_TRACKS':

View File

@ -161,10 +161,13 @@ export function connect(){
// Not authorized? Just use a generic lookup to test our connection
} else {
sendRequest(dispatch, getState, 'method=artist.getInfo&artist=')
sendRequest(dispatch, getState, 'method=artist.getInfo&artist=Moby')
.then(
response => {
dispatch({ type: 'LASTFM_CONNECTED' })
},
error => {
dispatch({ type: 'LASTFM_DISCONNECTED' })
}
)
}

View File

@ -120,6 +120,16 @@ class Album extends React.Component{
}
}
var tracks = [];
if (this.props.album.tracks_uris && this.props.tracks){
for (var i = 0; i < this.props.album.tracks_uris.length; i++){
var uri = this.props.album.tracks_uris[i]
if (this.props.tracks.hasOwnProperty(uri)){
tracks.push(this.props.tracks[uri])
}
}
}
return (
<div className="view album-view content-wrapper">
<div className="thumbnail-wrapper">
@ -135,8 +145,7 @@ class Album extends React.Component{
{ !this.props.slim_mode && artists.length > 0 ? <li><ArtistSentence artists={artists} /></li> : null }
{ this.props.album.release_date ? <li><Dater type="date" data={ this.props.album.release_date } /></li> : null }
<li>
{ this.props.album.tracks_total ? this.props.album.tracks_total : '0' } tracks,&nbsp;
{ this.props.album.tracks ? <Dater type="total-time" data={this.props.album.tracks} /> : '0 mins' }
{tracks ? <span>{tracks.length} tracks, <Dater type="total-time" data={tracks} /></span> : '0 tracks, 0 mins' }
</li>
</ul>
</div>
@ -148,7 +157,7 @@ class Album extends React.Component{
</div>
<section className="list-wrapper">
{ this.props.album.tracks ? <TrackList className="album-track-list" tracks={ this.props.album.tracks } uri={this.props.params.uri} /> : null }
<TrackList className="album-track-list" tracks={tracks} uri={this.props.params.uri} />
<LazyLoadListener loading={this.props.album.tracks_more} loadMore={ () => this.loadMore() }/>
</section>
@ -169,6 +178,7 @@ const mapStateToProps = (state, ownProps) => {
return {
slim_mode: state.ui.slim_mode,
load_queue: state.ui.load_queue,
tracks: state.core.tracks,
artists: state.core.artists,
album: (state.core.albums && state.core.albums[uri] !== undefined ? state.core.albums[uri] : false ),
albums: state.core.albums,