Using core.items to contain all loaded assets
This commit is contained in:
@ -167,6 +167,13 @@ export function loadUserPlaylists(uri, force_reload = false) {
|
||||
* We've got a loaded record, now we just need to plug it in to our state and stores.
|
||||
* */
|
||||
|
||||
export function itemLoaded(item) {
|
||||
return {
|
||||
type: 'ITEM_LOADED',
|
||||
item,
|
||||
};
|
||||
}
|
||||
|
||||
export function trackLoaded(track) {
|
||||
return tracksLoaded([track]);
|
||||
}
|
||||
@ -177,9 +184,6 @@ export function tracksLoaded(tracks) {
|
||||
};
|
||||
}
|
||||
|
||||
export function artistLoaded(artist) {
|
||||
return artistsLoaded([artist]);
|
||||
}
|
||||
export function artistsLoaded(artists) {
|
||||
return {
|
||||
type: 'ARTISTS_LOADED',
|
||||
|
||||
@ -399,7 +399,6 @@ const CoreMiddleware = (function () {
|
||||
if (action.item) {
|
||||
store.dispatch({
|
||||
type: 'RESTORED_FROM_COLD_STORE',
|
||||
item_type: uriType(action.item.uri),
|
||||
item: action.item,
|
||||
});
|
||||
}
|
||||
@ -618,40 +617,27 @@ const CoreMiddleware = (function () {
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'ITEM_LOADED':
|
||||
const mergedItem = {
|
||||
...core.items[action.item.uri] || {},
|
||||
...action.item,
|
||||
};
|
||||
store.dispatch(coreActions.updateColdStore([mergedItem]));
|
||||
next({
|
||||
...action,
|
||||
item: mergedItem,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'ARTISTS_LOADED':
|
||||
var artists_index = { ...core.artists };
|
||||
var artists_loaded = [];
|
||||
var tracks_loaded = [];
|
||||
|
||||
for (const raw_artist of action.artists) {
|
||||
console.log(raw_artist);
|
||||
var artist = formatArtist(raw_artist);
|
||||
|
||||
// Already have an artist in the index
|
||||
if (artists_index[artist.uri]) {
|
||||
// And we've already got some images, make sure we merge the arrays,
|
||||
// rather than overwriting
|
||||
if (artists_index[artist.uri].images && artist.images) {
|
||||
const existing_images = artists_index[artist.uri].images;
|
||||
let are_new_images = true;
|
||||
|
||||
// loop all extisting images to make sure we're not adding one that
|
||||
// we already have
|
||||
for (const existing_image of existing_images) {
|
||||
// We only need to check one size, the formatter should insist on consistency
|
||||
// Note that we depend on having a one-item array of images provided per action
|
||||
if (existing_image.huge == artist.images[0].huge) {
|
||||
are_new_images = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only if they're new images should we merge them in
|
||||
if (are_new_images) {
|
||||
artist.images = Object.assign([], [...existing_images, ...artist.images]);
|
||||
}
|
||||
}
|
||||
|
||||
artist = { ...artists_index[artist.uri], ...artist };
|
||||
}
|
||||
artist = { ...artists_index[artist.uri], ...artist };
|
||||
/*
|
||||
// Migrate nested tracks objects into references to our tracks index
|
||||
if (raw_artist.tracks) {
|
||||
@ -665,10 +651,11 @@ const CoreMiddleware = (function () {
|
||||
}
|
||||
|
||||
action.artists = artists_loaded;
|
||||
|
||||
/*
|
||||
if (tracks_loaded.length > 0) {
|
||||
store.dispatch(coreActions.tracksLoaded(tracks_loaded));
|
||||
}
|
||||
*/
|
||||
|
||||
store.dispatch(coreActions.updateColdStore(artists_loaded));
|
||||
|
||||
|
||||
@ -66,6 +66,10 @@ export default function reducer(core = {}, action) {
|
||||
* and appended to their relevant index.
|
||||
* */
|
||||
|
||||
|
||||
case 'ITEM_LOADED':
|
||||
return { ...core, items: { ...core.items, [action.item.uri]: action.item } };
|
||||
|
||||
case 'TRACKS_LOADED':
|
||||
var tracks = { ...core.tracks };
|
||||
for (const track of action.tracks) {
|
||||
@ -141,44 +145,16 @@ export default function reducer(core = {}, action) {
|
||||
|
||||
|
||||
case 'RESTORED_FROM_COLD_STORE':
|
||||
switch (action.item_type) {
|
||||
case 'artist':
|
||||
return {
|
||||
...core,
|
||||
artists: {
|
||||
...core.artists,
|
||||
[action.item.uri]: {
|
||||
...core.artists[action.item.uri],
|
||||
...action.item,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'album':
|
||||
return {
|
||||
...core,
|
||||
albums: {
|
||||
...core.albums,
|
||||
[action.item.uri]: {
|
||||
...core.albums[action.item.uri],
|
||||
...action.item,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'playlist':
|
||||
return {
|
||||
...core,
|
||||
playlists: {
|
||||
...core.playlists,
|
||||
[action.item.uri]: {
|
||||
...core.albums[action.item.uri],
|
||||
...action.item,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
default:
|
||||
return core;
|
||||
}
|
||||
return {
|
||||
...core,
|
||||
items: {
|
||||
...core.items,
|
||||
[action.item.uri]: {
|
||||
...core.items[action.item.uri],
|
||||
...action.item,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an item from an index
|
||||
|
||||
@ -211,9 +211,6 @@ export function getTrack(uri) {
|
||||
dispatch(coreActions.trackLoaded(merged_track));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.info(`LastFM: No results for track '${track_name}' by '${artist_name}'`);
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
@ -231,21 +228,16 @@ export function getArtist(uri, artist, mbid = false) {
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.artist) {
|
||||
const artist = {
|
||||
dispatch(coreActions.artistLoaded({
|
||||
uri,
|
||||
mbid: response.artist.mbid,
|
||||
biography: response.artist.bio.content,
|
||||
biography_publish_date: response.artist.bio.published,
|
||||
biography_link: response.artist.bio.links.link.href,
|
||||
listeners: parseInt(response.artist.stats.listeners),
|
||||
};
|
||||
|
||||
dispatch(coreActions.artistLoaded(artist));
|
||||
}));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.info(`LastFM: No results for artist '${artist}'`);
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
@ -284,9 +276,6 @@ export function getAlbum(uri, artist, album, mbid = false) {
|
||||
dispatch(coreActions.albumLoaded(album));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.info(`LastFM: No results for album '${album}'`);
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
formatPlaylist,
|
||||
formatUser,
|
||||
formatAlbum,
|
||||
formatArtist,
|
||||
formatArtists,
|
||||
formatAlbums,
|
||||
} from '../../util/format';
|
||||
@ -1078,104 +1079,54 @@ export function getGenres() {
|
||||
* */
|
||||
export function getArtist(uri, full = false) {
|
||||
return (dispatch, getState) => {
|
||||
// Start with an empty object
|
||||
// As each requests completes, they'll add to this object
|
||||
let artist = {};
|
||||
|
||||
// We need our artist, obviously
|
||||
const requests = [
|
||||
request(dispatch, getState, `artists/${getFromUri('artistid', uri)}`, 'GET', false, true)
|
||||
.then(
|
||||
(response) => {
|
||||
artist = { ...artist, ...response };
|
||||
},
|
||||
),
|
||||
];
|
||||
request(dispatch, getState, `artists/${getFromUri('artistid', uri)}`, 'GET', false, true)
|
||||
.then(
|
||||
(response) => {
|
||||
dispatch(coreActions.itemLoaded(formatArtist(response)));
|
||||
},
|
||||
);
|
||||
|
||||
// Do we want a full artist, with all supporting material?
|
||||
if (full) {
|
||||
requests.push(
|
||||
request(dispatch, getState, `artists/${getFromUri('artistid', uri)}/top-tracks?country=${getState().spotify.country}`)
|
||||
.then(
|
||||
(response) => {
|
||||
artist = { ...artist, tracks: formatTracks(response.tracks) };
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
requests.push(
|
||||
request(dispatch, getState, `artists/${getFromUri('artistid', uri)}/related-artists`)
|
||||
.then(
|
||||
(response) => {
|
||||
artist = { ...artist, related_artists: formatArtists(response.artists) };
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$.when.apply($, requests).then(() => {
|
||||
dispatch(coreActions.artistLoaded(artist));
|
||||
|
||||
// Get supporting biography and imagery
|
||||
if (artist.musicbrainz_id) {
|
||||
dispatch(lastfmActions.getArtist(artist.uri, false, artist.musicbrainz_id));
|
||||
} else {
|
||||
dispatch(lastfmActions.getArtist(artist.uri, artist.name.replace('&', 'and')));
|
||||
}
|
||||
|
||||
// Get all their albums
|
||||
if (full) {
|
||||
let albums = [];
|
||||
const fetchAlbums = (endpoint) => request(dispatch, getState, endpoint)
|
||||
.then((response) => {
|
||||
albums = [...albums, ...formatAlbums(response.items)];
|
||||
if (response.next) {
|
||||
fetchAlbums(response.next);
|
||||
} else {
|
||||
dispatch(coreActions.artistLoaded({
|
||||
uri: artist.uri,
|
||||
albums,
|
||||
}));
|
||||
}
|
||||
});
|
||||
fetchAlbums(`artists/${getFromUri('artistid', uri)}/albums?market=${getState().spotify.country}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function getArtists(uris) {
|
||||
return (dispatch, getState) => {
|
||||
// now get all the artists for this album (full objects)
|
||||
let ids = '';
|
||||
for (let i = 0; i < uris.length; i++) {
|
||||
if (ids != '') ids += ',';
|
||||
ids += getFromUri('artistid', uris[i]);
|
||||
}
|
||||
|
||||
request(dispatch, getState, `artists/?ids=${ids}`)
|
||||
.then(
|
||||
(response) => {
|
||||
for (var i = i; i < response.length; i++) {
|
||||
const artist = response;
|
||||
for (var i = 0; i < artist.albums.length; i++) {
|
||||
dispatch({
|
||||
type: 'ALBUM_LOADED',
|
||||
album: artist.albums[i],
|
||||
});
|
||||
}
|
||||
artist.albums_uris = arrayOf('uri', artist.albums);
|
||||
artist.albums_more = artist.albums.next;
|
||||
dispatch(coreActions.artistLoaded(artist));
|
||||
// All albums (gets all pages, may take some time to iterate them all)
|
||||
let albums = [];
|
||||
const fetchAlbums = (endpoint) => request(dispatch, getState, endpoint)
|
||||
.then((response) => {
|
||||
albums = [...albums, ...formatAlbums(response.items)];
|
||||
if (response.next) {
|
||||
fetchAlbums(response.next);
|
||||
} else {
|
||||
dispatch(coreActions.itemLoaded({
|
||||
uri,
|
||||
albums,
|
||||
}));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
dispatch(coreActions.handleException(
|
||||
'Could not load artists',
|
||||
error,
|
||||
));
|
||||
},
|
||||
);
|
||||
});
|
||||
fetchAlbums(`artists/${getFromUri('artistid', uri)}/albums?limit=50&include_groups=album,single&market=${getState().spotify.country}`);
|
||||
|
||||
// Get top tracks
|
||||
request(dispatch, getState, `artists/${getFromUri('artistid', uri)}/top-tracks?country=${getState().spotify.country}`)
|
||||
.then(
|
||||
(response) => {
|
||||
dispatch(coreActions.itemLoaded({
|
||||
uri,
|
||||
tracks: formatTracks(response.tracks),
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
// Related artists
|
||||
request(dispatch, getState, `artists/${getFromUri('artistid', uri)}/related-artists`)
|
||||
.then(
|
||||
(response) => {
|
||||
dispatch(coreActions.itemLoaded({
|
||||
uri,
|
||||
related_artists: formatArtists(response.artists),
|
||||
}));
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -1202,7 +1153,6 @@ export function getArtistImages(artist) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function playArtistTopTracks(uri) {
|
||||
return (dispatch, getState) => {
|
||||
const { artists } = getState().core;
|
||||
@ -1220,12 +1170,6 @@ export function playArtistTopTracks(uri) {
|
||||
const uris = arrayOf('uri', response.tracks);
|
||||
dispatch(mopidyActions.playURIs(uris, uri));
|
||||
},
|
||||
(error) => {
|
||||
dispatch(coreActions.handleException(
|
||||
'Could not play artist\'s top tracks',
|
||||
error,
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -1306,47 +1250,28 @@ export function getAlbum(uri) {
|
||||
request(dispatch, getState, `albums/${getFromUri('albumid', uri)}`)
|
||||
.then(
|
||||
(response) => {
|
||||
// dispatch our loaded artists (simple objects)
|
||||
dispatch(coreActions.artistsLoaded(response.artists));
|
||||
|
||||
const tracks = Object.assign([], response.tracks.items);
|
||||
|
||||
const album = {
|
||||
dispatch(coreActions.itemLoaded({
|
||||
...formatAlbum(response),
|
||||
artists_uris: arrayOf('uri', response.artists),
|
||||
tracks_more: response.tracks.next,
|
||||
tracks_total: response.tracks.total,
|
||||
};
|
||||
album.tracks = tracks.map((track) => ({
|
||||
...track,
|
||||
album: {
|
||||
name: album.name,
|
||||
uri: album.uri,
|
||||
},
|
||||
tracks: formatTracks(response.tracks.items),
|
||||
}));
|
||||
|
||||
dispatch(coreActions.albumLoaded(album));
|
||||
let tracks = formatTracks(response.tracks.items);
|
||||
const fetchTracks = (endpoint) => request(dispatch, getState, endpoint)
|
||||
.then((response) => {
|
||||
tracks = [...tracks, ...formatTracks(response.items)];
|
||||
if (response.next) {
|
||||
fetchTracks(response.next);
|
||||
} else {
|
||||
dispatch(coreActions.itemLoaded({
|
||||
uri,
|
||||
tracks,
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// now get all the artists for this album (full objects)
|
||||
// we do this to get the artist artwork
|
||||
const artist_ids = [];
|
||||
for (var i = 0; i < response.artists.length; i++) {
|
||||
artist_ids.push(getFromUri('artistid', response.artists[i].uri));
|
||||
if (response.tracks.next) {
|
||||
fetchTracks(response.tracks.next);
|
||||
}
|
||||
|
||||
// get all album artists as full objects
|
||||
request(dispatch, getState, `artists/?ids=${artist_ids}`)
|
||||
.then(
|
||||
(response) => {
|
||||
dispatch(coreActions.artistsLoaded(response.artists));
|
||||
},
|
||||
(error) => {
|
||||
dispatch(coreActions.handleException(
|
||||
'Could not load album\'s artists',
|
||||
error,
|
||||
));
|
||||
},
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
dispatch(coreActions.handleException(
|
||||
|
||||
Reference in New Issue
Block a user