Re-fetching incomplete albums, need to do the same for Artist and Playlists
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -106,7 +106,7 @@
|
||||
|
||||
// Release details
|
||||
// These are automatically injected to built HTML
|
||||
var build = "1599105011";
|
||||
var build = "1599193622";
|
||||
var version = "3.52.4";
|
||||
|
||||
// Construct the script tag
|
||||
|
||||
@ -32,7 +32,7 @@ export default class GridItem extends React.Component {
|
||||
case 'album':
|
||||
// If Mopidy doesn't find any images, then it will pass on the call to LastFM
|
||||
if (mopidyActions) {
|
||||
mopidyActions.getImages('albums', [item.uri]);
|
||||
mopidyActions.getImages([item.uri]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@ -77,10 +77,10 @@ export function clearStorage() {
|
||||
};
|
||||
}
|
||||
|
||||
export function restoreFromColdStore(item) {
|
||||
export function restoreFromColdStore(items) {
|
||||
return {
|
||||
type: 'RESTORE_FROM_COLD_STORE',
|
||||
item,
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
@ -175,6 +175,13 @@ 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 itemsLoaded(items) {
|
||||
return {
|
||||
type: 'ITEMS_LOADED',
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
export function itemLoaded(item) {
|
||||
return {
|
||||
type: 'ITEM_LOADED',
|
||||
|
||||
@ -20,6 +20,7 @@ import { handleException } from './actions';
|
||||
const coreActions = require('./actions.js');
|
||||
const uiActions = require('../ui/actions.js');
|
||||
const mopidyActions = require('../mopidy/actions.js');
|
||||
const googleActions = require('../google/actions.js');
|
||||
const spotifyActions = require('../spotify/actions.js');
|
||||
|
||||
const CoreMiddleware = (function () {
|
||||
@ -348,31 +349,47 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'LOAD_ALBUM':
|
||||
if (!action.force_reload && store.getState().core.items[action.uri]) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
const fetchAlbum = () => {
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
store.dispatch(spotifyActions.getAlbum(action.uri));
|
||||
|
||||
if (spotify.me) {
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
store.dispatch(mopidyActions.getAlbum(action.uri));
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
if (action.force_reload) {
|
||||
fetchAlbum();
|
||||
break;
|
||||
}
|
||||
if (
|
||||
store.getState().core.items[action.uri] &&
|
||||
store.getState().core.items[action.uri].tracks
|
||||
) {
|
||||
console.info(`Using "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
|
||||
// Try our cold storage
|
||||
localForage.getItem(action.uri).then((result) => {
|
||||
if (result && !action.force_reload) {
|
||||
if (result) {
|
||||
console.info(`Loading "${action.uri}" from database`);
|
||||
store.dispatch(coreActions.restoreFromColdStore(result));
|
||||
} else {
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
store.dispatch(spotifyActions.getAlbum(action.uri));
|
||||
store.dispatch(coreActions.restoreFromColdStore([result]));
|
||||
console.log(result);
|
||||
|
||||
if (spotify.me) {
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
store.dispatch(mopidyActions.getAlbum(action.uri));
|
||||
break;
|
||||
// We don't have the complete Album, so refetch
|
||||
if (!result.tracks) {
|
||||
fetchAlbum();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
fetchAlbum();
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
@ -380,7 +397,6 @@ const CoreMiddleware = (function () {
|
||||
|
||||
// TODO: Relocate this
|
||||
case 'UPDATE_COLD_STORE':
|
||||
console.log(action);
|
||||
if (action.items) {
|
||||
action.items.map((item) => {
|
||||
localForage.getItem(item.uri).then((result) => {
|
||||
@ -390,10 +406,10 @@ const CoreMiddleware = (function () {
|
||||
}
|
||||
break;
|
||||
case 'RESTORE_FROM_COLD_STORE':
|
||||
if (action.item) {
|
||||
if (action.items) {
|
||||
store.dispatch({
|
||||
type: 'RESTORED_FROM_COLD_STORE',
|
||||
item: action.item,
|
||||
items: action.items,
|
||||
});
|
||||
}
|
||||
break;
|
||||
@ -412,7 +428,7 @@ const CoreMiddleware = (function () {
|
||||
localForage.getItem(action.uri).then((result) => {
|
||||
if (result && !action.force_reload) {
|
||||
console.info(`Loading "${action.uri}" from database`);
|
||||
store.dispatch(coreActions.restoreFromColdStore(result));
|
||||
store.dispatch(coreActions.restoreFromColdStore([result]));
|
||||
} else {
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
@ -462,7 +478,7 @@ 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.restoreFromColdStore([result]));
|
||||
} else {
|
||||
fetchPlaylist();
|
||||
}
|
||||
@ -527,7 +543,11 @@ const CoreMiddleware = (function () {
|
||||
spotifyActions[`getLibrary${titleCase(uriType(action.uri))}`](action.uri),
|
||||
);
|
||||
break;
|
||||
|
||||
case 'google':
|
||||
store.dispatch(
|
||||
googleActions[`getLibrary${titleCase(uriType(action.uri))}`](action.uri),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
store.dispatch(
|
||||
mopidyActions[`getLibrary${titleCase(uriType(action.uri))}`](action.uri),
|
||||
@ -545,10 +565,17 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
}
|
||||
|
||||
localForage.getItem(action.uri).then((result) => {
|
||||
if (result) {
|
||||
console.info(`Restoring "${action.uri}" from database`);
|
||||
store.dispatch(coreActions.restoreFromColdStore(result));
|
||||
localForage.getItem(action.uri).then((library) => {
|
||||
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));
|
||||
});
|
||||
|
||||
//store.dispatch(coreActions.loadItems(result.items_uris));
|
||||
store.dispatch(coreActions.restoreFromColdStore([library]));
|
||||
} else {
|
||||
fetchLibrary();
|
||||
}
|
||||
@ -660,6 +687,11 @@ 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] || {},
|
||||
|
||||
@ -66,9 +66,14 @@ 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 } };
|
||||
return {
|
||||
...core,
|
||||
items: {
|
||||
...core.items,
|
||||
[action.item.uri]: action.item,
|
||||
},
|
||||
};
|
||||
|
||||
case 'TRACKS_LOADED':
|
||||
var tracks = { ...core.tracks };
|
||||
@ -145,15 +150,16 @@ export default function reducer(core = {}, action) {
|
||||
|
||||
|
||||
case 'RESTORED_FROM_COLD_STORE':
|
||||
const { items } = core;
|
||||
action.items.forEach((item) => {
|
||||
items[item.uri] = {
|
||||
...(items[item.uri] || {}),
|
||||
...item,
|
||||
};
|
||||
});
|
||||
return {
|
||||
...core,
|
||||
items: {
|
||||
...core.items,
|
||||
[action.item.uri]: {
|
||||
...core.items[action.item.uri],
|
||||
...action.item,
|
||||
},
|
||||
},
|
||||
items,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -405,10 +405,9 @@ export function shuffleTracklist() {
|
||||
* Asset-oriented actions
|
||||
* */
|
||||
|
||||
export function getImages(context, uris) {
|
||||
export function getImages(uris) {
|
||||
return {
|
||||
type: 'MOPIDY_GET_IMAGES',
|
||||
context,
|
||||
uris,
|
||||
};
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
formatTracks,
|
||||
formatSimpleObject,
|
||||
getTrackIcon,
|
||||
formatArtists,
|
||||
} from '../../util/format';
|
||||
import {
|
||||
arrayOf,
|
||||
@ -1622,9 +1623,10 @@ const MopidyMiddleware = (function () {
|
||||
});
|
||||
|
||||
if (index === playlist_uris.length - 1) {
|
||||
store.dispatch(coreActions.itemsLoaded(libraryPlaylists));
|
||||
store.dispatch(coreActions.itemLoaded({
|
||||
uri: 'mopidy:library:playlists',
|
||||
items: libraryPlaylists,
|
||||
items_uris: arrayOf('uri', libraryPlaylists),
|
||||
}));
|
||||
}
|
||||
});
|
||||
@ -1855,166 +1857,52 @@ const MopidyMiddleware = (function () {
|
||||
* ======================================================================================
|
||||
* */
|
||||
|
||||
|
||||
case 'MOPIDY_GET_LIBRARY_ALBUMS':
|
||||
var last_run = store.getState().ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR;
|
||||
|
||||
if (!last_run) {
|
||||
request(store, 'library.browse', { uri: store.getState().mopidy.library_albums_uri })
|
||||
.then((response) => {
|
||||
if (response.length <= 0) return;
|
||||
|
||||
const uris = arrayOf('uri', response);
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_LIBRARY_ALBUMS_LOADED',
|
||||
uris,
|
||||
});
|
||||
|
||||
// Start our process to load the full album objects
|
||||
store.dispatch(uiActions.startProcess(
|
||||
'MOPIDY_LIBRARY_ALBUMS_PROCESSOR',
|
||||
i18n('services.mopidy.loading_albums', { count: uris.length }),
|
||||
{
|
||||
uris,
|
||||
total: uris.length,
|
||||
remaining: uris.length,
|
||||
},
|
||||
));
|
||||
});
|
||||
} else if (last_run.status == 'cancelled') {
|
||||
store.dispatch(uiActions.resumeProcess('MOPIDY_LIBRARY_ALBUMS_PROCESSOR'));
|
||||
} else if (last_run.status == 'finished') {
|
||||
// TODO: do we want to force a refresh?
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'MOPIDY_LIBRARY_ALBUMS_PROCESSOR':
|
||||
if (store.getState().ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR !== undefined) {
|
||||
const processor = store.getState().ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR;
|
||||
|
||||
if (processor.status == 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_LIBRARY_ALBUMS_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_ALBUMS_PROCESSOR',
|
||||
`Loading ${uris.length} local albums`,
|
||||
{
|
||||
uris,
|
||||
remaining: uris.length,
|
||||
},
|
||||
));
|
||||
store.dispatch(mopidyActions.getAlbums(uris_to_load, { name: 'MOPIDY_LIBRARY_ALBUMS_PROCESSOR', data: { uris } }));
|
||||
} else {
|
||||
store.dispatch(uiActions.processFinished('MOPIDY_LIBRARY_ALBUMS_PROCESSOR'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'MOPIDY_GET_ALBUMS':
|
||||
request(store, 'library.lookup', { uris: action.uris })
|
||||
request(store, 'library.browse', { uri: store.getState().mopidy.library_albums_uri })
|
||||
.then((response) => {
|
||||
const albums_loaded = [];
|
||||
const artists_loaded = [];
|
||||
const tracks_loaded = [];
|
||||
|
||||
for (const uri in response) {
|
||||
if (response.hasOwnProperty(uri) && response[uri].length > 0 && response[uri][0].album) {
|
||||
const tracks = response[uri];
|
||||
const artists_uris = [];
|
||||
if (tracks[0].artists) {
|
||||
for (const artist of response[uri][0].artists) {
|
||||
artists_uris.push(artist.uri);
|
||||
artists_loaded.push(artist);
|
||||
}
|
||||
}
|
||||
|
||||
const tracks_uris = [];
|
||||
for (const track of tracks) {
|
||||
tracks_uris.push(track.uri);
|
||||
tracks_loaded.push(track);
|
||||
}
|
||||
|
||||
const album = {
|
||||
const uris = arrayOf('uri', response);
|
||||
request(store, 'library.lookup', { uris })
|
||||
.then((response) => {
|
||||
const libraryAlbums = indexToArray(response).map((tracks) => ({
|
||||
source: 'local',
|
||||
artists_uris,
|
||||
tracks_uris,
|
||||
tracks_total: tracks_uris.length,
|
||||
artists: tracks[0].artists || null,
|
||||
tracks,
|
||||
last_modified: tracks[0].last_modified,
|
||||
...tracks[0].album,
|
||||
};
|
||||
}));
|
||||
|
||||
albums_loaded.push(album);
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.albumsLoaded(albums_loaded));
|
||||
store.dispatch(coreActions.artistsLoaded(artists_loaded));
|
||||
store.dispatch(coreActions.tracksLoaded(tracks_loaded));
|
||||
|
||||
// Re-run any consequential processes in a few ms. This allows a small window for other
|
||||
// server requests before our next batch. It's a little crude but it means the server isn't
|
||||
// locked until we're completely done.
|
||||
if (action.processor) {
|
||||
setTimeout(
|
||||
() => {
|
||||
store.dispatch(uiActions.runProcess(action.processor.name, action.processor.data));
|
||||
},
|
||||
10,
|
||||
);
|
||||
}
|
||||
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] })
|
||||
.then((_response) => {
|
||||
const { uri } = action;
|
||||
if (!_response) return;
|
||||
let response = _response[action.uri];
|
||||
let response = _response[uri];
|
||||
if (!response || !response.length) return;
|
||||
|
||||
response = sortItems(response, 'track_number');
|
||||
const artists = [];
|
||||
if (response[0].artists) {
|
||||
for (const artist of response[0].artists) {
|
||||
artists.push(artist);
|
||||
}
|
||||
}
|
||||
|
||||
const album = {
|
||||
...response[0].album,
|
||||
source: 'local',
|
||||
artists_uris: arrayOf('uri', artists),
|
||||
tracks_uris: arrayOf('uri', response),
|
||||
tracks_total: response.length,
|
||||
artists: formatArtists(response[0].artists),
|
||||
tracks: formatTracks(response),
|
||||
};
|
||||
|
||||
store.dispatch(coreActions.albumLoaded(album));
|
||||
store.dispatch(coreActions.artistsLoaded(artists));
|
||||
store.dispatch(coreActions.itemLoaded(album));
|
||||
|
||||
// Load images
|
||||
if (!response[0].album.images) {
|
||||
store.dispatch(mopidyActions.getImages('albums', [album.uri]));
|
||||
if (!album.images) {
|
||||
store.dispatch(mopidyActions.getImages([album.uri]));
|
||||
}
|
||||
|
||||
request(store, 'library.lookup', { uris: album.tracks_uris })
|
||||
.then((response) => {
|
||||
const tracks_loaded = [];
|
||||
|
||||
for (const uri in response) {
|
||||
if (response.hasOwnProperty(uri)) {
|
||||
tracks_loaded.push(response[uri][0]);
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.tracksLoaded(tracks_loaded));
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
@ -2368,28 +2256,22 @@ const MopidyMiddleware = (function () {
|
||||
if (action.uris) {
|
||||
request(store, 'library.getImages', { uris: action.uris })
|
||||
.then((response) => {
|
||||
const records = [];
|
||||
for (const uri in response) {
|
||||
if (response.hasOwnProperty(uri)) {
|
||||
let images = response[uri];
|
||||
if (images.length) {
|
||||
images = formatImages(digestMopidyImages(store.getState().mopidy, images));
|
||||
records.push({
|
||||
uri,
|
||||
images,
|
||||
});
|
||||
} else {
|
||||
store.dispatch(lastfmActions.getImages(action.context, uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
const itemsWithImages = [];
|
||||
Object.keys(response).forEach((uri) => {
|
||||
const images = response[uri];
|
||||
|
||||
if (records.length) {
|
||||
const action_data = {
|
||||
type: (`${action.context}_LOADED`).toUpperCase(),
|
||||
if (images) {
|
||||
itemsWithImages.push({
|
||||
uri,
|
||||
images: formatImages(digestMopidyImages(store.getState().mopidy, images)),
|
||||
});
|
||||
} else {
|
||||
store.dispatch(lastfmActions.getImages(uri));
|
||||
};
|
||||
action_data[action.context] = records;
|
||||
store.dispatch(action_data);
|
||||
});
|
||||
|
||||
if (itemsWithImages.length) {
|
||||
store.dispatch(coreActions.itemsLoaded(itemsWithImages));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1735,90 +1735,39 @@ export function getLibraryPlaylists() {
|
||||
const fetchLibraryPlaylists = (endpoint) => request(dispatch, getState, endpoint)
|
||||
.then((response) => {
|
||||
libraryPlaylists = [...libraryPlaylists, ...formatPlaylists(response.items)];
|
||||
console.log('loaded page of playlists', response.items);
|
||||
if (response.next) {
|
||||
fetchLibraryPlaylists(response.next);
|
||||
} else {
|
||||
dispatch(coreActions.itemsLoaded(libraryPlaylists));
|
||||
dispatch(coreActions.itemLoaded({
|
||||
uri: 'spotify:library:playlists',
|
||||
items: libraryPlaylists,
|
||||
items_uris: arrayOf('uri', libraryPlaylists),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
fetchLibraryPlaylists('me/playlists?limit=50');
|
||||
/*
|
||||
const last_run = getState().ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR;
|
||||
|
||||
if (!last_run) {
|
||||
dispatch(uiActions.startProcess('SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR', 'Loading Spotify playlists', { next: 'me/playlists?limit=50' }));
|
||||
} else if (last_run.status === 'cancelled') {
|
||||
dispatch(uiActions.resumeProcess('SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR'));
|
||||
|
||||
// We've already finished, but the status has been flushed
|
||||
} else if (last_run.status === 'finished' && !getState().spotify.library_playlists_loaded_all) {
|
||||
dispatch(uiActions.startProcess('SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR', 'Loading Spotify playlists', { next: 'me/playlists?limit=50' }));
|
||||
}
|
||||
*/
|
||||
};
|
||||
}
|
||||
|
||||
export function getLibraryPlaylistsProcessor(data) {
|
||||
export function getLibraryAlbums() {
|
||||
return (dispatch, getState) => {
|
||||
request(dispatch, getState, data.next)
|
||||
.then(
|
||||
(response) => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED',
|
||||
playlists: response.items,
|
||||
});
|
||||
let libraryAlbums = [];
|
||||
const fetchLibraryAlbums = (endpoint) => request(dispatch, getState, endpoint)
|
||||
.then((response) => {
|
||||
libraryAlbums = [...libraryAlbums, ...formatAlbums(response.items)];
|
||||
if (response.next) {
|
||||
fetchLibraryAlbums(response.next);
|
||||
} else {
|
||||
dispatch(coreActions.itemsLoaded(libraryAlbums));
|
||||
dispatch(coreActions.itemLoaded({
|
||||
uri: 'spotify:library:albums',
|
||||
items_uris: arrayOf('uri', libraryAlbums),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// Check to see if we've been cancelled
|
||||
if (getState().ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR !== undefined) {
|
||||
const processor = getState().ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR;
|
||||
|
||||
if (processor.status == 'cancelling') {
|
||||
dispatch(uiActions.processCancelled('SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We got a next link, so we've got more work to be done
|
||||
if (response.next) {
|
||||
const { total } = response;
|
||||
const loaded = getState().spotify.library_playlists.length;
|
||||
const remaining = total - loaded;
|
||||
dispatch(uiActions.updateProcess(
|
||||
'SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR',
|
||||
`Loading ${remaining} Spotify playlists`,
|
||||
{
|
||||
next: response.next,
|
||||
total: response.total,
|
||||
remaining,
|
||||
},
|
||||
));
|
||||
dispatch(uiActions.runProcess('SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR', { next: response.next }));
|
||||
} else {
|
||||
dispatch(uiActions.processFinished('SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR'));
|
||||
dispatch({ type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED_ALL' });
|
||||
}
|
||||
},
|
||||
() => {
|
||||
dispatch(uiActions.processFinished(
|
||||
'SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR',
|
||||
{
|
||||
content: i18n(
|
||||
'errors.could_not_load_library',
|
||||
{
|
||||
name: i18n('library.playlists.title'),
|
||||
provider: i18n('services.spotify.title'),
|
||||
},
|
||||
),
|
||||
level: 'error',
|
||||
},
|
||||
));
|
||||
},
|
||||
);
|
||||
fetchLibraryAlbums('me/albums?limit=50');
|
||||
};
|
||||
}
|
||||
|
||||
@ -1889,82 +1838,3 @@ export function getLibraryArtistsProcessor(data) {
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ALbums
|
||||
* */
|
||||
|
||||
export function getLibraryAlbums() {
|
||||
return (dispatch, getState) => {
|
||||
const last_run = getState().ui.processes.SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR;
|
||||
|
||||
if (!last_run) {
|
||||
dispatch(uiActions.startProcess('SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR', 'Loading Spotify albums', { next: 'me/albums?limit=50' }));
|
||||
} else if (last_run.status === 'cancelled') {
|
||||
dispatch(uiActions.updateProcess('SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR', 'Loading Spotify albums', { next: 'me/albums?limit=50' }));
|
||||
|
||||
// We've already finished, but the status has been flushed
|
||||
} else if (last_run.status === 'finished' && !getState().spotify.library_albums_loaded_all) {
|
||||
dispatch(uiActions.startProcess('SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR', 'Loading Spotify albums', { next: 'me/albums?limit=50' }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getLibraryAlbumsProcessor(data) {
|
||||
return (dispatch, getState) => {
|
||||
request(dispatch, getState, data.next)
|
||||
.then(
|
||||
(response) => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_ALBUMS_LOADED',
|
||||
albums: response.items,
|
||||
});
|
||||
|
||||
// Check to see if we've been cancelled
|
||||
if (getState().ui.processes.SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR !== undefined) {
|
||||
const processor = getState().ui.processes.SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR;
|
||||
|
||||
if (processor.status == 'cancelling') {
|
||||
dispatch(uiActions.processCancelled('SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We got a next link, so we've got more work to be done
|
||||
if (response.next) {
|
||||
const { total } = response;
|
||||
const loaded = getState().spotify.library_albums.length;
|
||||
const remaining = total - loaded;
|
||||
dispatch(uiActions.updateProcess(
|
||||
'SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR',
|
||||
`Loading ${remaining} Spotify albums`,
|
||||
{
|
||||
next: response.next,
|
||||
total: response.total,
|
||||
remaining,
|
||||
},
|
||||
));
|
||||
dispatch(uiActions.runProcess('SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR', { next: response.next }));
|
||||
} else {
|
||||
dispatch(uiActions.processFinished('SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR'));
|
||||
}
|
||||
},
|
||||
() => {
|
||||
dispatch(uiActions.processFinished(
|
||||
'SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR',
|
||||
{
|
||||
content: i18n(
|
||||
'errors.could_not_load_library',
|
||||
{
|
||||
name: i18n('library.albums.title'),
|
||||
provider: i18n('services.spotify.title'),
|
||||
},
|
||||
),
|
||||
level: 'error',
|
||||
},
|
||||
));
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@ -289,14 +289,18 @@ const formatAlbum = function (data) {
|
||||
'wiki_publish_date',
|
||||
'popularity',
|
||||
'images',
|
||||
'artists_uris',
|
||||
'tracks',
|
||||
'tracks_uris',
|
||||
'tracks_total',
|
||||
'tracks_more',
|
||||
'artists', // Array of simple records
|
||||
'artists',
|
||||
];
|
||||
|
||||
// Nested album object (eg in spotify library)
|
||||
if (data && data.album && isObject(data.album)) {
|
||||
if (data.added_at) {
|
||||
data.album.added_at = data.added_at;
|
||||
}
|
||||
data = data.album;
|
||||
}
|
||||
|
||||
// Loop fields and import from data
|
||||
for (const field of fields) {
|
||||
if (data.hasOwnProperty(field)) {
|
||||
@ -307,6 +311,16 @@ const formatAlbum = function (data) {
|
||||
if (album.images && !album.images.formatted) {
|
||||
album.images = formatImages(album.images);
|
||||
}
|
||||
if (album.tracks) {
|
||||
if (album.tracks.items) {
|
||||
album.tracks = formatTracks(album.tracks.items);
|
||||
} else {
|
||||
album.tracks = formatTracks(album.tracks);
|
||||
}
|
||||
}
|
||||
if (album.artists) {
|
||||
album.artists = formatSimpleObjects(album.artists);
|
||||
}
|
||||
|
||||
if (data.last_modified && album.added_at === undefined) {
|
||||
album.added_at = data.last_modified;
|
||||
@ -591,33 +605,41 @@ const formatTrack = function (data) {
|
||||
}
|
||||
|
||||
if (track.track_number === undefined && data.track_no !== undefined) {
|
||||
track.track_number = data.track_no;
|
||||
track.track_number = data.track_no;
|
||||
}
|
||||
|
||||
if (track.disc_number === undefined && data.disc_no !== undefined) {
|
||||
track.disc_number = data.disc_no;
|
||||
track.disc_number = data.disc_no;
|
||||
}
|
||||
|
||||
if (track.release_date === undefined && data.date !== undefined) {
|
||||
track.release_date = data.date;
|
||||
track.release_date = data.date;
|
||||
}
|
||||
|
||||
if (track.explicit === undefined && data.explicit !== undefined) {
|
||||
track.is_explicit = data.explicit;
|
||||
track.is_explicit = data.explicit;
|
||||
}
|
||||
|
||||
// Copy images from albums (if applicable)
|
||||
// TOOD: Identify if we stil need this...
|
||||
if (data.album && data.album.images) {
|
||||
if (track.images === undefined || !track.images.formatted) {
|
||||
track.images = formatImages(data.album.images);
|
||||
}
|
||||
if (track.images === undefined || !track.images.formatted) {
|
||||
track.images = formatImages(data.album.images);
|
||||
}
|
||||
}
|
||||
|
||||
if (track.provider === undefined && track.uri !== undefined) {
|
||||
track.provider = uriSource(track.uri);
|
||||
}
|
||||
|
||||
if (track.artists) {
|
||||
track.artists = formatSimpleObjects(track.artists);
|
||||
}
|
||||
|
||||
if (track.album) {
|
||||
track.album = formatSimpleObject(track.album);
|
||||
}
|
||||
|
||||
return track;
|
||||
};
|
||||
|
||||
@ -739,6 +761,7 @@ const collate = function (obj, indexes = {}) {
|
||||
if (obj.playlists_uris !== undefined) obj.playlists = [];
|
||||
if (obj.related_artists_uris !== undefined) obj.related_artists = [];
|
||||
if (obj.clients_ids !== undefined) obj.clients = [];
|
||||
if (obj.items_uris !== undefined) obj.items = [];
|
||||
|
||||
if (indexes.artists) {
|
||||
if (obj.artists_uris) {
|
||||
@ -832,6 +855,16 @@ const collate = function (obj, indexes = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
if (indexes.items) {
|
||||
if (obj.items_uris) {
|
||||
for (const uri of obj.items_uris) {
|
||||
if (indexes.items[uri]) {
|
||||
obj.items.push(indexes.items[uri]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
@ -68,52 +68,44 @@ class LibraryAlbums extends React.Component {
|
||||
getMopidyLibrary = () => {
|
||||
const {
|
||||
source,
|
||||
mopidy_library_playlists,
|
||||
mopidyActions: {
|
||||
getLibraryAlbums,
|
||||
coreActions: {
|
||||
loadLibrary,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
if (source !== 'local' && source !== 'all') return;
|
||||
if (mopidy_library_playlists) return;
|
||||
|
||||
getLibraryAlbums();
|
||||
loadLibrary('mopidy:library:albums');
|
||||
};
|
||||
|
||||
getGoogleLibrary = () => {
|
||||
const {
|
||||
source,
|
||||
google_available,
|
||||
google_library_albums_status,
|
||||
googleActions: {
|
||||
getLibraryAlbums,
|
||||
coreActions: {
|
||||
loadLibrary,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
if (!google_available) return;
|
||||
if (source !== 'google' && source !== 'all') return;
|
||||
if (google_library_albums_status === 'finished') return;
|
||||
if (google_library_albums_status === 'started') return;
|
||||
|
||||
getLibraryAlbums();
|
||||
loadLibrary('google:library:albums');
|
||||
};
|
||||
|
||||
getSpotifyLibrary = () => {
|
||||
const {
|
||||
source,
|
||||
spotify_available,
|
||||
spotify_library_albums_status,
|
||||
spotifyActions: {
|
||||
getLibraryAlbums,
|
||||
coreActions: {
|
||||
loadLibrary,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
if (!spotify_available) return;
|
||||
if (source !== 'spotify' && source !== 'all') return;
|
||||
if (spotify_library_albums_status === 'finished') return;
|
||||
if (spotify_library_albums_status === 'started') return;
|
||||
|
||||
getLibraryAlbums();
|
||||
loadLibrary('spotify:library:albums');
|
||||
};
|
||||
|
||||
handleContextMenu = (e, item) => {
|
||||
@ -131,28 +123,6 @@ class LibraryAlbums extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
moreURIsToLoad = () => {
|
||||
const {
|
||||
albums,
|
||||
library_albums,
|
||||
} = this.props;
|
||||
|
||||
const uris = [];
|
||||
if (albums && library_albums) {
|
||||
for (let i = 0; i < library_albums.length; i++) {
|
||||
const uri = library_albums[i];
|
||||
if (!albums.hasOwnProperty(uri) && uriSource(uri) == 'local') {
|
||||
uris.push(uri);
|
||||
}
|
||||
|
||||
// limit each lookup to 50 URIs
|
||||
if (uris.length >= 50) break;
|
||||
}
|
||||
}
|
||||
|
||||
return uris;
|
||||
}
|
||||
|
||||
loadMore = () => {
|
||||
const {
|
||||
limit,
|
||||
@ -189,71 +159,40 @@ class LibraryAlbums extends React.Component {
|
||||
}
|
||||
|
||||
renderView = () => {
|
||||
let albums = [];
|
||||
const {
|
||||
spotify_library,
|
||||
google_library,
|
||||
mopidy_library,
|
||||
items,
|
||||
source,
|
||||
sort,
|
||||
sort_reverse,
|
||||
view,
|
||||
} = this.props;
|
||||
const {
|
||||
limit,
|
||||
filter,
|
||||
} = this.state;
|
||||
|
||||
// Spotify library items
|
||||
if (this.props.spotify_library_albums && (this.props.source == 'all' || this.props.source == 'spotify')) {
|
||||
for (var uri of this.props.spotify_library_albums) {
|
||||
if (this.props.albums.hasOwnProperty(uri)) {
|
||||
albums.push(this.props.albums[uri]);
|
||||
}
|
||||
}
|
||||
let albums = [
|
||||
...(source === 'all' || source === 'spotify' ? collate(spotify_library, { items }).items : []),
|
||||
...(source === 'all' || source === 'google' ? collate(google_library, { items }).items : []),
|
||||
...(source === 'all' || source === 'local' ? collate(mopidy_library, { items }).items : []),
|
||||
];
|
||||
|
||||
if (sort) {
|
||||
albums = sortItems(albums, sort, sort_reverse);
|
||||
}
|
||||
|
||||
// Mopidy library items
|
||||
if (this.props.mopidy_library_albums && (this.props.source == 'all' || this.props.source == 'local')) {
|
||||
for (var uri of this.props.mopidy_library_albums) {
|
||||
// Construct item placeholder. This is used as Mopidy needs to
|
||||
// lookup ref objects to get the full object which can take some time
|
||||
var source = uriSource(uri);
|
||||
var album = {
|
||||
uri,
|
||||
source,
|
||||
};
|
||||
|
||||
if (this.props.albums.hasOwnProperty(uri)) {
|
||||
albums.push(this.props.albums[uri]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Google library items
|
||||
if (this.props.google_library_albums && (this.props.source == 'all' || this.props.source == 'google')) {
|
||||
for (var uri of this.props.google_library_albums) {
|
||||
// Construct item placeholder. This is used as Mopidy needs to
|
||||
// lookup ref objects to get the full object which can take some time
|
||||
var source = uriSource(uri);
|
||||
var album = {
|
||||
uri,
|
||||
source,
|
||||
};
|
||||
|
||||
if (this.props.albums.hasOwnProperty(uri)) {
|
||||
album = this.props.albums[uri];
|
||||
}
|
||||
|
||||
albums.push(album);
|
||||
}
|
||||
}
|
||||
|
||||
// Collate each album into it's full object (including nested artists)
|
||||
for (let i = 0; i < albums.length; i++) {
|
||||
albums[i] = collate(albums[i], { artists: this.props.artists });
|
||||
}
|
||||
|
||||
if (this.props.sort) {
|
||||
albums = sortItems(albums, this.props.sort, this.props.sort_reverse);
|
||||
}
|
||||
|
||||
if (this.state.filter && this.state.filter !== '') {
|
||||
albums = applyFilter('name', this.state.filter, albums);
|
||||
if (filter && filter !== '') {
|
||||
albums = applyFilter('name', filter, albums);
|
||||
}
|
||||
|
||||
// Apply our lazy-load-rendering
|
||||
const total_albums = albums.length;
|
||||
albums = albums.slice(0, this.state.limit);
|
||||
albums = albums.slice(0, limit);
|
||||
|
||||
if (this.props.view == 'list') {
|
||||
if (view === 'list') {
|
||||
return (
|
||||
<section className="content-wrapper">
|
||||
<List
|
||||
@ -266,8 +205,8 @@ class LibraryAlbums extends React.Component {
|
||||
link_prefix="/album/"
|
||||
/>
|
||||
<LazyLoadListener
|
||||
loadKey={total_albums > this.state.limit ? this.state.limit : total_albums}
|
||||
showLoader={this.state.limit < total_albums}
|
||||
loadKey={total_albums > limit ? limit : total_albums}
|
||||
showLoader={limit < total_albums}
|
||||
loadMore={this.loadMore}
|
||||
/>
|
||||
</section>
|
||||
@ -280,15 +219,28 @@ class LibraryAlbums extends React.Component {
|
||||
albums={albums}
|
||||
/>
|
||||
<LazyLoadListener
|
||||
loadKey={total_albums > this.state.limit ? this.state.limit : total_albums}
|
||||
showLoader={this.state.limit < total_albums}
|
||||
loadKey={total_albums > limit ? limit : total_albums}
|
||||
showLoader={limit < total_albums}
|
||||
loadMore={() => this.loadMore()}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
const {
|
||||
spotify_available,
|
||||
google_available,
|
||||
sort,
|
||||
view,
|
||||
source,
|
||||
sort_reverse,
|
||||
} = this.props;
|
||||
const {
|
||||
filter,
|
||||
per_page,
|
||||
} = this.state;
|
||||
|
||||
const source_options = [
|
||||
{
|
||||
value: 'all',
|
||||
@ -300,14 +252,14 @@ class LibraryAlbums extends React.Component {
|
||||
},
|
||||
];
|
||||
|
||||
if (this.props.spotify_available) {
|
||||
if (spotify_available) {
|
||||
source_options.push({
|
||||
value: 'spotify',
|
||||
label: i18n('services.spotify.title'),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.props.google_available) {
|
||||
if (google_available) {
|
||||
source_options.push({
|
||||
value: 'google',
|
||||
label: i18n('services.google.title'),
|
||||
@ -355,23 +307,23 @@ class LibraryAlbums extends React.Component {
|
||||
const options = (
|
||||
<div className="header__options__wrapper">
|
||||
<FilterField
|
||||
initialValue={this.state.filter}
|
||||
handleChange={(value) => this.setState({ filter: value, limit: this.state.per_page })}
|
||||
initialValue={filter}
|
||||
handleChange={(value) => this.setState({ filter: value, limit: per_page })}
|
||||
onSubmit={e => this.props.uiActions.hideContextMenu()}
|
||||
/>
|
||||
<DropdownField
|
||||
icon="swap_vert"
|
||||
name={i18n('fields.sort')}
|
||||
value={this.props.sort}
|
||||
value={sort}
|
||||
valueAsLabel
|
||||
options={sort_options}
|
||||
selected_icon={this.props.sort ? (this.props.sort_reverse ? 'keyboard_arrow_up' : 'keyboard_arrow_down') : null}
|
||||
selected_icon={sort ? (sort_reverse ? 'keyboard_arrow_up' : 'keyboard_arrow_down') : null}
|
||||
handleChange={(val) => { this.setSort(val); this.props.uiActions.hideContextMenu(); }}
|
||||
/>
|
||||
<DropdownField
|
||||
icon="visibility"
|
||||
name={i18n('fields.view')}
|
||||
value={this.props.view}
|
||||
value={view}
|
||||
valueAsLabel
|
||||
options={view_options}
|
||||
handleChange={(val) => { this.props.uiActions.set({ library_albums_view: val }); this.props.uiActions.hideContextMenu(); }}
|
||||
@ -379,7 +331,7 @@ class LibraryAlbums extends React.Component {
|
||||
<DropdownField
|
||||
icon="cloud"
|
||||
name={i18n('fields.source')}
|
||||
value={this.props.source}
|
||||
value={source}
|
||||
valueAsLabel
|
||||
options={source_options}
|
||||
handleChange={(val) => { this.props.uiActions.set({ library_albums_source: val }); this.props.uiActions.hideContextMenu(); }}
|
||||
@ -399,19 +351,15 @@ class LibraryAlbums extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
load_queue: state.ui.load_queue,
|
||||
artists: state.core.artists,
|
||||
albums: state.core.albums,
|
||||
mopidy_library_albums: state.mopidy.library_albums,
|
||||
mopidy_library_albums_status: (state.ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR.status : null),
|
||||
items: state.core.items,
|
||||
mopidy_library: state.core.items['mopidy:library:albums'] || { items_uris: [] },
|
||||
spotify_library: state.core.items['spotify:library:albums'] || { items_uris: [] },
|
||||
google_library: state.core.items['google:library:albums'] || { items_uris: [] },
|
||||
google_available: (state.mopidy.uri_schemes && state.mopidy.uri_schemes.includes('gmusic:')),
|
||||
google_library_albums: state.google.library_albums,
|
||||
google_library_albums_status: (state.ui.processes.GOOGLE_LIBRARY_ALBUMS_PROCESSOR !== undefined ? state.ui.processes.GOOGLE_LIBRARY_ALBUMS_PROCESSOR.status : null),
|
||||
spotify_available: state.spotify.access_token,
|
||||
spotify_library_albums: state.spotify.library_albums,
|
||||
spotify_library_albums_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR.status : null),
|
||||
view: state.ui.library_albums_view,
|
||||
source: (state.ui.library_albums_source ? state.ui.library_albums_source : 'all'),
|
||||
sort: (state.ui.library_albums_sort ? state.ui.library_albums_sort : null),
|
||||
|
||||
@ -16,6 +16,7 @@ import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import { applyFilter, removeDuplicates, sortItems } from '../../util/arrays';
|
||||
import { I18n, i18n } from '../../locale';
|
||||
import { collate } from '../../util/format';
|
||||
|
||||
class LibraryPlaylists extends React.Component {
|
||||
constructor(props) {
|
||||
@ -114,33 +115,38 @@ class LibraryPlaylists extends React.Component {
|
||||
|
||||
renderView = () => {
|
||||
const {
|
||||
spotify_library_playlists: {
|
||||
items: spotify_playlists,
|
||||
},
|
||||
mopidy_library_playlists: {
|
||||
items: mopidy_playlists,
|
||||
},
|
||||
spotify_library,
|
||||
mopidy_library,
|
||||
items,
|
||||
sort,
|
||||
sort_reverse,
|
||||
view,
|
||||
source,
|
||||
} = this.props;
|
||||
const {
|
||||
filter,
|
||||
limit,
|
||||
} = this.state;
|
||||
|
||||
let playlists = [
|
||||
...spotify_playlists,
|
||||
...mopidy_playlists,
|
||||
...(source === 'all' || source === 'spotify' ? collate(spotify_library, { items }).items : []),
|
||||
...(source === 'all' || source === 'local' ? collate(mopidy_library, { items }).items : []),
|
||||
];
|
||||
|
||||
if (this.props.sort) {
|
||||
playlists = sortItems(playlists, this.props.sort, this.props.sort_reverse);
|
||||
if (sort) {
|
||||
playlists = sortItems(playlists, sort, sort_reverse);
|
||||
}
|
||||
playlists = removeDuplicates(playlists);
|
||||
|
||||
if (this.state.filter !== '') {
|
||||
playlists = applyFilter('name', this.state.filter, playlists);
|
||||
if (filter !== '') {
|
||||
playlists = applyFilter('name', filter, playlists);
|
||||
}
|
||||
|
||||
// Apply our lazy-load-rendering
|
||||
const total_playlists = playlists.length;
|
||||
playlists = playlists.slice(0, this.state.limit);
|
||||
playlists = playlists.slice(0, limit);
|
||||
|
||||
if (this.props.view == 'list') {
|
||||
if (view === 'list') {
|
||||
return (
|
||||
<section className="content-wrapper">
|
||||
<List
|
||||
@ -153,8 +159,8 @@ class LibraryPlaylists extends React.Component {
|
||||
link_prefix="/playlist/"
|
||||
/>
|
||||
<LazyLoadListener
|
||||
loadKey={total_playlists > this.state.limit ? this.state.limit : total_playlists}
|
||||
loading={this.state.limit < total_playlists}
|
||||
loadKey={total_playlists > limit ? limit : total_playlists}
|
||||
loading={limit < total_playlists}
|
||||
loadMore={() => this.loadMore()}
|
||||
/>
|
||||
</section>
|
||||
@ -167,8 +173,8 @@ class LibraryPlaylists extends React.Component {
|
||||
playlists={playlists}
|
||||
/>
|
||||
<LazyLoadListener
|
||||
loadKey={total_playlists > this.state.limit ? this.state.limit : total_playlists}
|
||||
loading={this.state.limit < total_playlists}
|
||||
loadKey={total_playlists > limit ? limit : total_playlists}
|
||||
loading={limit < total_playlists}
|
||||
loadMore={() => this.loadMore()}
|
||||
/>
|
||||
</section>
|
||||
@ -292,20 +298,23 @@ class LibraryPlaylists extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
slim_mode: state.ui.slim_mode,
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
spotify_available: state.spotify.access_token,
|
||||
mopidy_library_playlists: state.core.items['mopidy:library:playlists'] || { items: [] },
|
||||
spotify_library_playlists: state.core.items['spotify:library:playlists'] || { items: [] },
|
||||
load_queue: state.ui.load_queue,
|
||||
me_id: (state.spotify.me ? state.spotify.me.id : false),
|
||||
view: state.ui.library_playlists_view,
|
||||
source: (state.ui.library_playlists_source ? state.ui.library_playlists_source : 'all'),
|
||||
sort: (state.ui.library_playlists_sort ? state.ui.library_playlists_sort : null),
|
||||
sort_reverse: (state.ui.library_playlists_sort_reverse ? state.ui.library_playlists_sort_reverse : false),
|
||||
playlists: state.core.playlists,
|
||||
});
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
slim_mode: state.ui.slim_mode,
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
spotify_available: state.spotify.access_token,
|
||||
items: state.core.items,
|
||||
mopidy_library: state.core.items['mopidy:library:playlists'] || { items_uris: [] },
|
||||
spotify_library: state.core.items['spotify:library:playlists'] || { items_uris: [] },
|
||||
load_queue: state.ui.load_queue,
|
||||
me_id: (state.spotify.me ? state.spotify.me.id : false),
|
||||
view: state.ui.library_playlists_view,
|
||||
source: (state.ui.library_playlists_source ? state.ui.library_playlists_source : 'all'),
|
||||
sort: (state.ui.library_playlists_sort ? state.ui.library_playlists_sort : null),
|
||||
sort_reverse: (state.ui.library_playlists_sort_reverse ? state.ui.library_playlists_sort_reverse : false),
|
||||
playlists: state.core.playlists,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
|
||||
Reference in New Issue
Block a user