URI format for libraries, but own core.libraries for better control

This commit is contained in:
James Barnsley
2020-09-06 13:53:22 +12:00
parent f6f5e37aa9
commit 1bc7f2b372
21 changed files with 1231 additions and 1346 deletions

View File

@ -77,13 +77,20 @@ export function clearStorage() {
};
}
export function restoreFromColdStore(items) {
export function restoreItemsFromColdStore(items) {
return {
type: 'RESTORE_FROM_COLD_STORE',
type: 'RESTORE_ITEMS_FROM_COLD_STORE',
items,
};
}
export function restoreLibraryFromColdStore(library) {
return {
type: 'RESTORE_LIBRARY_FROM_COLD_STORE',
library,
};
}
export function updateColdStore(items) {
return {
type: 'UPDATE_COLD_STORE',
@ -175,29 +182,31 @@ export function loadLibrary(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 libraryLoaded(library) {
return {
type: 'LIBRARY_LOADED',
library,
};
}
export function itemsLoaded(items) {
return {
type: 'ITEMS_LOADED',
items,
};
}
export function itemLoaded(item) {
return {
type: 'ITEM_LOADED',
item,
};
return itemsLoaded([item]);
}
export function trackLoaded(track) {
return tracksLoaded([track]);
}
export function tracksLoaded(tracks) {
return {
type: 'TRACKS_LOADED',
tracks,
};
}
export function trackLoaded(track) {
return tracksLoaded([track]);
}
export function artistsLoaded(artists) {
return {
@ -206,35 +215,35 @@ export function artistsLoaded(artists) {
};
}
export function albumLoaded(album) {
return albumsLoaded([album]);
}
export function albumsLoaded(albums) {
return {
type: 'ALBUMS_LOADED',
albums,
};
}
export function playlistLoaded(playlist) {
return playlistsLoaded([playlist]);
export function albumLoaded(album) {
return albumsLoaded([album]);
}
export function playlistsLoaded(playlists) {
return {
type: 'PLAYLISTS_LOADED',
playlists,
};
}
export function userLoaded(user) {
return usersLoaded([user]);
export function playlistLoaded(playlist) {
return playlistsLoaded([playlist]);
}
export function usersLoaded(users) {
return {
type: 'USERS_LOADED',
users,
};
}
export function userLoaded(user) {
return usersLoaded([user]);
}
export function userPlaylistsLoaded(uri, playlists, more = null, total = null) {
return {
type: 'USER_PLAYLISTS_LOADED',

View File

@ -1,7 +1,7 @@
import React from 'react';
import ReactGA from 'react-ga';
import localForage from 'localforage';
import { compact } from 'lodash';
import { arrayOf } from '../../util/arrays';
import URILink from '../../components/URILink';
import { uriSource, upgradeSpotifyPlaylistUris, uriType, titleCase } from '../../util/helpers';
@ -366,12 +366,13 @@ const CoreMiddleware = (function () {
};
if (action.force_reload) {
console.info(`Force-reloading "${action.uri}"`);
fetchAlbum();
break;
}
if (
store.getState().core.items[action.uri] &&
store.getState().core.items[action.uri].tracks
store.getState().core.items[action.uri]
&& store.getState().core.items[action.uri].tracks
) {
console.info(`Using "${action.uri}" from index`);
break;
@ -380,8 +381,7 @@ const CoreMiddleware = (function () {
localForage.getItem(action.uri).then((result) => {
if (result) {
console.info(`Loading "${action.uri}" from database`);
store.dispatch(coreActions.restoreFromColdStore([result]));
console.log(result);
store.dispatch(coreActions.restoreItemsFromColdStore([result]));
// We don't have the complete Album, so refetch
if (!result.tracks) {
@ -395,54 +395,48 @@ const CoreMiddleware = (function () {
next(action);
break;
// TODO: Relocate this
case 'UPDATE_COLD_STORE':
if (action.items) {
action.items.map((item) => {
localForage.getItem(item.uri).then((result) => {
localForage.setItem(item.uri, { ...(result || {}), ...item });
});
});
}
break;
case 'RESTORE_FROM_COLD_STORE':
if (action.items) {
store.dispatch({
type: 'RESTORED_FROM_COLD_STORE',
items: action.items,
});
}
break;
case 'LOAD_ARTIST':
const fetchArtist = () => {
switch (uriSource(action.uri)) {
case 'spotify':
store.dispatch(spotifyActions.getArtist(action.uri, true));
if (spotify.me) {
store.dispatch(spotifyActions.following(action.uri));
}
break;
default:
store.dispatch(mopidyActions.getArtist(action.uri));
break;
}
};
if (action.force_reload) {
console.info(`Force-reloading "${action.uri}"`);
fetchArtist();
break;
}
if (
!action.force_reload
&& store.getState().core.artists[action.uri]
&& store.getState().core.artists[action.uri].albums
&& store.getState().core.artists[action.uri].tracks) {
console.info(`Loading "${action.uri}" from index`);
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].images
) {
console.info(`Using "${action.uri}" from index`);
break;
}
// Try our cold storage
localForage.getItem(action.uri).then((result) => {
if (result && !action.force_reload) {
console.info(`Loading "${action.uri}" from database`);
store.dispatch(coreActions.restoreFromColdStore([result]));
} else {
switch (uriSource(action.uri)) {
case 'spotify':
store.dispatch(spotifyActions.getArtist(action.uri, true));
if (result) {
console.info(`Restoring "${action.uri}" from database`);
store.dispatch(coreActions.restoreItemsFromColdStore([result]));
if (spotify.me) {
store.dispatch(spotifyActions.following(action.uri));
}
break;
default:
store.dispatch(mopidyActions.getArtist(action.uri));
break;
if (!result.tracks || !result.albums || !result.images) {
fetchArtist();
}
} else {
fetchArtist();
}
});
@ -467,10 +461,14 @@ const CoreMiddleware = (function () {
};
if (action.force_reload) {
console.info(`Force-reloading "${action.uri}"`);
fetchPlaylist();
break;
}
if (store.getState().core.items[action.uri]) {
if (
store.getState().core.items[action.uri]
&& store.getState().core.items[action.uri].tracks
) {
console.info(`Using "${action.uri}" from index`);
break;
}
@ -478,7 +476,11 @@ const CoreMiddleware = (function () {
localForage.getItem(action.uri).then((result) => {
if (result) {
console.info(`Restoring "${action.uri}" from database`);
store.dispatch(coreActions.restoreFromColdStore([result]));
store.dispatch(coreActions.restoreItemsFromColdStore([result]));
if (!result.tracks) {
fetchPlaylist();
}
} else {
fetchPlaylist();
}
@ -540,27 +542,28 @@ const CoreMiddleware = (function () {
switch (uriSource(action.uri)) {
case 'spotify':
store.dispatch(
spotifyActions[`getLibrary${titleCase(uriType(action.uri))}`](action.uri),
spotifyActions[`getLibrary${titleCase(uriType(action.uri))}`](),
);
break;
case 'google':
store.dispatch(
googleActions[`getLibrary${titleCase(uriType(action.uri))}`](action.uri),
googleActions[`getLibrary${titleCase(uriType(action.uri))}`](),
);
break;
default:
store.dispatch(
mopidyActions[`getLibrary${titleCase(uriType(action.uri))}`](action.uri),
mopidyActions[`getLibrary${titleCase(uriType(action.uri))}`](),
);
break;
}
};
if (action.force_reload) {
console.info(`Force-reloading "${action.uri}"`);
fetchLibrary();
break;
}
if (store.getState().core.items[action.uri]) {
if (store.getState().core.libraries[action.uri]) {
console.info(`Using "${action.uri}" from index`);
break;
}
@ -569,13 +572,12 @@ const CoreMiddleware = (function () {
if (library) {
console.info(`Restoring "${action.uri}" and ${library.items_uris.length} items from db`);
var promises = library.items_uris.map(function(item) { return localForage.getItem(item); });
Promise.all(promises).then(function(libraryItems) {
store.dispatch(coreActions.restoreFromColdStore(libraryItems));
});
const promises = library.items_uris.map((libraryItem) => localForage.getItem(libraryItem));
Promise.all(promises).then(
(libraryItems) => store.dispatch(coreActions.restoreItemsFromColdStore(compact(libraryItems))),
);
//store.dispatch(coreActions.loadItems(result.items_uris));
store.dispatch(coreActions.restoreFromColdStore([library]));
store.dispatch(coreActions.restoreLibraryFromColdStore(library));
} else {
fetchLibrary();
}
@ -687,23 +689,22 @@ const CoreMiddleware = (function () {
next(action);
break;
// TODO: Flatten ITEM_LOADED to become an alias for ITEMS_LOADED (prefer bulk)
case 'ITEMS_LOADED':
action.items.forEach((item) => store.dispatch(coreActions.itemLoaded(item)));
break;
case 'ITEM_LOADED':
const mergedItem = {
...core.items[action.item.uri] || {},
...action.item,
};
store.dispatch(coreActions.updateColdStore([mergedItem]));
const mergedItems = action.items.map((item) => ({
...core.items[item.uri] || {},
...item,
}));
store.dispatch(coreActions.updateColdStore(mergedItems));
next({
...action,
item: mergedItem,
items: mergedItems,
});
break;
case 'LIBRARY_LOADED':
store.dispatch(coreActions.updateColdStore([action.library]));
break;
case 'ARTISTS_LOADED':
var artists_index = { ...core.artists };
var artists_loaded = [];
@ -753,7 +754,7 @@ const CoreMiddleware = (function () {
case 'spotify':
if (spotify.authorization && spotify.me) {
playlist.can_edit = (playlist.owner.id == spotify.me.id);
playlist.can_edit = (playlist.owner && playlist.owner.id == spotify.me.id);
}
}
@ -911,6 +912,17 @@ const CoreMiddleware = (function () {
next(action);
break;
// TODO: Relocate this
case 'UPDATE_COLD_STORE':
if (action.items) {
action.items.map((item) => {
localForage.getItem(item.uri).then((result) => {
localForage.setItem(item.uri, { ...(result || {}), ...item });
});
});
}
break;
// This action is irrelevant to us, pass it on to the next middleware
default:
return next(action);

View File

@ -75,6 +75,26 @@ export default function reducer(core = {}, action) {
},
};
case 'ITEMS_LOADED':
const mergedItems = action.items.reduce((obj, item) => (obj[item.uri] = item, obj), {});
return {
...core,
items: {
...core.items,
...mergedItems,
},
};
case 'LIBRARY_LOADED':
console.log(action);
return {
...core,
libraries: {
...core.libraries,
[action.library.uri]: action.library,
},
};
case 'TRACKS_LOADED':
var tracks = { ...core.tracks };
for (const track of action.tracks) {
@ -148,8 +168,18 @@ export default function reducer(core = {}, action) {
users[action.uri] = user;
return { ...core, users };
case 'RESTORE_LIBRARY_FROM_COLD_STORE':
const { libraries } = core;
libraries[action.library.uri] = {
...(libraries[action.library.uri] || {}),
...action.library,
};
return {
...core,
libraries,
};
case 'RESTORED_FROM_COLD_STORE':
case 'RESTORE_ITEMS_FROM_COLD_STORE':
const { items } = core;
action.items.forEach((item) => {
items[item.uri] = {

View File

@ -228,7 +228,7 @@ export function getArtist(uri, artist, mbid = false) {
.then(
(response) => {
if (response.artist) {
dispatch(coreActions.artistLoaded({
dispatch(coreActions.itemLoaded({
uri,
mbid: response.artist.mbid,
biography: response.artist.bio.content,
@ -255,7 +255,7 @@ export function getAlbum(uri, artist, album, mbid = false) {
.then(
(response) => {
if (response.album) {
const existing_album = getState().core.albums[uri];
const existing_album = getState().core.items[uri];
const album = {
uri,
images: response.album.image,
@ -273,7 +273,7 @@ export function getAlbum(uri, artist, album, mbid = false) {
delete album.images;
}
dispatch(coreActions.albumLoaded(album));
dispatch(coreActions.itemLoaded(album));
}
},
);

View File

@ -652,7 +652,7 @@ const MopidyMiddleware = (function () {
* */
case 'MOPIDY_PLAY_PLAYLIST':
var playlist = store.getState().core.playlists[action.uri];
var playlist = store.getState().core.items[action.uri];
// We have the playlist loaded already, and we've got at least 1 track to start playing
if (playlist && playlist.tracks_uris && playlist.tracks_uris.length > 0) {
@ -700,7 +700,7 @@ const MopidyMiddleware = (function () {
case 'MOPIDY_ENQUEUE_PLAYLIST':
var playlist = store.getState().core.playlists[action.uri];
var playlist = store.getState().core.items[action.uri];
// We have the playlist loaded already, and we've got at least 1 track to start playing
if (playlist && playlist.tracks_uris && playlist.tracks_uris.length > 0) {
@ -1598,41 +1598,6 @@ const MopidyMiddleware = (function () {
* ======================================================================================
* */
case 'MOPIDY_GET_LIBRARY_PLAYLISTS':
request(store, 'playlists.asList')
.then((response) => {
// Remove any Spotify playlists. These will be handled by our Spotify API
const playlist_uris = arrayOf('uri', response).filter(
(uri) => uriSource(uri) !== 'spotify',
);
const libraryPlaylists = [];
// get the full playlist objects
playlist_uris.forEach((uri, index) => {
request(store, 'playlists.lookup', { uri })
.then((response) => {
libraryPlaylists.push({
type: 'playlist',
name: response.name,
uri: response.uri,
source: uriSource(response.uri),
provider: 'mopidy',
last_modified: response.last_modified,
tracks: response.tracks,
});
if (index === playlist_uris.length - 1) {
store.dispatch(coreActions.itemsLoaded(libraryPlaylists));
store.dispatch(coreActions.itemLoaded({
uri: 'mopidy:library:playlists',
items_uris: arrayOf('uri', libraryPlaylists),
}));
}
});
});
});
break;
case 'MOPIDY_GET_PLAYLIST':
request(store, 'playlists.lookup', action.data)
@ -1766,7 +1731,7 @@ const MopidyMiddleware = (function () {
// Overwrite our playlist with the response to our save
// This is essential to get the updated URI from Mopidy
const playlist = {
...store.getState().core.playlists[action.key],
...store.getState().core.items[action.key],
uri: response.uri,
name: response.name,
};
@ -1858,28 +1823,6 @@ const MopidyMiddleware = (function () {
* */
case 'MOPIDY_GET_LIBRARY_ALBUMS':
request(store, 'library.browse', { uri: store.getState().mopidy.library_albums_uri })
.then((response) => {
const uris = arrayOf('uri', response);
request(store, 'library.lookup', { uris })
.then((response) => {
const libraryAlbums = indexToArray(response).map((tracks) => ({
source: 'local',
artists: tracks[0].artists || null,
tracks,
last_modified: tracks[0].last_modified,
...tracks[0].album,
}));
store.dispatch(coreActions.itemsLoaded(libraryAlbums));
store.dispatch(coreActions.itemLoaded({
uri: 'mopidy:library:albums',
items_uris: arrayOf('uri', libraryAlbums),
}));
});
});
break;
case 'MOPIDY_GET_ALBUM':
request(store, 'library.lookup', { uris: [action.uri] })
@ -1911,7 +1854,8 @@ const MopidyMiddleware = (function () {
* =============================================================== ARTIST(S) ============
* ======================================================================================
**/
case 'MOPIDY_GET_LIBRARY_ARTISTS':
case 'MOPIDY_GET_LIBRARY_ARTISTSXXXXXXXXXXXX':
const uri = store.getState().mopidy.library_artists_uri;
request(store, 'library.browse', { uri })
.then((response) => {
@ -1919,8 +1863,6 @@ const MopidyMiddleware = (function () {
const uris = [];
for (let i = 0; i < response.length; i++) {
// Convert local URI to actual artist URI
// See https://github.com/mopidy/mopidy-local-sqlite/issues/39
response[i].uri = response[i].uri.replace('local:directory?albumartist=', '').replace('local:directory?artist=', '');
uris.push(response[i].uri);
}
@ -1934,62 +1876,6 @@ const MopidyMiddleware = (function () {
});
break;
/**
* TODO: Fetch and process library artists
*
* We can't get specific artist artwork from Mopidy. Perhaps we fetch additional
* artist metadata via LastFM? Their API limits will make this quite slow.
case 'MOPIDY_GET_LIBRARY_ARTISTS':
var last_run = store.getState().ui.processes.MOPIDY_LIBRARY_ARTISTS_PROCESSOR
if (!last_run){
request(store, 'library.browse', { uri: 'local:directory?type=artist' } )
.then(response => {
if (response.length <= 0) return;
var uris = arrayOf('uri',response);
store.dispatch({
type: 'MOPIDY_LIBRARY_ARTISTS_LOADED',
uris: uris
});
// Start our process to load the full album objects
store.dispatch(uiActions.startProcess('MOPIDY_LIBRARY_ARTISTS_PROCESSOR','Loading '+uris.length+' local artists', {uris: uris}));
})
} else if (last_run.status == 'cancelled'){
store.dispatch(uiActions.resumeProcess('MOPIDY_LIBRARY_ARTISTS_PROCESSOR'))
} else if (last_run.status == 'finished'){
// TODO: do we want to force a refresh?
}
break;
case 'MOPIDY_LIBRARY_ARTISTS_PROCESSOR':
if (store.getState().ui.processes['MOPIDY_LIBRARY_ARTISTS_PROCESSOR'] !== undefined){
var processor = store.getState().ui.processes['MOPIDY_LIBRARY_ARTISTS_PROCESSOR'];
if (processor.status == 'cancelling'){
store.dispatch(uiActions.processCancelled('MOPIDY_LIBRARY_ARTISTS_PROCESSOR'));
return false;
}
}
var uris = Object.assign([], action.data.uris)
var uris_to_load = uris.splice(0,50)
if (uris_to_load.length > 0){
store.dispatch(uiActions.updateProcess('MOPIDY_LIBRARY_ARTISTS_PROCESSOR', 'Loading '+uris.length+' local artists', {uris: uris}));
store.dispatch(mopidyActions.getArtists(uris_to_load, {name: 'MOPIDY_LIBRARY_ARTISTS_PROCESSOR', data: {uris: uris}}));
} else {
store.dispatch(uiActions.processFinished('MOPIDY_LIBRARY_ARTISTS_PROCESSOR'));
}
break;
* */
case 'MOPIDY_GET_ARTIST':
request(store, 'library.lookup', { uris: [action.uri] })
.then((_response) => {
@ -2016,10 +1902,9 @@ const MopidyMiddleware = (function () {
}
}
if (albums) {
store.dispatch(coreActions.albumsLoaded(albums));
store.dispatch(coreActions.itemsLoaded(albums));
}
// Start with an empty artist object
let artist = {
uri: action.uri,
provider: 'mopidy',
@ -2035,13 +1920,13 @@ const MopidyMiddleware = (function () {
}
// Add our tracks and albums
artist.albums_uris = arrayOf('uri', albums),
artist.tracks = response;
artist.albums_uris = arrayOf('uri', albums);
artist.tracks = response;
store.dispatch(coreActions.artistLoaded(artist));
store.dispatch(coreActions.itemLoaded(artist));
// Load supprting information from LastFM and Discogs
const existing_artist = store.getState().core.artists[artist.uri];
const existing_artist = store.getState().core.items[artist.uri];
if (existing_artist) {
if (!existing_artist.images) {
if (store.getState().spotify.enabled) {
@ -2049,7 +1934,7 @@ const MopidyMiddleware = (function () {
} else {
store.dispatch(discogsActions.getArtistImages(artist.uri, artist));
}
}
}
// Get biography and other stats from LastFM
if (!existing_artist.biography) {
@ -2380,6 +2265,88 @@ const MopidyMiddleware = (function () {
next(action);
break;
/**
* My Music libraries
*/
case 'MOPIDY_GET_LIBRARY_ARTISTS':
request(store, 'library.browse', { uri: store.getState().mopidy.library_artists_uri })
.then((raw_response) => {
if (raw_response.length <= 0) return;
// Convert local URI to actual artist URI
// See https://github.com/mopidy/mopidy-local-sqlite/issues/39
const response = raw_response.map((artist) => ({
...artist,
uri: artist.uri.replace('local:directory?albumartist=', '').replace('local:directory?artist=', '')
}));
store.dispatch(coreActions.itemsLoaded(response));
store.dispatch(coreActions.libraryLoaded({
uri: 'mopidy:library:artists',
items_uris: arrayOf('uri', response),
}));
});
break;
case 'MOPIDY_GET_LIBRARY_PLAYLISTS':
request(store, 'playlists.asList')
.then((response) => {
// Remove any Spotify playlists. These will be handled by our Spotify API
const playlist_uris = arrayOf('uri', response).filter(
(uri) => uriSource(uri) !== 'spotify',
);
const libraryPlaylists = [];
// get the full playlist objects
playlist_uris.forEach((uri, index) => {
request(store, 'playlists.lookup', { uri })
.then((response) => {
libraryPlaylists.push({
type: 'playlist',
name: response.name,
uri: response.uri,
source: uriSource(response.uri),
provider: 'mopidy',
last_modified: response.last_modified,
tracks: response.tracks,
});
if (index === playlist_uris.length - 1) {
store.dispatch(coreActions.itemsLoaded(libraryPlaylists));
store.dispatch(coreActions.libraryLoaded({
uri: 'mopidy:library:playlists',
items_uris: arrayOf('uri', libraryPlaylists),
}));
}
});
});
});
break;
case 'MOPIDY_GET_LIBRARY_ALBUMS':
request(store, 'library.browse', { uri: store.getState().mopidy.library_albums_uri })
.then((response) => {
const uris = arrayOf('uri', response);
request(store, 'library.lookup', { uris })
.then((response) => {
const libraryAlbums = indexToArray(response).map((tracks) => ({
source: 'local',
artists: tracks[0].artists || null,
tracks,
last_modified: tracks[0].last_modified,
...tracks[0].album,
}));
store.dispatch(coreActions.itemsLoaded(libraryAlbums));
store.dispatch(coreActions.libraryLoaded({
uri: 'mopidy:library:albums',
items_uris: arrayOf('uri', libraryAlbums),
}));
});
});
break;
// This action is irrelevant to us, pass it on to the next middleware
default:
return next(action);

View File

@ -19,6 +19,7 @@ import {
formatArtists,
formatAlbums,
formatPlaylists,
formatImages,
} from '../../util/format';
import URILink from '../../components/URILink';
import { i18n } from '../../locale';
@ -391,7 +392,6 @@ export function getFeaturedPlaylists() {
const playlists = [];
for (let i = 0; i < response.playlists.items.length; i++) {
playlists.push({
...response.playlists.items[i],
is_completely_loaded: false,
can_edit: (getState().spotify.me && response.playlists.items[i].owner.id == getState().spotify.me.id),
@ -891,38 +891,6 @@ export function resolveRadioSeeds(radio) {
* */
/**
* Get my favorites
*
* @param uri string
* */
export function getFavorites(limit = 50, term = 'long_term') {
return (dispatch, getState) => {
dispatch({ type: 'SPOTIFY_FAVORITES_LOADED', artists: [], tracks: [] });
$.when(
request(dispatch, getState, `me/top/artists?limit=${limit}&time_range=${term}`),
request(dispatch, getState, `me/top/tracks?limit=${limit}&time_range=${term}`),
).then(
(artists_response, tracks_response) => {
dispatch({
type: 'SPOTIFY_FAVORITES_LOADED',
artists: artists_response.items,
tracks: tracks_response.items,
});
},
(artists_error, tracks_error) => {
dispatch(coreActions.handleException(
'Could not load favorites',
{ ...artists_error, ...tracks_error },
));
},
);
};
}
/**
* Get our recommendations
* This is based off our 'favorites' and then we use those as seeds
@ -993,7 +961,7 @@ export function getRecommendations(uris = [], limit = 20, tunabilities = null) {
// is not one of the seeds
if (!artists_uris.includes(artist.uri) && !artists_ids.includes(artist.id)) {
artists_uris.push(artist.uri);
dispatch(getArtist(artist.uri));
dispatch(getArtist(artist.uri, false));
}
}
}
@ -1136,21 +1104,14 @@ export function getArtistImages(artist) {
return (dispatch, getState) => {
request(dispatch, getState, `search?q=${artist.name}&type=artist`)
.then(response => {
console.log('images', response);
if (response.artists.items.length > 0) {
const updatedArtist = {
dispatch(coreActions.itemLoaded({
uri: artist.uri,
images: response.artists.items[0].images,
}
dispatch(coreActions.artistLoaded(updatedArtist));
images: [formatImages(response.artists.items[0].images)],
}));
}
},
error => {
dispatch(coreActions.handleException(
'Could not load artists',
error,
));
},
);
});
};
}
@ -1724,22 +1685,18 @@ export function flushLibrary() {
};
}
/**
* Playlists
* */
export function getLibraryPlaylists() {
return (dispatch, getState) => {
let libraryPlaylists = [];
const fetchLibraryPlaylists = (endpoint) => request(dispatch, getState, endpoint)
.then((response) => {
console.log('spot', response);
libraryPlaylists = [...libraryPlaylists, ...formatPlaylists(response.items)];
if (response.next) {
fetchLibraryPlaylists(response.next);
} else {
dispatch(coreActions.itemsLoaded(libraryPlaylists));
dispatch(coreActions.itemLoaded({
dispatch(coreActions.libraryLoaded({
uri: 'spotify:library:playlists',
items_uris: arrayOf('uri', libraryPlaylists),
}));
@ -1760,7 +1717,7 @@ export function getLibraryAlbums() {
fetchLibraryAlbums(response.next);
} else {
dispatch(coreActions.itemsLoaded(libraryAlbums));
dispatch(coreActions.itemLoaded({
dispatch(coreActions.libraryLoaded({
uri: 'spotify:library:albums',
items_uris: arrayOf('uri', libraryAlbums),
}));
@ -1771,70 +1728,23 @@ export function getLibraryAlbums() {
};
}
/**
* Artists
* */
export function getLibraryArtists() {
return (dispatch, getState) => {
const last_run = getState().ui.processes.SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR;
let libraryArtists = [];
const fetchLibraryArtists = (endpoint) => request(dispatch, getState, endpoint)
.then((response) => {
libraryArtists = [...libraryArtists, ...formatArtists(response.artists.items)];
if (response.next) {
fetchLibraryArtists(response.next);
} else {
dispatch(coreActions.itemsLoaded(libraryArtists));
dispatch(coreActions.libraryLoaded({
uri: 'spotify:library:artists',
items_uris: arrayOf('uri', libraryArtists),
}));
}
});
if (!last_run) {
dispatch(uiActions.startProcess('SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR', 'Loading Spotify artists', { next: 'me/following?type=artist&limit=50' }));
} else if (last_run.status === 'cancelled') {
dispatch(uiActions.resumeProcess('SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR'));
// We've already finished, but the status has been flushed
} else if (last_run.status === 'finished' && !getState().spotify.library_artists_loaded_all) {
dispatch(uiActions.startProcess('SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR', 'Loading Spotify artists', { next: 'me/following?type=artist&limit=50' }));
}
};
}
export function getLibraryArtistsProcessor(data) {
return (dispatch, getState) => {
request(dispatch, getState, data.next)
.then(
(response) => {
dispatch({
type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED',
artists: response.artists.items,
});
// We got a next link, so we've got more work to be done
if (response.artists.next) {
const { total } = response.artists;
const loaded = getState().spotify.library_artists.length;
const remaining = total - loaded;
dispatch(uiActions.updateProcess(
'SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR',
`Loading ${remaining} Spotify artists`,
{
next: response.artists.next,
total: response.artists.total,
remaining,
},
));
dispatch(uiActions.runProcess('SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR', { next: response.artists.next }));
} else {
dispatch(uiActions.processFinished('SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR'));
}
},
() => {
dispatch(uiActions.processFinished(
'SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR',
{
content: i18n(
'errors.could_not_load_library',
{
name: i18n('library.artists.title'),
provider: i18n('services.spotify.title'),
},
),
level: 'error',
},
));
},
);
fetchLibraryArtists('me/following?type=artist&limit=50');
};
}