Adding killswitch to clear storage

This commit is contained in:
James Barnsley
2020-09-11 13:53:54 +12:00
parent a4fd0cd8e5
commit 5953fc84cf
12 changed files with 205 additions and 141 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -106,7 +106,7 @@
// Release details
// These are automatically injected to built HTML
var build = "1599594930";
var build = "1599762714";
var version = "3.52.4";
// Construct the script tag

View File

@ -62,11 +62,11 @@ export default class GridItem extends React.Component {
}) => {
switch (uriType(uri)) {
case 'playlist':
return tracks_total ? (
return (
<span className="grid__item__secondary__content">
<I18n path="specs.tracks" count={tracks_total} />
<I18n path="specs.tracks" count={tracks_total || 0} />
</span>
) : null;
);
case 'artist':
return (

View File

@ -40,7 +40,6 @@ class Hotkeys extends React.Component {
ctrlKey,
metaKey,
shiftKey,
preventDefault,
} = e;
key = key.toLowerCase();
@ -71,13 +70,13 @@ class Hotkeys extends React.Component {
uiActions.createNotification({ content: 'play_arrow', type: 'shortcut' });
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Play' });
}
preventDefault();
e.preventDefault();
break;
case 's': // Stop
mopidyActions.stop();
uiActions.createNotification({ content: 'stop', type: 'shortcut' });
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Stop' });
break;
@ -88,14 +87,14 @@ class Hotkeys extends React.Component {
}
mopidyActions.setTimePosition(new_position);
uiActions.createNotification({ content: 'fast_rewind', type: 'shortcut' });
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Rewind' });
break;
case 'f': // Seek forwards 30 sec
mopidyActions.setTimePosition(play_time_position + 30000);
uiActions.createNotification({ content: 'fast_forward', type: 'shortcut' });
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Fastforward' });
break;
@ -103,7 +102,7 @@ class Hotkeys extends React.Component {
case '<': // Previous track
mopidyActions.previous();
uiActions.createNotification({ content: 'skip_previous', type: 'shortcut' });
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Previous' });
break;
@ -111,7 +110,7 @@ class Hotkeys extends React.Component {
case '>': // Next track
mopidyActions.next();
uiActions.createNotification({ content: 'skip_next', type: 'shortcut' });
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Next' });
break;
@ -128,7 +127,7 @@ class Hotkeys extends React.Component {
}
uiActions.createNotification({ content: 'volume_up', type: 'shortcut' });
}
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Volume up' });
break;
@ -144,7 +143,7 @@ class Hotkeys extends React.Component {
}
}
uiActions.createNotification({ content: 'volume_down', type: 'shortcut' });
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Volume down' });
break;
@ -158,36 +157,36 @@ class Hotkeys extends React.Component {
uiActions.createNotification({ content: 'volume_off', type: 'shortcut' });
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Mute' });
}
preventDefault();
e.preventDefault();
break;
case 'escape': // Cancel current action/context
if (dragging) {
uiActions.dragEnd();
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Dragging' });
} else if ($('body').hasClass('modal-open')) {
window.history.back();
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Modal' });
}
break;
case '1': // Navigation: Queue
history.push('/queue');
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Queue' });
break;
case '2': // Navigation: Search
history.push('/search');
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Search' });
break;
case '3': // Navigation: Kiosk mode
history.push('/kiosk-mode');
preventDefault();
e.preventDefault();
if (allow_reporting) ReactGA.event({ category: 'Hotkey', action: key, label: 'Kiosk mode' });
break;

View File

@ -38,7 +38,6 @@ class TrackList extends React.Component {
ctrlKey,
metaKey,
shiftKey,
preventDefault,
} = e;
// 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) {
this.playTracks();
}
preventDefault();
e.preventDefault();
break;
case 'backspace':
@ -69,7 +68,7 @@ class TrackList extends React.Component {
if (tracks_keys && tracks_keys.length > 0) {
this.removeTracks();
}
preventDefault();
e.preventDefault();
break;
case 'a':
@ -78,7 +77,7 @@ class TrackList extends React.Component {
all_tracks.push(this.buildTrackKey(this.props.tracks[i], i));
}
this.props.uiActions.setSelectedTracks(all_tracks);
preventDefault();
e.preventDefault();
break;
}
}

View File

@ -365,6 +365,7 @@ settings:
share_configuration: Share configuration
restart: Restart server
reset_cache: Reset cache
reset_storage: Reset storage
reset: Reset all settings
about:
title: About

View File

@ -18,6 +18,7 @@ import {
getTrackIcon,
formatArtists,
formatArtist,
formatPlaylist,
} from '../../util/format';
import {
arrayOf,
@ -1564,25 +1565,27 @@ const MopidyMiddleware = (function () {
if (!response) return;
const playlist = {
...response,
...formatPlaylist(response),
uri: response.uri,
type: 'playlist',
provider: 'mopidy',
can_edit: true,
};
request(store, 'library.lookup', { uris: arrayOf('uri', response.tracks) })
.then((tracksResponse) => {
const tracks = response.tracks.map((simpleTrack) => {
const fullTracks = tracksResponse[simpleTrack.uri];
return {
...simpleTrack,
...(fullTracks.length ? fullTracks[0] : {}),
};
if (response.tracks) {
request(store, 'library.lookup', { uris: arrayOf('uri', response.tracks) })
.then((tracksResponse) => {
const tracks = response.tracks.map((simpleTrack) => {
const fullTracks = tracksResponse[simpleTrack.uri];
return {
...simpleTrack,
...(fullTracks.length ? fullTracks[0] : {}),
};
});
playlist.tracks = formatTracks(tracks);
store.dispatch(coreActions.itemLoaded(playlist));
});
playlist.tracks = tracks;
store.dispatch(coreActions.itemLoaded(playlist));
});
}
});
break;
@ -2194,15 +2197,17 @@ const MopidyMiddleware = (function () {
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,
});
libraryPlaylists.push(
formatPlaylist({
name: response.name,
uri: response.uri,
can_edit: uriSource(response.uri) === 'm3u',
last_modified: response.last_modified,
// By not including actual tracks they will be fetched when needed. We don't
// 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) {
store.dispatch(coreActions.itemsLoaded(libraryPlaylists));
@ -2223,7 +2228,6 @@ const MopidyMiddleware = (function () {
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,

View File

@ -426,6 +426,7 @@ const formatPlaylist = function (data) {
'can_edit',
'user',
'tracks',
'tracks_total',
];
// 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) {
playlist.last_modified = data.last_modified_date;
}

View File

@ -79,6 +79,24 @@ class Settings extends React.Component {
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 = () => {
const { coreActions: { handleException } } = this.props;
@ -533,10 +551,6 @@ class Settings extends React.Component {
>
<I18n path="settings.advanced.restart" />
</Button>
<ConfirmationButton
content={i18n('settings.advanced.reset')}
onConfirm={this.resetAllSettings}
/>
<Button
type="destructive"
onClick={this.resetServiceWorkerAndCache}
@ -544,6 +558,17 @@ class Settings extends React.Component {
>
<I18n path="settings.advanced.reset_cache" />
</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>
<h4 className="underline">

View File

@ -18,8 +18,8 @@ import { collate } from '../../util/format';
class AddToPlaylist extends React.Component {
componentDidMount = () => {
const {
spotify_library_playlists,
mopidy_library_playlists,
spotify_library,
mopidy_library,
spotify_available,
coreActions: {
loadLibrary,
@ -29,11 +29,11 @@ class AddToPlaylist extends React.Component {
},
} = this.props;
if (!spotify_library_playlists && spotify_available) {
if (!spotify_library && spotify_available) {
loadLibrary('spotify:library:playlists');
}
if (!mopidy_library_playlists) {
if (!mopidy_library) {
loadLibrary('mopidy:library:playlists');
}
@ -56,8 +56,8 @@ class AddToPlaylist extends React.Component {
const {
uris,
items,
spotify_library,
mopidy_library,
spotify_library = { items_uris: [] },
mopidy_library = { items_uris: [] },
} = this.props;
let playlists = [
@ -89,12 +89,8 @@ class AddToPlaylist extends React.Component {
<h4 className="list__item__name">{ playlist.name }</h4>
<ul className="list__item__details details">
<li><Icon type="fontawesome" className="source" name={sourceIcon(playlist.uri)} /></li>
<li>
{playlist.tracks_total && (
<span className="mid_grey-text">
{`${playlist.tracks_total} tracks`}
</span>
)}
<li className="mid_grey-text">
{`${playlist.tracks_total || 0} tracks`}
</li>
</ul>
</div>
@ -114,8 +110,8 @@ const mapStateToProps = (state, ownProps) => ({
uris: (ownProps.match.params.uris ? decodeURIComponent(ownProps.match.params.uris).split(',') : []),
mopidy_uri_schemes: state.mopidy.uri_schemes,
items: state.core.items,
mopidy_library: state.core.libraries['mopidy:library:playlists'] || { items_uris: [] },
spotify_library: state.core.libraries['spotify:library:playlists'] || { items_uris: [] },
mopidy_library: state.core.libraries['mopidy:library:playlists'],
spotify_library: state.core.libraries['spotify:library:playlists'],
spotify_available: state.spotify.access_token,
load_queue: state.ui.load_queue,
me_id: (state.spotify.me ? state.spotify.me.id : false),