Adding killswitch to clear storage
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
20
mopidy_iris/static/app.min.js
vendored
20
mopidy_iris/static/app.min.js
vendored
File diff suppressed because one or more lines are too long
@ -106,7 +106,7 @@
|
|||||||
|
|
||||||
// Release details
|
// Release details
|
||||||
// These are automatically injected to built HTML
|
// These are automatically injected to built HTML
|
||||||
var build = "1599594930";
|
var build = "1599762714";
|
||||||
var version = "3.52.4";
|
var version = "3.52.4";
|
||||||
|
|
||||||
// Construct the script tag
|
// Construct the script tag
|
||||||
|
|||||||
@ -62,11 +62,11 @@ export default class GridItem extends React.Component {
|
|||||||
}) => {
|
}) => {
|
||||||
switch (uriType(uri)) {
|
switch (uriType(uri)) {
|
||||||
case 'playlist':
|
case 'playlist':
|
||||||
return tracks_total ? (
|
return (
|
||||||
<span className="grid__item__secondary__content">
|
<span className="grid__item__secondary__content">
|
||||||
<I18n path="specs.tracks" count={tracks_total} />
|
<I18n path="specs.tracks" count={tracks_total || 0} />
|
||||||
</span>
|
</span>
|
||||||
) : null;
|
);
|
||||||
|
|
||||||
case 'artist':
|
case 'artist':
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -40,7 +40,6 @@ class Hotkeys extends React.Component {
|
|||||||
ctrlKey,
|
ctrlKey,
|
||||||
metaKey,
|
metaKey,
|
||||||
shiftKey,
|
shiftKey,
|
||||||
preventDefault,
|
|
||||||
} = e;
|
} = e;
|
||||||
key = key.toLowerCase();
|
key = key.toLowerCase();
|
||||||
|
|
||||||
@ -71,13 +70,13 @@ class Hotkeys extends React.Component {
|
|||||||
uiActions.createNotification({ content: 'play_arrow', type: 'shortcut' });
|
uiActions.createNotification({ content: 'play_arrow', type: 'shortcut' });
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Play' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Play' });
|
||||||
}
|
}
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's': // Stop
|
case 's': // Stop
|
||||||
mopidyActions.stop();
|
mopidyActions.stop();
|
||||||
uiActions.createNotification({ content: 'stop', type: 'shortcut' });
|
uiActions.createNotification({ content: 'stop', type: 'shortcut' });
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Stop' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Stop' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -88,14 +87,14 @@ class Hotkeys extends React.Component {
|
|||||||
}
|
}
|
||||||
mopidyActions.setTimePosition(new_position);
|
mopidyActions.setTimePosition(new_position);
|
||||||
uiActions.createNotification({ content: 'fast_rewind', type: 'shortcut' });
|
uiActions.createNotification({ content: 'fast_rewind', type: 'shortcut' });
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Rewind' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Rewind' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f': // Seek forwards 30 sec
|
case 'f': // Seek forwards 30 sec
|
||||||
mopidyActions.setTimePosition(play_time_position + 30000);
|
mopidyActions.setTimePosition(play_time_position + 30000);
|
||||||
uiActions.createNotification({ content: 'fast_forward', type: 'shortcut' });
|
uiActions.createNotification({ content: 'fast_forward', type: 'shortcut' });
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Fastforward' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Fastforward' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ class Hotkeys extends React.Component {
|
|||||||
case '<': // Previous track
|
case '<': // Previous track
|
||||||
mopidyActions.previous();
|
mopidyActions.previous();
|
||||||
uiActions.createNotification({ content: 'skip_previous', type: 'shortcut' });
|
uiActions.createNotification({ content: 'skip_previous', type: 'shortcut' });
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Previous' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Previous' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -111,7 +110,7 @@ class Hotkeys extends React.Component {
|
|||||||
case '>': // Next track
|
case '>': // Next track
|
||||||
mopidyActions.next();
|
mopidyActions.next();
|
||||||
uiActions.createNotification({ content: 'skip_next', type: 'shortcut' });
|
uiActions.createNotification({ content: 'skip_next', type: 'shortcut' });
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Next' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Next' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -128,7 +127,7 @@ class Hotkeys extends React.Component {
|
|||||||
}
|
}
|
||||||
uiActions.createNotification({ content: 'volume_up', type: 'shortcut' });
|
uiActions.createNotification({ content: 'volume_up', type: 'shortcut' });
|
||||||
}
|
}
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Volume up' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Volume up' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -144,7 +143,7 @@ class Hotkeys extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
uiActions.createNotification({ content: 'volume_down', type: 'shortcut' });
|
uiActions.createNotification({ content: 'volume_down', type: 'shortcut' });
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Volume down' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Volume down' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -158,36 +157,36 @@ class Hotkeys extends React.Component {
|
|||||||
uiActions.createNotification({ content: 'volume_off', type: 'shortcut' });
|
uiActions.createNotification({ content: 'volume_off', type: 'shortcut' });
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Mute' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Mute' });
|
||||||
}
|
}
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'escape': // Cancel current action/context
|
case 'escape': // Cancel current action/context
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
uiActions.dragEnd();
|
uiActions.dragEnd();
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Dragging' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Dragging' });
|
||||||
} else if ($('body').hasClass('modal-open')) {
|
} else if ($('body').hasClass('modal-open')) {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Modal' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Modal' });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '1': // Navigation: Queue
|
case '1': // Navigation: Queue
|
||||||
history.push('/queue');
|
history.push('/queue');
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Queue' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Queue' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2': // Navigation: Search
|
case '2': // Navigation: Search
|
||||||
history.push('/search');
|
history.push('/search');
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Search' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Search' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '3': // Navigation: Kiosk mode
|
case '3': // Navigation: Kiosk mode
|
||||||
history.push('/kiosk-mode');
|
history.push('/kiosk-mode');
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Kiosk mode' });
|
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Kiosk mode' });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,6 @@ class TrackList extends React.Component {
|
|||||||
ctrlKey,
|
ctrlKey,
|
||||||
metaKey,
|
metaKey,
|
||||||
shiftKey,
|
shiftKey,
|
||||||
preventDefault,
|
|
||||||
} = e;
|
} = e;
|
||||||
|
|
||||||
// When we're focussed on certian elements, don't fire any shortcuts
|
// When we're focussed on certian elements, don't fire any shortcuts
|
||||||
@ -61,7 +60,7 @@ class TrackList extends React.Component {
|
|||||||
if (tracks_keys && tracks_keys.length > 0) {
|
if (tracks_keys && tracks_keys.length > 0) {
|
||||||
this.playTracks();
|
this.playTracks();
|
||||||
}
|
}
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'backspace':
|
case 'backspace':
|
||||||
@ -69,7 +68,7 @@ class TrackList extends React.Component {
|
|||||||
if (tracks_keys && tracks_keys.length > 0) {
|
if (tracks_keys && tracks_keys.length > 0) {
|
||||||
this.removeTracks();
|
this.removeTracks();
|
||||||
}
|
}
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
@ -78,7 +77,7 @@ class TrackList extends React.Component {
|
|||||||
all_tracks.push(this.buildTrackKey(this.props.tracks[i], i));
|
all_tracks.push(this.buildTrackKey(this.props.tracks[i], i));
|
||||||
}
|
}
|
||||||
this.props.uiActions.setSelectedTracks(all_tracks);
|
this.props.uiActions.setSelectedTracks(all_tracks);
|
||||||
preventDefault();
|
e.preventDefault();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -365,6 +365,7 @@ settings:
|
|||||||
share_configuration: Share configuration
|
share_configuration: Share configuration
|
||||||
restart: Restart server
|
restart: Restart server
|
||||||
reset_cache: Reset cache
|
reset_cache: Reset cache
|
||||||
|
reset_storage: Reset storage
|
||||||
reset: Reset all settings
|
reset: Reset all settings
|
||||||
about:
|
about:
|
||||||
title: About
|
title: About
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import {
|
|||||||
getTrackIcon,
|
getTrackIcon,
|
||||||
formatArtists,
|
formatArtists,
|
||||||
formatArtist,
|
formatArtist,
|
||||||
|
formatPlaylist,
|
||||||
} from '../../util/format';
|
} from '../../util/format';
|
||||||
import {
|
import {
|
||||||
arrayOf,
|
arrayOf,
|
||||||
@ -1564,25 +1565,27 @@ const MopidyMiddleware = (function () {
|
|||||||
if (!response) return;
|
if (!response) return;
|
||||||
|
|
||||||
const playlist = {
|
const playlist = {
|
||||||
...response,
|
...formatPlaylist(response),
|
||||||
uri: response.uri,
|
uri: response.uri,
|
||||||
type: 'playlist',
|
type: 'playlist',
|
||||||
provider: 'mopidy',
|
provider: 'mopidy',
|
||||||
can_edit: true,
|
can_edit: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
request(store, 'library.lookup', { uris: arrayOf('uri', response.tracks) })
|
if (response.tracks) {
|
||||||
.then((tracksResponse) => {
|
request(store, 'library.lookup', { uris: arrayOf('uri', response.tracks) })
|
||||||
const tracks = response.tracks.map((simpleTrack) => {
|
.then((tracksResponse) => {
|
||||||
const fullTracks = tracksResponse[simpleTrack.uri];
|
const tracks = response.tracks.map((simpleTrack) => {
|
||||||
return {
|
const fullTracks = tracksResponse[simpleTrack.uri];
|
||||||
...simpleTrack,
|
return {
|
||||||
...(fullTracks.length ? fullTracks[0] : {}),
|
...simpleTrack,
|
||||||
};
|
...(fullTracks.length ? fullTracks[0] : {}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
playlist.tracks = formatTracks(tracks);
|
||||||
|
store.dispatch(coreActions.itemLoaded(playlist));
|
||||||
});
|
});
|
||||||
playlist.tracks = tracks;
|
}
|
||||||
store.dispatch(coreActions.itemLoaded(playlist));
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -2194,15 +2197,17 @@ const MopidyMiddleware = (function () {
|
|||||||
playlist_uris.forEach((uri, index) => {
|
playlist_uris.forEach((uri, index) => {
|
||||||
request(store, 'playlists.lookup', { uri })
|
request(store, 'playlists.lookup', { uri })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
libraryPlaylists.push({
|
libraryPlaylists.push(
|
||||||
type: 'playlist',
|
formatPlaylist({
|
||||||
name: response.name,
|
name: response.name,
|
||||||
uri: response.uri,
|
uri: response.uri,
|
||||||
source: uriSource(response.uri),
|
can_edit: uriSource(response.uri) === 'm3u',
|
||||||
provider: 'mopidy',
|
last_modified: response.last_modified,
|
||||||
last_modified: response.last_modified,
|
// By not including actual tracks they will be fetched when needed. We don't
|
||||||
tracks: response.tracks,
|
// want these simple tracks because they don't contain duration, artist, etc.
|
||||||
});
|
tracks_total: response.tracks ? response.tracks.length : null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
if (index === playlist_uris.length - 1) {
|
if (index === playlist_uris.length - 1) {
|
||||||
store.dispatch(coreActions.itemsLoaded(libraryPlaylists));
|
store.dispatch(coreActions.itemsLoaded(libraryPlaylists));
|
||||||
@ -2223,7 +2228,6 @@ const MopidyMiddleware = (function () {
|
|||||||
request(store, 'library.lookup', { uris })
|
request(store, 'library.lookup', { uris })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const libraryAlbums = indexToArray(response).map((tracks) => ({
|
const libraryAlbums = indexToArray(response).map((tracks) => ({
|
||||||
source: 'local',
|
|
||||||
artists: tracks[0].artists || null,
|
artists: tracks[0].artists || null,
|
||||||
tracks,
|
tracks,
|
||||||
last_modified: tracks[0].last_modified,
|
last_modified: tracks[0].last_modified,
|
||||||
|
|||||||
@ -426,6 +426,7 @@ const formatPlaylist = function (data) {
|
|||||||
'can_edit',
|
'can_edit',
|
||||||
'user',
|
'user',
|
||||||
'tracks',
|
'tracks',
|
||||||
|
'tracks_total',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Loop fields and import from data
|
// Loop fields and import from data
|
||||||
@ -448,6 +449,10 @@ const formatPlaylist = function (data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (playlist.tracks_total === undefined) {
|
||||||
|
playlist.tracks_total = playlist.tracks ? playlist.tracks.length : 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.last_modified_date && playlist.last_modified === undefined) {
|
if (data.last_modified_date && playlist.last_modified === undefined) {
|
||||||
playlist.last_modified = data.last_modified_date;
|
playlist.last_modified = data.last_modified_date;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,6 +79,24 @@ class Settings extends React.Component {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetStorage = () => {
|
||||||
|
localForage.keys().then((keys) => {
|
||||||
|
const keysToKeep = ['persist:root', 'persist:ui', 'persist:spotify'];
|
||||||
|
const keysToRemove = keys.filter((key) => keysToKeep.indexOf(key) < 0);
|
||||||
|
|
||||||
|
keysToRemove.forEach((key, index) => {
|
||||||
|
localForage.removeItem(key).then(() => {
|
||||||
|
console.debug(`Removed ${key}`);
|
||||||
|
if (index === keysToRemove.length) {
|
||||||
|
console.debug('Reloading...');
|
||||||
|
window.location = '#';
|
||||||
|
window.location.reload(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
resetServiceWorkerAndCache = () => {
|
resetServiceWorkerAndCache = () => {
|
||||||
const { coreActions: { handleException } } = this.props;
|
const { coreActions: { handleException } } = this.props;
|
||||||
|
|
||||||
@ -533,10 +551,6 @@ class Settings extends React.Component {
|
|||||||
>
|
>
|
||||||
<I18n path="settings.advanced.restart" />
|
<I18n path="settings.advanced.restart" />
|
||||||
</Button>
|
</Button>
|
||||||
<ConfirmationButton
|
|
||||||
content={i18n('settings.advanced.reset')}
|
|
||||||
onConfirm={this.resetAllSettings}
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
type="destructive"
|
type="destructive"
|
||||||
onClick={this.resetServiceWorkerAndCache}
|
onClick={this.resetServiceWorkerAndCache}
|
||||||
@ -544,6 +558,17 @@ class Settings extends React.Component {
|
|||||||
>
|
>
|
||||||
<I18n path="settings.advanced.reset_cache" />
|
<I18n path="settings.advanced.reset_cache" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="destructive"
|
||||||
|
onClick={this.resetStorage}
|
||||||
|
tracking={{ category: 'System', action: 'ResetStorage' }}
|
||||||
|
>
|
||||||
|
<I18n path="settings.advanced.reset_storage" />
|
||||||
|
</Button>
|
||||||
|
<ConfirmationButton
|
||||||
|
content={i18n('settings.advanced.reset')}
|
||||||
|
onConfirm={this.resetAllSettings}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 className="underline">
|
<h4 className="underline">
|
||||||
|
|||||||
@ -18,8 +18,8 @@ import { collate } from '../../util/format';
|
|||||||
class AddToPlaylist extends React.Component {
|
class AddToPlaylist extends React.Component {
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
const {
|
const {
|
||||||
spotify_library_playlists,
|
spotify_library,
|
||||||
mopidy_library_playlists,
|
mopidy_library,
|
||||||
spotify_available,
|
spotify_available,
|
||||||
coreActions: {
|
coreActions: {
|
||||||
loadLibrary,
|
loadLibrary,
|
||||||
@ -29,11 +29,11 @@ class AddToPlaylist extends React.Component {
|
|||||||
},
|
},
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!spotify_library_playlists && spotify_available) {
|
if (!spotify_library && spotify_available) {
|
||||||
loadLibrary('spotify:library:playlists');
|
loadLibrary('spotify:library:playlists');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mopidy_library_playlists) {
|
if (!mopidy_library) {
|
||||||
loadLibrary('mopidy:library:playlists');
|
loadLibrary('mopidy:library:playlists');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +56,8 @@ class AddToPlaylist extends React.Component {
|
|||||||
const {
|
const {
|
||||||
uris,
|
uris,
|
||||||
items,
|
items,
|
||||||
spotify_library,
|
spotify_library = { items_uris: [] },
|
||||||
mopidy_library,
|
mopidy_library = { items_uris: [] },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let playlists = [
|
let playlists = [
|
||||||
@ -89,12 +89,8 @@ class AddToPlaylist extends React.Component {
|
|||||||
<h4 className="list__item__name">{ playlist.name }</h4>
|
<h4 className="list__item__name">{ playlist.name }</h4>
|
||||||
<ul className="list__item__details details">
|
<ul className="list__item__details details">
|
||||||
<li><Icon type="fontawesome" className="source" name={sourceIcon(playlist.uri)} /></li>
|
<li><Icon type="fontawesome" className="source" name={sourceIcon(playlist.uri)} /></li>
|
||||||
<li>
|
<li className="mid_grey-text">
|
||||||
{playlist.tracks_total && (
|
{`${playlist.tracks_total || 0} tracks`}
|
||||||
<span className="mid_grey-text">
|
|
||||||
{`${playlist.tracks_total} tracks`}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -114,8 +110,8 @@ const mapStateToProps = (state, ownProps) => ({
|
|||||||
uris: (ownProps.match.params.uris ? decodeURIComponent(ownProps.match.params.uris).split(',') : []),
|
uris: (ownProps.match.params.uris ? decodeURIComponent(ownProps.match.params.uris).split(',') : []),
|
||||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||||
items: state.core.items,
|
items: state.core.items,
|
||||||
mopidy_library: state.core.libraries['mopidy:library:playlists'] || { items_uris: [] },
|
mopidy_library: state.core.libraries['mopidy:library:playlists'],
|
||||||
spotify_library: state.core.libraries['spotify:library:playlists'] || { items_uris: [] },
|
spotify_library: state.core.libraries['spotify:library:playlists'],
|
||||||
spotify_available: state.spotify.access_token,
|
spotify_available: state.spotify.access_token,
|
||||||
load_queue: state.ui.load_queue,
|
load_queue: state.ui.load_queue,
|
||||||
me_id: (state.spotify.me ? state.spotify.me.id : false),
|
me_id: (state.spotify.me ? state.spotify.me.id : false),
|
||||||
|
|||||||
Reference in New Issue
Block a user