Standardized ensureLoaded to load assets from index, coldstore or fetch()

This commit is contained in:
James Barnsley
2020-10-06 20:43:47 +13:00
parent 4e0a5a7f7d
commit 81399d6d72
10 changed files with 181 additions and 170 deletions

View File

@ -9,8 +9,6 @@ class Stream extends React.Component {
constructor(props) {
super(props);
console.log(props);
if (props.enabled && props.streaming_enabled) {
this.start();
}
@ -28,7 +26,6 @@ class Stream extends React.Component {
this.snapstream.play();
} else {
const protocol = (ssl ? 'wss' : 'ws');
console.log(protocol, host, port, username);
this.snapstream = new SnapStream(protocol, host, port, 'Iris');
}
}

View File

@ -65,12 +65,6 @@ export function clearCurrentTrack() {
};
}
export function cachebustHttpStream() {
return {
type: 'CACHEBUST_HTTP_STREAM',
};
}
export function clearStorage() {
return {
type: 'CLEAR_STORAGE',
@ -219,12 +213,6 @@ export function itemsLoaded(items) {
export function itemLoaded(item) {
return itemsLoaded([item]);
}
export function unloadItem(uri) {
return {
type: 'UNLOAD_ITEM',
uri,
};
}
export function tracksLoaded(tracks) {
return {

View File

@ -30,11 +30,13 @@ const spotifyActions = require('../spotify/actions.js');
*
* @param {*} Object { store, action, fetch, dependents}
*/
const ensureItemLoaded = ({
const ensureLoaded = ({
store,
containerName = 'items',
action,
fetch,
dependents = [],
fullDependents = [],
}) => {
const {
uri,
@ -45,12 +47,33 @@ const ensureItemLoaded = ({
} = action;
const {
core: {
items: {
[containerName]: {
[uri]: item,
} = {},
} = {},
} = store.getState();
const getMissingDependents = (parent) => {
const allDependents = [...dependents, ...fullDependents];
if (!parent) return allDependents;
if (full) {
return allDependents.filter((dep) => parent[dep] === undefined || parent[dep] === null);
}
return dependents.filter((dep) => parent[dep] === undefined || parent[dep] === null);
};
const getDependentUris = (parent) => {
if (!parent) return [];
return [...dependents, ...fullDependents].reduce(
(acc, dependent) => [
...acc,
...(dependent.match(new RegExp('/(.*)_uri(.*)')) ? parent[dependent] : []),
],
[],
);
};
// Forced refetch bypasses everything
if (forceRefetch) {
console.info(`Force-refetching "${uri}"`);
@ -58,61 +81,51 @@ const ensureItemLoaded = ({
return;
}
// Already-loaded asset; check we have all of it's dependents
// Item already in our index?
if (item) {
const loadableDependents = dependents.filter((k) => item[k] && item[k].length > 0);
if (!full || (loadableDependents.length === dependents.length)) {
console.info(`"${uri}" already in index`);
loadableDependents.forEach(
if (getMissingDependents(item).length === 0) {
console.info(`"${uri}" and all dependents already in index`);
store.dispatch(uiActions.stopLoading(uri));
getDependentUris(item).forEach(
(dependent) => store.dispatch(coreActions.loadItems(item[dependent])),
);
store.dispatch(uiActions.stopLoading(uri));
return;
}
}
// What about in the coldstore?
localForage.getItem(uri).then((restoredItem) => {
if (!restoredItem) {
if (!restoredItem || getMissingDependents(restoredItem).length > 0) {
fetch();
return;
}
const loadableDependents = dependents.filter(
(k) => restoredItem[k] && restoredItem[k].length > 0,
);
console.info(`Restoring "${uri}" from database`);
store.dispatch(coreActions.restoreItemsFromColdStore([restoredItem]));
if (full) {
// We already have the dependents of our restored item, so restore them.
// We assume that because THIS item is in the coldstore, its dependents
// are as well.
if (dependents.length && loadableDependents.length === dependents.length) {
const dependentUris = loadableDependents.reduce(
(acc, dependent) => [...acc, ...restoredItem[dependent]],
[],
);
// We already have the dependents of our restored item, so restore them.
// We assume that because THIS item is in the coldstore, its dependents
// are as well.
const dependentUris = getDependentUris(restoredItem);
if (dependentUris.length > 0) {
console.info(`Restoring ${dependentUris.length} dependents from database`);
console.info(`Restoring ${dependentUris.length} dependents from database`);
const restoreAllDependents = dependentUris.map(
(dependentUri) => localForage.getItem(dependentUri),
);
Promise.all(restoreAllDependents).then(
(dependentItems) => {
store.dispatch(
coreActions.restoreItemsFromColdStore(
compact(dependentItems), // Squash nulls (ie items not found in coldstore)
),
);
},
);
} else {
fetch();
}
const restoreAllDependents = dependentUris.map(
(dependentUri) => localForage.getItem(dependentUri),
);
Promise.all(restoreAllDependents).then(
(dependentItems) => {
store.dispatch(
coreActions.restoreItemsFromColdStore(
compact(dependentItems), // Squash nulls (ie items not found in coldstore)
),
);
},
);
}
});
}
};
const CoreMiddleware = (function () {
return (store) => (next) => (action = {}) => {
@ -410,7 +423,7 @@ const CoreMiddleware = (function () {
break;
}
};
ensureItemLoaded({
ensureLoaded({
store,
action,
fetch,
@ -435,11 +448,12 @@ const CoreMiddleware = (function () {
break;
};
};
ensureItemLoaded({
ensureLoaded({
store,
action,
fetch,
dependents: ['tracks'],
dependents: ['images'],
fullDependents: ['tracks'],
});
next(action);
break;
@ -459,11 +473,12 @@ const CoreMiddleware = (function () {
break;
}
};
ensureItemLoaded({
ensureLoaded({
store,
action,
fetch,
dependents: ['tracks', 'albums_uris'],
dependents: ['images'],
fullDependents: ['tracks', 'albums_uris'],
});
next(action);
break;
@ -485,11 +500,12 @@ const CoreMiddleware = (function () {
break;
}
};
ensureItemLoaded({
ensureLoaded({
store,
action,
fetch,
dependents: ['tracks'],
dependents: ['images'],
fullDependents: ['tracks'],
});
next(action);
break;
@ -509,11 +525,11 @@ const CoreMiddleware = (function () {
break;
}
};
ensureItemLoaded({
ensureLoaded({
store,
dependents: ['playlists_uris'],
action,
fetch,
fullDependents: ['playlists_uris'],
});
next(action);
break;
@ -530,11 +546,11 @@ const CoreMiddleware = (function () {
break;
}
};
ensureItemLoaded({
ensureLoaded({
store,
dependents: ['playlists_uris'],
action,
fetch,
fullDependents: ['playlists_uris'],
});
next(action);

View File

@ -1365,6 +1365,10 @@ export function getPlaylist(uri, { full, forceRefetch, callbackAction }) {
...formatPlaylist(response),
can_edit: (getState().spotify.me && getState().spotify.me.id === response.owner.id),
description,
// Remove tracks unless we're looking for the full object. This allows our detector
// to accurately identify whether we've loaded *ALL* the tracks. Without this, it
// doesn't know if we've loaded all tracks, or just the first page.
...(full ? {} : { tracks: null }),
}));
if (full) {

View File

@ -131,7 +131,7 @@ const getCurrentPusherConnection = function (connections, connectionid) {
* @param uri = string
* */
let uriSource = function (uri) {
if (!uri) return false;
if (!uri) return '';
const exploded = `${uri}`.split(':');
return exploded[0];
@ -143,7 +143,7 @@ let uriSource = function (uri) {
* @return string
* */
const uriType = function (uri) {
if (!uri) return null;
if (!uri) return '';
const exploded = `${uri}`.split(':');
@ -441,7 +441,7 @@ const getIndexedRecords = function (index, uris) {
* @param string String
* @return String
* */
const titleCase = function (string) {
const titleCase = function (string = '') {
return string.charAt(0).toUpperCase() + string.slice(1);
};

View File

@ -62,12 +62,15 @@ class Queue extends React.Component {
componentDidMount() {
const {
uiActions: { setWindowTitle },
location: { limit } = {},
uiActions: {
setWindowTitle,
},
location: {
limit,
} = {},
} = this.props;
if (limit) {
this.setState({ limit });
}
if (limit) this.setState({ limit });
setWindowTitle(i18n('now_playing.title'));
}
@ -86,7 +89,7 @@ class Queue extends React.Component {
} = this.props;
if (added_from_uri && added_from_uri !== prev_added_from_uri) {
loadItem(added_from_uri);
loadItem(added_from_uri, { full: false });
}
}