Track loading (current_track and next_track); Add to playlist

This commit is contained in:
James Barnsley
2020-09-09 07:54:19 +12:00
parent 9b3c0bcefe
commit 3e4fdd2c2f
14 changed files with 321 additions and 414 deletions

View File

@ -107,16 +107,17 @@ export function updateColdStore(items) {
* relevant service to load the record - all from one neat package.
* */
export function loadItems(uris, forceRefetch = false) {
export function loadItems(uris, forceRefetch = false, callbackAction = null) {
return {
type: 'LOAD_ITEMS',
uris,
forceRefetch,
callbackAction,
};
}
export function loadItem(uri, forceRefetch = false) {
return loadItems([uri], forceRefetch);
export function loadItem(uri, forceRefetch = false, callbackAction) {
return loadItems([uri], forceRefetch, callbackAction);
}
export function loadTrack(uri, forceRefetch = false) {

View File

@ -319,6 +319,7 @@ const CoreMiddleware = (function () {
type: `LOAD_${uriType(uri).toUpperCase()}`,
uri,
forceRefetch: action.forceRefetch,
callbackAction: action.callbackAction,
});
});
break;
@ -345,7 +346,10 @@ const CoreMiddleware = (function () {
fetchTrack();
break;
}
if (store.getState().core.items[action.uri]) {
if (
store.getState().core.items[action.uri]
&& store.getState().core.items[action.uri].images
) {
console.info(`Using "${action.uri}" from index`);
break;
}
@ -354,6 +358,10 @@ const CoreMiddleware = (function () {
if (result) {
console.info(`Loading "${action.uri}" from database`);
store.dispatch(coreActions.restoreItemsFromColdStore([result]));
if (!result.images) {
fetchTrack();
}
} else {
fetchTrack();
}
@ -435,19 +443,34 @@ const CoreMiddleware = (function () {
if (
store.getState().core.items[action.uri]
&& store.getState().core.items[action.uri].tracks
&& store.getState().core.items[action.uri].albums
&& store.getState().core.items[action.uri].albums_uris
&& store.getState().core.items[action.uri].images
) {
console.info(`Using "${action.uri}" from index`);
break;
}
localForage.getItem(action.uri).then((artist) => {
if (artist) {
console.info(`Restoring "${action.uri}" and ${artist.albums_uris.length} albums from database`);
const promises = artist.albums_uris.map((albumUri) => localForage.getItem(albumUri));
Promise.all(promises).then(
(albums) => store.dispatch(coreActions.restoreItemsFromColdStore(compact(albums))),
);
store.dispatch(coreActions.restoreLibraryFromColdStore(artist));
} else {
fetchArtist();
}
});
localForage.getItem(action.uri).then((result) => {
if (result) {
console.info(`Restoring "${action.uri}" from database`);
store.dispatch(coreActions.restoreItemsFromColdStore([result]));
if (!result.tracks || !result.albums || !result.images) {
if (!result.tracks || !result.albums_uris || !result.images) {
fetchArtist();
}
} else {
@ -459,7 +482,6 @@ const CoreMiddleware = (function () {
break;
case 'LOAD_PLAYLIST':
console.log(action);
const fetchPlaylist = () => {
switch (uriSource(action.uri)) {
case 'spotify':
@ -585,7 +607,7 @@ const CoreMiddleware = (function () {
localForage.getItem(action.uri).then((library) => {
if (library) {
console.info(`Restoring "${action.uri}" and ${library.items_uris.length} items from db`);
console.info(`Restoring "${action.uri}" and ${library.items_uris.length} items from database`);
const promises = library.items_uris.map((libraryItem) => localForage.getItem(libraryItem));
Promise.all(promises).then(

View File

@ -76,7 +76,10 @@ export default function reducer(core = {}, action) {
};
case 'ITEMS_LOADED':
const mergedItems = action.items.reduce((obj, item) => (obj[item.uri] = item, obj), {});
const mergedItems = action.items.reduce(
(obj, item) => (obj[item.uri] = item, obj),
{},
);
return {
...core,
items: {

View File

@ -17,6 +17,7 @@ import {
formatSimpleObject,
getTrackIcon,
formatArtists,
formatArtist,
} from '../../util/format';
import {
arrayOf,
@ -1566,55 +1567,23 @@ const MopidyMiddleware = (function () {
...response,
uri: response.uri,
type: 'playlist',
is_completely_loaded: true,
provider: 'mopidy',
tracks: (response.tracks ? response.tracks : []),
tracks_total: (response.tracks ? response.tracks.length : 0),
can_edit: true,
};
// tracks? get the full track objects
if (playlist.tracks.length > 0) {
store.dispatch({
type: 'MOPIDY_RESOLVE_PLAYLIST_TRACKS',
tracks: playlist.tracks,
key: playlist.uri,
request(store, 'library.lookup', { uris: arrayOf('uri', response.tracks) })
.then((tracksResponse) => {
const tracks = response.tracks.map((simpleTrack) => {
const fullTracks = tracksResponse[simpleTrack.uri];
return {
...simpleTrack,
...(fullTracks.length ? fullTracks[0] : {}),
};
});
playlist.tracks = tracks;
store.dispatch(coreActions.itemLoaded(playlist));
});
}
store.dispatch(coreActions.playlistLoaded(playlist));
});
break;
case 'MOPIDY_RESOLVE_PLAYLIST_TRACKS':
var tracks = Object.assign([], action.tracks);
var uris = arrayOf('uri', tracks);
request(store, 'library.lookup', { uris })
.then((response) => {
for (const uri in response) {
if (response.hasOwnProperty(uri)) {
var track = response[uri][0];
if (track) {
// find the track reference, and drop in the full track data
function getByURI(trackReference) {
return track.uri == trackReference.uri;
}
const trackReferences = tracks.filter(getByURI);
// there could be multiple instances of this track, so accommodate this
for (let j = 0; j < trackReferences.length; j++) {
const key = tracks.indexOf(trackReferences[j]);
tracks[key] = track;
}
}
}
}
store.dispatch({
type: 'PLAYLIST_TRACKS',
tracks,
key: action.key,
});
});
break;
@ -1873,36 +1842,22 @@ const MopidyMiddleware = (function () {
for (const raw_artist of response[0].artists) {
// We're only interested in the artist we asked for
if (raw_artist.uri === artist.uri) {
artist = { ...raw_artist };
artist = { ...formatArtist(raw_artist) };
}
}
// Add our tracks and albums
artist.albums_uris = arrayOf('uri', albums);
artist.tracks = response;
artist.tracks = formatTracks(response);
store.dispatch(coreActions.itemLoaded(artist));
store.dispatch(lastfmActions.getArtist(artist.uri, artist.name, artist.musicbrainz_id));
// Load supprting information from LastFM and Discogs
const existing_artist = store.getState().core.items[artist.uri];
if (existing_artist) {
if (!existing_artist.images) {
if (store.getState().spotify.enabled) {
store.dispatch(spotifyActions.getArtistImages(artist));
} else {
store.dispatch(discogsActions.getArtistImages(artist.uri, artist));
}
}
// Get biography and other stats from LastFM
if (!existing_artist.biography) {
// TODO: Move this condition into lastfmActions
if (artist.musicbrainz_id) {
store.dispatch(lastfmActions.getArtist(artist.uri, false, artist.musicbrainz_id));
} else {
store.dispatch(lastfmActions.getArtist(artist.uri, artist.name));
}
}
if (store.getState().spotify.enabled) {
store.dispatch(spotifyActions.getArtistImages(artist));
} else {
store.dispatch(discogsActions.getArtistImages(artist.uri, artist));
}
});
break;
@ -1982,24 +1937,13 @@ const MopidyMiddleware = (function () {
var track = formatTrack(action.tl_track);
if (track.uri) {
// Deliver the data we've got already
store.dispatch({
type: 'CURRENT_TRACK_LOADED',
track,
uri: track.uri,
});
// Now attempt to get supporting images
if (store.getState().core.tracks[track.uri] === undefined || store.getState().core.tracks[track.uri].images === undefined) {
// We've got Spotify running, and it's a spotify track - go straight to the source!
if (store.getState().spotify.enabled && uriSource(track.uri) == 'spotify') {
store.dispatch(spotifyActions.getTrack(track.uri));
// Some other source, rely on Mopidy backends to do their work
} else {
store.dispatch(mopidyActions.getImages([track.uri]));
}
}
store.dispatch(coreActions.loadItem(track.uri));
}
break;

View File

@ -1041,7 +1041,9 @@ export function getArtist(uri, full = false, forceRefetch = false) {
request(dispatch, getState, endpoint, 'GET', false, true)
.then(
(response) => {
dispatch(coreActions.itemLoaded(formatArtist(response)));
const artist = formatArtist(response);
dispatch(coreActions.itemLoaded(artist));
dispatch(lastfmActions.getArtist(uri, artist.name, artist.mbid));
},
);
@ -1058,8 +1060,9 @@ export function getArtist(uri, full = false, forceRefetch = false) {
} else {
dispatch(coreActions.itemLoaded({
uri,
albums,
albums_uris: arrayOf('uri', albums),
}));
dispatch(coreActions.itemsLoaded(albums));
}
});
fetchAlbums(`artists/${getFromUri('artistid', uri)}/albums?limit=50&include_groups=album,single&market=${getState().spotify.country}`);
@ -1257,18 +1260,11 @@ export function createPlaylist(name, description, is_public, is_collaborative) {
request(dispatch, getState, `users/${getState().spotify.me.id}/playlists/`, 'POST', data)
.then(
(response) => {
dispatch({
type: 'PLAYLIST_LOADED',
key: response.uri,
playlist: {
...response,
can_edit: true,
tracks: [],
tracks_more: null,
tracks_total: 0,
},
});
dispatch(coreActions.itemLoaded({
...formatPlaylist(response),
can_edit: true,
tracks: [],
}));
dispatch({
type: 'LIBRARY_PLAYLISTS_LOADED',
@ -1372,7 +1368,7 @@ export function getPlaylist(uri, forceRefetch = false, callbackAction = null) {
dispatch(coreActions.itemLoaded({
...formatPlaylist(response),
user: formatUser(response.owner),
can_edit: (getState().spotify.me && getState().spotify.me.id === response.owner.id),
tracks,
description,
}));