Using core.items to contain all loaded assets

This commit is contained in:
James Barnsley
2020-09-03 12:40:38 +12:00
parent 53be543dd3
commit 6020781be0
10 changed files with 270 additions and 528 deletions

View File

@ -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',

View File

@ -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));

View File

@ -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

View File

@ -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}'`);
},
);
};
}

View File

@ -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(