diff --git a/src/js/App.js b/src/js/App.js
index af78d3e6..301ad58c 100755
--- a/src/js/App.js
+++ b/src/js/App.js
@@ -1,63 +1,63 @@
-import React from "react";
-import { bindActionCreators } from "redux";
-import { Route, Switch } from "react-router-dom";
-import { connect } from "react-redux";
-import ReactGA from "react-ga";
+import React from 'react';
+import { bindActionCreators } from 'redux';
+import { Route, Switch } from 'react-router-dom';
+import { connect } from 'react-redux';
+import ReactGA from 'react-ga';
-import Sidebar from "./components/Sidebar";
-import PlaybackControls from "./components/PlaybackControls";
-import ContextMenu from "./components/ContextMenu";
-import Dragger from "./components/Dragger";
-import Notifications from "./components/Notifications";
-import ResizeListener from "./components/ResizeListener";
-import Hotkeys from "./components/Hotkeys";
-import DebugInfo from "./components/DebugInfo";
-import ErrorMessage from "./components/ErrorMessage";
+import Sidebar from './components/Sidebar';
+import PlaybackControls from './components/PlaybackControls';
+import ContextMenu from './components/ContextMenu';
+import Dragger from './components/Dragger';
+import Notifications from './components/Notifications';
+import ResizeListener from './components/ResizeListener';
+import Hotkeys from './components/Hotkeys';
+import DebugInfo from './components/DebugInfo';
+import ErrorMessage from './components/ErrorMessage';
-import Album from "./views/Album";
-import Artist from "./views/Artist";
-import Playlist from "./views/Playlist";
-import User from "./views/User";
-import Track from "./views/Track";
-import Queue from "./views/Queue";
-import QueueHistory from "./views/QueueHistory";
-import Debug from "./views/Debug";
-import Search from "./views/Search";
-import Settings from "./views/Settings";
+import Album from './views/Album';
+import Artist from './views/Artist';
+import Playlist from './views/Playlist';
+import User from './views/User';
+import Track from './views/Track';
+import Queue from './views/Queue';
+import QueueHistory from './views/QueueHistory';
+import Debug from './views/Debug';
+import Search from './views/Search';
+import Settings from './views/Settings';
-import DiscoverRecommendations from "./views/discover/DiscoverRecommendations";
-import DiscoverFeatured from "./views/discover/DiscoverFeatured";
-import DiscoverCategories from "./views/discover/DiscoverCategories";
-import DiscoverCategory from "./views/discover/DiscoverCategory";
-import DiscoverNewReleases from "./views/discover/DiscoverNewReleases";
+import DiscoverRecommendations from './views/discover/DiscoverRecommendations';
+import DiscoverFeatured from './views/discover/DiscoverFeatured';
+import DiscoverCategories from './views/discover/DiscoverCategories';
+import DiscoverCategory from './views/discover/DiscoverCategory';
+import DiscoverNewReleases from './views/discover/DiscoverNewReleases';
-import LibraryArtists from "./views/library/LibraryArtists";
-import LibraryAlbums from "./views/library/LibraryAlbums";
-import LibraryTracks from "./views/library/LibraryTracks";
-import LibraryPlaylists from "./views/library/LibraryPlaylists";
-import LibraryBrowse from "./views/library/LibraryBrowse";
-import LibraryBrowseDirectory from "./views/library/LibraryBrowseDirectory";
+import LibraryArtists from './views/library/LibraryArtists';
+import LibraryAlbums from './views/library/LibraryAlbums';
+import LibraryTracks from './views/library/LibraryTracks';
+import LibraryPlaylists from './views/library/LibraryPlaylists';
+import LibraryBrowse from './views/library/LibraryBrowse';
+import LibraryBrowseDirectory from './views/library/LibraryBrowseDirectory';
-import EditPlaylist from "./views/modals/EditPlaylist";
-import CreatePlaylist from "./views/modals/CreatePlaylist";
-import EditRadio from "./views/modals/EditRadio";
-import AddToQueue from "./views/modals/AddToQueue";
-import InitialSetup from "./views/modals/InitialSetup";
-import KioskMode from "./views/modals/KioskMode";
-import ShareConfiguration from "./views/modals/ShareConfiguration";
-import AddToPlaylist from "./views/modals/AddToPlaylist";
-import ImageZoom from "./views/modals/ImageZoom";
-import EditCommand from "./views/modals/EditCommand";
+import EditPlaylist from './views/modals/EditPlaylist';
+import CreatePlaylist from './views/modals/CreatePlaylist';
+import EditRadio from './views/modals/EditRadio';
+import AddToQueue from './views/modals/AddToQueue';
+import InitialSetup from './views/modals/InitialSetup';
+import KioskMode from './views/modals/KioskMode';
+import ShareConfiguration from './views/modals/ShareConfiguration';
+import AddToPlaylist from './views/modals/AddToPlaylist';
+import ImageZoom from './views/modals/ImageZoom';
+import EditCommand from './views/modals/EditCommand';
-import * as helpers from "./helpers";
-import * as coreActions from "./services/core/actions";
-import * as uiActions from "./services/ui/actions";
-import * as pusherActions from "./services/pusher/actions";
-import * as mopidyActions from "./services/mopidy/actions";
-import * as spotifyActions from "./services/spotify/actions";
-import * as lastfmActions from "./services/lastfm/actions";
-import * as geniusActions from "./services/genius/actions";
-import * as snapcastActions from "./services/snapcast/actions";
+import * as helpers from './helpers';
+import * as coreActions from './services/core/actions';
+import * as uiActions from './services/ui/actions';
+import * as pusherActions from './services/pusher/actions';
+import * as mopidyActions from './services/mopidy/actions';
+import * as spotifyActions from './services/spotify/actions';
+import * as lastfmActions from './services/lastfm/actions';
+import * as geniusActions from './services/genius/actions';
+import * as snapcastActions from './services/snapcast/actions';
export class App extends React.Component {
constructor(props) {
@@ -68,27 +68,27 @@ export class App extends React.Component {
componentWillMount() {
window.addEventListener(
- "beforeinstallprompt",
+ 'beforeinstallprompt',
this.handleInstallPrompt,
- false
+ false,
);
- window.addEventListener("focus", this.handleFocusAndBlur, false);
- window.addEventListener("blur", this.handleFocusAndBlur, false);
+ window.addEventListener('focus', this.handleFocusAndBlur, false);
+ window.addEventListener('blur', this.handleFocusAndBlur, false);
}
componentWillUnmount() {
window.removeEventListener(
- "beforeinstallprompt",
+ 'beforeinstallprompt',
this.handleInstallPrompt,
- false
+ false,
);
- window.removeEventListener("focus", this.handleFocusAndBlur, false);
- window.removeEventListener("blur", this.handleFocusAndBlur, false);
+ window.removeEventListener('focus', this.handleFocusAndBlur, false);
+ window.removeEventListener('blur', this.handleFocusAndBlur, false);
}
componentDidMount() {
if (this.props.allow_reporting) {
- ReactGA.initialize("UA-64701652-3");
+ ReactGA.initialize('UA-64701652-3');
}
// Fire up our services
@@ -97,10 +97,10 @@ export class App extends React.Component {
this.props.coreActions.getBroadcasts();
// Check for url-parsed configuration values
- var url_vars = this.props.location.query;
+ const url_vars = this.props.location.query;
if (url_vars) {
- var has_values = false;
- var values = {};
+ let has_values = false;
+ const values = {};
if (url_vars.host !== undefined) {
has_values = true;
values.host = url_vars.host;
@@ -115,14 +115,14 @@ export class App extends React.Component {
// Allow 100ms for the action above to complete before we re-route
setTimeout(() => {
- this.props.history.push("/");
+ this.props.history.push('/');
}, 100);
}
}
// show initial setup if required
if (!this.props.initial_setup_complete) {
- this.props.history.push("/initial-setup");
+ this.props.history.push('/initial-setup');
}
}
@@ -138,7 +138,7 @@ export class App extends React.Component {
// If the location has a "scroll_position" state variable, scroll to it.
// This is invisibly injected to the history by the Link component when navigating, so
// hitting back in the browser allows us to restore the position
- var location_state = this.props.location.state
+ const location_state = this.props.location.state
? this.props.location.state
: {};
if (location_state.scroll_position) {
@@ -166,45 +166,45 @@ export class App extends React.Component {
* quota significantly: https://developers.google.com/web/updates/2017/03/background_tabs
*
* @param e Event
- **/
+ * */
handleFocusAndBlur(e) {
this.props.uiActions.setWindowFocus(document.hasFocus());
}
handleInstallPrompt(e) {
e.preventDefault();
- console.log("Install prompt detected");
+ console.log('Install prompt detected');
this.props.uiActions.installPrompt(e);
}
render() {
- let className = this.props.theme + "-theme app-inner";
+ let className = `${this.props.theme}-theme app-inner`;
if (this.props.wide_scrollbar_enabled) {
- className += " wide-scrollbar";
+ className += ' wide-scrollbar';
}
if (this.props.dragging) {
- className += " dragging";
+ className += ' dragging';
}
if (this.props.sidebar_open) {
- className += " sidebar-open";
+ className += ' sidebar-open';
}
if (this.props.touch_dragging) {
- className += " touch-dragging";
- console.log("TOUCH DRAGGING");
+ className += ' touch-dragging';
+ console.log('TOUCH DRAGGING');
}
if (this.props.context_menu) {
- className += " context-menu-open";
+ className += ' context-menu-open';
}
if (this.props.slim_mode) {
- className += " slim-mode";
+ className += ' slim-mode';
}
if (this.props.smooth_scrolling_enabled) {
- className += " smooth-scrolling-enabled";
+ className += ' smooth-scrolling-enabled';
}
if (helpers.isTouchDevice()) {
- className += " touch";
+ className += ' touch';
} else {
- className += " notouch";
+ className += ' notouch';
}
return (
@@ -348,39 +348,35 @@ export class App extends React.Component {
}
}
-const mapStateToProps = (state, ownProps) => {
- return {
- theme: state.ui.theme,
- wide_scrollbar_enabled: state.ui.wide_scrollbar_enabled,
- smooth_scrolling_enabled: state.ui.smooth_scrolling_enabled,
- hotkeys_enabled: state.ui.hotkeys_enabled,
- allow_reporting: state.ui.allow_reporting,
- touch_dragging: state.ui.touch_dragging,
- initial_setup_complete: state.ui.initial_setup_complete,
- slim_mode: state.ui.slim_mode,
- mopidy_connected: state.mopidy.connected,
- spotify_authorized: state.spotify.authorization,
- sidebar_open: state.ui.sidebar_open,
- dragging: state.ui.dragger && state.ui.dragger.active,
- context_menu: state.ui.context_menu,
- debug_info: state.ui.debug_info
- };
-};
+const mapStateToProps = (state, ownProps) => ({
+ theme: state.ui.theme,
+ wide_scrollbar_enabled: state.ui.wide_scrollbar_enabled,
+ smooth_scrolling_enabled: state.ui.smooth_scrolling_enabled,
+ hotkeys_enabled: state.ui.hotkeys_enabled,
+ allow_reporting: state.ui.allow_reporting,
+ touch_dragging: state.ui.touch_dragging,
+ initial_setup_complete: state.ui.initial_setup_complete,
+ slim_mode: state.ui.slim_mode,
+ mopidy_connected: state.mopidy.connected,
+ spotify_authorized: state.spotify.authorization,
+ sidebar_open: state.ui.sidebar_open,
+ dragging: state.ui.dragger && state.ui.dragger.active,
+ context_menu: state.ui.context_menu,
+ debug_info: state.ui.debug_info,
+});
-const mapDispatchToProps = dispatch => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch),
- lastfmActions: bindActionCreators(lastfmActions, dispatch),
- geniusActions: bindActionCreators(geniusActions, dispatch),
- snapcastActions: bindActionCreators(snapcastActions, dispatch)
- };
-};
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+ lastfmActions: bindActionCreators(lastfmActions, dispatch),
+ geniusActions: bindActionCreators(geniusActions, dispatch),
+ snapcastActions: bindActionCreators(snapcastActions, dispatch),
+});
export default connect(
mapStateToProps,
- mapDispatchToProps
+ mapDispatchToProps,
)(App);
diff --git a/src/js/components/AlbumGrid.js b/src/js/components/AlbumGrid.js
index d4673462..0c00afc7 100755
--- a/src/js/components/AlbumGrid.js
+++ b/src/js/components/AlbumGrid.js
@@ -9,66 +9,58 @@ import * as lastfmActions from '../services/lastfm/actions';
import GridItem from './GridItem';
-class AlbumGrid extends React.Component{
+class AlbumGrid extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props)
- }
+ handleContextMenu(e, item) {
+ e.preventDefault();
+ const data = {
+ e,
+ context: 'album',
+ uris: [item.uri],
+ items: [item],
+ tracklist_uri: item.uri,
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- handleContextMenu(e,item){
- e.preventDefault()
- var data = {
- e: e,
- context: 'album',
- uris: [item.uri],
- items: [item],
- tracklist_uri: item.uri
- }
- this.props.uiActions.showContextMenu(data)
- }
+ render() {
+ if (this.props.albums) {
+ let className = 'grid grid--albums';
+ if (this.props.className) className += ` ${this.props.className}`;
+ if (this.props.single_row) className += ' grid--single-row';
+ if (this.props.mini) className += ' grid--mini';
- render(){
- if (this.props.albums){
- var className = "grid grid--albums";
- if (this.props.className) className += ' '+this.props.className;
- if (this.props.single_row) className += ' grid--single-row';
- if (this.props.mini) className += ' grid--mini';
-
- return (
-
- {
- this.props.albums.map(album => {
- return (
-
this.handleContextMenu(e,album)}
- />
- )}
- )
+ return (
+
+ {
+ this.props.albums.map((album) => (
+ this.handleContextMenu(e, album)}
+ />
+ ))
}
-
- );
- }
- return null;
- }
+
+ );
+ }
+ return null;
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- artists: state.core.artists
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ artists: state.core.artists,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- lastfmActions: bindActionCreators(lastfmActions, dispatch)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(AlbumGrid)
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ lastfmActions: bindActionCreators(lastfmActions, dispatch),
+});
+export default connect(mapStateToProps, mapDispatchToProps)(AlbumGrid);
diff --git a/src/js/components/ArtistGrid.js b/src/js/components/ArtistGrid.js
index 345ff903..dada755c 100755
--- a/src/js/components/ArtistGrid.js
+++ b/src/js/components/ArtistGrid.js
@@ -11,70 +11,63 @@ import * as uiActions from '../services/ui/actions';
import * as lastfmActions from '../services/lastfm/actions';
import * as discogsActions from '../services/discogs/actions';
-class ArtistGrid extends React.Component{
+class ArtistGrid extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ handleContextMenu(e, item) {
+ e.preventDefault();
+ const data = {
+ e,
+ context: 'artist',
+ uris: [item.uri],
+ items: [item],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- handleContextMenu(e,item){
- e.preventDefault();
- var data = {
- e: e,
- context: 'artist',
- uris: [item.uri],
- items: [item]
- }
- this.props.uiActions.showContextMenu(data)
- }
+ render() {
+ if (this.props.artists) {
+ let className = 'grid grid--artists';
+ if (this.props.className) className += ` ${this.props.className}`;
+ if (this.props.single_row) className += ' grid--single-row';
+ if (this.props.mini) className += ' grid--mini';
- render(){
- if (this.props.artists){
- var className = "grid grid--artists";
- if (this.props.className) className += ' '+this.props.className;
- if (this.props.single_row) className += ' grid--single-row';
- if (this.props.mini) className += ' grid--mini';
-
- return (
-
- {
- this.props.artists.map(item => {
- var artist = helpers.collate(item, {albums: this.props.albums});
- return (
-
{this.props.history.push('/artist/'+encodeURIComponent(artist.uri))}}
- discogsActions={this.props.discogsActions}
- lastfmActions={this.props.lastfmActions}
- onContextMenu={e => this.handleContextMenu(e,artist)}
- />
- )
- }
- )
+ return (
+
+ {
+ this.props.artists.map((item) => {
+ const artist = helpers.collate(item, { albums: this.props.albums });
+ return (
+ { this.props.history.push(`/artist/${encodeURIComponent(artist.uri)}`); }}
+ discogsActions={this.props.discogsActions}
+ lastfmActions={this.props.lastfmActions}
+ onContextMenu={(e) => this.handleContextMenu(e, artist)}
+ />
+ );
+ })
}
-
- );
- }
- return null;
- }
+
+ );
+ }
+ return null;
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- albums: state.core.albums
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ albums: state.core.albums,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- lastfmActions: bindActionCreators(lastfmActions, dispatch),
- discogsActions: bindActionCreators(discogsActions, dispatch),
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ArtistGrid)
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ lastfmActions: bindActionCreators(lastfmActions, dispatch),
+ discogsActions: bindActionCreators(discogsActions, dispatch),
+});
+export default connect(mapStateToProps, mapDispatchToProps)(ArtistGrid);
diff --git a/src/js/components/ArtistSentence.js b/src/js/components/ArtistSentence.js
index ea49fb27..5daf576b 100755
--- a/src/js/components/ArtistSentence.js
+++ b/src/js/components/ArtistSentence.js
@@ -1,45 +1,43 @@
-import React, { memo } from 'react'
-import URILink from './URILink'
+import React, { memo } from 'react';
+import URILink from './URILink';
-export default memo((props) => {
+export default memo((props) => {
+ if (!props.artists) {
+ return - ;
+ }
- if (!props.artists){
- return - ;
- }
+ return (
+
+ {
+ props.artists.map((artist, index) => {
+ if (!artist) {
+ return - ;
+ }
- return (
-
- {
- props.artists.map((artist, index) => {
+ let separator = null;
+ if (index == props.artists.length - 2) {
+ separator = ' and ';
+ } else if (index < props.artists.length - 2) {
+ separator = ', ';
+ }
- if (!artist){
- return - ;
- }
+ if (!artist.name) {
+ var content = - ;
+ } else if (!artist.uri || props.nolinks) {
+ var content = { artist.name } ;
+ } else {
+ var content = { artist.name } ;
+ }
- var separator = null;
- if (index == props.artists.length - 2){
- separator = ' and ';
- } else if (index < props.artists.length - 2){
- separator = ', ';
- }
-
- if (!artist.name){
- var content = -
- } else if (!artist.uri || props.nolinks){
- var content = { artist.name }
- } else {
- var content = { artist.name }
- }
-
- return (
-
- { content }
- { separator }
-
- );
+ return (
+
+ { content }
+ { separator }
+
+ );
})
}
-
- );
-});
\ No newline at end of file
+
+ );
+});
diff --git a/src/js/components/CategoryGrid.js b/src/js/components/CategoryGrid.js
index c2189bd4..76dd587a 100755
--- a/src/js/components/CategoryGrid.js
+++ b/src/js/components/CategoryGrid.js
@@ -1,32 +1,28 @@
-import React, { memo } from 'react'
-import GridItem from './GridItem'
+import React, { memo } from 'react';
+import GridItem from './GridItem';
-export default memo((props) => {
-
- if (!props.categories){
- return null;
- }
+export default memo((props) => {
+ if (!props.categories) {
+ return null;
+ }
- let className = "grid grid--tiles";
- if (props.className) className += ' '+props.className;
- if (props.mini) className += ' grid--mini';
+ let className = 'grid grid--tiles';
+ if (props.className) className += ` ${props.className}`;
+ if (props.mini) className += ' grid--mini';
- return (
-
- {
- props.categories.map(category => {
- return (
-
- )
- })
+ return (
+
+ {
+ props.categories.map((category) => (
+
+ ))
}
-
- );
+
+ );
});
-
diff --git a/src/js/components/ContextMenu.js b/src/js/components/ContextMenu.js
index 516bb43a..6f293ac4 100755
--- a/src/js/components/ContextMenu.js
+++ b/src/js/components/ContextMenu.js
@@ -18,851 +18,853 @@ import * as mopidyActions from '../services/mopidy/actions';
import * as lastfmActions from '../services/lastfm/actions';
import * as spotifyActions from '../services/spotify/actions';
-class ContextMenu extends React.Component{
+class ContextMenu extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ submenu: null,
+ };
+ this.handleScroll = this.handleScroll.bind(this);
+ this.handleMouseDown = this.handleMouseDown.bind(this);
+ this.handleTouchStart = this.handleTouchStart.bind(this);
+ }
- constructor(props){
- super(props)
- this.state = {
- submenu: null
- }
- this.handleScroll = this.handleScroll.bind(this);
- this.handleMouseDown = this.handleMouseDown.bind(this);
- this.handleTouchStart = this.handleTouchStart.bind(this);
- }
+ componentDidMount() {
+ window.addEventListener('scroll', this.handleScroll, false);
+ window.addEventListener('mousedown', this.handleMouseDown, false);
+ window.addEventListener('touchstart', this.handleTouchStart, false);
+ }
- componentDidMount(){
- window.addEventListener("scroll", this.handleScroll, false);
- window.addEventListener("mousedown", this.handleMouseDown, false);
- window.addEventListener("touchstart", this.handleTouchStart, false);
- }
+ componentWillUnmount() {
+ window.removeEventListener('scroll', this.handleScroll, false);
+ window.removeEventListener('mousedown', this.handleMouseDown, false);
+ window.removeEventListener('touchstart', this.handleTouchStart, false);
+ }
- componentWillUnmount(){
- window.removeEventListener("scroll", this.handleScroll, false);
- window.removeEventListener("mousedown", this.handleMouseDown, false);
- window.removeEventListener("touchstart", this.handleTouchStart, false);
- }
+ componentWillReceiveProps(nextProps) {
+ // if we've been given a menu object (ie activated) when we didn't have one prior
+ if (nextProps.menu && !this.props.menu) {
+ this.setState({ submenu: null });
- componentWillReceiveProps(nextProps){
+ const context = this.getContext(nextProps);
- // if we've been given a menu object (ie activated) when we didn't have one prior
- if (nextProps.menu && !this.props.menu){
- this.setState({ submenu: null });
+ // if we're able to be in the library, run a check
+ if (nextProps.spotify_authorized && context.source == 'spotify') {
+ switch (nextProps.menu.context) {
+ case 'artist':
+ case 'album':
+ case 'playlist':
+ case 'editable-playlist':
+ case 'track':
+ case 'playlist-track':
+ case 'editable-playlist-track':
+ case 'queue-track':
+ this.props.spotifyActions.following(nextProps.menu.items[0].uri);
+ break;
+ }
+ }
- var context = this.getContext(nextProps);
+ // if we're able to be in the LastFM library, run a check
+ if (nextProps.lastfm_authorized && context.is_track && context.items_count == 1) {
+ if (nextProps.menu.items[0].uri && this.props.tracks[nextProps.menu.items[0].uri] !== undefined && this.props.tracks[nextProps.menu.items[0].uri].userloved === undefined) {
+ this.props.lastfmActions.getTrack(nextProps.menu.items[0].uri);
+ }
+ }
+ }
+ }
- // if we're able to be in the library, run a check
- if (nextProps.spotify_authorized && context.source == 'spotify'){
- switch (nextProps.menu.context){
- case 'artist':
- case 'album':
- case 'playlist':
- case 'editable-playlist':
- case 'track':
- case 'playlist-track':
- case 'editable-playlist-track':
- case 'queue-track':
- this.props.spotifyActions.following(nextProps.menu.items[0].uri)
- break
- }
- }
+ handleScroll(e) {
+ if (this.props.menu) {
+ this.props.uiActions.hideContextMenu();
+ }
+ }
- // if we're able to be in the LastFM library, run a check
- if (nextProps.lastfm_authorized && context.is_track && context.items_count == 1){
- if (nextProps.menu.items[0].uri && this.props.tracks[nextProps.menu.items[0].uri] !== undefined && this.props.tracks[nextProps.menu.items[0].uri].userloved === undefined){
- this.props.lastfmActions.getTrack(nextProps.menu.items[0].uri);
- }
- }
- }
- }
+ handleMouseDown(e) {
+ // if we click (touch or mouse) outside of the context menu or context menu trigger, kill it
+ if ($(e.target).closest('.context-menu').length <= 0 && $(e.target).closest('.context-menu-trigger').length <= 0) {
+ this.props.uiActions.hideContextMenu();
+ }
+ }
- handleScroll(e){
- if (this.props.menu){
- this.props.uiActions.hideContextMenu();
- }
- }
+ handleTouchStart(e) {
+ // if we click (touch or mouse) outside of the context menu or context menu trigger, kill it
+ if ($(e.target).closest('.context-menu').length <= 0 && $(e.target).closest('.context-menu-trigger').length <= 0) {
+ this.props.uiActions.hideContextMenu();
+ }
+ }
- handleMouseDown(e){
- // if we click (touch or mouse) outside of the context menu or context menu trigger, kill it
- if ($(e.target).closest('.context-menu').length <= 0 && $(e.target).closest('.context-menu-trigger').length <= 0){
- this.props.uiActions.hideContextMenu();
- }
- }
+ getContext(props = this.props) {
+ const context = {
+ name: null,
+ nice_name: 'Unknown',
+ is_track: false,
+ };
- handleTouchStart(e){
+ if (props.menu && props.menu.context) {
+ context.name = props.menu.context;
+ context.nice_name = props.menu.context;
- // if we click (touch or mouse) outside of the context menu or context menu trigger, kill it
- if ($(e.target).closest('.context-menu').length <= 0 && $(e.target).closest('.context-menu-trigger').length <= 0){
- this.props.uiActions.hideContextMenu();
- }
- }
+ // handle ugly labels
+ switch (props.menu.context) {
+ case 'playlist':
+ case 'editable-playlist':
+ context.nice_name = 'playlist';
+ break;
- getContext(props = this.props){
- var context = {
- name: null,
- nice_name: 'Unknown',
- is_track: false
- }
+ case 'track':
+ case 'queue-track':
+ case 'playlist-track':
+ case 'editable-playlist-track':
+ context.nice_name = 'track';
+ context.is_track = true;
+ break;
+ }
- if (props.menu && props.menu.context){
- context.name = props.menu.context;
- context.nice_name = props.menu.context;
+ // Consider the object(s) themselves
+ // We can only really accommodate the first item. The only instances where
+ // there is multiple is tracklists, when they're all of the same source (except search?)
+ if (props.menu.items && props.menu.items.length > 0) {
+ const item = props.menu.items[0];
+ context.item = item;
+ context.items_count = props.menu.items.length;
+ context.source = helpers.uriSource(item.uri);
+ context.type = helpers.uriType(item.uri);
+ context.in_library = this.inLibrary(item);
+ context.is_loved = this.isLoved(item);
+ }
+ }
- // handle ugly labels
- switch (props.menu.context){
- case 'playlist':
- case 'editable-playlist':
- context.nice_name = 'playlist';
- break;
+ return context;
+ }
- case 'track':
- case 'queue-track':
- case 'playlist-track':
- case 'editable-playlist-track':
- context.nice_name = 'track';
- context.is_track = true;
- break;
- }
+ inLibrary(item = null) {
+ if (!item) {
+ return false;
+ }
- // Consider the object(s) themselves
- // We can only really accommodate the first item. The only instances where
- // there is multiple is tracklists, when they're all of the same source (except search?)
- if (props.menu.items && props.menu.items.length > 0){
- var item = props.menu.items[0]
- context.item = item;
- context.items_count = props.menu.items.length;
- context.source = helpers.uriSource(item.uri);
- context.type = helpers.uriType(item.uri);
- context.in_library = this.inLibrary(item);
- context.is_loved = this.isLoved(item);
- }
- }
+ switch (helpers.uriType(item.uri)) {
+ case 'artist':
+ return (this.props.spotify_library_artists && this.props.spotify_library_artists.indexOf(item.uri) > -1);
+ break;
+ case 'album':
+ return (this.props.spotify_library_albums && this.props.spotify_library_albums.indexOf(item.uri) > -1);
+ break;
+ case 'playlist':
+ return (this.props.spotify_library_playlists && this.props.spotify_library_playlists.indexOf(item.uri) > -1);
+ break;
+ case 'track':
+ return (this.props.spotify_library_tracks && this.props.spotify_library_tracks.indexOf(item.uri) > -1);
+ break;
+ }
+ return false;
+ }
- return context
- }
-
- inLibrary(item = null){
- if (!item){
- return false;
- }
-
- switch (helpers.uriType(item.uri)){
- case 'artist':
- return (this.props.spotify_library_artists && this.props.spotify_library_artists.indexOf(item.uri) > -1);
- break;
- case 'album':
- return (this.props.spotify_library_albums && this.props.spotify_library_albums.indexOf(item.uri) > -1);
- break;
- case 'playlist':
- return (this.props.spotify_library_playlists && this.props.spotify_library_playlists.indexOf(item.uri) > -1);
- break;
- case 'track':
- return (this.props.spotify_library_tracks && this.props.spotify_library_tracks.indexOf(item.uri) > -1);
- break;
- }
- return false;
- }
-
- /**
+ /**
* TODO: Currently the select track keys are the only details available. We need
* the actual track object reference (including name and artists) to getTrack from LastFM
- **/
- isLoved(item = null){
- if (!item){
- return false
- }
+ * */
+ isLoved(item = null) {
+ if (!item) {
+ return false;
+ }
- if (this.props.tracks[item.uri] === undefined){
- return false;
- }
- var track = this.props.tracks[item.uri];
+ if (this.props.tracks[item.uri] === undefined) {
+ return false;
+ }
+ const track = this.props.tracks[item.uri];
- return (track.userloved !== undefined && track.userloved == "1");
- }
+ return (track.userloved !== undefined && track.userloved == '1');
+ }
- canBeInLibrary(){
- if (!this.props.spotify_authorized){
- return false
- }
- return (helpers.uriSource(this.props.menu.items[0].uri) == 'spotify')
- }
+ canBeInLibrary() {
+ if (!this.props.spotify_authorized) {
+ return false;
+ }
+ return (helpers.uriSource(this.props.menu.items[0].uri) == 'spotify');
+ }
- toggleInLibrary(e, in_library){
- this.props.uiActions.hideContextMenu()
- if (in_library){
- this.props.spotifyActions.following(this.props.menu.items[0].uri, 'DELETE')
- } else {
- this.props.spotifyActions.following(this.props.menu.items[0].uri, 'PUT')
- }
- }
+ toggleInLibrary(e, in_library) {
+ this.props.uiActions.hideContextMenu();
+ if (in_library) {
+ this.props.spotifyActions.following(this.props.menu.items[0].uri, 'DELETE');
+ } else {
+ this.props.spotifyActions.following(this.props.menu.items[0].uri, 'PUT');
+ }
+ }
- playQueueItem(e){
- this.props.uiActions.hideContextMenu()
- var tracks = this.props.menu.items;
- this.props.mopidyActions.changeTrack(tracks[0].tlid);
- }
+ playQueueItem(e) {
+ this.props.uiActions.hideContextMenu();
+ const tracks = this.props.menu.items;
+ this.props.mopidyActions.changeTrack(tracks[0].tlid);
+ }
- removeFromQueue(e){
- this.props.uiActions.hideContextMenu()
- var tracks = this.props.menu.items;
- var tracks_tlids = [];
- for(var i = 0; i < tracks.length; i++){
- tracks_tlids.push(tracks[i].tlid );
- }
- this.props.mopidyActions.removeTracks(tracks_tlids);
- }
+ removeFromQueue(e) {
+ this.props.uiActions.hideContextMenu();
+ const tracks = this.props.menu.items;
+ const tracks_tlids = [];
+ for (let i = 0; i < tracks.length; i++) {
+ tracks_tlids.push(tracks[i].tlid);
+ }
+ this.props.mopidyActions.removeTracks(tracks_tlids);
+ }
- playURIs(e){
- this.props.uiActions.hideContextMenu();
- this.props.mopidyActions.playURIs(this.props.menu.uris, this.props.menu.tracklist_uri);
- }
+ playURIs(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.mopidyActions.playURIs(this.props.menu.uris, this.props.menu.tracklist_uri);
+ }
- playPlaylist(e){
- this.props.uiActions.hideContextMenu();
- this.props.mopidyActions.playPlaylist(this.props.menu.uris[0]);
- }
+ playPlaylist(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.mopidyActions.playPlaylist(this.props.menu.uris[0]);
+ }
- enqueuePlaylist(e, play_next = false){
- this.props.uiActions.hideContextMenu();
- this.props.mopidyActions.enqueuePlaylist(this.props.menu.uris[0], play_next);
- }
+ enqueuePlaylist(e, play_next = false) {
+ this.props.uiActions.hideContextMenu();
+ this.props.mopidyActions.enqueuePlaylist(this.props.menu.uris[0], play_next);
+ }
- shufflePlayPlaylist(e){
- this.props.uiActions.hideContextMenu();
- this.props.mopidyActions.playPlaylist(this.props.menu.uris[0], true);
- }
+ shufflePlayPlaylist(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.mopidyActions.playPlaylist(this.props.menu.uris[0], true);
+ }
- playArtistTopTracks(e){
- this.props.uiActions.hideContextMenu();
- this.props.spotifyActions.playArtistTopTracks(this.props.menu.uris[0]);
- }
+ playArtistTopTracks(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.spotifyActions.playArtistTopTracks(this.props.menu.uris[0]);
+ }
- addToQueue(e, play_next = false){
- this.props.uiActions.hideContextMenu();
- this.props.mopidyActions.enqueueURIs(this.props.menu.uris, this.props.menu.tracklist_uri, play_next);
- }
+ addToQueue(e, play_next = false) {
+ this.props.uiActions.hideContextMenu();
+ this.props.mopidyActions.enqueueURIs(this.props.menu.uris, this.props.menu.tracklist_uri, play_next);
+ }
- addTracksToPlaylist(e, playlist_uri){
- this.props.uiActions.hideContextMenu();
- this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.menu.uris);
- }
+ addTracksToPlaylist(e, playlist_uri) {
+ this.props.uiActions.hideContextMenu();
+ this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.menu.uris);
+ }
- toggleLoved(e, is_loved){
- this.props.uiActions.hideContextMenu();
- if (is_loved){
- this.props.lastfmActions.unloveTrack(this.props.menu.items[0].uri);
- } else {
- this.props.lastfmActions.loveTrack(this.props.menu.items[0].uri);
- }
- }
+ toggleLoved(e, is_loved) {
+ this.props.uiActions.hideContextMenu();
+ if (is_loved) {
+ this.props.lastfmActions.unloveTrack(this.props.menu.items[0].uri);
+ } else {
+ this.props.lastfmActions.loveTrack(this.props.menu.items[0].uri);
+ }
+ }
- unloveTrack(e){
- this.props.uiActions.hideContextMenu();
- this.props.lastfmActions.unloveTrack(this.props.menu.items[0]);
- }
+ unloveTrack(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.lastfmActions.unloveTrack(this.props.menu.items[0]);
+ }
- removeFromPlaylist(e){
- this.props.uiActions.hideContextMenu();
- this.props.coreActions.removeTracksFromPlaylist(this.props.menu.tracklist_uri, this.props.menu.indexes);
- }
+ removeFromPlaylist(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.coreActions.removeTracksFromPlaylist(this.props.menu.tracklist_uri, this.props.menu.indexes);
+ }
- deletePlaylist(e){
- this.props.uiActions.hideContextMenu();
- this.props.coreActions.deletePlaylist(this.props.menu.uris[0]);
- }
+ deletePlaylist(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.coreActions.deletePlaylist(this.props.menu.uris[0]);
+ }
- startRadio(e){
- this.props.uiActions.hideContextMenu();
- this.props.pusherActions.startRadio(this.props.menu.uris);
- }
+ startRadio(e) {
+ this.props.uiActions.hideContextMenu();
+ this.props.pusherActions.startRadio(this.props.menu.uris);
+ }
- goToRecommendations(e){
- this.props.uiActions.hideContextMenu();
- var uris_string = helpers.arrayOf('uri',this.props.menu.items).join(',');
- this.props.history.push('/discover/recommendations/'+ uris_string );
- }
+ goToRecommendations(e) {
+ this.props.uiActions.hideContextMenu();
+ const uris_string = helpers.arrayOf('uri', this.props.menu.items).join(',');
+ this.props.history.push(`/discover/recommendations/${uris_string}`);
+ }
- goToArtist(e){
- if (!this.props.menu.items || this.props.menu.items.length <= 0 || !this.props.menu.items[0].artists_uris || this.props.menu.items[0].artists_uris.length <= 0){
- return null;
- } else {
- this.props.uiActions.hideContextMenu();
-
- // note: we can only go to one artist (even if this item has multiple artists, just go to the first one)
- this.props.history.push(helpers.buildLink(this.props.menu.items[0].artists_uris[0]));
- }
- }
+ goToArtist(e) {
+ if (!this.props.menu.items || this.props.menu.items.length <= 0 || !this.props.menu.items[0].artists_uris || this.props.menu.items[0].artists_uris.length <= 0) {
+ return null;
+ }
+ this.props.uiActions.hideContextMenu();
- goToUser(e){
- if (!this.props.menu.items || this.props.menu.items.length <= 0 || !this.props.menu.items[0].user_uri){
- return null;
- } else {
- this.props.uiActions.hideContextMenu();
- this.props.history.push(helpers.buildLink(this.props.menu.items[0].user_uri));
- }
- }
+ // note: we can only go to one artist (even if this item has multiple artists, just go to the first one)
+ this.props.history.push(helpers.buildLink(this.props.menu.items[0].artists_uris[0]));
+ }
- goToTrack(e){
- if (!this.props.menu.items || this.props.menu.items.length <= 0){
- return null;
- } else {
- this.props.uiActions.hideContextMenu();
- this.props.history.push(helpers.buildLink(this.props.menu.items[0].uri));
- }
- }
+ goToUser(e) {
+ if (!this.props.menu.items || this.props.menu.items.length <= 0 || !this.props.menu.items[0].user_uri) {
+ return null;
+ }
+ this.props.uiActions.hideContextMenu();
+ this.props.history.push(helpers.buildLink(this.props.menu.items[0].user_uri));
+ }
- copyURIs(e){
- var temp = $(" ");
- $("body").append(temp);
- temp.val(this.props.menu.uris.join(',')).select();
- document.execCommand("copy");
- temp.remove();
+ goToTrack(e) {
+ if (!this.props.menu.items || this.props.menu.items.length <= 0) {
+ return null;
+ }
+ this.props.uiActions.hideContextMenu();
+ this.props.history.push(helpers.buildLink(this.props.menu.items[0].uri));
+ }
- this.props.uiActions.createNotification({content: "Copied "+this.props.menu.uris.length+" URIs"});
- this.props.uiActions.hideContextMenu()
- }
+ copyURIs(e) {
+ const temp = $(' ');
+ $('body').append(temp);
+ temp.val(this.props.menu.uris.join(',')).select();
+ document.execCommand('copy');
+ temp.remove();
- renderTitle(){
- var context = this.getContext();
+ this.props.uiActions.createNotification({ content: `Copied ${this.props.menu.uris.length} URIs` });
+ this.props.uiActions.hideContextMenu();
+ }
- if (context.items_count > 1){
- return (
-
-
- {context.items_count} {context.nice_name}{context.items_count > 1 ? 's' : null} selected {this.props.uiActions.setSelectedTracks([]); this.props.uiActions.hideContextMenu()}}>
-
-
- )
- }
+ renderTitle() {
+ const context = this.getContext();
- if (context.items_count == 1 && context.name == 'queue-track' && context.item !== undefined){
- if (this.props.queue_metadata["tlid_"+context.item.tlid] !== undefined){
- var metadata = this.props.queue_metadata["tlid_"+context.item.tlid];
+ if (context.items_count > 1) {
+ return (
+
+
+ {context.items_count}
+ {' '}
+ {context.nice_name}
+ {context.items_count > 1 ? 's' : null}
+ {' '}
+selected
+ { this.props.uiActions.setSelectedTracks([]); this.props.uiActions.hideContextMenu(); }}>
+
+
+ );
+ }
- if (metadata.added_from && metadata.added_by){
- var type = (metadata.added_from ? helpers.uriType(metadata.added_from) : null);
+ if (context.items_count == 1 && context.name == 'queue-track' && context.item !== undefined) {
+ if (this.props.queue_metadata[`tlid_${context.item.tlid}`] !== undefined) {
+ const metadata = this.props.queue_metadata[`tlid_${context.item.tlid}`];
- switch (type){
- case "discover":
- var link = discover
- break;
+ if (metadata.added_from && metadata.added_by) {
+ const type = (metadata.added_from ? helpers.uriType(metadata.added_from) : null);
- case "browse":
- var link = browse
- break;
+ switch (type) {
+ case 'discover':
+ var link = discover ;
+ break;
- case "search":
- var link = search
- break;
+ case 'browse':
+ var link = browse ;
+ break;
- default:
- var link = {type} ;
- }
+ case 'search':
+ var link = search ;
+ break;
- return (
-
-
- {metadata.added_by} added from {link}
-
-
- )
- }
- }
- }
+ default:
+ var link = {type} ;
+ }
- if (context.name == 'custom'){
- if (!this.props.menu.title){
- return null;
- }
+ return (
+
+
+ {metadata.added_by}
+ {' '}
+added from
+ {link}
+
+
+ );
+ }
+ }
+ }
- return (
-
-
- {this.props.menu.title}
-
-
- )
- }
- }
+ if (context.name == 'custom') {
+ if (!this.props.menu.title) {
+ return null;
+ }
- setSubmenu(name){
+ return (
+
+
+ {this.props.menu.title}
+
+
+ );
+ }
+ }
- if (this.state.submenu !== name && name == 'add-to-playlist'){
- if (!this.props.spotify_library_playlists_loaded_all){
- this.props.spotifyActions.getLibraryPlaylists()
- }
- if (!this.props.mopidy_library_playlists_loaded_all){
- this.props.mopidyActions.getLibraryPlaylists()
- }
- }
+ setSubmenu(name) {
+ if (this.state.submenu !== name && name == 'add-to-playlist') {
+ if (!this.props.spotify_library_playlists_loaded_all) {
+ this.props.spotifyActions.getLibraryPlaylists();
+ }
+ if (!this.props.mopidy_library_playlists_loaded_all) {
+ this.props.mopidyActions.getLibraryPlaylists();
+ }
+ }
- this.setState({submenu: name});
- }
+ this.setState({ submenu: name });
+ }
- renderSubmenu(){
- var list = null;
- var loader = null;
+ renderSubmenu() {
+ let list = null;
+ let loader = null;
- switch (this.state.submenu){
+ switch (this.state.submenu) {
+ case 'add-to-playlist':
- case 'add-to-playlist':
+ var playlists = [];
+ for (const uri in this.props.playlists) {
+ if (this.props.playlists[uri].can_edit) playlists.push(this.props.playlists[uri]);
+ }
- var playlists = []
- for (var uri in this.props.playlists){
- if (this.props.playlists[uri].can_edit) playlists.push(this.props.playlists[uri])
- }
+ playlists = helpers.sortItems(playlists, 'name');
- playlists = helpers.sortItems(playlists, 'name')
+ if (this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR && this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status == 'running') {
+ loader = (
+
+ );
+ }
- if (this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR && this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status == 'running'){
- loader = (
-
- )
- }
+ list = No writable playlists ;
+ if (playlists.length > 0) {
+ list = playlists.map((playlist) => (
+
+ this.addTracksToPlaylist(e, playlist.uri)}>
+ { playlist.name }
+
+
+ ));
+ }
+ }
- list = No writable playlists
- if (playlists.length > 0){
- list = playlists.map(playlist => {
- return (
-
- this.addTracksToPlaylist(e,playlist.uri) }>
- { playlist.name }
-
-
- )
- })
- }
+ return (
+
+ );
+ }
- }
+ renderItems() {
+ const context = this.getContext();
- return (
-
- );
- }
+ const play_uris = (
+
+ );
- renderItems(){
- var context = this.getContext()
+ const play_playlist = (
+
+ );
- var play_uris = (
-
- )
+ const shuffle_play_playlist = (
+
+ );
- var play_playlist = (
-
- )
+ const play_queue_item = (
+
+ );
- var shuffle_play_playlist = (
-
- )
+ const play_uris_next = (
+
+ );
- var play_queue_item = (
-
- )
+ const play_artist_top_tracks = (
+
+ );
- var play_uris_next = (
-
- )
+ const add_to_queue = (
+
+ );
- var play_artist_top_tracks = (
-
- )
+ const add_playlist_to_queue = (
+
+ );
- var add_to_queue = (
-
- )
+ const play_playlist_next = (
+
+ );
- var add_playlist_to_queue = (
-
- )
+ const add_to_playlist = (
+
+ );
- var play_playlist_next = (
-
- )
+ var toggle_in_library = (
+
+ );
- var add_to_playlist = (
-
- )
-
- var toggle_in_library = (
-
- )
-
- if (!this.props.spotify_authorized){
- var toggle_in_library = null;
- } else if (helpers.isLoading(this.props.load_queue,['spotify_me/tracks/contains','spotify_me/playlists/contains','spotify_me/albums/contains','spotify_me/artists/contains'])){
- var toggle_in_library = (
-
+ );
+ } else {
+ var toggle_in_library = (
+
+ );
+ }
- if (!this.props.lastfm_authorized){
- var toggle_loved = null;
- } else if (helpers.isLoading(this.props.load_queue,['lastfm_track.getInfo'])){
- var toggle_loved = (
-
+ );
+ } else {
+ var toggle_loved = (
+
+ );
+ }
- var go_to_artist = (
-
- )
+ const go_to_artist = (
+
+ );
- var go_to_user = (
-
- )
+ const go_to_user = (
+
+ );
- var go_to_track = (
-
- )
+ const go_to_track = (
+
+ );
- var go_to_recommendations = (
-
- )
+ const go_to_recommendations = (
+
+ );
- var start_radio = (
-
- )
+ const start_radio = (
+
+ );
- var remove_from_queue = (
-
- )
+ const remove_from_queue = (
+
+ );
- var remove_from_playlist = (
-
- )
+ const remove_from_playlist = (
+
+ );
- var edit_playlist = (
-
-
- Edit
-
-
- )
+ const edit_playlist = (
+
+
+ Edit
+
+
+ );
- var delete_playlist = (
-
- )
+ const delete_playlist = (
+
+ );
- var copy_uris = (
-
- )
+ const copy_uris = (
+
+ );
- switch (context.name){
+ switch (context.name) {
+ case 'album':
+ return (
+
+ {play_uris}
+ {play_uris_next}
+ {add_to_queue}
+ {this.canBeInLibrary() ?
: null}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+
+ {go_to_artist}
+ {copy_uris}
+
+ );
+ break;
- case 'album':
- return (
-
- {play_uris}
- {play_uris_next}
- {add_to_queue}
- {this.canBeInLibrary() ?
: null}
- {this.canBeInLibrary() ? toggle_in_library : null}
-
- {go_to_artist}
- {copy_uris}
-
- )
- break
+ case 'artist':
+ return (
+
+ {context.source == 'spotify' ? play_artist_top_tracks : null}
+ {context.source == 'spotify' ? start_radio : null}
+ {this.canBeInLibrary() ?
: null}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+
+ {context.source == 'spotify' ? go_to_recommendations : null}
+ {copy_uris}
+
+ );
+ break;
- case 'artist':
- return (
-
- {context.source == 'spotify' ? play_artist_top_tracks : null}
- {context.source == 'spotify' ? start_radio : null}
- {this.canBeInLibrary() ?
: null}
- {this.canBeInLibrary() ? toggle_in_library : null}
-
- {context.source == 'spotify' ? go_to_recommendations : null}
- {copy_uris}
-
- )
- break
+ case 'playlist':
+ return (
+
+ {play_playlist}
+ {play_playlist_next}
+ {shuffle_play_playlist}
+ {add_playlist_to_queue}
+ {this.canBeInLibrary() ?
: null}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+
+ {context.source == 'spotify' ? go_to_user : null}
+ {copy_uris}
+ {context.items_count == 1 && context.item.can_edit ? (
+
+
+ {edit_playlist}
+ {delete_playlist}
+
+ ) : null}
+
+ );
+ break;
- case 'playlist':
- return (
-
- {play_playlist}
- {play_playlist_next}
- {shuffle_play_playlist}
- {add_playlist_to_queue}
- {this.canBeInLibrary() ?
: null}
- {this.canBeInLibrary() ? toggle_in_library : null}
-
- {context.source == 'spotify' ? go_to_user : null}
- {copy_uris}
- {context.items_count == 1 && context.item.can_edit ?
-
- {edit_playlist}
- {delete_playlist}
-
: null}
-
- )
- break
+ case 'queue-track':
+ return (
+
+ {context.items_count == 1 ? play_queue_item : null}
+
+ {add_to_playlist}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+ {toggle_loved}
+
+ {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null}
+ {context.items_count == 1 ? go_to_track : null}
+ {copy_uris}
+
+ {remove_from_queue}
+
+ );
+ break;
- case 'queue-track':
- return (
-
- {context.items_count == 1 ? play_queue_item : null}
-
- {add_to_playlist}
- {this.canBeInLibrary() ? toggle_in_library : null}
- {toggle_loved}
-
- {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null}
- {context.items_count == 1 ? go_to_track : null}
- {copy_uris}
-
- {remove_from_queue}
-
- )
- break
+ case 'editable-playlist-track':
+ return (
+
+ {play_uris}
+ {play_uris_next}
+ {add_to_queue}
+ {context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
+
+ {add_to_playlist}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+ {toggle_loved}
+
+ {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null}
+ {context.items_count == 1 ? go_to_track : null}
+ {copy_uris}
+
+ {remove_from_playlist}
+
+ );
+ break;
- case 'editable-playlist-track':
- return (
-
- {play_uris}
- {play_uris_next}
- {add_to_queue}
- {context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
-
- {add_to_playlist}
- {this.canBeInLibrary() ? toggle_in_library : null}
- {toggle_loved}
-
- {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null}
- {context.items_count == 1 ? go_to_track : null}
- {copy_uris}
-
- {remove_from_playlist}
-
- )
- break
+ default:
+ return (
+
+ {play_uris}
+ {play_uris_next}
+ {add_to_queue}
+ {context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
+
+ {add_to_playlist}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+ {toggle_loved}
+
+ {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null}
+ {context.items_count == 1 ? go_to_track : null}
+
+ {copy_uris}
+
+ );
+ break;
+ }
+ }
- default:
- return (
-
- {play_uris}
- {play_uris_next}
- {add_to_queue}
- {context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
-
- {add_to_playlist}
- {this.canBeInLibrary() ? toggle_in_library : null}
- {toggle_loved}
-
- {context.source == 'spotify' && context.items_count <= 5 ? go_to_recommendations : null}
- {context.items_count == 1 ? go_to_track : null}
-
- {copy_uris}
-
- )
- break
- }
- }
+ render() {
+ if (!this.props.menu) {
+ return null;
+ }
- render(){
- if (!this.props.menu){
- return null;
- }
+ const style = {
+ left: this.props.menu.position_x,
+ top: this.props.menu.position_y,
+ };
+ const height = 200; // TODO: use jquery to detect height
+ let className = `context-menu ${this.props.menu.context}`;
+ if (this.state.submenu) {
+ className += ' context-menu--submenu-expanded';
+ }
- var style = {
- left: this.props.menu.position_x,
- top: this.props.menu.position_y,
- }
- var height = 200 // TODO: use jquery to detect height
- var className = "context-menu "+this.props.menu.context
- if (this.state.submenu){
- className += ' context-menu--submenu-expanded';
- }
-
- if (this.props.menu.closing){
- className += ' context-menu--closing';
- }
+ if (this.props.menu.closing) {
+ className += ' context-menu--closing';
+ }
- if (this.props.menu.position_x > (window.innerWidth - 174)){
- style.left = 'auto';
- style.right = 10;
- }
+ if (this.props.menu.position_x > (window.innerWidth - 174)) {
+ style.left = 'auto';
+ style.right = 10;
+ }
- if (this.props.menu.position_y > (window.innerHeight - height)){
- style.top = 'auto';
- style.bottom = 10;
- }
+ if (this.props.menu.position_y > (window.innerHeight - height)) {
+ style.top = 'auto';
+ style.bottom = 10;
+ }
- return (
-
- );
- }
+ return (
+
- this.play()}>
+ this.play()}>
Play
- {helpers.uriSource(this.props.uri) == "spotify" ? (
+ {helpers.uriSource(this.props.uri) == 'spotify' ? (
) : null}
- this.handleContextMenu(e)} />
+ this.handleContextMenu(e)} />
@@ -253,7 +263,9 @@ export class Album extends React.Component {
{album.wiki}
- Published: {album.wiki_publish_date}
+ Published:
+ {' '}
+ {album.wiki_publish_date}
@@ -264,9 +276,9 @@ export class Album extends React.Component {
}
const mapStateToProps = (state, ownProps) => {
- var uri = decodeURIComponent(ownProps.match.params.uri);
+ const uri = decodeURIComponent(ownProps.match.params.uri);
return {
- uri: uri,
+ uri,
slim_mode: state.ui.slim_mode,
theme: state.ui.theme,
load_queue: state.ui.load_queue,
@@ -280,21 +292,19 @@ const mapStateToProps = (state, ownProps) => {
spotify_library_albums: state.spotify.library_albums,
local_library_albums: state.mopidy.library_albums,
spotify_authorized: state.spotify.authorization,
- mopidy_connected: state.mopidy.connected
+ mopidy_connected: state.mopidy.connected,
};
};
-const mapDispatchToProps = dispatch => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch),
- lastfmActions: bindActionCreators(lastfmActions, dispatch)
- };
-};
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+ lastfmActions: bindActionCreators(lastfmActions, dispatch),
+});
export default connect(
mapStateToProps,
- mapDispatchToProps
+ mapDispatchToProps,
)(Album);
diff --git a/src/js/views/Artist.js b/src/js/views/Artist.js
index 1fe01da1..44d221a7 100755
--- a/src/js/views/Artist.js
+++ b/src/js/views/Artist.js
@@ -7,455 +7,508 @@ import { Route, Switch } from 'react-router-dom';
import ErrorMessage from '../components/ErrorMessage';
import Link from '../components/Link';
-import LazyLoadListener from '../components/LazyLoadListener'
-import TrackList from '../components/TrackList'
-import AlbumGrid from '../components/AlbumGrid'
-import Thumbnail from '../components/Thumbnail'
-import Parallax from '../components/Parallax'
-import ArtistGrid from '../components/ArtistGrid'
-import RelatedArtists from '../components/RelatedArtists'
-import FollowButton from '../components/Fields/FollowButton'
-import ContextMenuTrigger from '../components/ContextMenuTrigger'
-import DropdownField from '../components/Fields/DropdownField'
-import Icon from '../components/Icon'
+import LazyLoadListener from '../components/LazyLoadListener';
+import TrackList from '../components/TrackList';
+import AlbumGrid from '../components/AlbumGrid';
+import Thumbnail from '../components/Thumbnail';
+import Parallax from '../components/Parallax';
+import ArtistGrid from '../components/ArtistGrid';
+import RelatedArtists from '../components/RelatedArtists';
+import FollowButton from '../components/Fields/FollowButton';
+import ContextMenuTrigger from '../components/ContextMenuTrigger';
+import DropdownField from '../components/Fields/DropdownField';
+import Icon from '../components/Icon';
-import * as helpers from '../helpers'
-import * as coreActions from '../services/core/actions'
-import * as uiActions from '../services/ui/actions'
-import * as mopidyActions from '../services/mopidy/actions'
-import * as pusherActions from '../services/pusher/actions'
-import * as lastfmActions from '../services/lastfm/actions'
-import * as spotifyActions from '../services/spotify/actions'
+import * as helpers from '../helpers';
+import * as coreActions from '../services/core/actions';
+import * as uiActions from '../services/ui/actions';
+import * as mopidyActions from '../services/mopidy/actions';
+import * as pusherActions from '../services/pusher/actions';
+import * as lastfmActions from '../services/lastfm/actions';
+import * as spotifyActions from '../services/spotify/actions';
-class Artist extends React.Component{
+class Artist extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.setWindowTitle();
+ this.props.coreActions.loadArtist(this.props.uri);
+ }
- componentDidMount(){
- this.setWindowTitle();
- this.props.coreActions.loadArtist(this.props.uri);
- }
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.uri != this.props.uri) {
+ this.props.coreActions.loadArtist(nextProps.uri);
+ } else if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
+ if (helpers.uriSource(this.props.uri) != 'spotify') {
+ this.props.coreActions.loadArtist(nextProps.uri);
+ }
+ }
- componentWillReceiveProps(nextProps){
+ if (!this.props.artist && nextProps.artist) {
+ this.setWindowTitle(nextProps.artist);
+ }
- if (nextProps.uri != this.props.uri){
- this.props.coreActions.loadArtist(nextProps.uri);
+ if (this.props.uri !== nextProps.uri && nextProps.artist) {
+ this.setWindowTitle(nextProps.artist);
+ }
+ }
- } else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
- if (helpers.uriSource(this.props.uri ) != 'spotify'){
- this.props.coreActions.loadArtist(nextProps.uri);
- }
- }
+ setWindowTitle(artist = this.props.artist) {
+ if (artist) {
+ this.props.uiActions.setWindowTitle(`${artist.name} (artist)`);
+ } else {
+ this.props.uiActions.setWindowTitle('Artist');
+ }
+ }
- if (!this.props.artist && nextProps.artist){
- this.setWindowTitle(nextProps.artist);
- }
+ handleContextMenu(e) {
+ const data = {
+ e,
+ context: 'artist',
+ items: [this.props.artist],
+ uris: [this.props.uri],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- if (this.props.uri !== nextProps.uri && nextProps.artist){
- this.setWindowTitle(nextProps.artist);
- }
- }
+ loadMore() {
+ this.props.spotifyActions.getMore(
+ this.props.artist.albums_more,
+ {
+ parent_type: 'artist',
+ parent_key: this.props.uri,
+ records_type: 'album',
+ },
+ );
+ }
- setWindowTitle(artist = this.props.artist){
- if (artist){
- this.props.uiActions.setWindowTitle(artist.name+" (artist)");
- } else{
- this.props.uiActions.setWindowTitle("Artist");
- }
- }
+ inLibrary() {
+ const library = `${helpers.uriSource(this.props.uri)}_library_artists`;
+ return (this.props[library] && this.props[library].indexOf(this.props.uri) > -1);
+ }
- handleContextMenu(e){
- var data = {
- e: e,
- context: 'artist',
- items: [this.props.artist],
- uris: [this.props.uri]
- }
- this.props.uiActions.showContextMenu(data);
- }
+ setSort(value) {
+ let reverse = false;
+ if (value !== null && this.props.sort == value) {
+ reverse = !this.props.sort_reverse;
+ }
- loadMore(){
- this.props.spotifyActions.getMore(
- this.props.artist.albums_more,
- {
- parent_type: 'artist',
- parent_key: this.props.uri,
- records_type: 'album'
- }
- );
- }
+ const data = {
+ artist_albums_sort_reverse: reverse,
+ artist_albums_sort: value,
+ };
+ this.props.uiActions.set(data);
+ }
- inLibrary(){
- var library = helpers.uriSource(this.props.uri)+'_library_artists'
- return (this.props[library] && this.props[library].indexOf(this.props.uri) > -1)
- }
+ setFilter(value) {
+ this.props.uiActions.set({ artist_albums_filter: value });
+ }
- setSort(value){
- var reverse = false;
- if (value !== null && this.props.sort == value){
- reverse = !this.props.sort_reverse;
- }
+ renderOverview() {
+ const artist = helpers.collate(
+ this.props.artist,
+ {
+ artists: this.props.artists,
+ albums: this.props.albums,
+ tracks: this.props.tracks,
+ },
+ );
- var data = {
- artist_albums_sort_reverse: reverse,
- artist_albums_sort: value
- }
- this.props.uiActions.set(data);
- }
+ if (this.props.sort && artist.albums) {
+ artist.albums = helpers.sortItems(artist.albums, this.props.sort, this.props.sort_reverse);
+ }
- setFilter(value){
- this.props.uiActions.set({artist_albums_filter: value});
- }
+ if (this.props.filter && artist.albums) {
+ artist.albums = helpers.applyFilter('type', this.props.filter, artist.albums);
+ }
- renderOverview(){
- var artist = helpers.collate(
- this.props.artist,
- {
- artists: this.props.artists,
- albums: this.props.albums,
- tracks: this.props.tracks
- }
- );
+ const sort_options = [
+ {
+ value: null,
+ label: 'Default',
+ },
+ {
+ value: 'name',
+ label: 'Name',
+ },
+ {
+ value: 'release_date',
+ label: 'Date',
+ },
+ {
+ value: 'tracks_uris.length',
+ label: 'Tracks',
+ },
+ ];
- if (this.props.sort && artist.albums){
- artist.albums = helpers.sortItems(artist.albums, this.props.sort, this.props.sort_reverse);
- }
+ const filter_options = [
+ {
+ value: null,
+ label: 'All',
+ },
+ {
+ value: 'album',
+ label: 'Albums',
+ },
+ {
+ value: 'single',
+ label: 'Singles',
+ },
+ {
+ value: 'compilation',
+ label: 'Compilations',
+ },
+ ];
- if (this.props.filter && artist.albums){
- artist.albums = helpers.applyFilter('type', this.props.filter, artist.albums);
- }
+ if (!artist.tracks_uris || (artist.tracks_uris && !artist.tracks) || (artist.tracks_uris.length !== artist.tracks.length)) {
+ var is_loading_tracks = true;
+ } else {
+ var is_loading_tracks = false;
+ }
- var sort_options = [
- {
- value: null,
- label: 'Default'
- },
- {
- value: 'name',
- label: 'Name'
- },
- {
- value: 'release_date',
- label: 'Date'
- },
- {
- value: 'tracks_uris.length',
- label: 'Tracks'
- }
- ];
+ return (
+
+
0 ? '70' : '100'}`}>
+ {artist.tracks ?
Top tracks : null}
+
+
+
+
+
- var filter_options = [
- {
- value: null,
- label: 'All'
- },
- {
- value: 'album',
- label: 'Albums'
- },
- {
- value: 'single',
- label: 'Singles'
- },
- {
- value: 'compilation',
- label: 'Compilations'
- }
- ];
+
- if (!artist.tracks_uris || (artist.tracks_uris && !artist.tracks) || (artist.tracks_uris.length !== artist.tracks.length)){
- var is_loading_tracks = true;
- } else {
- var is_loading_tracks = false;
- }
+ {artist.related_artists && artist.related_artists.length > 0 ? (
+
+
Related artists
+
+
All related artists
+
+ ) : null}
- return (
-
-
0 ? "70" : "100")}>
- {artist.tracks ?
Top tracks : null}
-
-
-
-
-
+
-
-
- {artist.related_artists && artist.related_artists.length > 0 ?
Related artists
All related artists
: null}
-
-
-
- {artist.albums ?
-
+ {artist.albums ? (
+ : null}
-
- );
- }
+
+
+ this.loadMore()}
+ />
+
+
+ ) : null}
+
+ );
+ }
- renderTracks(){
- var artist = helpers.collate(
- this.props.artist,
- {
- artists: this.props.artists,
- tracks: this.props.tracks
- }
- );
+ renderTracks() {
+ const artist = helpers.collate(
+ this.props.artist,
+ {
+ artists: this.props.artists,
+ tracks: this.props.tracks,
+ },
+ );
- if (!artist.tracks_uris || (artist.tracks_uris && !artist.tracks) || (artist.tracks_uris.length !== artist.tracks.length)){
- var is_loading_tracks = true;
- } else {
- var is_loading_tracks = false;
- }
+ if (!artist.tracks_uris || (artist.tracks_uris && !artist.tracks) || (artist.tracks_uris.length !== artist.tracks.length)) {
+ var is_loading_tracks = true;
+ } else {
+ var is_loading_tracks = false;
+ }
- return (
-
-
-
- )
- }
+ return (
+
+
+
+ );
+ }
- renderRelatedArtists(){
- var artist = helpers.collate(
- this.props.artist,
- {
- artists: this.props.artists
- }
- );
+ renderRelatedArtists() {
+ const artist = helpers.collate(
+ this.props.artist,
+ {
+ artists: this.props.artists,
+ },
+ );
- return (
-
- )
- }
+ return (
+
+ );
+ }
- renderAbout(){
- var artist = helpers.collate(
- this.props.artist,
- {
- artists: this.props.artists
- }
- );
+ renderAbout() {
+ const artist = helpers.collate(
+ this.props.artist,
+ {
+ artists: this.props.artists,
+ },
+ );
- var thumbnails = [];
- if (artist.images && artist.images.length > 0){
- for (var images of artist.images){
+ const thumbnails = [];
+ if (artist.images && artist.images.length > 0) {
+ for (const images of artist.images) {
+ // Capture potential 'null' images
+ // TODO: Prevent these from existing in the first place
+ if (images.huge) {
+ thumbnails.push(
+
+
+
,
+ );
+ }
+ }
+ }
- // Capture potential 'null' images
- // TODO: Prevent these from existing in the first place
- if (images.huge){
- thumbnails.push(
-
-
-
- );
- }
- }
- }
+ return (
+
- return (
-
+
+ {thumbnails}
+ {artist.followers ? (
+
+
+
+ {artist.followers.toLocaleString()}
+ {' '}
+followers
+
+
+ ) : null}
+ {artist.popularity ? (
+
+
+
+ {artist.popularity }
+% popularity
+
+
+ ) : null}
+ {artist.listeners ? (
+
+
+
+ { artist.listeners.toLocaleString() }
+ {' '}
+listeners
+
+
+ ) : null }
+
-
- {thumbnails}
- {artist.followers ?
{artist.followers.toLocaleString()} followers
: null}
- {artist.popularity ?
{artist.popularity }% popularity
: null}
- {artist.listeners ?
{ artist.listeners.toLocaleString() } listeners
: null }
-
+
+
+ { artist.biography ? (
+
+
{artist.biography}
+
+
+Published:
+ { artist.biography_publish_date }
+
+
+
+ ) : null }
+
+
+
+ );
+ }
-
-
- { artist.biography ? {artist.biography}
-
Published: { artist.biography_publish_date }
-
: null }
-
-
-
- );
- }
+ render() {
+ const scheme = helpers.uriSource(this.props.uri);
- render(){
- var scheme = helpers.uriSource(this.props.uri);
+ if (!this.props.artist) {
+ if (helpers.isLoading(this.props.load_queue, [`spotify_artists/${helpers.getFromUri('artistid', this.props.uri)}`, 'lastfm_method=artist.getInfo'])) {
+ return (
+
+ );
+ }
+ return (
+
+
+Could not find artist with URI "
+ {encodeURIComponent(this.props.uri)}
+"
+
+
+ );
+ }
- if (!this.props.artist){
- if (helpers.isLoading(this.props.load_queue,['spotify_artists/'+helpers.getFromUri('artistid',this.props.uri), 'lastfm_method=artist.getInfo'])){
- return (
-
- )
- } else {
- return (
-
- Could not find artist with URI "{encodeURIComponent(this.props.uri)}"
-
- );
- }
- }
+ if (this.props.artist && this.props.artist.images && this.props.artist.images.length > 0) {
+ var image = this.props.artist.images[0].huge;
+ } else {
+ var image = null;
+ }
- if (this.props.artist && this.props.artist.images && this.props.artist.images.length > 0){
- var image = this.props.artist.images[0].huge;
- } else {
- var image = null;
- }
+ const is_spotify = (scheme == 'spotify');
- var is_spotify = (scheme == 'spotify')
+ if (this.props.artist.tracks_uris && this.props.artist.tracks_uris.length > 0) {
+ var uris_to_play = this.props.artist.tracks_uris;
+ } else {
+ var uris_to_play = this.props.artist.albums_uris;
+ }
- if (this.props.artist.tracks_uris && this.props.artist.tracks_uris.length > 0){
- var uris_to_play = this.props.artist.tracks_uris
- } else {
- var uris_to_play = this.props.artist.albums_uris
- }
+ return (
+
+
- return (
-
-
+
-
+
+
-
-
+
+
+
-
-
-
-
-
-
{this.props.artist ? this.props.artist.name : null}
-
- this.props.mopidyActions.playURIs(uris_to_play, this.props.artist.uri)}>Play
- {is_spotify ? : null}
- this.handleContextMenu(e)} />
-
-
-
-
-
-
-
-
-
- {this.renderRelatedArtists()}
-
-
- {this.renderTracks()}
-
-
- {this.renderAbout()}
-
-
- {this.renderOverview()}
-
-
-
-
- );
- }
+
+
{this.props.artist ? this.props.artist.name : null}
+
+ this.props.mopidyActions.playURIs(uris_to_play, this.props.artist.uri)}>Play
+ {is_spotify ? : null}
+ this.handleContextMenu(e)} />
+
+
+
+
+
+
+
+
+
+ {this.renderRelatedArtists()}
+
+
+ {this.renderTracks()}
+
+
+ {this.renderAbout()}
+
+
+ {this.renderOverview()}
+
+
+
+
+ );
+ }
}
const mapStateToProps = (state, ownProps) => {
- var uri = decodeURIComponent(ownProps.match.params.uri);
- return {
- uri: uri,
- theme: state.ui.theme,
- slim_mode: state.ui.slim_mode,
- load_queue: state.ui.load_queue,
- artist: (state.core.artists[uri] !== undefined ? state.core.artists[uri] : false),
- tracks: state.core.tracks,
- artists: state.core.artists,
- spotify_library_artists: state.spotify.library_artists,
- local_library_artists: state.mopidy.library_artists,
- albums: (state.core.albums ? state.core.albums : []),
- filter: (state.ui.artist_albums_filter ? state.ui.artist_albums_filter : null),
- sort: (state.ui.artist_albums_sort ? state.ui.artist_albums_sort : null),
- sort_reverse: (state.ui.artist_albums_sort_reverse ? true : false),
- spotify_authorized: state.spotify.authorization,
- mopidy_connected: state.mopidy.connected
- }
-}
+ const uri = decodeURIComponent(ownProps.match.params.uri);
+ return {
+ uri,
+ theme: state.ui.theme,
+ slim_mode: state.ui.slim_mode,
+ load_queue: state.ui.load_queue,
+ artist: (state.core.artists[uri] !== undefined ? state.core.artists[uri] : false),
+ tracks: state.core.tracks,
+ artists: state.core.artists,
+ spotify_library_artists: state.spotify.library_artists,
+ local_library_artists: state.mopidy.library_artists,
+ albums: (state.core.albums ? state.core.albums : []),
+ filter: (state.ui.artist_albums_filter ? state.ui.artist_albums_filter : null),
+ sort: (state.ui.artist_albums_sort ? state.ui.artist_albums_sort : null),
+ sort_reverse: (!!state.ui.artist_albums_sort_reverse),
+ spotify_authorized: state.spotify.authorization,
+ mopidy_connected: state.mopidy.connected,
+ };
+};
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- lastfmActions: bindActionCreators(lastfmActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ lastfmActions: bindActionCreators(lastfmActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(Artist)
+export default connect(mapStateToProps, mapDispatchToProps)(Artist);
diff --git a/src/js/views/Debug.js b/src/js/views/Debug.js
index 5fa0756a..3be4cd3e 100755
--- a/src/js/views/Debug.js
+++ b/src/js/views/Debug.js
@@ -1,237 +1,238 @@
-import React from 'react'
-import { connect } from 'react-redux'
+import React from 'react';
+import { connect } from 'react-redux';
-import { bindActionCreators } from 'redux'
+import { bindActionCreators } from 'redux';
-import Header from '../components/Header'
-import Thumbnail from '../components/Thumbnail'
-import Icon from '../components/Icon'
+import Header from '../components/Header';
+import Thumbnail from '../components/Thumbnail';
+import Icon from '../components/Icon';
import Link from '../components/Link';
-import * as uiActions from '../services/ui/actions'
-import * as pusherActions from '../services/pusher/actions'
-import * as mopidyActions from '../services/mopidy/actions'
-import * as spotifyActions from '../services/spotify/actions'
+import * as uiActions from '../services/ui/actions';
+import * as pusherActions from '../services/pusher/actions';
+import * as mopidyActions from '../services/mopidy/actions';
+import * as spotifyActions from '../services/spotify/actions';
-class Debug extends React.Component{
+class Debug extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ mopidy_call: 'playlists.asList',
+ mopidy_data: '{}',
+ pusher_data: '{"method":"get_config"}',
+ access_token: this.props.access_token,
+ toggling_test_mode: false,
+ };
+ }
- constructor(props){
- super(props);
- this.state = {
- mopidy_call: 'playlists.asList',
- mopidy_data: '{}',
- pusher_data: '{"method":"get_config"}',
- access_token: this.props.access_token,
- toggling_test_mode: false
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Debug');
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Debug");
- }
+ callMopidy(e) {
+ e.preventDefault();
+ this.props.mopidyActions.debug(this.state.mopidy_call, JSON.parse(this.state.mopidy_data));
+ }
- callMopidy(e){
- e.preventDefault()
- this.props.mopidyActions.debug(this.state.mopidy_call, JSON.parse(this.state.mopidy_data) )
- }
+ callPusher(e) {
+ e.preventDefault();
+ this.props.pusherActions.debug(JSON.parse(this.state.pusher_data));
+ }
- callPusher(e){
- e.preventDefault()
- this.props.pusherActions.debug(JSON.parse(this.state.pusher_data) )
- }
+ toggleTestMode(e) {
+ this.setState({ toggling_test_mode: true });
+ this.props.uiActions.set({ test_mode: !this.props.test_mode });
- toggleTestMode(e){
- this.setState({toggling_test_mode: true});
- this.props.uiActions.set({ test_mode: !this.props.test_mode });
+ // Wait a second to allow state to update, and then refresh
+ setTimeout(location.reload(), 1000);
+ }
- // Wait a second to allow state to update, and then refresh
- setTimeout(location.reload(), 1000);
- }
+ render() {
+ const options = (
+ this.props.history.push('/settings')}>
+
+Back
+
+ );
- render(){
-
- var options = (
- this.props.history.push('/settings')}>
- Back
-
- )
-
- return (
-
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- connection_id: state.pusher.connection_id,
- access_token: (state.spotify.access_token ? state.spotify.access_token : ''),
- log_actions: (state.ui.log_actions ? state.ui.log_actions : false),
- log_pusher: (state.ui.log_pusher ? state.ui.log_pusher : false),
- log_mopidy: (state.ui.log_mopidy ? state.ui.log_mopidy : false),
- test_mode: (state.ui.test_mode ? state.ui.test_mode : false),
- debug_info: (state.ui.debug_info ? state.ui.debug_info : false),
- debug_response: state.ui.debug_response
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ connection_id: state.pusher.connection_id,
+ access_token: (state.spotify.access_token ? state.spotify.access_token : ''),
+ log_actions: (state.ui.log_actions ? state.ui.log_actions : false),
+ log_pusher: (state.ui.log_pusher ? state.ui.log_pusher : false),
+ log_mopidy: (state.ui.log_mopidy ? state.ui.log_mopidy : false),
+ test_mode: (state.ui.test_mode ? state.ui.test_mode : false),
+ debug_info: (state.ui.debug_info ? state.ui.debug_info : false),
+ debug_response: state.ui.debug_response,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(Debug)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Debug);
diff --git a/src/js/views/Playlist.js b/src/js/views/Playlist.js
index 5d4a9646..0f44cfe7 100755
--- a/src/js/views/Playlist.js
+++ b/src/js/views/Playlist.js
@@ -6,291 +6,303 @@ import ReactGA from 'react-ga';
import ErrorMessage from '../components/ErrorMessage';
import Link from '../components/Link';
-import TrackList from '../components/TrackList'
-import Thumbnail from '../components/Thumbnail'
-import Parallax from '../components/Parallax'
+import TrackList from '../components/TrackList';
+import Thumbnail from '../components/Thumbnail';
+import Parallax from '../components/Parallax';
import NiceNumber from '../components/NiceNumber';
-import Dater from '../components/Dater'
-import ConfirmationButton from '../components/Fields/ConfirmationButton'
-import LazyLoadListener from '../components/LazyLoadListener'
-import FollowButton from '../components/Fields/FollowButton'
-import Header from '../components/Header'
-import ContextMenuTrigger from '../components/ContextMenuTrigger'
-import URILink from '../components/URILink'
-import Icon from '../components/Icon'
+import Dater from '../components/Dater';
+import ConfirmationButton from '../components/Fields/ConfirmationButton';
+import LazyLoadListener from '../components/LazyLoadListener';
+import FollowButton from '../components/Fields/FollowButton';
+import Header from '../components/Header';
+import ContextMenuTrigger from '../components/ContextMenuTrigger';
+import URILink from '../components/URILink';
+import Icon from '../components/Icon';
-import * as helpers from '../helpers'
-import * as coreActions from '../services/core/actions'
-import * as uiActions from '../services/ui/actions'
-import * as mopidyActions from '../services/mopidy/actions'
-import * as spotifyActions from '../services/spotify/actions'
+import * as helpers from '../helpers';
+import * as coreActions from '../services/core/actions';
+import * as uiActions from '../services/ui/actions';
+import * as mopidyActions from '../services/mopidy/actions';
+import * as spotifyActions from '../services/spotify/actions';
-class Playlist extends React.Component{
+class Playlist extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentWillMount() {
+ let { uri } = this.props;
- componentWillMount(){
- var uri = this.props.uri;
+ // Spotify upgraded their playlists URI to remove user component (Sept 2018)
+ // We accept the old format, and redirect to the new one
+ if (uri.includes('spotify:user:')) {
+ uri = uri.replace(/spotify:user:([^:]*?):/i, 'spotify:');
+ this.props.history.push(`/playlist/${encodeURIComponent(uri)}`);
+ }
+ }
- // Spotify upgraded their playlists URI to remove user component (Sept 2018)
- // We accept the old format, and redirect to the new one
- if (uri.includes("spotify:user:")){
- uri = uri.replace(/spotify:user:([^:]*?):/i, "spotify:");
- this.props.history.push('/playlist/'+encodeURIComponent(uri));
- }
- }
+ componentDidMount() {
+ this.setWindowTitle();
+ this.props.coreActions.loadPlaylist(this.props.uri);
+ }
- componentDidMount(){
- this.setWindowTitle();
- this.props.coreActions.loadPlaylist(this.props.uri);
- }
+ componentWillReceiveProps(nextProps) {
+ // Follow a URI moved_to instruction
+ if (this.props.playlist && nextProps.playlist && this.props.playlist.moved_to != nextProps.playlist.moved_to) {
+ this.props.history.push(`/playlist/${encodeURIComponent(nextProps.playlist.moved_to)}`);
+ }
- componentWillReceiveProps(nextProps){
+ if (nextProps.uri != this.props.uri) {
+ this.props.coreActions.loadPlaylist(nextProps.uri);
+ } else if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
+ if (helpers.uriSource(this.props.uri) != 'spotify') {
+ this.props.coreActions.loadPlaylist(nextProps.uri);
+ }
+ }
- // Follow a URI moved_to instruction
- if (this.props.playlist && nextProps.playlist && this.props.playlist.moved_to != nextProps.playlist.moved_to){
- this.props.history.push('/playlist/'+encodeURIComponent(nextProps.playlist.moved_to));
- }
+ if (!this.props.playlist && nextProps.playlist) {
+ this.setWindowTitle(nextProps.playlist);
+ }
- if (nextProps.uri != this.props.uri){
- this.props.coreActions.loadPlaylist(nextProps.uri);
- } else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
- if (helpers.uriSource(this.props.uri) != 'spotify'){
- this.props.coreActions.loadPlaylist(nextProps.uri);
- }
- }
+ if (this.props.uri !== nextProps.uri && nextProps.playlist) {
+ this.setWindowTitle(nextProps.playlist);
+ }
+ }
- if (!this.props.playlist && nextProps.playlist){
- this.setWindowTitle(nextProps.playlist);
- }
+ setWindowTitle(playlist = this.props.playlist) {
+ if (playlist) {
+ this.props.uiActions.setWindowTitle(`${playlist.name} (playlist)`);
+ } else {
+ this.props.uiActions.setWindowTitle('Playlist');
+ }
+ }
- if (this.props.uri !== nextProps.uri && nextProps.playlist){
- this.setWindowTitle(nextProps.playlist);
- }
- }
+ loadMore() {
+ this.props.spotifyActions.getMore(
+ this.props.playlist.tracks_more,
+ {
+ parent_type: 'playlist',
+ parent_key: this.props.playlist.uri,
+ records_type: 'track',
+ },
+ );
+ }
- setWindowTitle(playlist = this.props.playlist){
- if (playlist){
- this.props.uiActions.setWindowTitle(playlist.name+" (playlist)");
- } else{
- this.props.uiActions.setWindowTitle("Playlist");
- }
- }
+ handleContextMenu(e) {
+ const data = {
+ e,
+ context: 'playlist',
+ items: [this.props.playlist],
+ uris: [this.props.uri],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- loadMore(){
- this.props.spotifyActions.getMore(
- this.props.playlist.tracks_more,
- {
- parent_type: 'playlist',
- parent_key: this.props.playlist.uri,
- records_type: 'track'
- }
- );
- }
+ play() {
+ this.props.mopidyActions.playPlaylist(this.props.playlist.uri);
+ }
- handleContextMenu(e){
- var data = {
- e: e,
- context: 'playlist',
- items: [this.props.playlist],
- uris: [this.props.uri]
- }
- this.props.uiActions.showContextMenu(data)
- }
-
- play(){
- this.props.mopidyActions.playPlaylist(this.props.playlist.uri);
- }
-
- follow(){
- if (this.props.allow_reporting){
+ follow() {
+ if (this.props.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Follow', label: this.props.playlist.uri });
}
- this.props.spotifyActions.toggleFollowingPlaylist(this.props.playlist.uri, 'PUT')
- }
+ this.props.spotifyActions.toggleFollowingPlaylist(this.props.playlist.uri, 'PUT');
+ }
- // TODO: Once unfollowing occurs, remove playlist from global playlists list
- unfollow(){
- if (this.props.allow_reporting){
+ // TODO: Once unfollowing occurs, remove playlist from global playlists list
+ unfollow() {
+ if (this.props.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Unfollow', label: this.props.playlist.uri });
}
- this.props.spotifyActions.toggleFollowingPlaylist(this.props.playlist.uri, 'DELETE' )
- }
+ this.props.spotifyActions.toggleFollowingPlaylist(this.props.playlist.uri, 'DELETE');
+ }
- // TODO: Once deletion occurs, remove playlist from global playlists list
- delete(){
- this.props.mopidyActions.deletePlaylist(this.props.playlist.uri);
- }
+ // TODO: Once deletion occurs, remove playlist from global playlists list
+ delete() {
+ this.props.mopidyActions.deletePlaylist(this.props.playlist.uri);
+ }
- reorderTracks(indexes, index){
- this.props.coreActions.reorderPlaylistTracks(this.props.playlist.uri, indexes, index, this.props.playlist.snapshot_id);
- }
+ reorderTracks(indexes, index) {
+ this.props.coreActions.reorderPlaylistTracks(this.props.playlist.uri, indexes, index, this.props.playlist.snapshot_id);
+ }
- removeTracks(tracks_indexes){
- this.props.coreActions.removeTracksFromPlaylist(this.props.playlist.uri, tracks_indexes);
- }
+ removeTracks(tracks_indexes) {
+ this.props.coreActions.removeTracksFromPlaylist(this.props.playlist.uri, tracks_indexes);
+ }
- inLibrary(){
- var library = helpers.uriSource(this.props.uri)+'_library_playlists';
- return (this.props[library] && this.props[library].indexOf(this.props.uri) > -1);
- }
+ inLibrary() {
+ const library = `${helpers.uriSource(this.props.uri)}_library_playlists`;
+ return (this.props[library] && this.props[library].indexOf(this.props.uri) > -1);
+ }
- renderActions(){
- switch(helpers.uriSource(this.props.uri)){
+ renderActions() {
+ switch (helpers.uriSource(this.props.uri)) {
+ case 'm3u':
+ return (
+
+ this.play()}>Play
+ Edit
+ this.handleContextMenu(e)} />
+
+ );
- case 'm3u':
- return (
-
- this.play() }>Play
- Edit
- this.handleContextMenu(e)} />
-
- )
+ case 'spotify':
+ if (this.props.playlist.can_edit) {
+ return (
+
+ this.play()}>Play
+ Edit
+ this.handleContextMenu(e)} />
+
+ );
+ }
+ return (
+
+ this.play()}>Play
+
+ this.handleContextMenu(e)} />
+
+ );
- case 'spotify':
- if (this.props.playlist.can_edit){
- return (
-
- this.play() }>Play
- Edit
- this.handleContextMenu(e)} />
-
- )
- }
- return (
-
- this.play() }>Play
-
- this.handleContextMenu(e)} />
-
- )
+ default:
+ return (
+
+ this.play()}>Play
+ this.handleContextMenu(e)} />
+
+ );
+ }
+ }
- default:
- return (
-
- this.play() }>Play
- this.handleContextMenu(e)} />
-
- )
- }
- }
+ render() {
+ const playlist_id = helpers.getFromUri('playlistid', this.props.uri);
- render(){
- var playlist_id = helpers.getFromUri('playlistid',this.props.uri);
-
- if (!this.props.playlist){
- if (helpers.isLoading(this.props.load_queue,['spotify_playlists/'+playlist_id+'?'])){
- return (
-
- )
- } else {
- return (
-
- Could not find playlist with URI "{encodeURIComponent(this.props.uri)}"
-
- );
- }
- }
+ if (!this.props.playlist) {
+ if (helpers.isLoading(this.props.load_queue, [`spotify_playlists/${playlist_id}?`])) {
+ return (
+
+ );
+ }
+ return (
+
+
+Could not find playlist with URI "
+ {encodeURIComponent(this.props.uri)}
+"
+
+
+ );
+ }
- var playlist = helpers.collate(this.props.playlist, {tracks: this.props.tracks, users: this.props.users});
+ const playlist = helpers.collate(this.props.playlist, { tracks: this.props.tracks, users: this.props.users });
- var context = 'playlist';
- if (playlist.can_edit){
- context = 'editable-playlist';
- }
+ let context = 'playlist';
+ if (playlist.can_edit) {
+ context = 'editable-playlist';
+ }
- if (playlist.tracks_total !== 0 && (!playlist.tracks_uris || (playlist.tracks_uris && !playlist.tracks) || (playlist.tracks_uris.length !== playlist.tracks.length))){
- var is_loading_tracks = true;
- } else {
- var is_loading_tracks = false;
- }
+ if (playlist.tracks_total !== 0 && (!playlist.tracks_uris || (playlist.tracks_uris && !playlist.tracks) || (playlist.tracks_uris.length !== playlist.tracks.length))) {
+ var is_loading_tracks = true;
+ } else {
+ var is_loading_tracks = false;
+ }
- return (
-
+ return (
+
-
-
-
-
-
+
-
-
{playlist.name}
- {playlist.description ?
: null }
+
+
+
-
- {!this.props.slim_mode ? : null }
- {playlist.user_uri ? {playlist.user ? playlist.user.name : helpers.getFromUri('userid',playlist.user_uri)} : null }
- {playlist.tracks_total ? playlist.tracks_total : '0'} tracks
- {!this.props.slim_mode && playlist.tracks && playlist.tracks_total > 0 ? : null }
- {!this.props.slim_mode && playlist.followers !== undefined ? followers : null }
- {!this.props.slim_mode && playlist.last_modified_date ? Edited : null }
-
-
+
+
{playlist.name}
+ {playlist.description ?
: null }
- {this.renderActions()}
+
+ {!this.props.slim_mode ? : null }
+ {playlist.user_uri ? {playlist.user ? playlist.user.name : helpers.getFromUri('userid', playlist.user_uri)} : null }
+
+ {playlist.tracks_total ? playlist.tracks_total : '0'}
+ {' '}
+tracks
+
+ {!this.props.slim_mode && playlist.tracks && playlist.tracks_total > 0 ? : null }
+ {!this.props.slim_mode && playlist.followers !== undefined ? (
+
+
+ {' '}
+followers
+
+ ) : null }
+ {!this.props.slim_mode && playlist.last_modified_date ? (
+
+Edited
+
+
+ ) : null }
+
+
-
- this.removeTracks(tracks_indexes)}
- reorderTracks={(indexes, index) => this.reorderTracks(indexes, index)}
- />
- this.loadMore()}
- />
-
-
- )
- }
+ {this.renderActions()}
+
+
+ this.removeTracks(tracks_indexes)}
+ reorderTracks={(indexes, index) => this.reorderTracks(indexes, index)}
+ />
+ this.loadMore()}
+ />
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
+const mapStateToProps = (state, ownProps) => {
+ // Decode the URI, and then re-encode selected characters
+ // This is needed as Mopidy encodes *some* characters in playlist URIs (but not other characters)
+ // We need to retain ":" because this a reserved URI separator
+ let uri = decodeURIComponent(ownProps.match.params.uri);
+ uri = uri.replace(/\s/g, '%20'); // space
+ uri = uri.replace(/\[/g, '%5B'); // [
+ uri = uri.replace(/\]/g, '%5D'); // ]
+ uri = uri.replace(/\(/g, '%28'); // (
+ uri = uri.replace(/\)/g, '%29'); // )
+ uri = uri.replace(/\#/g, '%23'); // #
- // Decode the URI, and then re-encode selected characters
- // This is needed as Mopidy encodes *some* characters in playlist URIs (but not other characters)
- // We need to retain ":" because this a reserved URI separator
- var uri = decodeURIComponent(ownProps.match.params.uri);
- uri = uri.replace(/\s/g, '%20'); // space
- uri = uri.replace(/\[/g, '%5B'); // [
- uri = uri.replace(/\]/g, '%5D'); // ]
- uri = uri.replace(/\(/g, '%28'); // (
- uri = uri.replace(/\)/g, '%29'); // )
- uri = uri.replace(/\#/g, '%23'); // #
+ return {
+ uri,
+ allow_reporting: state.ui.allow_reporting,
+ slim_mode: state.ui.slim_mode,
+ theme: state.ui.theme,
+ load_queue: state.ui.load_queue,
+ users: state.core.users,
+ tracks: state.core.tracks,
+ playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : false),
+ spotify_library_playlists: state.spotify.library_playlists,
+ local_library_playlists: state.mopidy.library_playlists,
+ mopidy_connected: state.mopidy.connected,
+ spotify_authorized: state.spotify.authorization,
+ spotify_userid: (state.spotify.me && state.spotify.me.id ? state.spotify.me.id : null),
+ };
+};
- return {
- uri: uri,
- allow_reporting: state.ui.allow_reporting,
- slim_mode: state.ui.slim_mode,
- theme: state.ui.theme,
- load_queue: state.ui.load_queue,
- users: state.core.users,
- tracks: state.core.tracks,
- playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : false ),
- spotify_library_playlists: state.spotify.library_playlists,
- local_library_playlists: state.mopidy.library_playlists,
- mopidy_connected: state.mopidy.connected,
- spotify_authorized: state.spotify.authorization,
- spotify_userid: (state.spotify.me && state.spotify.me.id ? state.spotify.me.id : null)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(Playlist)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Playlist);
diff --git a/src/js/views/Queue.js b/src/js/views/Queue.js
index b3d33e3e..e6a4e774 100755
--- a/src/js/views/Queue.js
+++ b/src/js/views/Queue.js
@@ -1,24 +1,24 @@
-import React from "react";
-import { connect } from "react-redux";
-import { bindActionCreators } from "redux";
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
-import Link from "../components/Link";
-import Icon from "../components/Icon";
-import Parallax from "../components/Parallax";
-import TrackList from "../components/TrackList";
-import Dater from "../components/Dater";
-import ArtistSentence from "../components/ArtistSentence";
-import Thumbnail from "../components/Thumbnail";
-import Header from "../components/Header";
-import URILink from "../components/URILink";
-import LazyLoadListener from "../components/LazyLoadListener";
+import Link from '../components/Link';
+import Icon from '../components/Icon';
+import Parallax from '../components/Parallax';
+import TrackList from '../components/TrackList';
+import Dater from '../components/Dater';
+import ArtistSentence from '../components/ArtistSentence';
+import Thumbnail from '../components/Thumbnail';
+import Header from '../components/Header';
+import URILink from '../components/URILink';
+import LazyLoadListener from '../components/LazyLoadListener';
-import * as helpers from "../helpers";
-import * as coreActions from "../services/core/actions";
-import * as uiActions from "../services/ui/actions";
-import * as pusherActions from "../services/pusher/actions";
-import * as spotifyActions from "../services/spotify/actions";
-import * as mopidyActions from "../services/mopidy/actions";
+import * as helpers from '../helpers';
+import * as coreActions from '../services/core/actions';
+import * as uiActions from '../services/ui/actions';
+import * as pusherActions from '../services/pusher/actions';
+import * as spotifyActions from '../services/spotify/actions';
+import * as mopidyActions from '../services/mopidy/actions';
class Queue extends React.Component {
constructor(props) {
@@ -26,22 +26,22 @@ class Queue extends React.Component {
this.state = {
limit: 50,
- per_page: 50
+ per_page: 50,
};
}
componentWillMount() {
// Before we mount, restore any limit defined in our location state
- var state = this.props.location.state ? this.props.location.state : {};
+ const state = this.props.location.state ? this.props.location.state : {};
if (state.limit) {
this.setState({
- limit: state.limit
+ limit: state.limit,
});
}
}
componentDidMount() {
- this.props.uiActions.setWindowTitle("Now playing");
+ this.props.uiActions.setWindowTitle('Now playing');
}
shouldComponentUpdate(nextProps) {
@@ -54,13 +54,13 @@ class Queue extends React.Component {
if (added_from_uri && this.props.added_from_uri !== added_from_uri) {
const item_type = helpers.uriType(added_from_uri);
switch (item_type) {
- case "album":
+ case 'album':
this.props.coreActions.loadAlbum(added_from_uri);
break;
- case "artist":
+ case 'artist':
this.props.coreActions.loadArtist(added_from_uri);
break;
- case "playlist":
+ case 'playlist':
this.props.coreActions.loadPlaylist(added_from_uri);
break;
}
@@ -68,23 +68,22 @@ class Queue extends React.Component {
}
loadMore() {
- var new_limit = this.state.limit + this.state.per_page;
+ const new_limit = this.state.limit + this.state.per_page;
this.setState({ limit: new_limit });
// Set our pagination to location state
- var state =
- this.props.location && this.props.location.state
- ? this.props.location.state
- : {};
+ const state = this.props.location && this.props.location.state
+ ? this.props.location.state
+ : {};
state.limit = new_limit;
- this.props.history.replace({ state: state });
+ this.props.history.replace({ state });
}
removeTracks(track_indexes) {
- var tlids = [];
- for (var i = 0; i < track_indexes.length; i++) {
- var track = this.props.queue_tracks[track_indexes[i]];
+ const tlids = [];
+ for (let i = 0; i < track_indexes.length; i++) {
+ const track = this.props.queue_tracks[track_indexes[i]];
if (track.tlid !== undefined) {
tlids.push(track.tlid);
}
@@ -108,11 +107,15 @@ class Queue extends React.Component {
}
renderQueueStats() {
- var total_time = 0;
+ const total_time = 0;
return (
-
{this.props.current_tracklist.length} tracks
+
+ {this.props.current_tracklist.length}
+ {' '}
+tracks
+
|
{this.props.current_tracklist.length > 0 ? (
@@ -129,8 +132,8 @@ class Queue extends React.Component {
{this.props.radio_enabled ? (
@@ -144,7 +147,7 @@ class Queue extends React.Component {
);
}
- var uri = null;
+ let uri = null;
if (this.props.current_track.album && this.props.current_track.album.uri) {
uri = this.props.current_track.album.uri;
}
@@ -152,8 +155,8 @@ class Queue extends React.Component {
@@ -174,7 +177,7 @@ class Queue extends React.Component {
if (!added_from_uri) return null;
const item_type = helpers.uriType(added_from_uri);
- const item_library = this.props[item_type + "s"];
+ const item_library = this.props[`${item_type}s`];
if (!item_library) return null;
const item = item_library[added_from_uri];
@@ -190,11 +193,12 @@ class Queue extends React.Component {
- Playing from{" "}
+ Playing from
+ {' '}
{item.name}
@@ -208,17 +212,17 @@ class Queue extends React.Component {
const total_queue_tracks = queue_tracks.length;
const tracks = queue_tracks.slice(0, this.state.limit);
- var current_track_image = null;
+ let current_track_image = null;
if (current_track && this.props.current_track_uri) {
if (current_track.images !== undefined && current_track.images) {
current_track_image = current_track.images.large;
}
}
- var options = (
+ const options = (
{this.props.spotify_enabled ? (
-
+
Radio
{this.props.radio && this.props.radio.enabled ? (
@@ -226,13 +230,13 @@ class Queue extends React.Component {
) : null}
) : null}
-
+
History
{
+ onClick={(e) => {
this.props.mopidyActions.clearTracklist();
this.props.uiActions.hideContextMenu();
}}
@@ -240,7 +244,7 @@ class Queue extends React.Component {
Clear
-
+
Add URI
@@ -287,12 +291,10 @@ class Queue extends React.Component {
track_context="queue"
className="queue-track-list"
tracks={tracks}
- removeTracks={track_indexes => this.removeTracks(track_indexes)}
- playTracks={tracks => this.playTracks(tracks)}
- playTrack={track => this.playTrack(track)}
- reorderTracks={(indexes, index) =>
- this.reorderTracks(indexes, index)
- }
+ removeTracks={(track_indexes) => this.removeTracks(track_indexes)}
+ playTracks={(tracks) => this.playTracks(tracks)}
+ playTrack={(track) => this.playTrack(track)}
+ reorderTracks={(indexes, index) => this.reorderTracks(indexes, index)}
/>
@@ -312,29 +314,27 @@ class Queue extends React.Component {
}
const mapStateToProps = (state, ownProps) => {
- let current_track = state.core.current_track;
- let queue_tracks = [];
+ let { current_track } = state.core;
+ const queue_tracks = [];
if (state.core.queue && state.core.tracks) {
- for (let queue_track of state.core.queue) {
- let track = Object.assign({}, queue_track);
+ for (const queue_track of state.core.queue) {
+ let track = { ...queue_track };
// If we have the track in our index, merge it in.
// We prioritise queue track over index track as queue has unique data, like which track
// is playing and tlids.
if (state.core.tracks.hasOwnProperty(track.uri)) {
- track = Object.assign({}, state.core.tracks[track.uri], track, {
- playing: current_track && current_track.tlid == track.tlid
- });
+ track = { ...state.core.tracks[track.uri], ...track, playing: current_track && current_track.tlid == track.tlid };
}
// Now merge in our queue metadata
- if (state.core.queue_metadata["tlid_" + track.tlid] !== undefined) {
- track = Object.assign(
- {},
- track,
- state.core.queue_metadata["tlid_" + track.tlid]
- );
+ if (state.core.queue_metadata[`tlid_${track.tlid}`] !== undefined) {
+ track = {
+
+ ...track,
+ ...state.core.queue_metadata[`tlid_${track.tlid}`],
+ };
}
// Siphon off this track if it's a full representation of our current track (by tlid)
@@ -351,31 +351,29 @@ const mapStateToProps = (state, ownProps) => {
theme: state.ui.theme,
spotify_enabled: state.spotify.enabled,
radio: state.core.radio,
- radio_enabled: state.core.radio && state.core.radio.enabled ? true : false,
+ radio_enabled: !!(state.core.radio && state.core.radio.enabled),
artists: state.core.artists,
albums: state.core.albums,
playlists: state.core.playlists,
- queue_tracks: queue_tracks,
+ queue_tracks,
current_track_uri: state.core.current_track_uri,
- current_track: current_track,
+ current_track,
added_from_uri:
current_track && current_track.added_from
? current_track.added_from
- : null
+ : null,
};
};
-const mapDispatchToProps = dispatch => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch)
- };
-};
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+});
export default connect(
mapStateToProps,
- mapDispatchToProps
+ mapDispatchToProps,
)(Queue);
diff --git a/src/js/views/QueueHistory.js b/src/js/views/QueueHistory.js
index 692072e4..82288bd8 100755
--- a/src/js/views/QueueHistory.js
+++ b/src/js/views/QueueHistory.js
@@ -1,83 +1,83 @@
-import React from 'react'
-import { connect } from 'react-redux'
+import React from 'react';
+import { connect } from 'react-redux';
-import { bindActionCreators } from 'redux'
+import { bindActionCreators } from 'redux';
-import TrackList from '../components/TrackList'
-import Header from '../components/Header'
-import Icon from '../components/Icon'
+import TrackList from '../components/TrackList';
+import Header from '../components/Header';
+import Icon from '../components/Icon';
-import * as uiActions from '../services/ui/actions'
-import * as pusherActions from '../services/pusher/actions'
-import * as spotifyActions from '../services/spotify/actions'
-import * as mopidyActions from '../services/mopidy/actions'
+import * as uiActions from '../services/ui/actions';
+import * as pusherActions from '../services/pusher/actions';
+import * as spotifyActions from '../services/spotify/actions';
+import * as mopidyActions from '../services/mopidy/actions';
-class QueueHistory extends React.Component{
+class QueueHistory extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Queue history');
+ this.loadHistory();
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Queue history");
- this.loadHistory()
- }
+ componentWillReceiveProps(nextProps) {
+ if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
+ this.loadHistory(nextProps);
+ }
+ }
- componentWillReceiveProps(nextProps){
- if (!this.props.mopidy_connected && nextProps.mopidy_connected){
- this.loadHistory(nextProps)
- }
- }
+ loadHistory(props = this.props) {
+ if (props.mopidy_connected) {
+ this.props.mopidyActions.getQueueHistory();
+ }
+ }
- loadHistory(props = this.props){
- if (props.mopidy_connected){
- this.props.mopidyActions.getQueueHistory()
- }
- }
-
- render(){
- var options = (
- this.props.history.push('/queue')}>
-
+ render() {
+ const options = (
+ this.props.history.push('/queue')}>
+
+
Back
-
- )
+
+ );
- var tracks = [];
- for (var i = 0; i < this.props.queue_history.length; i++){
- var track = Object.assign({}, this.props.queue_history[i]);
+ const tracks = [];
+ for (let i = 0; i < this.props.queue_history.length; i++) {
+ let track = { ...this.props.queue_history[i] };
- // We have the track in the index, so merge the track objects
- if (this.props.tracks[track.uri] !== undefined){
- track = Object.assign(
- {},
- track,
- this.props.tracks[track.uri]
- );
- }
-
- tracks.push(track);
- }
+ // We have the track in the index, so merge the track objects
+ if (this.props.tracks[track.uri] !== undefined) {
+ track = {
- return (
-
+ );
+ }
}
@@ -85,23 +85,19 @@ class QueueHistory extends React.Component{
* Export our component
*
* We also integrate our global store, using connect()
- **/
+ * */
-const mapStateToProps = (state, ownProps) => {
- return {
- mopidy_connected: state.mopidy.connected,
- tracks: (state.core.tracks ? state.core.tracks : {}),
- queue_history: (state.mopidy.queue_history ? state.mopidy.queue_history : [])
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ mopidy_connected: state.mopidy.connected,
+ tracks: (state.core.tracks ? state.core.tracks : {}),
+ queue_history: (state.mopidy.queue_history ? state.mopidy.queue_history : []),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(QueueHistory)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(QueueHistory);
diff --git a/src/js/views/Search.js b/src/js/views/Search.js
index c5040afd..7497b335 100755
--- a/src/js/views/Search.js
+++ b/src/js/views/Search.js
@@ -5,456 +5,463 @@ import { bindActionCreators } from 'redux';
import { Switch, Route } from 'react-router-dom';
import Link from '../components/Link';
-import Header from '../components/Header'
-import Icon from '../components/Icon'
-import DropdownField from '../components/Fields/DropdownField'
-import TrackList from '../components/TrackList'
-import ArtistGrid from '../components/ArtistGrid'
-import AlbumGrid from '../components/AlbumGrid'
-import PlaylistGrid from '../components/PlaylistGrid'
-import LazyLoadListener from '../components/LazyLoadListener'
-import SearchForm from '../components/Fields/SearchForm'
-import URILink from '../components/URILink'
+import Header from '../components/Header';
+import Icon from '../components/Icon';
+import DropdownField from '../components/Fields/DropdownField';
+import TrackList from '../components/TrackList';
+import ArtistGrid from '../components/ArtistGrid';
+import AlbumGrid from '../components/AlbumGrid';
+import PlaylistGrid from '../components/PlaylistGrid';
+import LazyLoadListener from '../components/LazyLoadListener';
+import SearchForm from '../components/Fields/SearchForm';
+import URILink from '../components/URILink';
-import * as helpers from '../helpers'
-import * as coreActions from '../services/core/actions'
-import * as uiActions from '../services/ui/actions'
-import * as mopidyActions from '../services/mopidy/actions'
-import * as spotifyActions from '../services/spotify/actions'
+import * as helpers from '../helpers';
+import * as coreActions from '../services/core/actions';
+import * as uiActions from '../services/ui/actions';
+import * as mopidyActions from '../services/mopidy/actions';
+import * as spotifyActions from '../services/spotify/actions';
-class Search extends React.Component{
+class Search extends React.Component {
+ constructor(props) {
+ super(props);
- constructor(props){
- super(props);
+ this.state = {
+ type: 'all',
+ term: '',
+ };
+ }
- this.state = {
- type: 'all',
- term: ''
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Search');
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Search");
+ // Auto-focus on the input field
+ $(document).find('.search-form input').focus();
- // Auto-focus on the input field
- $(document).find('.search-form input').focus();
+ // Listen for a query baked-in to the URL
+ // This would be the case when we've clicked from a link elsewhere
+ this.digestUri();
+ }
- // Listen for a query baked-in to the URL
- // This would be the case when we've clicked from a link elsewhere
- this.digestUri();
- }
+ componentWillReceiveProps(nextProps) {
+ // Query changed
+ if (nextProps.term !== this.props.term || nextProps.type !== this.props.type) {
+ this.digestUri(nextProps);
+ }
- componentWillReceiveProps(nextProps){
+ // Services came online
+ if (!this.props.mopidy_connected && nextProps.mopidy_connected && nextProps.uri_schemes_search_enabled) {
+ this.search(this.state.type, this.state.term, 'mopidy');
- // Query changed
- if (nextProps.term !== this.props.term || nextProps.type !== this.props.type){
- this.digestUri(nextProps);
- }
+ if (nextProps.uri_schemes_search_enabled.includes('spotify:')) {
+ this.search(this.state.type, this.state.term, 'spotify');
+ }
+ }
+ }
- // Services came online
- if (!this.props.mopidy_connected && nextProps.mopidy_connected && nextProps.uri_schemes_search_enabled){
- this.search(this.state.type, this.state.term, 'mopidy');
+ handleSubmit(term) {
+ this.setState(
+ { term }, () => {
+ // Unchanged term, so this is a forced re-search
+ // Often the other search parameters have changed instead, but we can't
+ // push a URL change when the term hasn't changed
+ if (this.props.term == term) {
+ this.search();
+ } else {
+ this.props.history.push(`/search/${this.state.type}/${term}`);
+ }
+ },
+ );
+ }
- if (nextProps.uri_schemes_search_enabled.includes('spotify:')){
- this.search(this.state.type, this.state.term, 'spotify');
- }
- }
- }
+ // Digest the URI query property
+ // Triggered when the URL changes
+ digestUri(props = this.props) {
+ if (props.type && props.term) {
+ this.setState({
+ type: props.type,
+ term: props.term,
+ });
- handleSubmit(term){
- this.setState(
- {term: term}, () =>
- {
- // Unchanged term, so this is a forced re-search
- // Often the other search parameters have changed instead, but we can't
- // push a URL change when the term hasn't changed
- if (this.props.term == term){
- this.search();
- } else {
- this.props.history.push(`/search/${this.state.type}/${term}`);
- }
- }
- );
- }
+ this.search(props.type, props.term);
+ } else if (!props.term || props.term == '') {
+ this.props.spotifyActions.clearSearchResults();
+ this.props.mopidyActions.clearSearchResults();
+ }
+ }
- // Digest the URI query property
- // Triggered when the URL changes
- digestUri(props = this.props){
- if (props.type && props.term){
- this.setState({
- type: props.type,
- term: props.term
- });
+ search(type = this.state.type, term = this.state.term, provider) {
+ this.props.uiActions.setWindowTitle(`Search: ${term}`);
- this.search(props.type, props.term);
- } else if (!props.term || props.term == ''){
- this.props.spotifyActions.clearSearchResults();
- this.props.mopidyActions.clearSearchResults();
- }
- }
+ if (type && term) {
+ if (provider == 'mopidy' || (this.props.mopidy_connected && this.props.uri_schemes_search_enabled)) {
+ if (this.props.mopidy_search_results.query === undefined || this.props.mopidy_search_results.query != term) {
+ this.props.mopidyActions.clearSearchResults();
+ this.props.mopidyActions.getSearchResults(type, term);
+ }
+ }
- search(type = this.state.type, term = this.state.term, provider){
+ if (provider == 'spotify' || (this.props.mopidy_connected && this.props.uri_schemes_search_enabled && this.props.uri_schemes_search_enabled.includes('spotify:'))) {
+ if (this.props.spotify_search_results.query === undefined || this.props.spotify_search_results.query != term) {
+ this.props.spotifyActions.clearSearchResults();
+ this.props.spotifyActions.getSearchResults(type, term);
+ }
+ }
+ }
+ }
- this.props.uiActions.setWindowTitle("Search: "+term);
+ loadMore(type) {
+ alert(`load more: ${type}`);
+ // this.props.spotifyActions.getURL(this.props['spotify_'+type+'_more'], 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_'+type.toUpperCase());
+ }
- if (type && term){
+ setSort(value) {
+ let reverse = false;
+ if (this.props.sort == value) reverse = !this.props.sort_reverse;
- if (provider == 'mopidy' || (this.props.mopidy_connected && this.props.uri_schemes_search_enabled)){
- if (this.props.mopidy_search_results.query === undefined || this.props.mopidy_search_results.query != term){
- this.props.mopidyActions.clearSearchResults();
- this.props.mopidyActions.getSearchResults(type, term);
- }
- }
+ const data = {
+ search_results_sort_reverse: reverse,
+ search_results_sort: value,
+ };
+ this.props.uiActions.set(data);
+ }
- if (provider == 'spotify' || (this.props.mopidy_connected && this.props.uri_schemes_search_enabled && this.props.uri_schemes_search_enabled.includes('spotify:'))){
- if (this.props.spotify_search_results.query === undefined || this.props.spotify_search_results.query != term){
- this.props.spotifyActions.clearSearchResults();
- this.props.spotifyActions.getSearchResults(type, term);
- }
- }
- }
- }
-
- loadMore(type){
- alert('load more: '+type)
- //this.props.spotifyActions.getURL(this.props['spotify_'+type+'_more'], 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_'+type.toUpperCase());
- }
-
- setSort(value){
- var reverse = false
- if (this.props.sort == value ) reverse = !this.props.sort_reverse
-
- var data = {
- search_results_sort_reverse: reverse,
- search_results_sort: value
- }
- this.props.uiActions.set(data)
- }
-
- renderArtists(artists, spotify_search_enabled){
- return (
-
-
-
+ renderArtists(artists, spotify_search_enabled) {
+ return (
+
+
+
Search
-
-
+
+
+
Artists
-
-
-
- this.loadMore('artists') }/>
-
-
- );
- }
+
+
+
+ this.loadMore('artists')} />
+
+
+ );
+ }
- renderAlbums(albums, spotify_search_enabled){
- return (
-
-
-
+ renderAlbums(albums, spotify_search_enabled) {
+ return (
+
+
+
Search
-
-
+
+
+
Albums
-
-
-
- this.loadMore('albums') }/>
-
-
- );
- }
+
+
+
+ this.loadMore('albums')} />
+
+
+ );
+ }
- renderPlaylists(playlists, spotify_search_enabled){
- return (
-
-
-
+ renderPlaylists(playlists, spotify_search_enabled) {
+ return (
+
+
+
Search
-
-
+
+
+
Playlists
-
-
-
- this.loadMore('playlists') }/>
-
-
- );
- }
+
+
+
+ this.loadMore('playlists')} />
+
+
+ );
+ }
- renderTracks(tracks, spotify_search_enabled){
- return (
-
-
-
+ renderTracks(tracks, spotify_search_enabled) {
+ return (
+
+
+
Search
-
-
+
+
+
Tracks
-
-
-
- this.loadMore('tracks') }/>
-
-
- );
- }
+
+
+
+ this.loadMore('tracks')} />
+
+
+ );
+ }
- renderAll(artists, albums, playlists, tracks, spotify_search_enabled){
- if (artists.length > 0){
- var artists_section = (
-
-
-
- Artists
-
-
- {artists.length >= 6 ?
- All artists ({artists.length})
- : null}
-
-
- )
- } else {
- var artists_section = null;
- }
+ renderAll(artists, albums, playlists, tracks, spotify_search_enabled) {
+ if (artists.length > 0) {
+ var artists_section = (
+
+
+
+ Artists
+
+
+ {artists.length >= 6 ? (
+
+ All artists (
+ {artists.length}
+)
+
+ ) : null}
+
+
+ );
+ } else {
+ var artists_section = null;
+ }
- if (albums.length > 0){
- var albums_section = (
-
-
-
- Albums
-
-
- {albums.length >= 6 ?
- All albums ({albums.length})
- : null}
-
-
- )
- } else {
- var albums_section = null;
- }
-
- if (playlists.length > 0){
- var playlists_section = (
-
-
-
- Playlists
-
-
- {playlists.length >= 6 ?
- All playlists ({playlists.length})
- : null}
-
-
- )
- } else {
- var playlists_section = null;
- }
+ if (albums.length > 0) {
+ var albums_section = (
+
+
+
+ Albums
+
+
+ {albums.length >= 6 ? (
+
+ All albums (
+ {albums.length}
+)
+
+ ) : null}
+
+
+ );
+ } else {
+ var albums_section = null;
+ }
- if (tracks.length > 0){
- var tracks_section = (
-
-
- this.loadMore('tracks') }/>
-
- )
- } else {
- var tracks_section = null;
- }
+ if (playlists.length > 0) {
+ var playlists_section = (
+
+
+
+ Playlists
+
+
+ {playlists.length >= 6 ? (
+
+ All playlists (
+ {playlists.length}
+)
+
+ ) : null}
+
+
+ );
+ } else {
+ var playlists_section = null;
+ }
- return (
-
-
- {artists_section}
- {albums_section}
- {playlists_section}
-
- {tracks_section}
-
- )
- }
+ if (tracks.length > 0) {
+ var tracks_section = (
+
+
+ this.loadMore('tracks')} />
+
+ );
+ } else {
+ var tracks_section = null;
+ }
- render(){
- var sort_options = [
- {
- value: 'followers',
- label: 'Popularity'
- },
- {
- value: 'name',
- label: 'Name'
- },
- {
- value: 'artists.name',
- label: 'Artist'
- },
- {
- value: 'duration',
- label: 'Duration'
- },
- {
- value: 'uri',
- label: 'Source'
- }
- ];
+ return (
+
+
+ {artists_section}
+ {albums_section}
+ {playlists_section}
+
+ {tracks_section}
+
+ );
+ }
- var provider_options = [];
- for (var i = 0; i < this.props.uri_schemes.length; i++){
- provider_options.push({
- value: this.props.uri_schemes[i],
- label: helpers.titleCase(this.props.uri_schemes[i].replace(':','').replace('+',' '))
- });
- }
- var spotify_search_enabled = (this.props.search_settings && this.props.search_settings.spotify);
+ render() {
+ const sort_options = [
+ {
+ value: 'followers',
+ label: 'Popularity',
+ },
+ {
+ value: 'name',
+ label: 'Name',
+ },
+ {
+ value: 'artists.name',
+ label: 'Artist',
+ },
+ {
+ value: 'duration',
+ label: 'Duration',
+ },
+ {
+ value: 'uri',
+ label: 'Source',
+ },
+ ];
- var sort = this.props.sort;
- var sort_reverse = this.props.sort_reverse;
- var sort_map = null;
+ const provider_options = [];
+ for (let i = 0; i < this.props.uri_schemes.length; i++) {
+ provider_options.push({
+ value: this.props.uri_schemes[i],
+ label: helpers.titleCase(this.props.uri_schemes[i].replace(':', '').replace('+', ' ')),
+ });
+ }
+ const spotify_search_enabled = (this.props.search_settings && this.props.search_settings.spotify);
- switch (this.props.sort){
- case 'uri':
- sort_map = this.props.uri_schemes_priority;
- break;
+ const { sort } = this.props;
+ let { sort_reverse } = this.props;
+ let sort_map = null;
- // Followers (aka popularlity works in reverse-numerical order)
- // Ie "more popular" is a bigger number
- case 'followers':
- sort_reverse = !sort_reverse;
- break;
- }
+ switch (this.props.sort) {
+ case 'uri':
+ sort_map = this.props.uri_schemes_priority;
+ break;
- var artists = [];
- if (this.props.mopidy_search_results.artists){
- artists = [...artists, ...helpers.getIndexedRecords(this.props.artists,this.props.mopidy_search_results.artists)];
- }
- if (this.props.spotify_search_results.artists){
- artists = [...artists, ...helpers.getIndexedRecords(this.props.artists,this.props.spotify_search_results.artists)];
- }
- artists = helpers.sortItems(artists, sort, sort_reverse, sort_map);
+ // Followers (aka popularlity works in reverse-numerical order)
+ // Ie "more popular" is a bigger number
+ case 'followers':
+ sort_reverse = !sort_reverse;
+ break;
+ }
- var albums = [];
- if (this.props.mopidy_search_results.albums){
- albums = [...albums, ...helpers.getIndexedRecords(this.props.albums,this.props.mopidy_search_results.albums)];
- }
- if (this.props.spotify_search_results.albums){
- albums = [...albums, ...helpers.getIndexedRecords(this.props.albums,this.props.spotify_search_results.albums)]
- }
- albums = helpers.sortItems(albums, sort, sort_reverse, sort_map);
+ let artists = [];
+ if (this.props.mopidy_search_results.artists) {
+ artists = [...artists, ...helpers.getIndexedRecords(this.props.artists, this.props.mopidy_search_results.artists)];
+ }
+ if (this.props.spotify_search_results.artists) {
+ artists = [...artists, ...helpers.getIndexedRecords(this.props.artists, this.props.spotify_search_results.artists)];
+ }
+ artists = helpers.sortItems(artists, sort, sort_reverse, sort_map);
- var playlists = []
- if (this.props.mopidy_search_results.playlists){
- playlists = [...playlists, ...helpers.getIndexedRecords(this.props.playlists,this.props.mopidy_search_results.playlists)];
- }
- if (this.props.spotify_search_results.playlists){
- playlists = [...playlists, ...helpers.getIndexedRecords(this.props.playlists,this.props.spotify_search_results.playlists)];
- }
- playlists = helpers.sortItems(playlists, sort, sort_reverse, sort_map);
+ let albums = [];
+ if (this.props.mopidy_search_results.albums) {
+ albums = [...albums, ...helpers.getIndexedRecords(this.props.albums, this.props.mopidy_search_results.albums)];
+ }
+ if (this.props.spotify_search_results.albums) {
+ albums = [...albums, ...helpers.getIndexedRecords(this.props.albums, this.props.spotify_search_results.albums)];
+ }
+ albums = helpers.sortItems(albums, sort, sort_reverse, sort_map);
- var tracks = [];
- if (this.props.mopidy_search_results.tracks){
- tracks = [...tracks, ...this.props.mopidy_search_results.tracks];
- }
- if (this.props.spotify_search_results.tracks){
- tracks = [...tracks, ...this.props.spotify_search_results.tracks];
- }
+ let playlists = [];
+ if (this.props.mopidy_search_results.playlists) {
+ playlists = [...playlists, ...helpers.getIndexedRecords(this.props.playlists, this.props.mopidy_search_results.playlists)];
+ }
+ if (this.props.spotify_search_results.playlists) {
+ playlists = [...playlists, ...helpers.getIndexedRecords(this.props.playlists, this.props.spotify_search_results.playlists)];
+ }
+ playlists = helpers.sortItems(playlists, sort, sort_reverse, sort_map);
- tracks = helpers.sortItems(tracks, (sort == 'followers' ? 'popularity' : sort), sort_reverse, sort_map);
+ let tracks = [];
+ if (this.props.mopidy_search_results.tracks) {
+ tracks = [...tracks, ...this.props.mopidy_search_results.tracks];
+ }
+ if (this.props.spotify_search_results.tracks) {
+ tracks = [...tracks, ...this.props.spotify_search_results.tracks];
+ }
- var options = (
-
- {this.setSort(value); this.props.uiActions.hideContextMenu()}}
- />
- {this.props.uiActions.set({uri_schemes_search_enabled: value}); this.props.uiActions.hideContextMenu()}}
- />
-
- )
+ tracks = helpers.sortItems(tracks, (sort == 'followers' ? 'popularity' : sort), sort_reverse, sort_map);
- return (
-
-
+ const options = (
+
+ { this.setSort(value); this.props.uiActions.hideContextMenu(); }}
+ />
+ { this.props.uiActions.set({ uri_schemes_search_enabled: value }); this.props.uiActions.hideContextMenu(); }}
+ />
+
+ );
-
this.handleSubmit(term)}
- />
+ return (
+
+
-
-
+ this.handleSubmit(term)}
+ />
-
- {this.renderArtists(artists, spotify_search_enabled)}
-
+
+
-
- {this.renderAlbums(albums, spotify_search_enabled)}
-
+
+ {this.renderArtists(artists, spotify_search_enabled)}
+
-
- {this.renderPlaylists(playlists, spotify_search_enabled)}
-
+
+ {this.renderAlbums(albums, spotify_search_enabled)}
+
-
- {this.renderTracks(tracks, spotify_search_enabled)}
-
+
+ {this.renderPlaylists(playlists, spotify_search_enabled)}
+
-
- {this.renderAll(artists, albums, playlists, tracks, spotify_search_enabled)}
-
+
+ {this.renderTracks(tracks, spotify_search_enabled)}
+
-
-
-
- );
- }
+
+ {this.renderAll(artists, albums, playlists, tracks, spotify_search_enabled)}
+
+
+
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- type: ownProps.match.params.type,
- term: ownProps.match.params.term,
- mopidy_connected: state.mopidy.connected,
- albums: (state.core.albums ? state.core.albums : []),
- artists: (state.core.artists ? state.core.artists : []),
- playlists: (state.core.playlists ? state.core.playlists : []),
- tracks: (state.core.tracks ? state.core.tracks : []),
- uri_schemes_search_enabled: (state.ui.uri_schemes_search_enabled ? state.ui.uri_schemes_search_enabled : []),
- uri_schemes_priority: (state.ui.uri_schemes_priority ? state.ui.uri_schemes_priority : []),
- uri_schemes: (state.mopidy.uri_schemes ? state.mopidy.uri_schemes : []),
- mopidy_search_results: (state.mopidy.search_results ? state.mopidy.search_results : {}),
- spotify_search_results: (state.spotify.search_results ? state.spotify.search_results : {}),
- sort: (state.ui.search_results_sort ? state.ui.search_results_sort : 'followers.total'),
- sort_reverse: (state.ui.search_results_sort_reverse ? true : false)
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ type: ownProps.match.params.type,
+ term: ownProps.match.params.term,
+ mopidy_connected: state.mopidy.connected,
+ albums: (state.core.albums ? state.core.albums : []),
+ artists: (state.core.artists ? state.core.artists : []),
+ playlists: (state.core.playlists ? state.core.playlists : []),
+ tracks: (state.core.tracks ? state.core.tracks : []),
+ uri_schemes_search_enabled: (state.ui.uri_schemes_search_enabled ? state.ui.uri_schemes_search_enabled : []),
+ uri_schemes_priority: (state.ui.uri_schemes_priority ? state.ui.uri_schemes_priority : []),
+ uri_schemes: (state.mopidy.uri_schemes ? state.mopidy.uri_schemes : []),
+ mopidy_search_results: (state.mopidy.search_results ? state.mopidy.search_results : {}),
+ spotify_search_results: (state.spotify.search_results ? state.spotify.search_results : {}),
+ sort: (state.ui.search_results_sort ? state.ui.search_results_sort : 'followers.total'),
+ sort_reverse: (!!state.ui.search_results_sort_reverse),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(Search)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Search);
diff --git a/src/js/views/Settings.js b/src/js/views/Settings.js
index bcef0fa8..ebe72e1c 100755
--- a/src/js/views/Settings.js
+++ b/src/js/views/Settings.js
@@ -21,425 +21,484 @@ import * as mopidyActions from '../services/mopidy/actions';
import * as lastfmActions from '../services/lastfm/actions';
import * as spotifyActions from '../services/spotify/actions';
-class Settings extends React.Component {
+class Settings extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ mopidy_host: this.props.mopidy.host,
+ mopidy_port: this.props.mopidy.port,
+ mopidy_library_artists_uri: this.props.mopidy.library_artists_uri,
+ mopidy_library_albums_uri: this.props.mopidy.library_albums_uri,
+ pusher_username: this.props.pusher.username,
+ input_in_focus: null,
+ };
+ }
- constructor(props){
- super(props);
- this.state = {
- mopidy_host: this.props.mopidy.host,
- mopidy_port: this.props.mopidy.port,
- mopidy_library_artists_uri: this.props.mopidy.library_artists_uri,
- mopidy_library_albums_uri: this.props.mopidy.library_albums_uri,
- pusher_username: this.props.pusher.username,
- input_in_focus: null
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Settings');
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Settings");
- }
+ componentWillReceiveProps(nextProps) {
+ let changed = false;
+ const { state } = this;
- componentWillReceiveProps(nextProps){
- var changed = false
- var state = this.state
-
- if (nextProps.pusher.username && nextProps.pusher.username != this.state.pusher_username && this.state.input_in_focus != 'pusher_username'){
- state.pusher_username = nextProps.pusher.username
- changed = true
- }
+ if (nextProps.pusher.username && nextProps.pusher.username != this.state.pusher_username && this.state.input_in_focus != 'pusher_username') {
+ state.pusher_username = nextProps.pusher.username;
+ changed = true;
+ }
- if (changed){
- this.setState(state)
- }
- }
+ if (changed) {
+ this.setState(state);
+ }
+ }
- resetAllSettings(){
- localStorage.clear();
- window.location = '#'
- window.location.reload(true)
- return false;
- }
+ resetAllSettings() {
+ localStorage.clear();
+ window.location = '#';
+ window.location.reload(true);
+ return false;
+ }
- setConfig(e){
- this.setState({input_in_focus: null});
- e.preventDefault();
-
- this.props.mopidyActions.set({
- host: this.state.mopidy_host,
- port: this.state.mopidy_port
- });
+ setConfig(e) {
+ this.setState({ input_in_focus: null });
+ e.preventDefault();
- window.location.reload(true);
- return false;
- }
+ this.props.mopidyActions.set({
+ host: this.state.mopidy_host,
+ port: this.state.mopidy_port,
+ });
- handleBlur(service, name, value){
- this.setState({input_in_focus: null});
- var data = {};
- data[name] = value;
- this.props[service+'Actions'].set(data);
+ window.location.reload(true);
+ return false;
+ }
- // Any per-field actions
- switch (name){
- case 'library_albums_uri':
- this.props.mopidyActions.clearLibraryAlbums();
- break;
- case 'library_artists_uri':
- this.props.mopidyActions.clearLibraryArtists();
- break;
- }
- }
+ handleBlur(service, name, value) {
+ this.setState({ input_in_focus: null });
+ const data = {};
+ data[name] = value;
+ this.props[`${service}Actions`].set(data);
- renderApplyButton(){
- if (this.props.mopidy.host == this.state.mopidy_host &&
- this.props.mopidy.port == this.state.mopidy_port){
- return null;
- }
+ // Any per-field actions
+ switch (name) {
+ case 'library_albums_uri':
+ this.props.mopidyActions.clearLibraryAlbums();
+ break;
+ case 'library_artists_uri':
+ this.props.mopidyActions.clearLibraryArtists();
+ break;
+ }
+ }
- return (
-
-
-
- Apply and reload
-
-
- )
- }
+ renderApplyButton() {
+ if (this.props.mopidy.host == this.state.mopidy_host
+ && this.props.mopidy.port == this.state.mopidy_port) {
+ return null;
+ }
- renderServerStatus(){
- var colour = 'grey';
- var icon = 'help';
- var status = 'Unknown';
- var className = null;
+ return (
+
+
+
+ Apply and reload
+
+
+ );
+ }
- if (this.props.mopidy.connecting || this.props.pusher.connecting){
- icon = 'autorenew';
- status = 'Connecting...';
- className = 'icon--spin';
- } else if (!this.props.mopidy.connected || !this.props.pusher.connected){
- colour = 'red';
- icon = 'close';
- status = 'Disconnected';
- } else if (this.props.mopidy.connected && this.props.pusher.connected){
- colour = 'green';
- icon = 'check';
- status = 'Connected';
- }
+ renderServerStatus() {
+ let colour = 'grey';
+ let icon = 'help';
+ let status = 'Unknown';
+ let className = null;
- return (
-
- {status}
-
- );
- }
+ if (this.props.mopidy.connecting || this.props.pusher.connecting) {
+ icon = 'autorenew';
+ status = 'Connecting...';
+ className = 'icon--spin';
+ } else if (!this.props.mopidy.connected || !this.props.pusher.connected) {
+ colour = 'red';
+ icon = 'close';
+ status = 'Disconnected';
+ } else if (this.props.mopidy.connected && this.props.pusher.connected) {
+ colour = 'green';
+ icon = 'check';
+ status = 'Connected';
+ }
- render(){
+ return (
+
+
+ {' '}
+ {status}
+
+ );
+ }
- var options = (
-
- this.props.history.push('/settings/debug')}>
- Debug
-
-
- Help
-
-
- )
+ render() {
+ const options = (
+
+ this.props.history.push('/settings/debug')}>
+
+Debug
+
+
+
+Help
+
+
+ );
- return (
-
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return state;
-}
+const mapStateToProps = (state, ownProps) => state;
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- lastfmActions: bindActionCreators(lastfmActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ lastfmActions: bindActionCreators(lastfmActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(Settings)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Settings);
diff --git a/src/js/views/Track.js b/src/js/views/Track.js
index 78675ea8..39f5fc66 100755
--- a/src/js/views/Track.js
+++ b/src/js/views/Track.js
@@ -27,243 +27,269 @@ import * as spotifyActions from '../services/spotify/actions';
import * as lastfmActions from '../services/lastfm/actions';
import * as geniusActions from '../services/genius/actions';
-class Track extends React.Component{
+class Track extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.props.coreActions.loadTrack(this.props.uri);
- componentDidMount(){
- this.props.coreActions.loadTrack(this.props.uri);
+ // We already have the track in our index, so it won't fire componentWillReceiveProps
+ if (this.props.track) {
+ this.setWindowTitle(this.props.track);
- // We already have the track in our index, so it won't fire componentWillReceiveProps
- if (this.props.track){
- this.setWindowTitle(this.props.track);
+ if (this.props.genius_authorized && this.props.track.artists && !this.props.track.lyrics_results) {
+ this.props.geniusActions.findTrackLyrics(this.props.track);
+ }
+ }
+ }
- if (this.props.genius_authorized && this.props.track.artists && !this.props.track.lyrics_results){
- this.props.geniusActions.findTrackLyrics(this.props.track);
- }
- }
- }
+ handleContextMenu(e) {
+ e.preventDefault();
+ const data = { uris: [this.props.uri] };
+ this.props.uiActions.showContextMenu(e, data, 'track', 'click');
+ }
- handleContextMenu(e){
- e.preventDefault()
- var data = { uris: [this.props.uri] }
- this.props.uiActions.showContextMenu(e, data, 'track', 'click' )
- }
+ componentWillReceiveProps(nextProps) {
+ // if our URI has changed, fetch new track
+ if (nextProps.uri != this.props.uri) {
+ this.props.coreActions.loadTrack(nextProps.uri);
- componentWillReceiveProps(nextProps){
+ if (nextProps.genius_authorized && nextProps.tracks.artists) {
+ this.props.geniusActions.findTrackLyrics(nextProps.track);
+ }
- // if our URI has changed, fetch new track
- if (nextProps.uri != this.props.uri){
- this.props.coreActions.loadTrack(nextProps.uri);
+ // if mopidy has just connected AND we're not a Spotify track, go get
+ } else if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
+ if (helpers.uriSource(this.props.uri) != 'spotify') {
+ this.props.coreActions.loadTrack(nextProps.uri);
+ }
+ }
- if (nextProps.genius_authorized && nextProps.tracks.artists){
- this.props.geniusActions.findTrackLyrics(nextProps.track);
- }
+ // We have just received our full track or our track artists
+ if ((!this.props.track && nextProps.track) || (!this.props.track.artists && nextProps.track.artists)) {
+ this.setWindowTitle(nextProps.track);
- // if mopidy has just connected AND we're not a Spotify track, go get
- } else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
- if (helpers.uriSource(this.props.uri) != 'spotify'){
- this.props.coreActions.loadTrack(nextProps.uri);
- }
- }
+ // Ready to load LastFM
+ if (nextProps.lastfm_authorized) {
+ this.props.lastfmActions.getTrack(nextProps.track.uri);
+ }
- // We have just received our full track or our track artists
- if ((!this.props.track && nextProps.track) || (!this.props.track.artists && nextProps.track.artists)){
+ // Ready to load lyrics
+ if (nextProps.genius_authorized && !nextProps.track.lyrics_results) {
+ this.props.geniusActions.findTrackLyrics(nextProps.track);
+ }
+ }
- this.setWindowTitle(nextProps.track);
+ if (!this.props.track && nextProps.track) {
+ this.setWindowTitle(nextProps.track);
+ }
+ }
- // Ready to load LastFM
- if (nextProps.lastfm_authorized){
- this.props.lastfmActions.getTrack(nextProps.track.uri);
- }
+ setWindowTitle(track = this.props.track) {
+ if (track) {
+ let artists = '';
+ for (let i = 0; i < track.artists.length; i++) {
+ if (artists != '') {
+ artists += ', ';
+ }
+ artists += track.artists[i].name;
+ }
+ this.props.uiActions.setWindowTitle(`${track.name} by ${artists} (track)`);
+ } else {
+ this.props.uiActions.setWindowTitle('Track');
+ }
+ }
- // Ready to load lyrics
- if (nextProps.genius_authorized && !nextProps.track.lyrics_results){
- this.props.geniusActions.findTrackLyrics(nextProps.track);
- }
- }
+ handleContextMenu(e) {
+ const data = {
+ e,
+ context: 'track',
+ items: [this.props.track],
+ uris: [this.props.uri],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- if (!this.props.track && nextProps.track){
- this.setWindowTitle(nextProps.track);
- }
- }
+ play() {
+ this.props.mopidyActions.playURIs([this.props.uri], this.props.uri);
+ }
- setWindowTitle(track = this.props.track){
- if (track){
- var artists = "";
- for (var i = 0; i < track.artists.length; i++){
- if (artists != ""){
- artists += ", ";
- }
- artists += track.artists[i].name;
- }
- this.props.uiActions.setWindowTitle(track.name+" by "+artists+" (track)");
- } else{
- this.props.uiActions.setWindowTitle("Track");
- }
- }
-
- handleContextMenu(e){
- var data = {
- e: e,
- context: 'track',
- items: [this.props.track],
- uris: [this.props.uri]
- }
- this.props.uiActions.showContextMenu(data)
- }
-
- play(){
- this.props.mopidyActions.playURIs([this.props.uri], this.props.uri)
- }
-
- renderLyricsSelector(){
- if (this.props.track.lyrics_results === undefined || this.props.track.lyrics_results === null){
- return null;
-
- } else if (this.props.track.lyrics_results.length <= 0){
- return (
-
-
-
-
+ renderLyricsSelector() {
+ if (this.props.track.lyrics_results === undefined || this.props.track.lyrics_results === null) {
+ return null;
+ } if (this.props.track.lyrics_results.length <= 0) {
+ return (
+
+
+
+
Switch to another lyrics seach result
-
-
-
- );
- }
+
+
+
+ );
+ }
- return (
-
-
-
this.props.geniusActions.getTrackLyrics(this.props.track.uri, e.target.value)}>
- {
- this.props.track.lyrics_results.map(result => {
- return (
-
- {result.title}
-
- )
- })
+ return (
+
+
+
this.props.geniusActions.getTrackLyrics(this.props.track.uri, e.target.value)}
+ >
+ {
+ this.props.track.lyrics_results.map((result) => (
+
+ {result.title}
+
+ ))
}
-
-
+
+
Switch to another lyrics seach result
-
-
-
- );
- }
+
+
+
+ );
+ }
- renderLyrics(){
- if (helpers.isLoading(this.props.load_queue,['genius_'])){
- return (
-
- );
- } else if (this.props.track.lyrics){
- return (
-
- )
- } else {
- return (
-
- Could not find track with URI "{encodeURIComponent(this.props.uri)}"
-
- );
- }
- }
+ renderLyrics() {
+ if (helpers.isLoading(this.props.load_queue, ['genius_'])) {
+ return (
+
+ );
+ } if (this.props.track.lyrics) {
+ return (
+
+ );
+ }
+ return (
+
+
+Could not find track with URI "
+ {encodeURIComponent(this.props.uri)}
+"
+
+
+ );
+ }
- render(){
- if (helpers.isLoading(this.props.load_queue,['spotify_track/'+helpers.getFromUri('trackid',this.props.uri)])){
- return (
-
- )
- }
+ render() {
+ if (helpers.isLoading(this.props.load_queue, [`spotify_track/${helpers.getFromUri('trackid', this.props.uri)}`])) {
+ return (
+
+ );
+ }
- if (!this.props.track){
- return null
- } else {
- var track = this.props.track;
+ if (!this.props.track) {
+ return null;
+ }
+ const { track } = this.props;
- // Flatten our simple album so we can inherit artwork
- if (track.album){
- var album = this.props.albums[track.album.uri];
+ // Flatten our simple album so we can inherit artwork
+ if (track.album) {
+ const album = this.props.albums[track.album.uri];
- if (album && album.images){
- track.images = album.images;
- }
- }
- }
+ if (album && album.images) {
+ track.images = album.images;
+ }
+ }
- return (
-
- {this.props.slim_mode ?
+ );
+ }
}
/**
@@ -276,53 +302,51 @@ class Track extends React.Component{
*
* @param uri String
* @return String
- **/
+ * */
const rebuildUri = (uri) => {
- var rebuilt_uri = helpers.uriSource(uri)+':'+helpers.uriType(uri)+':';
+ const rebuilt_uri = `${helpers.uriSource(uri)}:${helpers.uriType(uri)}:`;
- // Escape unreserved characters (RFC 3986)
- // https://stackoverflow.com/questions/18251399/why-doesnt-encodeuricomponent-encode-single-quotes-apostrophes
- var id = helpers.getFromUri('trackid', uri);
- id = encodeURIComponent(id).replace(/[!'()*]/g, escape);
+ // Escape unreserved characters (RFC 3986)
+ // https://stackoverflow.com/questions/18251399/why-doesnt-encodeuricomponent-encode-single-quotes-apostrophes
+ let id = helpers.getFromUri('trackid', uri);
+ id = encodeURIComponent(id).replace(/[!'()*]/g, escape);
- // Reinstate slashes for the Mopidy-Local structure
- id = id.replace(/%2F/g, '/');
+ // Reinstate slashes for the Mopidy-Local structure
+ id = id.replace(/%2F/g, '/');
- return rebuilt_uri+id;
-}
+ return rebuilt_uri + id;
+};
const mapStateToProps = (state, ownProps) => {
- var uri = decodeURIComponent(ownProps.match.params.uri);
- uri = rebuildUri(uri);
+ let uri = decodeURIComponent(ownProps.match.params.uri);
+ uri = rebuildUri(uri);
- console.log(uri);
+ console.log(uri);
- return {
- uri: uri,
- slim_mode: state.ui.slim_mode,
- load_queue: state.ui.load_queue,
- track: (state.core.tracks && state.core.tracks[uri] !== undefined ? state.core.tracks[uri] : false),
- tracks: state.core.tracks,
- artists: state.core.artists,
- albums: state.core.albums,
- spotify_library_albums: state.spotify.library_albums,
- local_library_albums: state.mopidy.library_albums,
- lastfm_authorized: state.lastfm.authorization,
- spotify_authorized: state.spotify.authorization,
- genius_authorized: state.genius.authorization,
- mopidy_connected: state.mopidy.connected
- };
-}
+ return {
+ uri,
+ slim_mode: state.ui.slim_mode,
+ load_queue: state.ui.load_queue,
+ track: (state.core.tracks && state.core.tracks[uri] !== undefined ? state.core.tracks[uri] : false),
+ tracks: state.core.tracks,
+ artists: state.core.artists,
+ albums: state.core.albums,
+ spotify_library_albums: state.spotify.library_albums,
+ local_library_albums: state.mopidy.library_albums,
+ lastfm_authorized: state.lastfm.authorization,
+ spotify_authorized: state.spotify.authorization,
+ genius_authorized: state.genius.authorization,
+ mopidy_connected: state.mopidy.connected,
+ };
+};
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- lastfmActions: bindActionCreators(lastfmActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch),
- geniusActions: bindActionCreators(geniusActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ lastfmActions: bindActionCreators(lastfmActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+ geniusActions: bindActionCreators(geniusActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(Track)
+export default connect(mapStateToProps, mapDispatchToProps)(Track);
diff --git a/src/js/views/User.js b/src/js/views/User.js
index 18127665..9a046ce7 100755
--- a/src/js/views/User.js
+++ b/src/js/views/User.js
@@ -1,7 +1,7 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
import ErrorMessage from '../components/ErrorMessage';
import Thumbnail from '../components/Thumbnail';
@@ -19,147 +19,159 @@ import * as uiActions from '../services/ui/actions';
import * as mopidyActions from '../services/mopidy/actions';
import * as spotifyActions from '../services/spotify/actions';
-class User extends React.Component{
+class User extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.setWindowTitle();
+ this.props.coreActions.loadUser(this.props.uri);
+ this.props.coreActions.loadUserPlaylists(this.props.uri);
+ }
- componentDidMount(){
- this.setWindowTitle();
- this.props.coreActions.loadUser(this.props.uri);
- this.props.coreActions.loadUserPlaylists(this.props.uri);
- }
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.uri != this.props.uri) {
+ this.props.coreActions.loadUser(nextProps.uri);
+ this.props.coreActions.loadUserPlaylists(this.props.uri);
+ }
- componentWillReceiveProps(nextProps){
- if (nextProps.uri != this.props.uri){
- this.props.coreActions.loadUser(nextProps.uri);
- this.props.coreActions.loadUserPlaylists(this.props.uri);
- }
+ if (!this.props.user && nextProps.user) {
+ this.setWindowTitle(nextProps.user);
+ }
+ }
- if (!this.props.user && nextProps.user){
- this.setWindowTitle(nextProps.user);
- }
- }
+ setWindowTitle(user = this.props.user) {
+ if (user) {
+ this.props.uiActions.setWindowTitle(`${user.name} (user)`);
+ } else {
+ this.props.uiActions.setWindowTitle('User');
+ }
+ }
- setWindowTitle(user = this.props.user){
- if (user){
- this.props.uiActions.setWindowTitle(user.name+" (user)");
- } else{
- this.props.uiActions.setWindowTitle("User");
- }
- }
+ loadMore() {
+ this.props.spotifyActions.getMore(
+ this.props.user.playlists_more,
+ {
+ parent_type: 'user',
+ parent_key: this.props.uri,
+ records_type: 'playlist',
+ },
+ );
+ }
- loadMore(){
- this.props.spotifyActions.getMore(
- this.props.user.playlists_more,
- {
- parent_type: 'user',
- parent_key: this.props.uri,
- records_type: 'playlist'
- }
- );
- }
+ isMe() {
+ const userid = helpers.getFromUri('userid', this.props.uri);
+ return (this.props.me && this.props.me.id && this.props.me.id == userid);
+ }
- isMe(){
- let userid = helpers.getFromUri('userid',this.props.uri);
- return (this.props.me && this.props.me.id && this.props.me.id == userid);
- }
+ render() {
+ const user_id = helpers.getFromUri('userid', this.props.uri);
- render(){
- var user_id = helpers.getFromUri('userid',this.props.uri);
+ if (!this.props.user) {
+ if (helpers.isLoading(this.props.load_queue, [`spotify_users/${user_id}`, `spotify_users/${user_id}/playlists/?`])) {
+ return (
+
+ );
+ }
+ return (
+
+
+Could not find user with URI "
+ {encodeURIComponent(this.props.uri)}
+"
+
+
+ );
+ }
- if (!this.props.user){
- if (helpers.isLoading(this.props.load_queue,['spotify_users/'+user_id,'spotify_users/'+user_id+'/playlists/?'])){
- return (
-
- )
- } else {
- return (
-
- Could not find user with URI "{encodeURIComponent(this.props.uri)}"
-
- );
- }
- }
+ const user = helpers.collate(this.props.user, { playlists: this.props.playlists });
- var user = helpers.collate(this.props.user, {playlists: this.props.playlists});
+ if (user && user.images) {
+ var image = user.images.huge;
+ } else {
+ var image = null;
+ }
- if (user && user.images){
- var image = user.images.huge;
- } else {
- var image = null;
- }
+ return (
+
+
- return (
-
-
+
-
+
+
-
-
+
+
+
-
-
-
+
+
{user.name}
+
+
+
+
+
+
+ {!this.props.slim_mode ? : null}
+ {user.playlists_total ? (
+
+
+ {' '}
+playlists
+
+ ) : null}
+ {user.followers ? (
+
+
+ {' '}
+followers
+
+ ) : null}
+ {this.isMe() ? You : null}
+
+
+
+
+
+
+
-
-
{user.name}
-
-
-
-
-
-
- {!this.props.slim_mode ? : null}
- {user.playlists_total ? playlists : null}
- {user.followers ? followers : null}
- {this.isMe() ? You : null}
-
-
-
-
-
-
-
-
-
-
- Playlists
-
- this.loadMore()}
- />
-
-
-
- )
- }
+
+
+ Playlists
+
+ this.loadMore()}
+ />
+
+
+
+ );
+ }
}
const mapStateToProps = (state, ownProps) => {
- var uri = decodeURIComponent(ownProps.match.params.uri);
- return {
- uri: uri,
- me: state.spotify.me,
- load_queue: state.ui.load_queue,
- spotify_authorized: state.spotify.authorization,
- playlists: state.core.playlists,
- user: (state.core.users[uri] !== undefined ? state.core.users[uri] : false)
- };
-}
+ const uri = decodeURIComponent(ownProps.match.params.uri);
+ return {
+ uri,
+ me: state.spotify.me,
+ load_queue: state.ui.load_queue,
+ spotify_authorized: state.spotify.authorization,
+ playlists: state.core.playlists,
+ user: (state.core.users[uri] !== undefined ? state.core.users[uri] : false),
+ };
+};
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(User)
+export default connect(mapStateToProps, mapDispatchToProps)(User);
diff --git a/src/js/views/discover/DiscoverCategories.js b/src/js/views/discover/DiscoverCategories.js
index a8fb795a..ae369746 100755
--- a/src/js/views/discover/DiscoverCategories.js
+++ b/src/js/views/discover/DiscoverCategories.js
@@ -1,67 +1,65 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
-import Header from '../../components/Header'
-import Icon from '../../components/Icon'
-import CategoryGrid from '../../components/CategoryGrid'
+import Header from '../../components/Header';
+import Icon from '../../components/Icon';
+import CategoryGrid from '../../components/CategoryGrid';
-import * as helpers from '../../helpers'
-import * as uiActions from '../../services/ui/actions'
-import * as spotifyActions from '../../services/spotify/actions'
+import * as helpers from '../../helpers';
+import * as uiActions from '../../services/ui/actions';
+import * as spotifyActions from '../../services/spotify/actions';
-class DiscoverCategories extends React.Component{
+class DiscoverCategories extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ // Check for an empty category index, or where we've only got one loaded
+ // This would be the case if you've refreshed from within a category and only loaded
+ // the single record.
+ if (!this.props.categories || Object.keys(this.props.categories).length <= 1) {
+ this.props.spotifyActions.getCategories();
+ }
+ this.props.uiActions.setWindowTitle('Genre / Mood');
+ }
- componentDidMount(){
+ render() {
+ if (helpers.isLoading(this.props.load_queue, ['spotify_browse/categories'])) {
+ return (
+
+ );
+ }
- // Check for an empty category index, or where we've only got one loaded
- // This would be the case if you've refreshed from within a category and only loaded
- // the single record.
- if (!this.props.categories || Object.keys(this.props.categories).length <= 1){
- this.props.spotifyActions.getCategories();
- }
- this.props.uiActions.setWindowTitle("Genre / Mood");
- }
+ // convert categories object into simple array
+ const categories = [];
+ if (this.props.categories) {
+ for (const key in this.props.categories) {
+ if (this.props.categories.hasOwnProperty(key)) {
+ categories.push(this.props.categories[key]);
+ }
+ }
+ }
- render(){
- if (helpers.isLoading(this.props.load_queue,['spotify_browse/categories'])){
- return (
-
- )
- }
-
- // convert categories object into simple array
- var categories = []
- if (this.props.categories){
- for (var key in this.props.categories){
- if (this.props.categories.hasOwnProperty(key)){
- categories.push(this.props.categories[key])
- }
- }
- }
-
- return (
-
+ );
+ }
}
@@ -69,20 +67,16 @@ class DiscoverCategories extends React.Component{
* Export our component
*
* We also integrate our global store, using connect()
- **/
+ * */
-const mapStateToProps = (state, ownProps) => {
- return {
- categories: state.spotify.categories,
- load_queue: state.ui.load_queue
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ categories: state.spotify.categories,
+ load_queue: state.ui.load_queue,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(DiscoverCategories)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(DiscoverCategories);
diff --git a/src/js/views/discover/DiscoverCategory.js b/src/js/views/discover/DiscoverCategory.js
index 410146ec..cdde6d99 100755
--- a/src/js/views/discover/DiscoverCategory.js
+++ b/src/js/views/discover/DiscoverCategory.js
@@ -1,122 +1,117 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
-import Header from '../../components/Header'
-import Icon from '../../components/Icon'
-import PlaylistGrid from '../../components/PlaylistGrid'
-import LazyLoadListener from '../../components/LazyLoadListener'
+import Header from '../../components/Header';
+import Icon from '../../components/Icon';
+import PlaylistGrid from '../../components/PlaylistGrid';
+import LazyLoadListener from '../../components/LazyLoadListener';
-import * as helpers from '../../helpers'
-import * as uiActions from '../../services/ui/actions'
-import * as spotifyActions from '../../services/spotify/actions'
+import * as helpers from '../../helpers';
+import * as uiActions from '../../services/ui/actions';
+import * as spotifyActions from '../../services/spotify/actions';
-class DiscoverCategory extends React.Component{
+class DiscoverCategory extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.loadCategory();
+ this.setWindowTitle();
+ }
- componentDidMount(){
- this.loadCategory();
- this.setWindowTitle();
- }
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.match.params.id != this.props.match.params.id) {
+ this.loadCategory();
+ }
- componentWillReceiveProps(nextProps){
- if (nextProps.match.params.id != this.props.match.params.id){
- this.loadCategory();
- }
+ if (!this.props.category && nextProps.category) {
+ this.setWindowTitle(nextProps.category);
+ }
+ }
- if (!this.props.category && nextProps.category){
- this.setWindowTitle(nextProps.category);
- }
- }
+ setWindowTitle(category = this.props.category) {
+ if (category) {
+ this.props.uiActions.setWindowTitle(category.name);
+ } else {
+ this.props.uiActions.setWindowTitle('Genre / Mood');
+ }
+ }
- setWindowTitle(category = this.props.category){
- if (category){
- this.props.uiActions.setWindowTitle(category.name);
- } else{
- this.props.uiActions.setWindowTitle("Genre / Mood");
- }
- }
+ loadCategory() {
+ if (!this.props.category) {
+ this.props.spotifyActions.getCategory(this.props.match.params.id);
+ }
- loadCategory(){
- if (!this.props.category){
- this.props.spotifyActions.getCategory(this.props.match.params.id);
- }
+ if (!this.props.category.playlists_uris) {
+ this.props.spotifyActions.getCategoryPlaylists(this.props.match.params.id);
+ }
+ }
- if (!this.props.category.playlists_uris){
- this.props.spotifyActions.getCategoryPlaylists(this.props.match.params.id);
- }
- }
+ loadMore() {
+ this.props.spotifyActions.getMore(
+ this.props.category.playlists_more,
+ null,
+ {
+ type: 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED_MORE',
+ uri: `category:${this.props.match.params.id}`,
+ },
+ );
+ }
- loadMore(){
- this.props.spotifyActions.getMore(
- this.props.category.playlists_more,
- null,
- {
- type: 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED_MORE',
- uri: 'category:'+this.props.match.params.id
- }
- );
- }
+ render() {
+ if (helpers.isLoading(this.props.load_queue, ['spotify_browse/categories/'])) {
+ return (
+
+
+
+ {(this.props.category ? this.props.category.name : 'Category')}
+
+
+
+ );
+ }
- render(){
- if (helpers.isLoading(this.props.load_queue,['spotify_browse/categories/'])){
- return (
-
-
-
- {(this.props.category ? this.props.category.name : 'Category')}
-
-
-
- )
- }
+ if (!this.props.category) {
+ return null;
+ }
- if (!this.props.category){
- return null;
- }
+ const category = helpers.collate(this.props.category, { playlists: this.props.playlists });
- var category = helpers.collate(this.props.category, {playlists: this.props.playlists});
-
- return (
-
-
-
-
-
this.loadMore()}
- />
-
-
- );
- }
+ return (
+
+
+
+
+
this.loadMore()}
+ />
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- load_queue: state.ui.load_queue,
- playlists: state.core.playlists,
- category: (state.spotify.categories && state.spotify.categories['category:'+ownProps.match.params.id] !== undefined ? state.spotify.categories['category:'+ownProps.match.params.id] : false )
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ load_queue: state.ui.load_queue,
+ playlists: state.core.playlists,
+ category: (state.spotify.categories && state.spotify.categories[`category:${ownProps.match.params.id}`] !== undefined ? state.spotify.categories[`category:${ownProps.match.params.id}`] : false),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(DiscoverCategory)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(DiscoverCategory);
diff --git a/src/js/views/discover/DiscoverFeatured.js b/src/js/views/discover/DiscoverFeatured.js
index b218bd54..4557da41 100755
--- a/src/js/views/discover/DiscoverFeatured.js
+++ b/src/js/views/discover/DiscoverFeatured.js
@@ -1,7 +1,7 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
import Link from '../../components/Link';
import PlaylistGrid from '../../components/PlaylistGrid';
@@ -17,114 +17,109 @@ import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
-class DiscoverFeatured extends React.Component{
+class DiscoverFeatured extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Featured playlists');
+ if (!this.props.featured_playlists) {
+ this.props.spotifyActions.getFeaturedPlaylists();
+ }
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Featured playlists");
- if (!this.props.featured_playlists){
- this.props.spotifyActions.getFeaturedPlaylists();
- }
- }
+ playPlaylist(e, playlist) {
+ this.props.mopidyActions.playPlaylist(playlist.uri);
+ }
- playPlaylist(e,playlist){
- this.props.mopidyActions.playPlaylist(playlist.uri)
- }
+ handleContextMenu(e, item) {
+ e.preventDefault();
+ const data = {
+ e,
+ context: 'playlist',
+ uris: [item.uri],
+ items: [item],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- handleContextMenu(e,item){
- e.preventDefault()
- var data = {
- e: e,
- context: 'playlist',
- uris: [item.uri],
- items: [item]
- }
- this.props.uiActions.showContextMenu(data)
- }
+ renderIntro(playlist = null) {
+ if (playlist) {
+ return (
+
+ );
+ }
+ return (
+
+ );
+ }
- renderIntro(playlist = null){
- if (playlist){
- return (
-
- )
- } else {
- return (
-
- )
- }
- }
-
- render(){
- if (helpers.isLoading(this.props.load_queue,['spotify_browse/featured-playlists'])){
- return (
-
-
-
+ render() {
+ if (helpers.isLoading(this.props.load_queue, ['spotify_browse/featured-playlists'])) {
+ return (
+
- )
- }
+
+
+
+ );
+ }
- var playlists = []
- if (this.props.featured_playlists){
- for (var i = 0; i < this.props.featured_playlists.playlists.length; i++){
- var uri = this.props.featured_playlists.playlists[i]
- if (this.props.playlists.hasOwnProperty(uri)){
- playlists.push(this.props.playlists[uri])
- }
- }
- }
+ const playlists = [];
+ if (this.props.featured_playlists) {
+ for (let i = 0; i < this.props.featured_playlists.playlists.length; i++) {
+ const uri = this.props.featured_playlists.playlists[i];
+ if (this.props.playlists.hasOwnProperty(uri)) {
+ playlists.push(this.props.playlists[uri]);
+ }
+ }
+ }
- // Pull the first playlist out and we'll use this for the parallax artwork
- var first_playlist = playlists[0];
+ // Pull the first playlist out and we'll use this for the parallax artwork
+ const first_playlist = playlists[0];
- var options = (
- {this.props.uiActions.hideContextMenu(); this.props.spotifyActions.getFeaturedPlaylists()}}>
- Refresh
-
- );
+ const options = (
+ { this.props.uiActions.hideContextMenu(); this.props.spotifyActions.getFeaturedPlaylists(); }}>
+
+Refresh
+
+ );
- return (
-
-
+ {this.renderIntro(first_playlist)}
+
+ {playlists ? : null }
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- theme: state.ui.theme,
- load_queue: state.ui.load_queue,
- featured_playlists: state.spotify.featured_playlists,
- playlists: state.core.playlists
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ theme: state.ui.theme,
+ load_queue: state.ui.load_queue,
+ featured_playlists: state.spotify.featured_playlists,
+ playlists: state.core.playlists,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(DiscoverFeatured)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(DiscoverFeatured);
diff --git a/src/js/views/discover/DiscoverNewReleases.js b/src/js/views/discover/DiscoverNewReleases.js
index cb221e4b..53effd98 100755
--- a/src/js/views/discover/DiscoverNewReleases.js
+++ b/src/js/views/discover/DiscoverNewReleases.js
@@ -17,135 +17,130 @@ import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
-class DiscoverNewReleases extends React.Component{
+class DiscoverNewReleases extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('New releases');
- componentDidMount(){
- this.props.uiActions.setWindowTitle("New releases");
+ if (!this.props.new_releases) {
+ this.props.spotifyActions.getNewReleases();
+ }
+ }
- if (!this.props.new_releases){
- this.props.spotifyActions.getNewReleases();
- }
- }
+ loadMore() {
+ this.props.spotifyActions.getMore(
+ this.props.new_releases_more,
+ null,
+ {
+ type: 'SPOTIFY_NEW_RELEASES_LOADED',
+ },
+ );
+ }
- loadMore(){
- this.props.spotifyActions.getMore(
- this.props.new_releases_more,
- null,
- {
- type: 'SPOTIFY_NEW_RELEASES_LOADED'
- }
- );
- }
+ playAlbum(e, album) {
+ this.props.mopidyActions.playURIs([album.uri], album.uri);
+ }
- playAlbum(e,album){
- this.props.mopidyActions.playURIs([album.uri],album.uri)
- }
+ handleContextMenu(e, item) {
+ e.preventDefault();
+ const data = {
+ e,
+ context: 'album',
+ uris: [item.uri],
+ items: [item],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- handleContextMenu(e,item){
- e.preventDefault()
- var data = {
- e: e,
- context: 'album',
- uris: [item.uri],
- items: [item]
- }
- this.props.uiActions.showContextMenu(data)
- }
+ renderIntro(album = null) {
+ if (album) {
+ return (
+
+ );
+ }
+ return (
+
+ );
+ }
- renderIntro(album = null){
- if (album){
- return (
-
- )
- } else {
- return (
-
- )
- }
- }
-
- render(){
- if (helpers.isLoading(this.props.load_queue,['spotify_browse/new-releases'])){
- return (
-
-
-
+ render() {
+ if (helpers.isLoading(this.props.load_queue, ['spotify_browse/new-releases'])) {
+ return (
+
- )
- }
+
+
+
+ );
+ }
- var albums = [];
- if (this.props.new_releases){
- for (var uri of this.props.new_releases){
- if (this.props.albums.hasOwnProperty(uri)){
- albums.push(this.props.albums[uri]);
- }
- }
- }
+ const albums = [];
+ if (this.props.new_releases) {
+ for (const uri of this.props.new_releases) {
+ if (this.props.albums.hasOwnProperty(uri)) {
+ albums.push(this.props.albums[uri]);
+ }
+ }
+ }
- // Pull the first playlist out and we'll use this as a banner
- var first_album = albums[0];
- if (first_album){
- first_album = helpers.collate(first_album, {artists: this.props.artists});
- }
+ // Pull the first playlist out and we'll use this as a banner
+ let first_album = albums[0];
+ if (first_album) {
+ first_album = helpers.collate(first_album, { artists: this.props.artists });
+ }
- var options = (
- {this.props.uiActions.hideContextMenu(); this.props.spotifyActions.getNewReleases()}}>
- Refresh
-
- );
+ const options = (
+ { this.props.uiActions.hideContextMenu(); this.props.spotifyActions.getNewReleases(); }}>
+
+Refresh
+
+ );
- return (
-
-
+ {this.renderIntro(first_album)}
+
+
this.loadMore()}
+ />
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- theme: state.ui.theme,
- load_queue: state.ui.load_queue,
- artists: state.core.artists,
- albums: state.core.albums,
- new_releases: (state.spotify.new_releases ? state.spotify.new_releases : null),
- new_releases_more: (state.spotify.new_releases_more ? state.spotify.new_releases_more : null),
- new_releases_total: (state.spotify.new_releases_total ? state.spotify.new_releases_total : null)
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ theme: state.ui.theme,
+ load_queue: state.ui.load_queue,
+ artists: state.core.artists,
+ albums: state.core.albums,
+ new_releases: (state.spotify.new_releases ? state.spotify.new_releases : null),
+ new_releases_more: (state.spotify.new_releases_more ? state.spotify.new_releases_more : null),
+ new_releases_total: (state.spotify.new_releases_total ? state.spotify.new_releases_total : null),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(DiscoverNewReleases)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(DiscoverNewReleases);
diff --git a/src/js/views/discover/DiscoverRecommendations.js b/src/js/views/discover/DiscoverRecommendations.js
index 07915981..5266e111 100755
--- a/src/js/views/discover/DiscoverRecommendations.js
+++ b/src/js/views/discover/DiscoverRecommendations.js
@@ -23,550 +23,532 @@ import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
-class Discover extends React.Component{
+class Discover extends React.Component {
+ constructor(props) {
+ super(props);
- constructor(props){
- super(props)
+ this._autocomplete_timer = false;
- this._autocomplete_timer = false
+ this.state = {
+ add_seed: '',
+ adding_seed: false,
+ seeds: [],
+ tunabilities: {
+ acousticness: {
+ enabled: false,
+ convert_to_decimal: true,
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ danceability: {
+ enabled: false,
+ convert_to_decimal: true,
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ energy: {
+ enabled: false,
+ convert_to_decimal: true,
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ instrumentalness: {
+ enabled: false,
+ convert_to_decimal: true,
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ key: {
+ enabled: false,
+ min: 0,
+ max: 11,
+ value: {
+ min: 3,
+ max: 8,
+ },
+ },
+ liveness: {
+ enabled: false,
+ convert_to_decimal: true,
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ loudness: {
+ enabled: false,
+ convert_to_decimal: true,
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ popularity: {
+ enabled: false,
+ min: 0,
+ max: 100,
+ value: {
+ min: 0,
+ max: 100,
+ },
+ },
+ speechiness: {
+ enabled: false,
+ convert_to_decimal: true,
+ description: 'The presence of spoken words in a track',
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ tempo: {
+ enabled: false,
+ convert_to_decimal: true,
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ valence: {
+ enabled: false,
+ convert_to_decimal: true,
+ description: 'The musical positiveness conveyed by a track',
+ min: 0,
+ max: 100,
+ value: {
+ min: 25,
+ max: 75,
+ },
+ },
+ },
+ };
+ }
- this.state = {
- add_seed: '',
- adding_seed: false,
- seeds: [],
- tunabilities: {
- acousticness: {
- enabled: false,
- convert_to_decimal: true,
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- danceability: {
- enabled: false,
- convert_to_decimal: true,
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- energy: {
- enabled: false,
- convert_to_decimal: true,
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- instrumentalness: {
- enabled: false,
- convert_to_decimal: true,
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- key: {
- enabled: false,
- min: 0,
- max: 11,
- value: {
- min: 3,
- max: 8
- }
- },
- liveness: {
- enabled: false,
- convert_to_decimal: true,
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- loudness: {
- enabled: false,
- convert_to_decimal: true,
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- popularity: {
- enabled: false,
- min: 0,
- max: 100,
- value: {
- min: 0,
- max: 100
- }
- },
- speechiness: {
- enabled: false,
- convert_to_decimal: true,
- description: "The presence of spoken words in a track",
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- tempo: {
- enabled: false,
- convert_to_decimal: true,
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- },
- valence: {
- enabled: false,
- convert_to_decimal: true,
- description: "The musical positiveness conveyed by a track",
- min: 0,
- max: 100,
- value: {
- min: 25,
- max: 75
- }
- }
- }
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Discover');
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Discover");
+ // We have seeds provided in the URL
+ if (this.props.match.params.seeds) {
+ this.handleURLSeeds(this.props.match.params.seeds);
+ }
+ }
- // We have seeds provided in the URL
- if (this.props.match.params.seeds){
- this.handleURLSeeds(this.props.match.params.seeds);
- }
- }
+ componentWillReceiveProps(newProps, newState) {
+ // New seeds via URL
+ if (newProps.match.params.seeds != this.props.match.params.seeds) {
+ this.handleURLSeeds(newProps.match.params.seeds);
+ }
+ }
- componentWillReceiveProps(newProps, newState){
+ handleContextMenu(e) {
+ var uri = 'iris:discover';
+ if (this.state.seeds) {
+ uri += ':';
+ for (var i = 0; i < this.state.seeds.length; i++) {
+ if (i > 0) {
+ uri += ',';
+ }
+ uri += this.state.seeds[i].split(':').join('_');
+ }
+ }
- // New seeds via URL
- if (newProps.match.params.seeds != this.props.match.params.seeds){
- this.handleURLSeeds(newProps.match.params.seeds)
- }
- }
+ const tracks = [];
+ if (this.props.recommendations.tracks_uris && this.props.tracks) {
+ for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++) {
+ var uri = this.props.recommendations.tracks_uris[i];
+ if (this.props.tracks.hasOwnProperty(uri)) {
+ tracks.push(this.props.tracks[uri]);
+ }
+ }
+ }
- handleContextMenu(e){
+ const data = {
+ e,
+ context: 'track',
+ items: tracks,
+ uris: helpers.arrayOf('uri', tracks),
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- var uri = 'iris:discover';
- if (this.state.seeds){
- uri += ':';
- for (var i = 0; i < this.state.seeds.length; i++){
- if (i > 0){
- uri += ',';
- }
- uri += this.state.seeds[i].split(':').join('_');
- }
- }
+ handleURLSeeds(seeds_string = this.props.match.params.seeds) {
+ // Rejoin if we've had to uri-encode these as strings
+ // We'd need to do this if our URL has been encoded so the whole URL can become
+ // it's own URI (eg iris:discover:spotify_artist_1234) where we can't use ":"
+ const seeds = seeds_string.split('_').join(':').split(',');
- var tracks = [];
- if (this.props.recommendations.tracks_uris && this.props.tracks){
- for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++){
- var uri = this.props.recommendations.tracks_uris[i];
- if (this.props.tracks.hasOwnProperty(uri)){
- tracks.push(this.props.tracks[uri]);
- }
- }
- }
+ for (let i = 0; i < seeds.length; i++) {
+ switch (helpers.uriType(seeds[i])) {
+ case 'artist':
+ this.props.spotifyActions.getArtist(seeds[i]);
+ break;
- var data = {
- e: e,
- context: 'track',
- items: tracks,
- uris: helpers.arrayOf('uri',tracks)
- }
- this.props.uiActions.showContextMenu(data);
- }
+ case 'track':
+ this.props.spotifyActions.getTrack(seeds[i]);
+ break;
+ }
+ }
- handleURLSeeds(seeds_string = this.props.match.params.seeds){
+ this.setState({ seeds });
+ this.getRecommendations(seeds);
+ }
- // Rejoin if we've had to uri-encode these as strings
- // We'd need to do this if our URL has been encoded so the whole URL can become
- // it's own URI (eg iris:discover:spotify_artist_1234) where we can't use ":"
- var seeds = seeds_string.split('_').join(':').split(',')
+ getRecommendations(seeds = this.state.seeds, tunabilities = this.state.tunabilities) {
+ if (seeds.length > 0) {
+ const digested_tunabilities = {};
+ for (const key in tunabilities) {
+ if (tunabilities.hasOwnProperty(key) && tunabilities[key].enabled) {
+ const tunability = tunabilities[key];
- for (var i = 0; i < seeds.length; i++){
- switch (helpers.uriType(seeds[i])){
-
- case 'artist':
- this.props.spotifyActions.getArtist(seeds[i])
- break
+ let { max } = tunability.value;
+ let { min } = tunability.value;
- case 'track':
- this.props.spotifyActions.getTrack(seeds[i])
- break
- }
- }
-
- this.setState({seeds: seeds})
- this.getRecommendations(seeds)
- }
+ if (tunability.convert_to_decimal) {
+ max /= 100;
+ min /= 100;
+ }
- getRecommendations(seeds = this.state.seeds, tunabilities = this.state.tunabilities){
- if (seeds.length > 0){
- var digested_tunabilities = {};
- for (var key in tunabilities){
- if (tunabilities.hasOwnProperty(key) && tunabilities[key].enabled){
- var tunability = tunabilities[key];
+ digested_tunabilities[`${key}_max`] = max.toString();
+ digested_tunabilities[`${key}_min`] = min.toString();
+ }
+ }
+ this.props.spotifyActions.getRecommendations(seeds, 50, digested_tunabilities);
+ }
+ }
- var max = tunability.value.max;
- var min = tunability.value.min;
+ playTracks() {
+ this.props.mopidyActions.playURIs(this.props.recommendations.tracks_uris);
+ }
- if (tunability.convert_to_decimal){
- max = max / 100;
- min = min / 100;
- }
+ removeSeed(index) {
+ const { seeds } = this.state;
+ seeds.splice(index, 1);
+ this.setState({ seeds });
+ }
- digested_tunabilities[key+"_max"] = max.toString();
- digested_tunabilities[key+"_min"] = min.toString();
- }
- }
- this.props.spotifyActions.getRecommendations(seeds, 50, digested_tunabilities)
- }
- }
+ handleSelect(e, uri) {
+ const { seeds } = this.state;
+ seeds.push(uri);
+ this.setState({ seeds });
+ }
- playTracks(){
- this.props.mopidyActions.playURIs(this.props.recommendations.tracks_uris);
- }
+ renderSeeds() {
+ const seeds_objects = [];
- removeSeed(index){
- var seeds = this.state.seeds;
- seeds.splice(index,1);
- this.setState({seeds: seeds});
- }
+ if (this.state.seeds.length > 0) {
+ for (let i = 0; i < this.state.seeds.length; i++) {
+ const uri = this.state.seeds[i];
- handleSelect(e,uri){
- var seeds = this.state.seeds;
- seeds.push(uri);
- this.setState({seeds: seeds});
- }
+ switch (helpers.uriType(uri)) {
+ case 'track':
+ if (typeof (this.props.tracks[uri]) !== 'undefined') {
+ seeds_objects.push(this.props.tracks[uri]);
+ } else {
+ seeds_objects.push({
+ name: 'Loading...',
+ uri,
+ });
+ }
+ break;
- renderSeeds(){
- var seeds_objects = []
+ case 'artist':
+ if (typeof (this.props.artists[uri]) !== 'undefined') {
+ seeds_objects.push(this.props.artists[uri]);
+ } else {
+ seeds_objects.push({
+ name: 'Loading...',
+ uri,
+ });
+ }
+ break;
- if (this.state.seeds.length > 0){
- for (var i = 0; i < this.state.seeds.length; i++){
- var uri = this.state.seeds[i]
+ case 'genre':
+ var name = helpers.getFromUri('genreid', uri);
+ seeds_objects.push({
+ name: (name.charAt(0).toUpperCase() + name.slice(1)).replace('-', ' '),
+ uri,
+ });
+ break;
+ }
+ }
+ }
- switch (helpers.uriType(uri)){
+ return (
+
+ {
+ seeds_objects.map((seed, index) => {
+ const type = helpers.uriType(seed.uri);
+ let images = null;
+ if (seed.images) {
+ if (type == 'artist') {
+ if (seed.images.length > 0) {
+ images = seed.images[0];
+ }
+ } else {
+ images = seed.images;
+ }
+ }
- case 'track':
- if (typeof(this.props.tracks[uri]) !== 'undefined'){
- seeds_objects.push(this.props.tracks[uri]);
- } else {
- seeds_objects.push({
- name: 'Loading...',
- uri: uri
- })
- }
- break
-
- case 'artist':
- if (typeof(this.props.artists[uri]) !== 'undefined'){
- seeds_objects.push(this.props.artists[uri]);
- } else {
- seeds_objects.push({
- name: 'Loading...',
- uri: uri
- })
- }
- break
-
- case 'genre':
- var name = helpers.getFromUri('genreid',uri)
- seeds_objects.push({
- name: (name.charAt(0).toUpperCase() + name.slice(1)).replace('-',' '),
- uri: uri
- })
- break
- }
- }
- }
-
- return (
-
- {
- seeds_objects.map((seed,index) => {
- var type = helpers.uriType(seed.uri);
- var images = null;
- if (seed.images){
- if (type == 'artist'){
- if (seed.images.length > 0){
- images = seed.images[0];
- }
- } else {
- images = seed.images;
- }
- }
-
- return (
-
- {images ?
: null}
-
- {helpers.titleCase(type)}
- this.removeSeed(index)} />
-
-
{seed.name}
-
- )
+ return (
+
+ {images ?
: null}
+
+ {helpers.titleCase(type)}
+ this.removeSeed(index)} />
+
+
{seed.name}
+
+ );
})
}
-
- )
- }
+
+ );
+ }
- setTunability(name, value){
- var tunabilities = this.state.tunabilities;
- tunabilities[name].value = value;
- this.setState({ tunabilities: tunabilities });
- }
+ setTunability(name, value) {
+ const { tunabilities } = this.state;
+ tunabilities[name].value = value;
+ this.setState({ tunabilities });
+ }
- toggleTunability(name){
- var tunabilities = this.state.tunabilities;
- tunabilities[name].enabled = !tunabilities[name].enabled;
- this.setState({ tunabilities: tunabilities });
- }
+ toggleTunability(name) {
+ const { tunabilities } = this.state;
+ tunabilities[name].enabled = !tunabilities[name].enabled;
+ this.setState({ tunabilities });
+ }
- renderTunabilities(){
- var addable_tunabilities = [];
- var enabled_tunabilities = [];
- for (var key in this.state.tunabilities){
- if (this.state.tunabilities.hasOwnProperty(key)){
+ renderTunabilities() {
+ const addable_tunabilities = [];
+ const enabled_tunabilities = [];
+ for (const key in this.state.tunabilities) {
+ if (this.state.tunabilities.hasOwnProperty(key)) {
+ const tunability = {
- var tunability = Object.assign(
- {},
- this.state.tunabilities[key],
- {
- name: key
- }
- );
+ ...this.state.tunabilities[key],
+ name: key,
+ };
- if (tunability.enabled){
- enabled_tunabilities.push(tunability);
- } else {
- addable_tunabilities.push({
- label: helpers.titleCase(tunability.name),
- value: tunability.name
- });
+ if (tunability.enabled) {
+ enabled_tunabilities.push(tunability);
+ } else {
+ addable_tunabilities.push({
+ label: helpers.titleCase(tunability.name),
+ value: tunability.name,
+ });
+ }
+ }
+ }
+
+ return (
+
+ {
+ enabled_tunabilities.map((tunability) => (
+
+
+ {helpers.titleCase(tunability.name)}
+ this.toggleTunability(tunability.name)}>
+
+
+
+
+ this.setTunability(tunability.name, value)}
+ />
+
+
+ ))
}
- }
- }
+
+ );
+ }
- return (
-
- {
- enabled_tunabilities.map(tunability => {
- return (
-
-
- {helpers.titleCase(tunability.name)}
- this.toggleTunability(tunability.name)}>
-
-
-
-
- this.setTunability(tunability.name, value)}
- />
-
-
- );
- })
- }
-
- );
- }
+ renderResults() {
+ // Results not in
+ if (!this.props.recommendations || this.props.recommendations.albums_uris === undefined || this.props.recommendations.artists_uris === undefined) {
+ return
;
+ }
- renderResults(){
+ const tracks = [];
+ if (this.props.recommendations.tracks_uris && this.props.tracks) {
+ for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++) {
+ var uri = this.props.recommendations.tracks_uris[i];
+ if (this.props.tracks.hasOwnProperty(uri)) {
+ tracks.push(this.props.tracks[uri]);
+ }
+ }
+ }
- // Results not in
- if (!this.props.recommendations || this.props.recommendations.albums_uris === undefined || this.props.recommendations.artists_uris === undefined){
- return
;
- }
+ const artists = [];
+ if (this.props.recommendations.artists_uris && this.props.artists) {
+ for (var i = 0; i < this.props.recommendations.artists_uris.length; i++) {
+ var uri = this.props.recommendations.artists_uris[i];
+ if (this.props.artists.hasOwnProperty(uri)) {
+ artists.push(this.props.artists[uri]);
+ }
+ }
+ }
- var tracks = [];
- if (this.props.recommendations.tracks_uris && this.props.tracks){
- for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++){
- var uri = this.props.recommendations.tracks_uris[i];
- if (this.props.tracks.hasOwnProperty(uri)){
- tracks.push(this.props.tracks[uri]);
- }
- }
- }
+ const albums = [];
+ if (this.props.recommendations.albums_uris && this.props.albums) {
+ for (var i = 0; i < this.props.recommendations.albums_uris.length; i++) {
+ var uri = this.props.recommendations.albums_uris[i];
+ if (this.props.albums.hasOwnProperty(uri)) {
+ albums.push(this.props.albums[uri]);
+ }
+ }
+ }
- var artists = [];
- if (this.props.recommendations.artists_uris && this.props.artists){
- for (var i = 0; i < this.props.recommendations.artists_uris.length; i++){
- var uri = this.props.recommendations.artists_uris[i];
- if (this.props.artists.hasOwnProperty(uri)){
- artists.push(this.props.artists[uri]);
- }
- }
- }
+ // Complete records not yet in our index
+ if (tracks.length <= 0 && artists.length <= 0 && albums.length <= 0) {
+ return null;
+ }
- var albums = [];
- if (this.props.recommendations.albums_uris && this.props.albums){
- for (var i = 0; i < this.props.recommendations.albums_uris.length; i++){
- var uri = this.props.recommendations.albums_uris[i];
- if (this.props.albums.hasOwnProperty(uri)){
- albums.push(this.props.albums[uri]);
- }
- }
- }
+ var uri = 'iris:discover';
+ if (this.state.seeds) {
+ uri += ':';
+ for (var i = 0; i < this.state.seeds.length; i++) {
+ if (i > 0) {
+ uri += ',';
+ }
+ uri += this.state.seeds[i].split(':').join('_');
+ }
+ }
- // Complete records not yet in our index
- if (tracks.length <= 0 && artists.length <= 0 && albums.length <= 0){
- return null;
- }
+ return (
+
- var uri = 'iris:discover';
- if (this.state.seeds){
- uri += ':';
- for (var i = 0; i < this.state.seeds.length; i++){
- if (i > 0){
- uri += ',';
- }
- uri += this.state.seeds[i].split(':').join('_');
- }
- }
-
- return (
-
-
-
-
+
+
Tracks
-
- this.handleContextMenu(e)} />
- this.playTracks(e)}>Play all
-
-
-
-
+
+ this.handleContextMenu(e)} />
+ this.playTracks(e)}>Play all
+
+
+
+
-
+
-
+
-
- )
- }
+
+ );
+ }
- render(){
- var is_loading = helpers.isLoading(this.props.load_queue,['spotify_recommendations']);
- var addable_tunabilities = [];
- for (var key in this.state.tunabilities){
- if (this.state.tunabilities.hasOwnProperty(key)){
+ render() {
+ const is_loading = helpers.isLoading(this.props.load_queue, ['spotify_recommendations']);
+ const addable_tunabilities = [];
+ for (const key in this.state.tunabilities) {
+ if (this.state.tunabilities.hasOwnProperty(key)) {
+ const tunability = {
- var tunability = Object.assign(
- {},
- this.state.tunabilities[key],
- {
- name: key
- }
- );
+ ...this.state.tunabilities[key],
+ name: key,
+ };
- if (!tunability.enabled){
- addable_tunabilities.push({
- label: helpers.titleCase(tunability.name),
- value: tunability.name
- });
- }
- }
- }
+ if (!tunability.enabled) {
+ addable_tunabilities.push({
+ label: helpers.titleCase(tunability.name),
+ value: tunability.name,
+ });
+ }
+ }
+ }
- return (
-
-
+ return (
+
+
- {this.props.theme == 'dark' &&
}
+ {this.props.theme == 'dark' &&
}
-
-
Explore new music
-
Add seeds and musical properties below to build your sound
-
+
+
Explore new music
+
Add seeds and musical properties below to build your sound
+
- {this.renderSeeds()}
- {this.renderTunabilities()}
- {this.state.seeds.length > 5 ?
Too many seeds! You can use up to a total of 5 seed tracks, artists and genres.
: null}
+ {this.renderSeeds()}
+ {this.renderTunabilities()}
+ {this.state.seeds.length > 5 ?
Too many seeds! You can use up to a total of 5 seed tracks, artists and genres.
: null}
-
-
+
+
-
this.handleSelect(e,uri)} />
- {this.toggleTunability(val)}} />
- this.getRecommendations()}>
-
+ this.handleSelect(e, uri)} />
+ { this.toggleTunability(val); }} />
+ this.getRecommendations()}>
+
+
Find recommendations
-
+
-
-
+
+
-
+
- {this.renderResults()}
+ {this.renderResults()}
-
- )
- }
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- theme: state.ui.theme,
- albums: state.core.albums,
- artists: state.core.artists,
- tracks: state.core.tracks,
- genres: (state.core.genres ? state.core.genres : []),
- authorized: state.spotify.authorization,
- load_queue: state.ui.load_queue,
- quick_search_results: (state.spotify.quick_search_results ? state.spotify.quick_search_results : {artists: [], tracks: []}),
- recommendations: (state.spotify.recommendations ? state.spotify.recommendations : {})
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ theme: state.ui.theme,
+ albums: state.core.albums,
+ artists: state.core.artists,
+ tracks: state.core.tracks,
+ genres: (state.core.genres ? state.core.genres : []),
+ authorized: state.spotify.authorization,
+ load_queue: state.ui.load_queue,
+ quick_search_results: (state.spotify.quick_search_results ? state.spotify.quick_search_results : { artists: [], tracks: [] }),
+ recommendations: (state.spotify.recommendations ? state.spotify.recommendations : {}),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(Discover)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Discover);
diff --git a/src/js/views/library/LibraryAlbums.js b/src/js/views/library/LibraryAlbums.js
index 0c8f6d19..04c3f1c8 100755
--- a/src/js/views/library/LibraryAlbums.js
+++ b/src/js/views/library/LibraryAlbums.js
@@ -18,370 +18,358 @@ import * as mopidyActions from '../../services/mopidy/actions';
import * as googleActions from '../../services/google/actions';
import * as spotifyActions from '../../services/spotify/actions';
-class LibraryAlbums extends React.Component{
+class LibraryAlbums extends React.Component {
+ constructor(props) {
+ super(props);
- constructor(props){
- super(props);
+ this.state = {
+ filter: '',
+ limit: 50,
+ per_page: 50,
+ };
+ }
- this.state = {
- filter: '',
- limit: 50,
- per_page: 50
- }
- }
+ componentWillMount() {
+ // Before we mount, restore any limit defined in our location state
+ const state = (this.props.location.state ? this.props.location.state : {});
+ if (state.limit) {
+ this.setState({
+ limit: state.limit,
+ });
+ }
+ }
- componentWillMount(){
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Albums');
- // Before we mount, restore any limit defined in our location state
- var state = (this.props.location.state ? this.props.location.state : {});
- if (state.limit){
- this.setState({
- limit: state.limit
- });
- }
- }
+ if (this.props.mopidy_connected && this.props.mopidy_library_albums_status != 'finished' && this.props.mopidy_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'local')) {
+ this.props.mopidyActions.getLibraryAlbums();
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Albums");
+ if (this.props.google_enabled && this.props.google_library_albums_status != 'finished' && this.props.google_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'google')) {
+ this.props.googleActions.getLibraryAlbums();
+ }
- if (this.props.mopidy_connected && this.props.mopidy_library_albums_status != 'finished' && this.props.mopidy_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'local')){
- this.props.mopidyActions.getLibraryAlbums();
- }
+ if (this.props.spotify_enabled && this.props.spotify_library_albums_status != 'finished' && this.props.spotify_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'spotify')) {
+ this.props.spotifyActions.getLibraryAlbums();
+ }
+ }
- if (this.props.google_enabled && this.props.google_library_albums_status != 'finished' && this.props.google_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'google')){
- this.props.googleActions.getLibraryAlbums();
- }
+ componentWillReceiveProps(newProps) {
+ if (newProps.mopidy_connected && (newProps.source == 'all' || newProps.source == 'local')) {
+ // We've just connected
+ if (!this.props.mopidy_connected) {
+ this.props.mopidyActions.getLibraryAlbums();
+ }
- if (this.props.spotify_enabled && this.props.spotify_library_albums_status != 'finished' && this.props.spotify_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'spotify')){
- this.props.spotifyActions.getLibraryAlbums();
- }
- }
+ // Filter changed, but we haven't got this provider's library yet
+ if (this.props.source != 'all' && this.props.source != 'local' && newProps.mopidy_library_albums_status != 'finished' && newProps.mopidy_library_albums_status != 'started') {
+ this.props.mopidyActions.getLibraryAlbums();
+ }
+ }
- componentWillReceiveProps(newProps){
- if (newProps.mopidy_connected && (newProps.source == 'all' || newProps.source == 'local')){
+ if (newProps.google_enabled && (newProps.source == 'all' || newProps.source == 'google')) {
+ // We've just been enabled (or detected as such)
+ if (!this.props.google_enabled) {
+ this.props.googleActions.getLibraryAlbums();
+ }
- // We've just connected
- if (!this.props.mopidy_connected){
- this.props.mopidyActions.getLibraryAlbums();
- }
+ // Filter changed, but we haven't got this provider's library yet
+ if (this.props.source != 'all' && this.props.source != 'google' && newProps.google_library_albums_status != 'finished' && newProps.google_library_albums_status != 'started') {
+ this.props.googleActions.getLibraryAlbums();
+ }
+ }
- // Filter changed, but we haven't got this provider's library yet
- if (this.props.source != 'all' && this.props.source != 'local' && newProps.mopidy_library_albums_status != 'finished' && newProps.mopidy_library_albums_status != 'started'){
- this.props.mopidyActions.getLibraryAlbums();
- }
- }
+ if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')) {
+ // Filter changed, but we haven't got this provider's library yet
+ if (newProps.spotify_library_albums_status != 'finished' && newProps.spotify_library_albums_status != 'started') {
+ this.props.spotifyActions.getLibraryAlbums();
+ }
+ }
+ }
- if (newProps.google_enabled && (newProps.source == 'all' || newProps.source == 'google')){
+ handleContextMenu(e, item) {
+ const data = {
+ e,
+ context: 'album',
+ uris: [item.uri],
+ items: [item],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- // We've just been enabled (or detected as such)
- if (!this.props.google_enabled){
- this.props.googleActions.getLibraryAlbums();
- }
+ moreURIsToLoad() {
+ const uris = [];
+ if (this.props.albums && this.props.library_albums) {
+ for (let i = 0; i < this.props.library_albums.length; i++) {
+ const uri = this.props.library_albums[i];
+ if (!this.props.albums.hasOwnProperty(uri) && helpers.uriSource(uri) == 'local') {
+ uris.push(uri);
+ }
- // Filter changed, but we haven't got this provider's library yet
- if (this.props.source != 'all' && this.props.source != 'google' && newProps.google_library_albums_status != 'finished' && newProps.google_library_albums_status != 'started'){
- this.props.googleActions.getLibraryAlbums();
- }
- }
+ // limit each lookup to 50 URIs
+ if (uris.length >= 50) break;
+ }
+ }
- if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')){
+ return uris;
+ }
- // Filter changed, but we haven't got this provider's library yet
- if (newProps.spotify_library_albums_status != 'finished' && newProps.spotify_library_albums_status != 'started'){
- this.props.spotifyActions.getLibraryAlbums();
- }
- }
- }
+ loadMore() {
+ const new_limit = this.state.limit + this.state.per_page;
- handleContextMenu(e,item){
- var data = {
- e: e,
- context: 'album',
- uris: [item.uri],
- items: [item]
- }
- this.props.uiActions.showContextMenu(data)
- }
+ this.setState({ limit: new_limit });
- moreURIsToLoad(){
- var uris = []
- if (this.props.albums && this.props.library_albums){
- for (var i = 0; i < this.props.library_albums.length; i++){
- var uri = this.props.library_albums[i]
- if (!this.props.albums.hasOwnProperty(uri) && helpers.uriSource(uri) == 'local'){
- uris.push(uri)
- }
+ // Set our pagination to location state
+ const state = (this.props.location && this.props.location.state ? this.props.location.state : {});
+ state.limit = new_limit;
+ this.props.history.replace({ state });
+ }
- // limit each lookup to 50 URIs
- if (uris.length >= 50) break
- }
- }
+ setSort(value) {
+ let reverse = false;
+ if (this.props.sort == value) reverse = !this.props.sort_reverse;
- return uris
- }
+ const data = {
+ library_albums_sort_reverse: reverse,
+ library_albums_sort: value,
+ };
+ this.props.uiActions.set(data);
+ }
- loadMore(){
- var new_limit = this.state.limit + this.state.per_page;
+ renderView() {
+ let albums = [];
- this.setState({limit: new_limit});
+ // 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]);
+ }
+ }
+ }
- // Set our pagination to location state
- var state = (this.props.location && this.props.location.state ? this.props.location.state : {});
- state.limit = new_limit;
- this.props.history.replace({state: state});
- }
+ // 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 = helpers.uriSource(uri);
+ var album = {
+ uri,
+ source,
+ };
- setSort(value){
- var reverse = false
- if (this.props.sort == value ) reverse = !this.props.sort_reverse
+ if (this.props.albums.hasOwnProperty(uri)) {
+ albums.push(this.props.albums[uri]);
+ }
+ }
+ }
- var data = {
- library_albums_sort_reverse: reverse,
- library_albums_sort: value
- }
- this.props.uiActions.set(data)
- }
+ // 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 = helpers.uriSource(uri);
+ var album = {
+ uri,
+ source,
+ };
- renderView(){
- var albums = [];
+ if (this.props.albums.hasOwnProperty(uri)) {
+ album = this.props.albums[uri];
+ }
- // 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]);
- }
- }
- }
+ albums.push(album);
+ }
+ }
- // 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){
+ // Collate each album into it's full object (including nested artists)
+ for (let i = 0; i < albums.length; i++) {
+ albums[i] = helpers.collate(albums[i], { artists: this.props.artists });
+ }
- // 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 = helpers.uriSource(uri);
- var album = {
- uri: uri,
- source: source
- }
+ if (this.props.sort) {
+ albums = helpers.sortItems(albums, this.props.sort, this.props.sort_reverse);
+ }
- if (this.props.albums.hasOwnProperty(uri)){
- albums.push(this.props.albums[uri]);
- }
+ if (this.state.filter && this.state.filter !== '') {
+ albums = helpers.applyFilter('name', this.state.filter, albums);
+ }
- }
- }
+ // Apply our lazy-load-rendering
+ const total_albums = albums.length;
+ albums = albums.slice(0, this.state.limit);
- // 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){
+ if (this.props.view == 'list') {
+ return (
+
+ this.handleContextMenu(e, item)}
+ rows={albums}
+ thumbnail
+ details={['artists', 'tracks_uris.length']}
+ right_column={['added_at']}
+ className="albums"
+ link_prefix="/album/"
+ />
+ this.state.limit ? this.state.limit : total_albums}
+ showLoader={this.state.limit < total_albums}
+ loadMore={() => this.loadMore()}
+ />
+
+ );
+ }
+ return (
+
+ this.handleContextMenu(e, item)}
+ albums={albums}
+ />
+ this.state.limit ? this.state.limit : total_albums}
+ showLoader={this.state.limit < total_albums}
+ loadMore={() => this.loadMore()}
+ />
+
+ );
+ }
- // 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 = helpers.uriSource(uri);
- var album = {
- uri: uri,
- source: source
- }
+ render() {
+ const source_options = [
+ {
+ value: 'all',
+ label: 'All',
+ },
+ {
+ value: 'local',
+ label: 'Local',
+ },
+ ];
- if (this.props.albums.hasOwnProperty(uri)){
- album = this.props.albums[uri]
- }
+ if (this.props.spotify_enabled) {
+ source_options.push({
+ value: 'spotify',
+ label: 'Spotify',
+ });
+ }
- albums.push(album);
- }
- }
+ if (this.props.google_enabled) {
+ source_options.push({
+ value: 'google',
+ label: 'Google',
+ });
+ }
- // Collate each album into it's full object (including nested artists)
- for (let i = 0; i < albums.length; i++) {
- albums[i] = helpers.collate(albums[i], {artists: this.props.artists});
- }
+ const view_options = [
+ {
+ value: 'thumbnails',
+ label: 'Thumbnails',
+ },
+ {
+ value: 'list',
+ label: 'List',
+ },
+ ];
- if (this.props.sort){
- albums = helpers.sortItems(albums, this.props.sort, this.props.sort_reverse);
- }
+ const sort_options = [
+ {
+ value: null,
+ label: 'Default',
+ },
+ {
+ value: 'name',
+ label: 'Name',
+ },
+ {
+ value: 'artists.first.name',
+ label: 'Artist',
+ },
+ {
+ value: 'added_at',
+ label: 'Added',
+ },
+ {
+ value: 'tracks_uris.length',
+ label: 'Tracks',
+ },
+ {
+ value: 'uri',
+ label: 'Source',
+ },
+ ];
- if (this.state.filter && this.state.filter !== ''){
- albums = helpers.applyFilter('name', this.state.filter, albums)
- }
+ const options = (
+
+ this.setState({ filter: value, limit: this.state.per_page })}
+ />
+ { this.setSort(val); this.props.uiActions.hideContextMenu(); }}
+ />
+ { this.props.uiActions.set({ library_albums_view: val }); this.props.uiActions.hideContextMenu(); }}
+ />
+ { this.props.uiActions.set({ library_albums_source: val }); this.props.uiActions.hideContextMenu(); }}
+ />
+
+ );
- // Apply our lazy-load-rendering
- var total_albums = albums.length;
- albums = albums.slice(0, this.state.limit);
-
- if (this.props.view == 'list'){
- return (
-
- this.handleContextMenu(e,item)}
- rows={albums}
- thumbnail={true}
- details={['artists','tracks_uris.length']}
- right_column={['added_at']}
- className="albums"
- link_prefix={"/album/"}
- />
- this.state.limit ? this.state.limit : total_albums}
- showLoader={this.state.limit < total_albums}
- loadMore={() => this.loadMore()}
- />
-
- )
- } else {
- return (
-
- this.handleContextMenu(e,item)}
- albums={albums} />
- this.state.limit ? this.state.limit : total_albums}
- showLoader={this.state.limit < total_albums}
- loadMore={() => this.loadMore()}
- />
-
- )
- }
- }
-
- render(){
- var source_options = [
- {
- value: 'all',
- label: 'All'
- },
- {
- value: 'local',
- label: 'Local'
- }
- ];
-
- if (this.props.spotify_enabled){
- source_options.push({
- value: 'spotify',
- label: 'Spotify'
- });
- }
-
- if (this.props.google_enabled){
- source_options.push({
- value: 'google',
- label: 'Google'
- });
- }
-
- var view_options = [
- {
- value: 'thumbnails',
- label: 'Thumbnails'
- },
- {
- value: 'list',
- label: 'List'
- }
- ]
-
- var sort_options = [
- {
- value: null,
- label: 'Default'
- },
- {
- value: 'name',
- label: 'Name'
- },
- {
- value: 'artists.first.name',
- label: 'Artist'
- },
- {
- value: 'added_at',
- label: 'Added'
- },
- {
- value: 'tracks_uris.length',
- label: 'Tracks'
- },
- {
- value: 'uri',
- label: 'Source'
- }
- ]
-
- var options = (
-
- this.setState({filter: value, limit: this.state.per_page})}
- />
- {this.setSort(val); this.props.uiActions.hideContextMenu() }}
- />
- {this.props.uiActions.set({ library_albums_view: val }); this.props.uiActions.hideContextMenu() }}
- />
- {this.props.uiActions.set({ library_albums_source: val}); this.props.uiActions.hideContextMenu() }}
- />
-
- )
-
- return (
-
-
+ {this.renderView()}
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- mopidy_connected: state.mopidy.connected,
- 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),
- google_enabled: state.google.enabled,
- 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_enabled: state.spotify.enabled,
- 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),
- sort_reverse: (state.ui.library_albums_sort_reverse ? state.ui.library_albums_sort_reverse : false)
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ mopidy_connected: state.mopidy.connected,
+ 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),
+ google_enabled: state.google.enabled,
+ 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_enabled: state.spotify.enabled,
+ 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),
+ sort_reverse: (state.ui.library_albums_sort_reverse ? state.ui.library_albums_sort_reverse : false),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- googleActions: bindActionCreators(googleActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ googleActions: bindActionCreators(googleActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(LibraryAlbums)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(LibraryAlbums);
diff --git a/src/js/views/library/LibraryArtists.js b/src/js/views/library/LibraryArtists.js
index b3839254..b8819b6b 100755
--- a/src/js/views/library/LibraryArtists.js
+++ b/src/js/views/library/LibraryArtists.js
@@ -18,309 +18,303 @@ import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
import * as googleActions from '../../services/google/actions';
-class LibraryArtists extends React.Component{
+class LibraryArtists extends React.Component {
+ constructor(props) {
+ super(props);
- constructor(props){
- super(props)
+ this.state = {
+ filter: '',
+ limit: 50,
+ per_page: 50,
+ };
+ }
- this.state = {
- filter: '',
- limit: 50,
- per_page: 50
- }
- }
+ componentWillMount() {
+ // Before we mount, restore any limit defined in our location state
+ const state = (this.props.location.state ? this.props.location.state : {});
+ if (state.limit) {
+ this.setState({
+ limit: state.limit,
+ });
+ }
+ }
- componentWillMount(){
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Artists');
- // Before we mount, restore any limit defined in our location state
- var state = (this.props.location.state ? this.props.location.state : {});
- if (state.limit){
- this.setState({
- limit: state.limit
- });
- }
- }
+ if (!this.props.mopidy_library_artists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'local')) {
+ this.props.mopidyActions.getLibraryArtists();
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Artists");
+ if (this.props.google_enabled && !this.props.google_library_artists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'google')) {
+ this.props.googleActions.getLibraryArtists();
+ }
- if (!this.props.mopidy_library_artists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'local')){
- this.props.mopidyActions.getLibraryArtists();
- }
+ if (this.props.spotify_enabled && this.props.spotify_library_artists_status != 'finished' && (this.props.source == 'all' || this.props.source == 'spotify')) {
+ this.props.spotifyActions.getLibraryArtists();
+ }
+ }
- if (this.props.google_enabled && !this.props.google_library_artists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'google')){
- this.props.googleActions.getLibraryArtists();
- }
+ componentWillReceiveProps(newProps) {
+ if (newProps.mopidy_connected && (newProps.source == 'all' || newProps.source == 'local')) {
+ // We've just connected
+ if (!this.props.mopidy_connected) {
+ this.props.mopidyActions.getLibraryArtists();
+ }
- if (this.props.spotify_enabled && this.props.spotify_library_artists_status != 'finished' && (this.props.source == 'all' || this.props.source == 'spotify')){
- this.props.spotifyActions.getLibraryArtists();
- }
- }
+ // Filter changed, but we haven't got this provider's library yet
+ if (this.props.source != 'all' && this.props.source != 'local' && !newProps.mopidy_library_artists) {
+ this.props.mopidyActions.getLibraryArtists();
+ }
+ }
- componentWillReceiveProps(newProps){
- if (newProps.mopidy_connected && (newProps.source == 'all' || newProps.source == 'local')){
+ if (newProps.mopidy_connected && newProps.google_enabled && (newProps.source == 'all' || newProps.source == 'google')) {
+ // We've just been enabled (or detected as such)
+ if (!this.props.google_enabled) {
+ this.props.googleActions.getLibraryArtists();
+ }
- // We've just connected
- if (!this.props.mopidy_connected){
- this.props.mopidyActions.getLibraryArtists();
- }
+ // Filter changed, but we haven't got this provider's library yet
+ if (this.props.source != 'all' && this.props.source != 'google' && !newProps.google_library_artists) {
+ this.props.googleActions.getLibraryArtists();
+ }
+ }
- // Filter changed, but we haven't got this provider's library yet
- if (this.props.source != 'all' && this.props.source != 'local' && !newProps.mopidy_library_artists){
- this.props.mopidyActions.getLibraryArtists();
- }
- }
+ if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')) {
+ // Filter changed, but we haven't got this provider's library yet
+ if (newProps.spotify_library_artists_status != 'finished' && newProps.spotify_library_artists_status != 'started') {
+ this.props.spotifyActions.getLibraryArtists();
+ }
+ }
+ }
- if (newProps.mopidy_connected && newProps.google_enabled && (newProps.source == 'all' || newProps.source == 'google')){
+ handleContextMenu(e, item) {
+ const data = {
+ e,
+ context: 'artist',
+ uris: [item.uri],
+ items: [item],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- // We've just been enabled (or detected as such)
- if (!this.props.google_enabled){
- this.props.googleActions.getLibraryArtists();
- }
+ loadMore() {
+ const new_limit = this.state.limit + this.state.per_page;
- // Filter changed, but we haven't got this provider's library yet
- if (this.props.source != 'all' && this.props.source != 'google' && !newProps.google_library_artists){
- this.props.googleActions.getLibraryArtists();
- }
- }
+ this.setState({ limit: new_limit });
- if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')){
+ // Set our pagination to location state
+ const state = (this.props.location && this.props.location.state ? this.props.location.state : {});
+ state.limit = new_limit;
+ this.props.history.replace({ state });
+ }
- // Filter changed, but we haven't got this provider's library yet
- if (newProps.spotify_library_artists_status != 'finished' && newProps.spotify_library_artists_status != 'started'){
- this.props.spotifyActions.getLibraryArtists();
- }
- }
- }
+ setSort(value) {
+ let reverse = false;
+ if (this.props.sort == value) reverse = !this.props.sort_reverse;
- handleContextMenu(e,item){
- var data = {
- e: e,
- context: 'artist',
- uris: [item.uri],
- items: [item]
- }
- this.props.uiActions.showContextMenu(data)
- }
+ const data = {
+ library_artists_sort_reverse: reverse,
+ library_artists_sort: value,
+ };
+ this.props.uiActions.set(data);
+ }
- loadMore(){
- var new_limit = this.state.limit + this.state.per_page;
+ renderView() {
+ let artists = [];
- this.setState({limit: new_limit});
+ // Mopidy library items
+ if (this.props.mopidy_library_artists && (this.props.source == 'all' || this.props.source == 'local')) {
+ for (uri of this.props.mopidy_library_artists) {
+ // 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 = helpers.uriSource(uri);
+ var artist = {
+ uri,
+ source,
+ };
- // Set our pagination to location state
- var state = (this.props.location && this.props.location.state ? this.props.location.state : {});
- state.limit = new_limit;
- this.props.history.replace({state: state});
- }
+ if (this.props.artists.hasOwnProperty(uri)) {
+ artist = this.props.artists[uri];
+ }
- setSort(value){
- var reverse = false
- if (this.props.sort == value ) reverse = !this.props.sort_reverse
+ artists.push(artist);
+ }
+ }
- var data = {
- library_artists_sort_reverse: reverse,
- library_artists_sort: value
- }
- this.props.uiActions.set(data);
- }
+ // Google library items
+ if (this.props.google_library_artists && (this.props.source == 'all' || this.props.source == 'google')) {
+ for (uri of this.props.google_library_artists) {
+ // 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 = helpers.uriSource(uri);
+ var artist = {
+ uri,
+ source,
+ };
- renderView(){
- var artists = [];
+ if (this.props.artists.hasOwnProperty(uri)) {
+ artist = this.props.artists[uri];
+ }
- // Mopidy library items
- if (this.props.mopidy_library_artists && (this.props.source == 'all' || this.props.source == 'local')){
- for (uri of this.props.mopidy_library_artists){
+ artists.push(artist);
+ }
+ }
- // 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 = helpers.uriSource(uri)
- var artist = {
- uri: uri,
- source: source
- }
+ // Spotify library items
+ if (this.props.spotify_library_artists && (this.props.source == 'all' || this.props.source == 'spotify')) {
+ for (let i = 0; i < this.props.spotify_library_artists.length; i++) {
+ var uri = this.props.spotify_library_artists[i];
+ if (this.props.artists.hasOwnProperty(uri)) {
+ artists.push(this.props.artists[uri]);
+ }
+ }
+ }
- if (this.props.artists.hasOwnProperty(uri)){
- artist = this.props.artists[uri]
- }
+ if (this.props.sort) {
+ artists = helpers.sortItems(artists, this.props.sort, this.props.sort_reverse);
+ }
- artists.push(artist)
- }
- }
+ if (this.state.filter !== '') {
+ artists = helpers.applyFilter('name', this.state.filter, artists);
+ }
- // Google library items
- if (this.props.google_library_artists && (this.props.source == 'all' || this.props.source == 'google')){
- for (uri of this.props.google_library_artists){
+ // Apply our lazy-load-rendering
+ const total_artists = artists.length;
+ artists = artists.slice(0, this.state.limit);
- // 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 = helpers.uriSource(uri)
- var artist = {
- uri: uri,
- source: source
- }
+ if (this.props.view == 'list') {
+ return (
+
+ this.handleContextMenu(e, item)}
+ rows={artists}
+ thumbnail
+ details={['followers']}
+ middle_column={['source']}
+ className="artists"
+ link_prefix="/artist/"
+ />
+ this.state.limit ? this.state.limit : total_artists}
+ showLoader={this.state.limit < total_artists}
+ loadMore={() => this.loadMore()}
+ />
+
+ );
+ }
+ return (
+
+ this.handleContextMenu(e, item)}
+ artists={artists}
+ />
+ this.state.limit ? this.state.limit : total_artists}
+ showLoader={this.state.limit < total_artists}
+ loadMore={() => this.loadMore()}
+ />
+
+ );
+ }
- if (this.props.artists.hasOwnProperty(uri)){
- artist = this.props.artists[uri]
- }
+ render() {
+ const source_options = [
+ {
+ value: 'all',
+ label: 'All',
+ },
+ {
+ value: 'local',
+ label: 'Local',
+ },
+ ];
- artists.push(artist)
- }
- }
+ if (this.props.spotify_enabled) {
+ source_options.push({
+ value: 'spotify',
+ label: 'Spotify',
+ });
+ }
- // Spotify library items
- if (this.props.spotify_library_artists && (this.props.source == 'all' || this.props.source == 'spotify')){
- for (var i = 0; i < this.props.spotify_library_artists.length; i++){
- var uri = this.props.spotify_library_artists[i]
- if (this.props.artists.hasOwnProperty(uri)){
- artists.push(this.props.artists[uri])
- }
- }
- }
+ if (this.props.google_enabled) {
+ source_options.push({
+ value: 'google',
+ label: 'Google',
+ });
+ }
- if (this.props.sort){
- artists = helpers.sortItems(artists, this.props.sort, this.props.sort_reverse);
- }
+ const view_options = [
+ {
+ label: 'Thumbnails',
+ value: 'thumbnails',
+ },
+ {
+ label: 'List',
+ value: 'list',
+ },
+ ];
- if (this.state.filter !== ''){
- artists = helpers.applyFilter('name', this.state.filter, artists)
- }
+ const sort_options = [
+ {
+ label: 'Default',
+ value: null,
+ },
+ {
+ label: 'Name',
+ value: 'name',
+ },
+ {
+ label: 'Followers',
+ value: 'followers',
+ },
+ {
+ label: 'Popularity',
+ value: 'popularity',
+ },
+ ];
- // Apply our lazy-load-rendering
- var total_artists = artists.length;
- artists = artists.slice(0, this.state.limit);
+ const options = (
+
+ this.setState({ filter: value, limit: this.state.per_page })}
+ />
+ { this.setSort(value); this.props.uiActions.hideContextMenu(); }}
+ />
+ { this.props.uiActions.set({ library_artists_view: value }); this.props.uiActions.hideContextMenu(); }}
+ />
+ { this.props.uiActions.set({ library_artists_source: value }); this.props.uiActions.hideContextMenu(); }}
+ />
+
+ );
- if (this.props.view == 'list'){
- return (
-
- this.handleContextMenu(e,item)}
- rows={artists}
- thumbnail={true}
- details={['followers']}
- middle_column={['source']}
- className="artists"
- link_prefix={"/artist/"} />
- this.state.limit ? this.state.limit : total_artists}
- showLoader={this.state.limit < total_artists}
- loadMore={() => this.loadMore()}
- />
-
- )
- } else {
- return (
-
- this.handleContextMenu(e,item)}
- artists={artists} />
- this.state.limit ? this.state.limit : total_artists}
- showLoader={this.state.limit < total_artists}
- loadMore={() => this.loadMore()}
- />
-
- )
- }
- }
-
- render(){
- var source_options = [
- {
- value: 'all',
- label: 'All'
- },
- {
- value: 'local',
- label: 'Local'
- }
- ];
-
- if (this.props.spotify_enabled){
- source_options.push({
- value: 'spotify',
- label: 'Spotify'
- });
- }
-
- if (this.props.google_enabled){
- source_options.push({
- value: 'google',
- label: 'Google'
- });
- }
-
- var view_options = [
- {
- label: 'Thumbnails',
- value: 'thumbnails'
- },
- {
- label: 'List',
- value: 'list'
- }
- ];
-
- var sort_options = [
- {
- label: 'Default',
- value: null
- },
- {
- label: 'Name',
- value: 'name'
- },
- {
- label: 'Followers',
- value: 'followers'
- },
- {
- label: 'Popularity',
- value: 'popularity'
- }
- ];
-
- var options = (
-
- this.setState({filter: value, limit: this.state.per_page})}
- />
- {this.setSort(value); this.props.uiActions.hideContextMenu() }}
- />
- {this.props.uiActions.set({ library_artists_view: value }); this.props.uiActions.hideContextMenu()}}
- />
- {this.props.uiActions.set({ library_artists_source: value}); this.props.uiActions.hideContextMenu() }}
- />
-
- )
-
- return (
-
-
+ {this.renderView()}
+
+ );
+ }
}
@@ -328,33 +322,29 @@ class LibraryArtists extends React.Component{
* Export our component
*
* We also integrate our global store, using connect()
- **/
+ * */
-const mapStateToProps = (state, ownProps) => {
- return {
- mopidy_connected: state.mopidy.connected,
- mopidy_uri_schemes: state.mopidy.uri_schemes,
- mopidy_library_artists: state.mopidy.library_artists,
- google_enabled: state.google.enabled,
- google_library_artists: state.google.library_artists,
- spotify_enabled: state.spotify.enabled,
- spotify_library_artists: state.spotify.library_artists,
- spotify_library_artists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR.status : null),
- artists: state.core.artists,
- source: (state.ui.library_artists_source ? state.ui.library_artists_source : 'all'),
- sort: (state.ui.library_artists_sort ? state.ui.library_artists_sort : null),
- sort_reverse: (state.ui.library_artists_sort_reverse ? state.ui.library_artists_sort_reverse : false),
- view: state.ui.library_artists_view
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ mopidy_connected: state.mopidy.connected,
+ mopidy_uri_schemes: state.mopidy.uri_schemes,
+ mopidy_library_artists: state.mopidy.library_artists,
+ google_enabled: state.google.enabled,
+ google_library_artists: state.google.library_artists,
+ spotify_enabled: state.spotify.enabled,
+ spotify_library_artists: state.spotify.library_artists,
+ spotify_library_artists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR.status : null),
+ artists: state.core.artists,
+ source: (state.ui.library_artists_source ? state.ui.library_artists_source : 'all'),
+ sort: (state.ui.library_artists_sort ? state.ui.library_artists_sort : null),
+ sort_reverse: (state.ui.library_artists_sort_reverse ? state.ui.library_artists_sort_reverse : false),
+ view: state.ui.library_artists_view,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch),
- googleActions: bindActionCreators(googleActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+ googleActions: bindActionCreators(googleActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(LibraryArtists)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(LibraryArtists);
diff --git a/src/js/views/library/LibraryBrowse.js b/src/js/views/library/LibraryBrowse.js
index 39f470c1..03d87467 100755
--- a/src/js/views/library/LibraryBrowse.js
+++ b/src/js/views/library/LibraryBrowse.js
@@ -19,133 +19,124 @@ import * as helpers from '../../helpers';
import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
-class LibraryBrowse extends React.Component{
+class LibraryBrowse extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.loadDirectory();
+ this.props.uiActions.setWindowTitle('Browse');
+ }
- componentDidMount(){
- this.loadDirectory();
- this.props.uiActions.setWindowTitle("Browse");
- }
+ componentWillReceiveProps(nextProps) {
+ // mopidy goes online
+ if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
+ this.loadDirectory(nextProps);
+ }
+ }
- componentWillReceiveProps(nextProps){
+ loadDirectory(props = this.props) {
+ if (props.mopidy_connected) {
+ this.props.mopidyActions.getDirectory(null);
+ }
+ }
- // mopidy goes online
- if (!this.props.mopidy_connected && nextProps.mopidy_connected){
- this.loadDirectory(nextProps);
- }
- }
+ render() {
+ const grid_items = [];
+ if (this.props.directory) {
+ for (const subdirectory of this.props.directory.subdirectories) {
+ switch (subdirectory.name) {
+ case 'Dirble':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-dirble.jpg'];
+ break;
- loadDirectory(props = this.props){
- if (props.mopidy_connected){
- this.props.mopidyActions.getDirectory(null);
- }
- }
+ case 'Files':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-folders.jpg'];
+ break;
- render(){
- var grid_items = []
- if (this.props.directory){
- for (var subdirectory of this.props.directory.subdirectories){
+ case 'Local media':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-folders.jpg'];
+ break;
- switch (subdirectory.name){
- case 'Dirble':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-dirble.jpg']
- break
+ case 'Spotify':
+ case 'Spotify Browse':
+ case 'Spotify Web Browse':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-spotify.jpg'];
+ break;
- case 'Files':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-folders.jpg']
- break
+ case 'Spotify Tunigo':
+ case 'Tunigo':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-tunigo.jpg'];
+ break;
- case 'Local media':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-folders.jpg']
- break
+ case 'TuneIn':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-tunein.jpg'];
+ break;
- case 'Spotify':
- case 'Spotify Browse':
- case 'Spotify Web Browse':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-spotify.jpg']
- break
+ case 'SoundCloud':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-soundcloud.jpg'];
+ break;
- case 'Spotify Tunigo':
- case 'Tunigo':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-tunigo.jpg']
- break
+ case 'iTunes Store: Podcasts':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-itunes.jpg'];
+ break;
- case 'TuneIn':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-tunein.jpg']
- break
+ case 'Soma FM':
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-somafm.jpg'];
+ break;
- case 'SoundCloud':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-soundcloud.jpg']
- break
+ default:
+ subdirectory.icons = ['/iris/assets/backgrounds/browse-default.jpg'];
+ }
- case 'iTunes Store: Podcasts':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-itunes.jpg']
- break
+ grid_items.push({
+ name: subdirectory.name,
+ link: `/library/browse/${encodeURIComponent(subdirectory.uri)}`,
+ icons: helpers.formatImages(subdirectory.icons),
+ });
+ }
+ }
- case 'Soma FM':
- subdirectory.icons = ['/iris/assets/backgrounds/browse-somafm.jpg']
- break
-
- default:
- subdirectory.icons = ['/iris/assets/backgrounds/browse-default.jpg']
- }
-
- grid_items.push({
- name: subdirectory.name,
- link: '/library/browse/'+encodeURIComponent(subdirectory.uri),
- icons: helpers.formatImages(subdirectory.icons)
- })
- }
- }
-
- return (
-
-
-
+ return (
+
+
-
-
-
- {
+
+
+
+
+ {
grid_items.map(
- (item, index) => {
- return (
-
- )
- }
+ (item, index) => (
+
+ ),
)
}
-
-
-
-
- );
- }
+
+
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- load_queue: state.ui.load_queue,
- mopidy_connected: state.mopidy.connected,
- directory: state.mopidy.directory,
- view: state.ui.library_directory_view
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ load_queue: state.ui.load_queue,
+ mopidy_connected: state.mopidy.connected,
+ directory: state.mopidy.directory,
+ view: state.ui.library_directory_view,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(LibraryBrowse)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(LibraryBrowse);
diff --git a/src/js/views/library/LibraryBrowseDirectory.js b/src/js/views/library/LibraryBrowseDirectory.js
index 7d9fe3ec..21b04509 100755
--- a/src/js/views/library/LibraryBrowseDirectory.js
+++ b/src/js/views/library/LibraryBrowseDirectory.js
@@ -18,230 +18,232 @@ import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
-class LibraryBrowseDirectory extends React.Component{
+class LibraryBrowseDirectory extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Browse');
+ this.loadDirectory();
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Browse");
- this.loadDirectory();
- }
+ componentWillReceiveProps(nextProps) {
+ // mopidy goes online
+ if (!this.props.mopidy_connected && nextProps.mopidy_connected) {
+ this.loadDirectory(nextProps);
+ }
- componentWillReceiveProps(nextProps){
+ // our uri changes
+ if (nextProps.uri && nextProps.uri !== this.props.uri) {
+ this.loadDirectory(nextProps);
+ }
+ }
- // mopidy goes online
- if (!this.props.mopidy_connected && nextProps.mopidy_connected){
- this.loadDirectory(nextProps);
- }
+ loadDirectory(props = this.props) {
+ if (props.mopidy_connected) {
+ let uri = null;
+ if (props.uri !== undefined) {
+ uri = props.uri;
+ }
+ this.props.mopidyActions.getDirectory(uri);
+ }
+ }
- // our uri changes
- if (nextProps.uri && nextProps.uri !== this.props.uri){
- this.loadDirectory(nextProps);
- }
- }
+ playAll(e, tracks) {
+ const tracks_uris = helpers.arrayOf('uri', tracks);
+ this.props.mopidyActions.playURIs(tracks_uris, `iris:browse:${this.props.uri}`);
+ this.props.uiActions.hideContextMenu();
+ }
- loadDirectory(props = this.props){
- if (props.mopidy_connected){
- var uri = null
- if (props.uri !== undefined){
- uri = props.uri;
- }
- this.props.mopidyActions.getDirectory(uri);
- }
- }
+ goBack(e) {
+ window.history.back();
+ this.props.uiActions.hideContextMenu();
+ }
- playAll(e, tracks){
- var tracks_uris = helpers.arrayOf('uri',tracks);
- this.props.mopidyActions.playURIs(tracks_uris, "iris:browse:"+this.props.uri);
- this.props.uiActions.hideContextMenu();
- }
+ renderBreadcrumbs() {
+ if (this.props.uri) {
+ var parent_uri = this.props.uri;
+ } else {
+ return null;
+ }
- goBack(e){
- window.history.back();
- this.props.uiActions.hideContextMenu();
- }
+ if (parent_uri.startsWith('file://')) {
+ const uri = parent_uri.replace('file:///', '');
+ const uri_elements = uri.split('/');
- renderBreadcrumbs(){
+ return (
+
+ {uri_elements.map((uri_element, index) => {
+ // Reconstruct a URL to this element
+ let uri = 'file://';
+ for (let i = 0; i <= index; i++) {
+ uri += `/${uri_elements[i]}`;
+ }
- if (this.props.uri){
- var parent_uri = this.props.uri;
- } else {
- return null;
- }
+ return (
+
+ {index > 0 ? (
+
+
+ {' '}
+
+
+ ) : null}
+
+ {decodeURI(uri_element)}
+
+
+ );
+ })}
+
+ );
+ }
- if (parent_uri.startsWith('file://')){
- var uri = parent_uri.replace('file:///','');
- var uri_elements = uri.split('/');
+ return null;
+ }
- return (
-
- {uri_elements.map((uri_element, index) => {
-
- // Reconstruct a URL to this element
- var uri = "file://";
- for (var i = 0; i <= index; i++){
- uri += "/"+uri_elements[i];
- }
-
- return (
-
- {index > 0 ? : null}
-
- {decodeURI(uri_element)}
-
-
- );
- })}
-
- );
- }
-
- return null;
- }
-
- renderSubdirectories(subdirectories){
- if (this.props.view == 'list'){
- return (
-
- );
- } else {
- return (
-
- {
- subdirectories.map(subdirectory => {
- return (
-
- );
- })
+ renderSubdirectories(subdirectories) {
+ if (this.props.view == 'list') {
+ return (
+
+ );
+ }
+ return (
+
+ {
+ subdirectories.map((subdirectory) => (
+
+ ))
}
-
- );
- }
- }
+
+ );
+ }
- render(){
- var title = 'Directory';
- var uri_exploded = this.props.uri.split(':');
- if (uri_exploded.length > 0){
- title = uri_exploded[0];
- title = title.charAt(0).toUpperCase() + title.slice(1);
- }
+ render() {
+ let title = 'Directory';
+ const uri_exploded = this.props.uri.split(':');
+ if (uri_exploded.length > 0) {
+ title = uri_exploded[0];
+ title = title.charAt(0).toUpperCase() + title.slice(1);
+ }
- if (!this.props.directory || helpers.isLoading(this.props.load_queue,['mopidy_browse'])){
- return (
-
- )
- }
+ if (!this.props.directory || helpers.isLoading(this.props.load_queue, ['mopidy_browse'])) {
+ return (
+
+ );
+ }
- var tracks = (this.props.directory.tracks && this.props.directory.tracks.length > 0 ? this.props.directory.tracks : null);
- tracks = helpers.sortItems(tracks, 'name');
-
- var subdirectories = (this.props.directory.subdirectories && this.props.directory.subdirectories.length > 0 ? this.props.directory.subdirectories : null);
- subdirectories = helpers.sortItems(subdirectories, 'name');
+ let tracks = (this.props.directory.tracks && this.props.directory.tracks.length > 0 ? this.props.directory.tracks : null);
+ tracks = helpers.sortItems(tracks, 'name');
- var view_options = [
- {
- label: 'Thumbnails',
- value: 'thumbnails'
- },
- {
- label: 'List',
- value: 'list'
- }
- ];
+ let subdirectories = (this.props.directory.subdirectories && this.props.directory.subdirectories.length > 0 ? this.props.directory.subdirectories : null);
+ subdirectories = helpers.sortItems(subdirectories, 'name');
- var options = (
-
- {this.props.uiActions.set({ library_directory_view: value }); this.props.uiActions.hideContextMenu()}}
- />
- {tracks ? {this.props.uiActions.hideContextMenu(); this.playAll(e, tracks)}}>
- Play all
- : null }
- {this.props.uiActions.hideContextMenu(); this.goBack(e)}}>
- Back
-
-
- );
+ const view_options = [
+ {
+ label: 'Thumbnails',
+ value: 'thumbnails',
+ },
+ {
+ label: 'List',
+ value: 'list',
+ },
+ ];
- return (
-
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
+const mapStateToProps = (state, ownProps) => {
+ // Decode the URI, and then re-encode selected characters
+ // This is needed as Mopidy encodes *some* characters in URIs (but not other characters)
+ // We need to retain ":" because this a reserved URI separator
+ let uri = decodeURIComponent(ownProps.match.params.uri);
+ uri = uri.replace(/\s/g, '%20'); // space
+ uri = uri.replace(/&/g, '%26'); // &
+ uri = uri.replace(/\[/g, '%5B'); // [
+ uri = uri.replace(/\]/g, '%5D'); // ]
+ uri = uri.replace(/\(/g, '%28'); // (
+ uri = uri.replace(/\)/g, '%29'); // )
+ uri = uri.replace(/\#/g, '%23'); // #
- // Decode the URI, and then re-encode selected characters
- // This is needed as Mopidy encodes *some* characters in URIs (but not other characters)
- // We need to retain ":" because this a reserved URI separator
- var uri = decodeURIComponent(ownProps.match.params.uri);
- uri = uri.replace(/\s/g, '%20'); // space
- uri = uri.replace(/&/g, '%26'); // &
- uri = uri.replace(/\[/g, '%5B'); // [
- uri = uri.replace(/\]/g, '%5D'); // ]
- uri = uri.replace(/\(/g, '%28'); // (
- uri = uri.replace(/\)/g, '%29'); // )
- uri = uri.replace(/\#/g, '%23'); // #
+ return {
+ uri,
+ load_queue: state.ui.load_queue,
+ mopidy_connected: state.mopidy.connected,
+ directory: state.mopidy.directory,
+ view: state.ui.library_directory_view,
+ };
+};
- return {
- uri: uri,
- load_queue: state.ui.load_queue,
- mopidy_connected: state.mopidy.connected,
- directory: state.mopidy.directory,
- view: state.ui.library_directory_view
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(LibraryBrowseDirectory)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(LibraryBrowseDirectory);
diff --git a/src/js/views/library/LibraryPlaylists.js b/src/js/views/library/LibraryPlaylists.js
index 7fe8d6e3..4e15b549 100755
--- a/src/js/views/library/LibraryPlaylists.js
+++ b/src/js/views/library/LibraryPlaylists.js
@@ -1,314 +1,307 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
import Link from '../../components/Link';
-import PlaylistGrid from '../../components/PlaylistGrid'
-import List from '../../components/List'
-import DropdownField from '../../components/Fields/DropdownField'
-import Header from '../../components/Header'
-import FilterField from '../../components/Fields/FilterField'
-import LazyLoadListener from '../../components/LazyLoadListener'
-import Icon from '../../components/Icon'
+import PlaylistGrid from '../../components/PlaylistGrid';
+import List from '../../components/List';
+import DropdownField from '../../components/Fields/DropdownField';
+import Header from '../../components/Header';
+import FilterField from '../../components/Fields/FilterField';
+import LazyLoadListener from '../../components/LazyLoadListener';
+import Icon from '../../components/Icon';
-import * as helpers from '../../helpers'
-import * as coreActions from '../../services/core/actions'
-import * as uiActions from '../../services/ui/actions'
-import * as mopidyActions from '../../services/mopidy/actions'
-import * as spotifyActions from '../../services/spotify/actions'
+import * as helpers from '../../helpers';
+import * as coreActions from '../../services/core/actions';
+import * as uiActions from '../../services/ui/actions';
+import * as mopidyActions from '../../services/mopidy/actions';
+import * as spotifyActions from '../../services/spotify/actions';
-class LibraryPlaylists extends React.Component{
+class LibraryPlaylists extends React.Component {
+ constructor(props) {
+ super(props);
- constructor(props){
- super(props)
+ this.state = {
+ filter: '',
+ limit: 50,
+ per_page: 50,
+ };
+ }
- this.state = {
- filter: '',
- limit: 50,
- per_page: 50
- }
- }
+ componentWillMount() {
+ // Before we mount, restore any limit defined in our location state
+ const state = (this.props.location.state ? this.props.location.state : {});
+ if (state.limit) {
+ this.setState({
+ limit: state.limit,
+ });
+ }
+ }
- componentWillMount(){
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Playlists');
- // Before we mount, restore any limit defined in our location state
- var state = (this.props.location.state ? this.props.location.state : {});
- if (state.limit){
- this.setState({
- limit: state.limit
- });
- }
- }
+ if (!this.props.mopidy_library_playlists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'local')) {
+ this.props.mopidyActions.getLibraryPlaylists();
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Playlists");
+ if (this.props.spotify_enabled && this.props.spotify_library_playlists_status !== 'finished' && (this.props.source == 'all' || this.props.source == 'spotify')) {
+ this.props.spotifyActions.getLibraryPlaylists();
+ }
+ }
- if (!this.props.mopidy_library_playlists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'local')){
- this.props.mopidyActions.getLibraryPlaylists()
- }
+ componentWillReceiveProps(newProps) {
+ if (newProps.mopidy_connected && (newProps.source == 'all' || newProps.source == 'local')) {
+ // We've just connected
+ if (!this.props.mopidy_connected) {
+ this.props.mopidyActions.getLibraryPlaylists();
+ }
- if (this.props.spotify_enabled && this.props.spotify_library_playlists_status !== 'finished' && (this.props.source == 'all' || this.props.source == 'spotify')){
- this.props.spotifyActions.getLibraryPlaylists()
- }
- }
+ // Filter changed, but we haven't got this provider's library yet
+ if (this.props.source != 'all' && this.props.source != 'local' && !newProps.mopidy_library_playlists) {
+ this.props.mopidyActions.getLibraryPlaylists();
+ }
+ }
- componentWillReceiveProps(newProps){
+ if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')) {
+ // Filter changed, but we haven't got this provider's library yet
+ if (newProps.spotify_library_playlists_status != 'finished' && newProps.spotify_library_playlists_status != 'started') {
+ this.props.spotifyActions.getLibraryPlaylists();
+ }
+ }
+ }
- if (newProps.mopidy_connected && (newProps.source == 'all' || newProps.source == 'local')){
+ handleContextMenu(e, item) {
+ const data = {
+ e,
+ context: 'playlist',
+ uris: [item.uri],
+ items: [item],
+ };
+ this.props.uiActions.showContextMenu(data);
+ }
- // We've just connected
- if (!this.props.mopidy_connected){
- this.props.mopidyActions.getLibraryPlaylists();
- }
+ loadMore() {
+ const new_limit = this.state.limit + this.state.per_page;
- // Filter changed, but we haven't got this provider's library yet
- if (this.props.source != 'all' && this.props.source != 'local' && !newProps.mopidy_library_playlists){
- this.props.mopidyActions.getLibraryPlaylists()
- }
- }
+ this.setState({ limit: new_limit });
- if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')){
+ // Set our pagination to location state
+ const state = (this.props.location && this.props.location.state ? this.props.location.state : {});
+ state.limit = new_limit;
+ this.props.history.replace({ state });
+ }
- // Filter changed, but we haven't got this provider's library yet
- if (newProps.spotify_library_playlists_status != 'finished' && newProps.spotify_library_playlists_status != 'started'){
- this.props.spotifyActions.getLibraryPlaylists()
- }
- }
- }
+ setSort(value) {
+ let reverse = false;
+ if (this.props.sort == value) reverse = !this.props.sort_reverse;
- handleContextMenu(e,item){
- var data = {
- e: e,
- context: 'playlist',
- uris: [item.uri],
- items: [item]
- }
- this.props.uiActions.showContextMenu(data)
- }
+ const data = {
+ library_playlists_sort_reverse: reverse,
+ library_playlists_sort: value,
+ };
+ this.props.uiActions.set(data);
+ }
- loadMore(){
- var new_limit = this.state.limit + this.state.per_page;
+ renderView() {
+ let playlists = [];
- this.setState({limit: new_limit});
+ // Spotify library items
+ if (this.props.spotify_library_playlists && (this.props.source == 'all' || this.props.source == 'spotify')) {
+ for (var i = 0; i < this.props.spotify_library_playlists.length; i++) {
+ var uri = this.props.spotify_library_playlists[i];
+ if (this.props.playlists.hasOwnProperty(uri)) {
+ playlists.push(this.props.playlists[uri]);
+ }
+ }
+ }
- // Set our pagination to location state
- var state = (this.props.location && this.props.location.state ? this.props.location.state : {});
- state.limit = new_limit;
- this.props.history.replace({state: state});
- }
+ // Mopidy library items
+ if (this.props.mopidy_library_playlists && (this.props.source == 'all' || this.props.source == 'local')) {
+ for (var i = 0; i < this.props.mopidy_library_playlists.length; i++) {
+ var uri = this.props.mopidy_library_playlists[i];
+ if (this.props.playlists.hasOwnProperty(uri)) {
+ playlists.push(this.props.playlists[uri]);
+ }
+ }
+ }
- setSort(value){
- var reverse = false
- if (this.props.sort == value ) reverse = !this.props.sort_reverse
+ if (this.props.sort) {
+ playlists = helpers.sortItems(playlists, this.props.sort, this.props.sort_reverse);
+ }
+ playlists = helpers.removeDuplicates(playlists);
- var data = {
- library_playlists_sort_reverse: reverse,
- library_playlists_sort: value
- }
- this.props.uiActions.set(data)
- }
+ if (this.state.filter !== '') {
+ playlists = helpers.applyFilter('name', this.state.filter, playlists);
+ }
- renderView(){
- var playlists = [];
+ // Apply our lazy-load-rendering
+ const total_playlists = playlists.length;
+ playlists = playlists.slice(0, this.state.limit);
- // Spotify library items
- if (this.props.spotify_library_playlists && (this.props.source == 'all' || this.props.source == 'spotify')){
- for (var i = 0; i < this.props.spotify_library_playlists.length; i++){
- var uri = this.props.spotify_library_playlists[i]
- if (this.props.playlists.hasOwnProperty(uri)){
- playlists.push(this.props.playlists[uri])
- }
- }
- }
+ if (this.props.view == 'list') {
+ return (
+
+ this.handleContextMenu(e, item)}
+ rows={playlists}
+ thumbnail
+ details={['owner', 'tracks_total']}
+ right_column={['source']}
+ className="playlists"
+ link_prefix="/playlist/"
+ />
+ this.state.limit ? this.state.limit : total_playlists}
+ loading={this.state.limit < total_playlists}
+ loadMore={() => this.loadMore()}
+ />
+
+ );
+ }
+ return (
+
+ this.handleContextMenu(e, item)}
+ playlists={playlists}
+ />
+ this.state.limit ? this.state.limit : total_playlists}
+ loading={this.state.limit < total_playlists}
+ loadMore={() => this.loadMore()}
+ />
+
+ );
+ }
- // Mopidy library items
- if (this.props.mopidy_library_playlists && (this.props.source == 'all' || this.props.source == 'local')){
- for (var i = 0; i < this.props.mopidy_library_playlists.length; i++){
- var uri = this.props.mopidy_library_playlists[i]
- if (this.props.playlists.hasOwnProperty(uri)){
- playlists.push(this.props.playlists[uri])
- }
- }
- }
+ render() {
+ const source_options = [
+ {
+ value: 'all',
+ label: 'All',
+ },
+ {
+ value: 'local',
+ label: 'Local',
+ },
+ ];
- if (this.props.sort){
- playlists = helpers.sortItems(playlists, this.props.sort, this.props.sort_reverse);
- }
- playlists = helpers.removeDuplicates(playlists);
+ if (this.props.spotify_enabled) {
+ source_options.push({
+ value: 'spotify',
+ label: 'Spotify',
+ });
+ }
- if (this.state.filter !== ''){
- playlists = helpers.applyFilter('name', this.state.filter, playlists);
- }
+ const view_options = [
+ {
+ value: 'thumbnails',
+ label: 'Thumbnails',
+ },
+ {
+ value: 'list',
+ label: 'List',
+ },
+ ];
- // Apply our lazy-load-rendering
- var total_playlists = playlists.length;
- playlists = playlists.slice(0, this.state.limit);
+ const sort_options = [
+ {
+ value: null,
+ label: 'Default',
+ },
+ {
+ value: 'name',
+ label: 'Name',
+ },
+ {
+ value: 'can_edit',
+ label: 'Editable',
+ },
+ {
+ value: 'owner.id',
+ label: 'Owner',
+ },
+ {
+ value: 'tracks_total',
+ label: 'Tracks',
+ },
+ {
+ value: 'source',
+ label: 'Source',
+ },
+ ];
- if (this.props.view == 'list'){
- return (
-
- this.handleContextMenu(e,item)}
- rows={playlists}
- thumbnail={true}
- details={['owner','tracks_total']}
- right_column={['source']}
- className="playlists"
- link_prefix={"/playlist/"} />
- this.state.limit ? this.state.limit : total_playlists}
- loading={this.state.limit < total_playlists}
- loadMore={() => this.loadMore()}
- />
-
- )
- } else {
- return (
-
- this.handleContextMenu(e,item)}
- playlists={playlists} />
- this.state.limit ? this.state.limit : total_playlists}
- loading={this.state.limit < total_playlists}
- loadMore={() => this.loadMore()}
- />
-
- )
- }
- }
+ const options = (
+
+ this.setState({ filter: value })}
+ />
+ { this.setSort(value); this.props.uiActions.hideContextMenu(); }}
+ />
+ { this.props.uiActions.set({ library_playlists_view: value }); this.props.uiActions.hideContextMenu(); }}
+ />
+ { this.props.uiActions.set({ library_playlists_source: value }); this.props.uiActions.hideContextMenu(); }}
+ />
+
+
+New
+
+
+ );
- render(){
- var source_options = [
- {
- value: 'all',
- label: 'All'
- },
- {
- value: 'local',
- label: 'Local'
- }
- ];
-
- if (this.props.spotify_enabled){
- source_options.push({
- value: 'spotify',
- label: 'Spotify'
- });
- }
-
- var view_options = [
- {
- value: 'thumbnails',
- label: 'Thumbnails'
- },
- {
- value: 'list',
- label: 'List'
- }
- ];
-
- var sort_options = [
- {
- value: null,
- label: 'Default'
- },
- {
- value: 'name',
- label: 'Name'
- },
- {
- value: 'can_edit',
- label: 'Editable'
- },
- {
- value: 'owner.id',
- label: 'Owner'
- },
- {
- value: 'tracks_total',
- label: 'Tracks'
- },
- {
- value: 'source',
- label: 'Source'
- }
- ];
-
- var options = (
-
- this.setState({filter: value})}
- />
- {this.setSort(value); this.props.uiActions.hideContextMenu() }}
- />
- {this.props.uiActions.set({ library_playlists_view: value}); this.props.uiActions.hideContextMenu() }}
- />
- {this.props.uiActions.set({ library_playlists_source: value}); this.props.uiActions.hideContextMenu() }}
- />
-
- New
-
-
- )
-
- return (
-
-
+ { this.renderView() }
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- slim_mode: state.ui.slim_mode,
- mopidy_connected: state.mopidy.connected,
- mopidy_uri_schemes: state.mopidy.uri_schemes,
- mopidy_library_playlists: state.mopidy.library_playlists,
- mopidy_library_playlists_status: (state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
- spotify_enabled: (state.mopidy.uri_schemes && state.mopidy.uri_schemes.includes('spotify:')),
- spotify_library_playlists: state.spotify.library_playlists,
- spotify_library_playlists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
- 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, ownProps) => ({
+ slim_mode: state.ui.slim_mode,
+ mopidy_connected: state.mopidy.connected,
+ mopidy_uri_schemes: state.mopidy.uri_schemes,
+ mopidy_library_playlists: state.mopidy.library_playlists,
+ mopidy_library_playlists_status: (state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
+ spotify_enabled: (state.mopidy.uri_schemes && state.mopidy.uri_schemes.includes('spotify:')),
+ spotify_library_playlists: state.spotify.library_playlists,
+ spotify_library_playlists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
+ 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) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(LibraryPlaylists)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(LibraryPlaylists);
diff --git a/src/js/views/library/LibraryTracks.js b/src/js/views/library/LibraryTracks.js
index 33c74a57..778f6f0e 100755
--- a/src/js/views/library/LibraryTracks.js
+++ b/src/js/views/library/LibraryTracks.js
@@ -1,97 +1,96 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
import Link from '../../components/Link';
-import TrackList from '../../components/TrackList'
-import Header from '../../components/Header'
-import LazyLoadListener from '../../components/LazyLoadListener'
-import Icon from '../../components/Icon'
+import TrackList from '../../components/TrackList';
+import Header from '../../components/Header';
+import LazyLoadListener from '../../components/LazyLoadListener';
+import Icon from '../../components/Icon';
-import * as helpers from '../../helpers'
-import * as uiActions from '../../services/ui/actions'
-import * as mopidyActions from '../../services/mopidy/actions'
-import * as spotifyActions from '../../services/spotify/actions'
+import * as helpers from '../../helpers';
+import * as uiActions from '../../services/ui/actions';
+import * as mopidyActions from '../../services/mopidy/actions';
+import * as spotifyActions from '../../services/spotify/actions';
-class LibraryTracks extends React.Component{
+class LibraryTracks extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ // on render
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Tracks');
- // on render
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Tracks");
+ if (!this.props.spotify_me) {
+ this.props.uiActions.createNotification({ type: 'warning', content: 'Enable Spotify to browse tracks' });
+ } else if (this.props.library_tracks === undefined) {
+ this.props.spotifyActions.getLibraryTracks();
+ }
+ }
- if (!this.props.spotify_me){
- this.props.uiActions.createNotification({type: 'warning', content: 'Enable Spotify to browse tracks'});
- } else if (this.props.library_tracks === undefined){
- this.props.spotifyActions.getLibraryTracks();
- }
- }
+ loadMore() {
+ this.props.spotifyActions.getMore(
+ this.props.library_tracks_more,
+ null,
+ {
+ type: 'SPOTIFY_LIBRARY_TRACKS_LOADED_MORE',
+ },
+ );
+ }
- loadMore(){
- this.props.spotifyActions.getMore(
- this.props.library_tracks_more,
- null,
- {
- type: 'SPOTIFY_LIBRARY_TRACKS_LOADED_MORE'
- }
- );
- }
+ playAll() {
+ this.props.spotifyActions.getLibraryTracksAndPlay();
+ }
- playAll(){
- this.props.spotifyActions.getLibraryTracksAndPlay();
- }
+ render() {
+ // Note trailing "?" makes sure our context menu in_library checks doesn't interfere
+ if (helpers.isLoading(this.props.load_queue, ['spotify_me/tracks?'])) {
+ return (
+
+ );
+ }
- render(){
-
- // Note trailing "?" makes sure our context menu in_library checks doesn't interfere
- if (helpers.isLoading(this.props.load_queue,['spotify_me/tracks?'])){
- return (
-
- )
- }
+ const tracks = [];
+ if (this.props.library_tracks && this.props.tracks) {
+ for (let i = 0; i < this.props.library_tracks.length; i++) {
+ const uri = this.props.library_tracks[i];
+ if (this.props.tracks.hasOwnProperty(uri)) {
+ tracks.push(this.props.tracks[uri]);
+ }
+ }
+ }
- var tracks = [];
- if (this.props.library_tracks && this.props.tracks){
- for (var i = 0; i < this.props.library_tracks.length; i++){
- var uri = this.props.library_tracks[i]
- if (this.props.tracks.hasOwnProperty(uri)){
- tracks.push(this.props.tracks[uri])
- }
- }
- }
+ const options = (
+ this.playAll(e)}>
+
+Play all
+
+ );
- var options = (
- this.playAll(e)}>
- Play all
-
- );
-
- return (
-
-
+
+
+ this.loadMore()}
+ />
+
+
+ );
+ }
}
@@ -99,24 +98,20 @@ class LibraryTracks extends React.Component{
* Export our component
*
* We also integrate our global store, using connect()
- **/
+ * */
-const mapStateToProps = (state, ownProps) => {
- return {
- load_queue: state.ui.load_queue,
- tracks: state.core.tracks,
- spotify_me: state.spotify.me,
- library_tracks: state.spotify.library_tracks,
- library_tracks_more: state.spotify.library_tracks_more
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ load_queue: state.ui.load_queue,
+ tracks: state.core.tracks,
+ spotify_me: state.spotify.me,
+ library_tracks: state.spotify.library_tracks,
+ library_tracks_more: state.spotify.library_tracks_more,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(LibraryTracks)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(LibraryTracks);
diff --git a/src/js/views/modals/AddToPlaylist.js b/src/js/views/modals/AddToPlaylist.js
index f12eea80..efd9f223 100755
--- a/src/js/views/modals/AddToPlaylist.js
+++ b/src/js/views/modals/AddToPlaylist.js
@@ -1,105 +1,114 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-import Link from '../../components/Link'
-import ReactGA from 'react-ga'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import ReactGA from 'react-ga';
+import Link from '../../components/Link';
import Modal from './Modal';
import Icon from '../../components/Icon';
import Thumbnail from '../../components/Thumbnail';
-import * as coreActions from '../../services/core/actions'
-import * as uiActions from '../../services/ui/actions'
-import * as mopidyActions from '../../services/mopidy/actions'
-import * as spotifyActions from '../../services/spotify/actions'
+import * as coreActions from '../../services/core/actions';
+import * as uiActions from '../../services/ui/actions';
+import * as mopidyActions from '../../services/mopidy/actions';
+import * as spotifyActions from '../../services/spotify/actions';
import * as helpers from '../../helpers';
-class AddToPlaylist extends React.Component{
+class AddToPlaylist extends React.Component {
+ constructor(props) {
+ super(props);
- constructor(props){
- super(props)
+ if (!this.props.spotify_library_playlists) {
+ this.props.spotifyActions.getLibraryPlaylists();
+ }
- if (!this.props.spotify_library_playlists){
- this.props.spotifyActions.getLibraryPlaylists()
- }
-
- if (!this.props.mopidy_library_playlists && this.props.mopidy_connected){
- this.props.mopidyActions.getLibraryPlaylists()
- }
- }
+ if (!this.props.mopidy_library_playlists && this.props.mopidy_connected) {
+ this.props.mopidyActions.getLibraryPlaylists();
+ }
+ }
- playlistSelected(playlist_uri){
- this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.uris);
- window.history.back();
- }
+ playlistSelected(playlist_uri) {
+ this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.uris);
+ window.history.back();
+ }
- render(){
- if (!this.props.playlists ) return No editable playlists
- var playlists = []
- for (var uri in this.props.playlists){
- if (this.props.playlists[uri].can_edit ) playlists.push(this.props.playlists[uri] )
- }
+ render() {
+ if (!this.props.playlists) return No editable playlists
;
+ let playlists = [];
+ for (const uri in this.props.playlists) {
+ if (this.props.playlists[uri].can_edit) playlists.push(this.props.playlists[uri]);
+ }
- playlists = helpers.sortItems(playlists, 'name')
+ playlists = helpers.sortItems(playlists, 'name');
- var loader = null
- if (this.props.spotify_library_playlists_status == 'running'){
- loader = (
-
- )
- }
+ let loader = null;
+ if (this.props.spotify_library_playlists_status == 'running') {
+ loader = (
+
+ );
+ }
- return (
-
- Add to playlist
- Select playlist to add {this.props.uris.length} track{this.props.uris.length>1?'s':null} to
- {playlists.length <= 0 ? No playlists available
: null}
-
- {
- playlists.map(playlist => {
- return (
-
this.playlistSelected(playlist.uri) }>
-
-
{ playlist.name }
-
-
- { playlist.tracks_total ? { playlist.tracks_total } tracks : null }
-
-
- )
- })
+ return (
+
+ Add to playlist
+
+Select playlist to add
+ {this.props.uris.length}
+ {' '}
+track
+ {this.props.uris.length > 1 ? 's' : null}
+ {' '}
+to
+
+ {playlists.length <= 0 ? No playlists available
: null}
+
+ {
+ playlists.map((playlist) => (
+
this.playlistSelected(playlist.uri)}>
+
+
{ playlist.name }
+
+
+
+ { playlist.tracks_total ? (
+
+ { playlist.tracks_total }
+ {' '}
+tracks
+
+ ) : null }
+
+
+
+ ))
}
-
- {loader}
-
- )
- }
+
+ {loader}
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- uris: (ownProps.match.params.uris ? decodeURIComponent(ownProps.match.params.uris).split(',') : []),
- mopidy_connected: state.mopidy.connected,
- mopidy_uri_schemes: state.mopidy.uri_schemes,
- mopidy_library_playlists: state.mopidy.library_playlists,
- mopidy_library_playlists_status: (state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
- spotify_library_playlists: state.spotify.library_playlists,
- spotify_library_playlists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
- load_queue: state.ui.load_queue,
- me_id: (state.spotify.me ? state.spotify.me.id : false),
- playlists: state.core.playlists
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ uris: (ownProps.match.params.uris ? decodeURIComponent(ownProps.match.params.uris).split(',') : []),
+ mopidy_connected: state.mopidy.connected,
+ mopidy_uri_schemes: state.mopidy.uri_schemes,
+ mopidy_library_playlists: state.mopidy.library_playlists,
+ mopidy_library_playlists_status: (state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
+ spotify_library_playlists: state.spotify.library_playlists,
+ spotify_library_playlists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
+ load_queue: state.ui.load_queue,
+ me_id: (state.spotify.me ? state.spotify.me.id : false),
+ playlists: state.core.playlists,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(AddToPlaylist)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(AddToPlaylist);
diff --git a/src/js/views/modals/AddToQueue.js b/src/js/views/modals/AddToQueue.js
index 668ffa65..5b4d8629 100755
--- a/src/js/views/modals/AddToQueue.js
+++ b/src/js/views/modals/AddToQueue.js
@@ -1,104 +1,102 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-import Link from '../../components/Link'
-import ReactGA from 'react-ga'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import ReactGA from 'react-ga';
+import Link from '../../components/Link';
import Modal from './Modal';
import Icon from '../../components/Icon';
-import * as coreActions from '../../services/core/actions'
-import * as uiActions from '../../services/ui/actions'
-import * as mopidyActions from '../../services/mopidy/actions'
-import * as spotifyActions from '../../services/spotify/actions'
+import * as coreActions from '../../services/core/actions';
+import * as uiActions from '../../services/ui/actions';
+import * as mopidyActions from '../../services/mopidy/actions';
+import * as spotifyActions from '../../services/spotify/actions';
import * as helpers from '../../helpers';
-class AddToQueue extends React.Component{
+class AddToQueue extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ uris: '',
+ next: false,
+ };
+ }
- constructor(props){
- super(props)
- this.state = {
- uris: '',
- next: false
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Add to queue');
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Add to queue");
- }
+ handleSubmit(e) {
+ e.preventDefault();
+ const uris = this.state.uris.split(',');
+ this.props.mopidyActions.enqueueURIs(uris, null, this.state.next);
+ window.history.back();
+ }
- handleSubmit(e){
- e.preventDefault();
- var uris = this.state.uris.split(',');
- this.props.mopidyActions.enqueueURIs(uris, null, this.state.next);
- window.history.back();
- }
+ render() {
+ return (
+
+ Add to queue
+ Add a comma-separated list of URIs to the play queue. You must have the appropriate Mopidy backend enabled for each URI schema (eg spotify:, yt:).
- render(){
- return (
-
- Add to queue
- Add a comma-separated list of URIs to the play queue. You must have the appropriate Mopidy backend enabled for each URI schema (eg spotify:, yt:).
+ this.handleSubmit(e)}>
+
+
URI(s)
+
+ this.setState({ uris: e.target.value })}
+ value={this.state.uris}
+ />
+
+
- this.handleSubmit(e)}>
-
-
URI(s)
-
- this.setState({uris: e.target.value})}
- value={this.state.uris} />
-
-
-
-
-
- Add
-
-
-
- )
- }
+
+ Add
+
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- mopidy_connected: state.mopidy.connected,
- playlist: (state.core.playlists[ownProps.match.params.uri] !== undefined ? state.core.playlists[ownProps.match.params.uri] : null),
- playlists: state.core.playlists
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ mopidy_connected: state.mopidy.connected,
+ playlist: (state.core.playlists[ownProps.match.params.uri] !== undefined ? state.core.playlists[ownProps.match.params.uri] : null),
+ playlists: state.core.playlists,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(AddToQueue)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(AddToQueue);
diff --git a/src/js/views/modals/CreatePlaylist.js b/src/js/views/modals/CreatePlaylist.js
index 4b398aa2..25caa2da 100755
--- a/src/js/views/modals/CreatePlaylist.js
+++ b/src/js/views/modals/CreatePlaylist.js
@@ -1,176 +1,177 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-import Link from '../../components/Link'
-import ReactGA from 'react-ga'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import ReactGA from 'react-ga';
+import Link from '../../components/Link';
import Modal from './Modal';
import Icon from '../../components/Icon';
-import * as coreActions from '../../services/core/actions'
-import * as uiActions from '../../services/ui/actions'
+import * as coreActions from '../../services/core/actions';
+import * as uiActions from '../../services/ui/actions';
import * as helpers from '../../helpers';
-class CreatePlaylist extends React.Component{
+class CreatePlaylist extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ name: '',
+ description: '',
+ scheme: 'spotify',
+ is_public: true,
+ is_collaborative: false,
+ };
+ }
- constructor(props){
- super(props)
- this.state = {
- name: '',
- description: '',
- scheme: 'spotify',
- is_public: true,
- is_collaborative: false
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Create playlist');
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Create playlist");
- }
+ createPlaylist(e) {
+ e.preventDefault();
- createPlaylist(e){
- e.preventDefault();
+ if (!this.state.name || this.state.name == '') {
+ this.setState({ error: 'Name is required' });
+ return false;
+ }
+ this.props.coreActions.createPlaylist(
+ this.state.scheme,
+ this.state.name,
+ this.state.description,
+ this.state.is_public,
+ this.state.is_collaborative,
+ );
+ window.history.back();
- if (!this.state.name || this.state.name == ''){
- this.setState({error: 'Name is required'})
- return false
- } else {
- this.props.coreActions.createPlaylist(
- this.state.scheme,
- this.state.name,
- this.state.description,
- this.state.is_public,
- this.state.is_collaborative
- );
- window.history.back();
- }
- return false
- }
+ return false;
+ }
- renderFields(){
- switch (this.state.scheme){
+ renderFields() {
+ switch (this.state.scheme) {
+ case 'spotify':
+ return (
+
+
+
Name
+
+ this.setState({ name: e.target.value })}
+ value={this.state.name}
+ />
+
+
- case 'spotify':
- return (
-
-
-
Name
-
- this.setState({ name: e.target.value })}
- value={ this.state.name } />
-
-
+
+
Description
+
+
this.setState({ description: e.target.value })}
-
-
Description
-
- this.setState({ description: e.target.value })}
-
- value={ this.state.description } />
-
-
+ value={this.state.description}
+ />
+
+
-
+
+
+ this.setState({ is_public: !this.state.is_public })}
+ />
+ Public
+
+
+ this.setState({ is_collaborative: !this.state.is_collaborative })}
+ />
+ Collaborative
+
+
+
+
+ );
- default:
- return (
-
-
-
Name
-
- this.setState({ name: e.target.value })}
- value={ this.state.name } />
-
-
-
- )
- }
- }
+ default:
+ return (
+
+
+
Name
+
+ this.setState({ name: e.target.value })}
+ value={this.state.name}
+ />
+
+
+
+ );
+ }
+ }
- render(){
- return (
-
- Create playlist
- this.createPlaylist(e)}>
+ render() {
+ return (
+
+ Create playlist
+ this.createPlaylist(e)}>
-
-
+
-
- {this.renderFields()}
+
+
+
+ this.setState({ scheme: e.target.value })}
+ />
+ Spotify
+
+
+ this.setState({ scheme: e.target.value })}
+ />
+ Mopidy
+
+
+
-
- Create playlist
-
+ {this.renderFields()}
-
-
- )
- }
+
+ Create playlist
+
+
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {}
-}
+const mapStateToProps = (state, ownProps) => ({});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(CreatePlaylist)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(CreatePlaylist);
diff --git a/src/js/views/modals/EditCommand.js b/src/js/views/modals/EditCommand.js
index d16b9ec4..fbd5cc86 100755
--- a/src/js/views/modals/EditCommand.js
+++ b/src/js/views/modals/EditCommand.js
@@ -15,240 +15,242 @@ import * as pusherActions from '../../services/pusher/actions';
import * as uiActions from '../../services/ui/actions';
import * as helpers from '../../helpers';
-class EditCommand extends React.Component{
+class EditCommand extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ id: helpers.generateGuid(),
+ icon: 'power_settings_new',
+ name: '',
+ colour: '',
+ url: `https://${window.location.hostname}/broadlink/sendCommand/power/`,
+ method: 'GET',
+ post_data: '',
+ additional_headers: '',
+ };
+ }
- constructor(props){
- super(props)
- this.state = {
- id: helpers.generateGuid(),
- icon: 'power_settings_new',
- name: '',
- colour: '',
- url: "https://"+window.location.hostname+"/broadlink/sendCommand/power/",
- method: 'GET',
- post_data: "",
- additional_headers: ""
- }
- }
+ componentDidMount() {
+ if (this.props.command) {
+ this.props.uiActions.setWindowTitle('Edit command');
+ this.setState(this.props.command);
+ } else {
+ this.props.uiActions.setWindowTitle('Create command');
+ }
+ }
- componentDidMount(){
- if (this.props.command){
- this.props.uiActions.setWindowTitle("Edit command");
- this.setState(this.props.command);
- } else {
- this.props.uiActions.setWindowTitle("Create command");
- }
- }
+ handleSubmit(e) {
+ e.preventDefault();
- handleSubmit(e){
- e.preventDefault();
+ this.props.pusherActions.setCommand(this.state);
- this.props.pusherActions.setCommand(this.state);
+ window.history.back();
- window.history.back();
+ // A bit hacky, but wait for a moment to allow the back navigation
+ // and then scroll down to our commands list
+ setTimeout(() => {
+ helpers.scrollTo('#commands-setup');
+ },
+ 10);
- // A bit hacky, but wait for a moment to allow the back navigation
- // and then scroll down to our commands list
- setTimeout(() => {
- helpers.scrollTo("#commands-setup");
- },
- 10
- );
+ return false;
+ }
- return false;
- }
+ handleDelete(e) {
+ this.props.pusherActions.removeCommand(this.state.id);
+ window.history.back();
- handleDelete(e){
- this.props.pusherActions.removeCommand(this.state.id);
- window.history.back();
+ // A bit hacky, but wait for a moment to allow the back navigation
+ // and then scroll down to our commands list
+ setTimeout(() => {
+ helpers.scrollTo('#commands-setup');
+ },
+ 10);
+ }
- // A bit hacky, but wait for a moment to allow the back navigation
- // and then scroll down to our commands list
- setTimeout(() => {
- helpers.scrollTo("#commands-setup");
- },
- 10
- );
- }
+ render() {
+ const icons = [
+ 'power_settings_new',
+ 'eject',
+ 'grade',
+ 'query_builder',
+ 'settings_input_component',
+ 'settings_input_hdmi',
+ 'settings_input_svideo',
+ 'forward_5',
+ 'forward_10',
+ 'forward_30',
+ 'replay',
+ 'replay_5',
+ 'replay_10',
+ 'replay_30',
+ 'skip_next',
+ 'skip_previous',
+ 'play_arrow',
+ 'pause',
+ 'stop',
+ 'shuffle',
+ 'snooze',
+ 'volume_off',
+ 'volume_down',
+ 'volume_up',
+ 'arrow_left',
+ 'arrow_drop_up',
+ 'arrow_right',
+ 'arrow_drop_down',
+ 'done',
+ 'done_all',
+ 'add',
+ 'remove',
+ 'clear',
+ 'cast',
+ 'speaker',
+ 'speaker_group',
+ 'audiotrack',
+ 'videogame_asset',
+ 'computer',
+ 'tv',
+ ];
- render(){
-
- var icons = [
- "power_settings_new",
- "eject",
- "grade",
- "query_builder",
- "settings_input_component",
- "settings_input_hdmi",
- "settings_input_svideo",
- "forward_5",
- "forward_10",
- "forward_30",
- "replay",
- "replay_5",
- "replay_10",
- "replay_30",
- "skip_next",
- "skip_previous",
- "play_arrow",
- "pause",
- "stop",
- "shuffle",
- "snooze",
- "volume_off",
- "volume_down",
- "volume_up",
- "arrow_left",
- "arrow_drop_up",
- "arrow_right",
- "arrow_drop_down",
- "done",
- "done_all",
- "add",
- "remove",
- "clear",
- "cast",
- "speaker",
- "speaker_group",
- "audiotrack",
- "videogame_asset",
- "computer",
- "tv"
- ];
-
- return (
-
- {this.props.command ? "Edit" : "Create"} command
- this.handleSubmit(e)}>
-
-
-
- Name
-
-
- this.setState({ name: value })}
- />
-
-
-
-
-
- Colour
-
-
- this.setState({colour: colour})}
- />
-
-
-
-
-
- Icon
-
-
- this.setState({icon: icon})}
- />
-
-
-
-
-
- URL
-
-
- this.setState({ url: value })}
- />
-
-
-
-
-
- {this.state.method == 'POST' &&
-
- Data
-
-
- this.setState({ post_data: e.target.value })}>
-
-
-
}
+ return (
+
+
+ {this.props.command ? 'Edit' : 'Create'}
+ {' '}
+command
+
+ this.handleSubmit(e)}>
-
+
+ Name
+
+
+ this.setState({ name: value })}
+ />
+
+
+
+
+
+ Colour
+
+
+ this.setState({ colour })}
+ />
+
+
+
+
+
+ Icon
+
+
+ this.setState({ icon })}
+ />
+
+
+
+
+
+ URL
+
+
+ this.setState({ url: value })}
+ />
+
+
+
+
+
+ {this.state.method == 'POST' && (
+
+
+ Data
+
+
+ this.setState({ post_data: e.target.value })}
+ />
+
+
+ )}
+
+
+
Additional Headers
-
-
- this.setState({ additional_headers: e.target.value })}>
-
-
-
+
+
+ this.setState({ additional_headers: e.target.value })}
+ />
+
+
-
- {this.props.command ? this.handleDelete(e)}>Delete : null}
- Save
-
+
+ {this.props.command ? this.handleDelete(e)}>Delete : null}
+ Save
+
-
-
- )
- }
+
+
+ );
+ }
}
const mapStateToProps = (state, ownProps) => {
- var id = ownProps.match.params.id;
- return {
- id: id,
- command: (id && state.pusher.commands && state.pusher.commands[id] !== undefined ? state.pusher.commands[id] : null)
- }
-}
+ const { id } = ownProps.match.params;
+ return {
+ id,
+ command: (id && state.pusher.commands && state.pusher.commands[id] !== undefined ? state.pusher.commands[id] : null),
+ };
+};
-const mapDispatchToProps = (dispatch) => {
- return {
- pusherActions: bindActionCreators(pusherActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(EditCommand)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(EditCommand);
diff --git a/src/js/views/modals/EditPlaylist.js b/src/js/views/modals/EditPlaylist.js
index b75dd2db..bfa13d93 100755
--- a/src/js/views/modals/EditPlaylist.js
+++ b/src/js/views/modals/EditPlaylist.js
@@ -1,242 +1,236 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-import Link from '../../components/Link'
-import ReactGA from 'react-ga'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import ReactGA from 'react-ga';
+import Link from '../../components/Link';
import Modal from './Modal';
import Icon from '../../components/Icon';
-import * as coreActions from '../../services/core/actions'
-import * as uiActions from '../../services/ui/actions'
-import * as mopidyActions from '../../services/mopidy/actions'
-import * as spotifyActions from '../../services/spotify/actions'
+import * as coreActions from '../../services/core/actions';
+import * as uiActions from '../../services/ui/actions';
+import * as mopidyActions from '../../services/mopidy/actions';
+import * as spotifyActions from '../../services/spotify/actions';
import * as helpers from '../../helpers';
-class EditPlaylist extends React.Component{
+class EditPlaylist extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ error: null,
+ name: '',
+ description: '',
+ image: null,
+ public: false,
+ collaborative: false,
+ };
+ }
- constructor(props){
- super(props)
- this.state = {
- error: null,
- name: '',
- description: '',
- image: null,
- public: false,
- collaborative: false
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Edit playlist');
- componentDidMount(){
+ if (this.props.playlist) {
+ this.setState({
+ name: this.props.playlist.name,
+ description: this.props.playlist.description,
+ public: (this.props.playlist.public == true),
+ collaborative: (this.props.playlist.collaborative == true),
+ });
+ } else {
+ switch (helpers.uriSource(this.props.uri)) {
+ case 'spotify':
+ this.props.spotifyActions.getPlaylist(this.props.uri);
+ this.props.spotifyActions.following(this.props.uri);
+ break;
- this.props.uiActions.setWindowTitle("Edit playlist");
+ default:
+ if (this.props.mopidy_connected) {
+ this.props.mopidyActions.getPlaylist(this.props.uri);
+ }
+ break;
+ }
+ }
+ }
- if (this.props.playlist){
- this.setState({
- name: this.props.playlist.name,
- description: this.props.playlist.description,
- public: (this.props.playlist.public == true),
- collaborative: (this.props.playlist.collaborative == true)
- });
- } else {
- switch (helpers.uriSource(this.props.uri)){
+ componentWillReceiveProps(nextProps) {
+ // Playlist just loaded
+ if (!this.props.playlist && nextProps.playlist) {
+ this.setState({
+ name: nextProps.playlist.name,
+ description: nextProps.playlist.description,
+ public: (nextProps.playlist.public == true),
+ collaborative: (nextProps.playlist.collaborative == true),
+ });
- case 'spotify':
- this.props.spotifyActions.getPlaylist(this.props.uri);
- this.props.spotifyActions.following(this.props.uri);
- break
+ // Mopidy just connected, and we don't have the playlist yet
+ } else if (this.props.mopidy_connected != nextProps.mopidy_connected && !nextProps.playlist) {
+ this.props.mopidyActions.getPlaylist(this.props.uri);
+ }
+ }
- default:
- if (this.props.mopidy_connected){
- this.props.mopidyActions.getPlaylist(this.props.uri);
- }
- break
- }
- }
- }
+ savePlaylist(e) {
+ e.preventDefault();
- componentWillReceiveProps(nextProps){
+ if (!this.state.name || this.state.name == '') {
+ this.setState({ error: 'Name is required' });
+ return false;
+ }
+ this.props.coreActions.savePlaylist(
+ this.props.uri,
+ this.state.name,
+ this.state.description,
+ this.state.public,
+ this.state.collaborative,
+ this.state.image,
+ );
+ window.history.back();
+ return false;
+ }
- // Playlist just loaded
- if (!this.props.playlist && nextProps.playlist){
- this.setState({
- name: nextProps.playlist.name,
- description: nextProps.playlist.description,
- public: (nextProps.playlist.public == true),
- collaborative: (nextProps.playlist.collaborative == true)
- });
+ setImage(e) {
+ const self = this;
- // Mopidy just connected, and we don't have the playlist yet
- } else if (this.props.mopidy_connected != nextProps.mopidy_connected && !nextProps.playlist){
- this.props.mopidyActions.getPlaylist(this.props.uri);
- }
- }
+ // Create a file-reader to import the selected image as a base64 string
+ const file_reader = new FileReader();
- savePlaylist(e){
- e.preventDefault();
-
- if (!this.state.name || this.state.name == ''){
- this.setState({error: 'Name is required'})
- return false
- } else {
- this.props.coreActions.savePlaylist(
- this.props.uri,
- this.state.name,
- this.state.description,
- this.state.public,
- this.state.collaborative,
- this.state.image
- );
- window.history.back();
- return false;
- }
- }
-
- setImage(e){
- var self = this;
-
- // Create a file-reader to import the selected image as a base64 string
- var file_reader = new FileReader();
-
// Once the image is loaded, convert the result
- file_reader.addEventListener("load", function(e){
- var image_base64 = e.target.result.replace('data:image/jpeg;base64,','');
- self.setState({image: image_base64});
- });
-
- // This calls the filereader to load the file
- file_reader.readAsDataURL(e.target.files[0]);
- }
+ file_reader.addEventListener('load', (e) => {
+ const image_base64 = e.target.result.replace('data:image/jpeg;base64,', '');
+ self.setState({ image: image_base64 });
+ });
- renderFields(){
- switch (helpers.uriSource(this.props.uri)){
+ // This calls the filereader to load the file
+ file_reader.readAsDataURL(e.target.files[0]);
+ }
- case 'spotify':
- return (
-
-
-
Name
-
- this.setState({ name: e.target.value })}
- value={ this.state.name }
- />
-
-
-
-
Description
-
- this.setState({ description: e.target.value })}
- value={ this.state.description }
- />
-
-
-
-
Cover image
-
-
this.setImage(e)}
- />
-
+ renderFields() {
+ switch (helpers.uriSource(this.props.uri)) {
+ case 'spotify':
+ return (
+
+
+
Name
+
+ this.setState({ name: e.target.value })}
+ value={this.state.name}
+ />
+
+
+
+
Description
+
+ this.setState({ description: e.target.value })}
+ value={this.state.description}
+ />
+
+
+
+
Cover image
+
+
this.setImage(e)}
+ />
+
JPEG only, 256kB max. Leave empty to keep cover image unchanged.
-
-
-
-
+
+
-
- )
- break
+
+
+
+ this.setState({ public: !this.state.public })}
+ />
+ Public
+
+
+ this.setState({ collaborative: !this.state.collaborative })}
+ />
+ Collaborative
+
+
+
+
+ );
+ break;
- default:
- return (
-
-
-
Name
-
- this.setState({ name: e.target.value })}
- value={ this.state.name } />
-
-
-
- )
- }
- }
+ default:
+ return (
+
+
+
Name
+
+ this.setState({ name: e.target.value })}
+ value={this.state.name}
+ />
+
+
+
+ );
+ }
+ }
- render(){
- return (
-
- Edit playlist
- {this.state.error ? {this.state.error} : null}
- this.savePlaylist(e)}>
+ render() {
+ return (
+
+ Edit playlist
+ {this.state.error ? {this.state.error} : null}
+ this.savePlaylist(e)}>
- {this.renderFields()}
+ {this.renderFields()}
-
- Save
-
-
-
- )
- }
+
+ Save
+
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
+const mapStateToProps = (state, ownProps) => {
+ // Decode the URI, and then re-encode selected characters
+ // This is needed as Mopidy encodes *some* characters in playlist URIs (but not other characters)
+ // We need to retain ":" because this a reserved URI separator
+ let uri = decodeURIComponent(ownProps.match.params.uri);
+ uri = uri.replace(/\s/g, '%20'); // space
+ uri = uri.replace(/\[/g, '%5B'); // [
+ uri = uri.replace(/\]/g, '%5D'); // ]
+ uri = uri.replace(/\(/g, '%28'); // (
+ uri = uri.replace(/\)/g, '%29'); // )
+ uri = uri.replace(/\#/g, '%23'); // #
- // Decode the URI, and then re-encode selected characters
- // This is needed as Mopidy encodes *some* characters in playlist URIs (but not other characters)
- // We need to retain ":" because this a reserved URI separator
- var uri = decodeURIComponent(ownProps.match.params.uri);
- uri = uri.replace(/\s/g, '%20'); // space
- uri = uri.replace(/\[/g, '%5B'); // [
- uri = uri.replace(/\]/g, '%5D'); // ]
- uri = uri.replace(/\(/g, '%28'); // (
- uri = uri.replace(/\)/g, '%29'); // )
- uri = uri.replace(/\#/g, '%23'); // #
-
- return {
- uri: uri,
- mopidy_connected: state.mopidy.connected,
- playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : null),
- playlists: state.core.playlists
- }
-}
+ return {
+ uri,
+ mopidy_connected: state.mopidy.connected,
+ playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : null),
+ playlists: state.core.playlists,
+ };
+};
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(EditPlaylist)
+export default connect(mapStateToProps, mapDispatchToProps)(EditPlaylist);
diff --git a/src/js/views/modals/EditRadio.js b/src/js/views/modals/EditRadio.js
index 37882b75..fe9f7118 100755
--- a/src/js/views/modals/EditRadio.js
+++ b/src/js/views/modals/EditRadio.js
@@ -1,271 +1,271 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-import Link from '../../components/Link'
-import ReactGA from 'react-ga'
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import ReactGA from 'react-ga';
+import Link from '../../components/Link';
import Modal from './Modal';
import Icon from '../../components/Icon';
-import * as coreActions from '../../services/core/actions'
-import * as uiActions from '../../services/ui/actions'
-import * as mopidyActions from '../../services/mopidy/actions'
-import * as spotifyActions from '../../services/spotify/actions'
-import * as pusherActions from '../../services/pusher/actions'
+import * as coreActions from '../../services/core/actions';
+import * as uiActions from '../../services/ui/actions';
+import * as mopidyActions from '../../services/mopidy/actions';
+import * as spotifyActions from '../../services/spotify/actions';
+import * as pusherActions from '../../services/pusher/actions';
import * as helpers from '../../helpers';
-class EditRadio extends React.Component{
+class EditRadio extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ enabled: false,
+ seeds: [],
+ uri: '',
+ error_message: null,
+ };
+ }
- constructor(props){
- super(props)
- this.state = {
- enabled: false,
- seeds: [],
- uri: '',
- error_message: null
- }
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Edit radio');
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Edit radio");
+ if (this.props.radio && this.props.radio.enabled) {
+ this.loadRadio(this.props.radio);
+ }
+ }
- if (this.props.radio && this.props.radio.enabled){
- this.loadRadio(this.props.radio);
- }
- }
+ componentWillReceiveProps(nextProps) {
+ if (!this.props.radio && nextProps.radio) {
+ this.loadRadio(nextProps.radio);
+ }
+ }
- componentWillReceiveProps(nextProps){
- if (!this.props.radio && nextProps.radio){
- this.loadRadio(nextProps.radio);
- }
- }
+ loadRadio(radio) {
+ const seeds = [...radio.seed_tracks, ...radio.seed_artists, ...radio.seed_genres];
+ this.setState({ seeds, enabled: radio.enabled });
+ this.props.spotifyActions.resolveRadioSeeds(radio);
+ }
- loadRadio(radio){
- var seeds = [...radio.seed_tracks, ...radio.seed_artists, ...radio.seed_genres];
- this.setState({seeds: seeds, enabled: radio.enabled});
- this.props.spotifyActions.resolveRadioSeeds(radio);
- }
+ handleStart(e) {
+ e.preventDefault();
- handleStart(e){
- e.preventDefault();
+ let valid_seeds = true;
+ const seeds = this.mapSeeds();
+ for (let i = 0; i < seeds.length; i++) {
+ if (seeds[i].unresolved !== undefined) {
+ valid_seeds = false;
+ continue;
+ }
+ }
- let valid_seeds = true;
- let seeds = this.mapSeeds();
- for (let i = 0; i < seeds.length; i++){
- if (seeds[i].unresolved !== undefined){
- valid_seeds = false;
- continue;
- }
- }
+ if (valid_seeds) {
+ this.props.pusherActions.startRadio(this.state.seeds);
+ window.history.back();
+ } else {
+ this.setState({ error_message: 'Invalid seed URI(s)' });
+ }
+ }
- if (valid_seeds){
- this.props.pusherActions.startRadio(this.state.seeds);
- window.history.back();
- } else {
- this.setState({error_message: "Invalid seed URI(s)"});
- }
- }
+ handleUpdate(e) {
+ e.preventDefault();
- handleUpdate(e){
- e.preventDefault();
+ let valid_seeds = true;
+ const seeds = this.mapSeeds();
+ for (let i = 0; i < seeds.length; i++) {
+ if (seeds[i].unresolved !== undefined) {
+ valid_seeds = false;
+ continue;
+ }
+ }
- var valid_seeds = true;
- var seeds = this.mapSeeds();
- for (var i = 0; i < seeds.length; i++){
- if (seeds[i].unresolved !== undefined){
- valid_seeds = false;
- continue;
- }
- }
+ if (valid_seeds) {
+ this.props.pusherActions.updateRadio(this.state.seeds);
+ this.props.uiActions.closeModal();
+ } else {
+ this.setState({ error_message: 'Invalid seed URI(s)' });
+ }
+ }
- if (valid_seeds){
- this.props.pusherActions.updateRadio(this.state.seeds);
- this.props.uiActions.closeModal();
- } else {
- this.setState({error_message: "Invalid seed URI(s)"});
- }
- }
+ handleStop(e) {
+ e.preventDefault();
+ this.props.pusherActions.stopRadio();
+ this.props.uiActions.closeModal();
+ }
- handleStop(e){
- e.preventDefault()
- this.props.pusherActions.stopRadio()
- this.props.uiActions.closeModal()
- }
+ addSeed(e) {
+ e.preventDefault();
- addSeed(e){
- e.preventDefault();
+ if (this.state.uri == '') {
+ this.setState({ error_message: 'Cannot be empty' });
+ return;
+ }
- if (this.state.uri == ''){
- this.setState({error_message: 'Cannot be empty'});
- return;
- }
+ this.setState({ error_message: null });
- this.setState({error_message: null});
+ const seeds = Object.assign([], this.state.seeds);
+ let uris = this.state.uri.split(',');
- var seeds = Object.assign([],this.state.seeds);
- var uris = this.state.uri.split(',');
+ if (uris.length >= 5) {
+ uris = uris.slice(0, 5);
+ this.setState({ error_message: 'More than 5 seeds provided, ignoring rest' });
+ }
- if (uris.length >= 5) {
- uris = uris.slice(0, 5);
- this.setState({error_message: 'More than 5 seeds provided, ignoring rest'});
- }
+ for (let i = 0; i < uris.length; i++) {
+ if (helpers.uriSource(uris[i]) !== 'spotify') {
+ this.setState({ error_message: 'Non-Spotify URIs not supported' });
+ return;
+ } if (seeds.indexOf(uris[i]) > -1) {
+ this.setState({ error_message: 'URI already added' });
+ } else {
+ seeds.push(uris[i]);
+ }
- for (var i = 0; i < uris.length; i++){
- if (helpers.uriSource(uris[i]) !== 'spotify'){
- this.setState({error_message: 'Non-Spotify URIs not supported'});
- return;
- } else if (seeds.indexOf(uris[i]) > -1){
- this.setState({error_message: 'URI already added'});
- } else {
- seeds.push(uris[i]);
- }
+ // Resolve
+ switch (helpers.uriType(uris[i])) {
+ case 'track':
+ this.props.spotifyActions.getTrack(uris[i]);
+ break;
- // Resolve
- switch (helpers.uriType(uris[i])){
- case 'track':
- this.props.spotifyActions.getTrack(uris[i]);
- break;
+ case 'artist':
+ this.props.spotifyActions.getArtist(uris[i]);
+ break;
+ }
+ }
- case 'artist':
- this.props.spotifyActions.getArtist(uris[i]);
- break;
- }
- }
+ // commit to state
+ this.setState({
+ seeds,
+ uri: '',
+ });
+ }
- // commit to state
- this.setState({
- seeds: seeds,
- uri: ''
- })
- }
+ removeSeed(uri) {
+ const seeds = [];
+ for (let i = 0; i < this.state.seeds.length; i++) {
+ if (this.state.seeds[i] != uri) {
+ seeds.push(this.state.seeds[i]);
+ }
+ }
+ this.setState({ seeds });
+ }
- removeSeed(uri){
- var seeds = []
- for (var i = 0; i < this.state.seeds.length; i++){
- if (this.state.seeds[i] != uri){
- seeds.push(this.state.seeds[i])
- }
- }
- this.setState({seeds: seeds});
- }
+ mapSeeds() {
+ const seeds = [];
- mapSeeds(){
- var seeds = []
+ if (this.state.seeds) {
+ for (let i = 0; i < this.state.seeds.length && i < 5; i++) {
+ const uri = this.state.seeds[i];
+ if (uri) {
+ if (helpers.uriType(uri) == 'artist') {
+ if (this.props.artists && this.props.artists.hasOwnProperty(uri)) {
+ seeds.push(this.props.artists[uri]);
+ } else {
+ seeds.push({
+ unresolved: true,
+ uri,
+ });
+ }
+ } else if (helpers.uriType(uri) == 'track') {
+ if (this.props.tracks && this.props.tracks.hasOwnProperty(uri)) {
+ seeds.push(this.props.tracks[uri]);
+ } else {
+ seeds.push({
+ unresolved: true,
+ uri,
+ });
+ }
+ }
+ }
+ }
+ }
- if (this.state.seeds){
- for (var i = 0; i < this.state.seeds.length && i < 5; i++){
- var uri = this.state.seeds[i]
- if (uri){
- if (helpers.uriType(uri) == 'artist'){
- if (this.props.artists && this.props.artists.hasOwnProperty(uri)){
- seeds.push(this.props.artists[uri]);
- } else {
- seeds.push({
- unresolved: true,
- uri: uri
- })
+ return seeds;
+ }
+
+ renderSeeds() {
+ const seeds = this.mapSeeds();
+
+ if (seeds.length > 0) {
+ return (
+
+
+ {
+ seeds.map((seed, index) => (
+
+ {seed.unresolved ? {seed.uri} : {seed.name} }
+ {!seed.unresolved ? (
+
+ (
+ {helpers.uriType(seed.uri)}
+)
+
+ ) : null}
+ this.removeSeed(seed.uri)}>
+
+Remove
+
+
+ ))
}
- } else if (helpers.uriType(uri) == 'track'){
- if (this.props.tracks && this.props.tracks.hasOwnProperty(uri)){
- seeds.push(this.props.tracks[uri]);
- } else {
- seeds.push({
- unresolved: true,
- uri: uri
- })
- }
- }
- }
- }
- }
+
+
+ );
+ }
+ return (
+
No seeds
+ );
+ }
- return seeds;
- }
+ render() {
+ return (
+
+ Radio
+ Add and remove seeds to shape the sound of your radio. Radio uses Spotify's recommendations engine to suggest tracks similar to your seeds.
- renderSeeds(){
- var seeds = this.mapSeeds();
+ { (this.state.enabled ? this.handleUpdate(e) : this.handleStart(e)); }}>
- if (seeds.length > 0){
- return (
-
-
- {
- seeds.map((seed,index) => {
- return (
-
- {seed.unresolved ? {seed.uri} : {seed.name} }
- {!seed.unresolved ? ({helpers.uriType(seed.uri)}) : null}
- this.removeSeed(seed.uri)}>
- Remove
-
-
- )
- })
- }
-
-
- )
- } else {
- return (
- No seeds
- )
- }
- }
+ {this.renderSeeds()}
- render(){
- return (
-
- Radio
- Add and remove seeds to shape the sound of your radio. Radio uses Spotify's recommendations engine to suggest tracks similar to your seeds.
+
+
URI(s)
+
+ this.setState({ uri: e.target.value, error_message: null })}
+ value={this.state.uri}
+ />
+ this.addSeed(e)}>
+
+Add
+
+ {this.state.error_message ? {this.state.error_message} : null}
+
+
- {(this.state.enabled ? this.handleUpdate(e) : this.handleStart(e))}}>
+
+ {this.state.enabled ?
this.handleStop(e)}>Stop : null}
- {this.renderSeeds()}
-
-
-
URI(s)
-
- this.setState({uri: e.target.value, error_message: null})}
- value={this.state.uri}
- />
- this.addSeed(e)}>
- Add
-
- {this.state.error_message ? {this.state.error_message} : null}
-
-
-
-
- {this.state.enabled ? this.handleStop(e)}>Stop : null}
-
- {this.state.enabled ? this.handleUpdate(e)}>Save : this.handleStart(e)}>Start }
-
-
-
- )
- }
+ {this.state.enabled ?
this.handleUpdate(e)}>Save :
this.handleStart(e)}>Start }
+
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- mopidy_connected: state.mopidy.connected,
- radio: state.core.radio,
- artists: state.core.artists,
- tracks: state.core.tracks
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ mopidy_connected: state.mopidy.connected,
+ radio: state.core.radio,
+ artists: state.core.artists,
+ tracks: state.core.tracks,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ spotifyActions: bindActionCreators(spotifyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(EditRadio)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(EditRadio);
diff --git a/src/js/views/modals/ImageZoom.js b/src/js/views/modals/ImageZoom.js
index 7528fc8e..02c3b65a 100755
--- a/src/js/views/modals/ImageZoom.js
+++ b/src/js/views/modals/ImageZoom.js
@@ -9,33 +9,28 @@ import Thumbnail from '../../components/Thumbnail';
import * as helpers from '../../helpers';
import * as uiActions from '../../services/ui/actions';
-class ImageZoom extends React.Component{
+class ImageZoom extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props)
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Zoomed image');
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Zoomed image");
- }
-
- render(){
- return (
-
-
-
- )
- }
+ render() {
+ return (
+
+
+
+ );
+ }
}
-const mapStateToProps = (state) => {
- return {}
-}
+const mapStateToProps = (state) => ({});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(ImageZoom)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(ImageZoom);
diff --git a/src/js/views/modals/InitialSetup.js b/src/js/views/modals/InitialSetup.js
index 7026671c..e9367fa3 100755
--- a/src/js/views/modals/InitialSetup.js
+++ b/src/js/views/modals/InitialSetup.js
@@ -11,145 +11,151 @@ import * as pusherActions from '../../services/pusher/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as helpers from '../../helpers';
-class InitialSetup extends React.Component{
- constructor(props){
- super(props);
+class InitialSetup extends React.Component {
+ constructor(props) {
+ super(props);
- this.state = {
- username: this.props.username,
- allow_reporting: this.props.allow_reporting,
- host: this.props.host,
- port: this.props.port
- }
- }
+ this.state = {
+ username: this.props.username,
+ allow_reporting: this.props.allow_reporting,
+ host: this.props.host,
+ port: this.props.port,
+ };
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Welcome to Iris");
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Welcome to Iris');
+ }
- handleSubmit(e){
- e.preventDefault();
- var self = this;
+ handleSubmit(e) {
+ e.preventDefault();
+ const self = this;
- // Only if we've changed the username do we set it
- if (this.props.username !== this.state.username){
- this.props.pusherActions.setUsername(this.state.username);
- }
+ // Only if we've changed the username do we set it
+ if (this.props.username !== this.state.username) {
+ this.props.pusherActions.setUsername(this.state.username);
+ }
- this.props.uiActions.set({
- initial_setup_complete: true,
- allow_reporting: this.state.allow_reporting
- });
+ this.props.uiActions.set({
+ initial_setup_complete: true,
+ allow_reporting: this.state.allow_reporting,
+ });
- this.props.mopidyActions.set({
- host: this.state.host,
- port: this.state.port
- });
+ this.props.mopidyActions.set({
+ host: this.state.host,
+ port: this.state.port,
+ });
- this.setState({saving: true});
+ this.setState({ saving: true });
- // Wait a jiffy to allow changes to apply to store
- setTimeout(() => {
+ // Wait a jiffy to allow changes to apply to store
+ setTimeout(() => {
+ // We've changed a connection setting, so need to reload
+ if (self.state.host !== self.props.host || self.state.port !== self.props.port) {
+ window.location = '/';
- // We've changed a connection setting, so need to reload
- if (self.state.host !== self.props.host || self.state.port !== self.props.port){
- window.location = '/';
+ // Safe to just close modal
+ } else {
+ self.props.history.push('/');
+ }
+ },
+ 200);
- // Safe to just close modal
- } else {
- self.props.history.push('/');
- }
- },
- 200
- );
+ return false;
+ }
- return false;
- }
+ render() {
+ return (
+
+ Get started
+ this.handleSubmit(e)}>
- render(){
- return (
-
- Get started
- this.handleSubmit(e)}>
-
-
-
+
+
Username
-
-
-
this.setState({username: e.target.value.replace(/\W/g, '')})}
- value={this.state.username } />
-
+
+
+
this.setState({ username: e.target.value.replace(/\W/g, '') })}
+ value={this.state.username}
+ />
+
A non-unique string used to identify this client (no special characters)
-
-
-
+
+
+
-
-
Host
-
- this.setState({host: e.target.value})}
- value={ this.state.host } />
-
-
-
-
Port
-
- this.setState({port: e.target.value})}
- value={ this.state.port } />
-
-
-
- {helpers.isHosted() ? null :
-
-
- this.setState({ allow_reporting: !this.state.allow_reporting })} />
-
+
+
Host
+
+ this.setState({ host: e.target.value })}
+ value={this.state.host}
+ />
+
+
+
+
Port
+
+ this.setState({ port: e.target.value })}
+ value={this.state.port}
+ />
+
+
+
+ {helpers.isHosted() ? null : (
+
+
+
+ this.setState({ allow_reporting: !this.state.allow_reporting })}
+ />
+
Allow reporting of anonymous usage statistics
-
-
-
This anonymous usage data is important in identifying errors and potential features that make Iris better for everyone. Want to know more? Read the privacy policy {!this.state.allow_reporting ? Are you sure you don't want to support this? : null}.
-
-
}
+
+
+
+This anonymous usage data is important in identifying errors and potential features that make Iris better for everyone. Want to know more? Read the
+ privacy policy
+ {!this.state.allow_reporting ? Are you sure you don't want to support this? : null}
+.
+ {' '}
+
+
+
+ )}
-
- this.handleSubmit(e)}>
- {this.state.saving ? "Saving" : "Save"}
-
-
+
+ this.handleSubmit(e)}>
+ {this.state.saving ? 'Saving' : 'Save'}
+
+
-
-
- )
- }
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- allow_reporting: state.ui.allow_reporting,
- username: (state.pusher && state.pusher.username ? state.pusher.username : null),
- host: state.mopidy.host,
- port: state.mopidy.port
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ allow_reporting: state.ui.allow_reporting,
+ username: (state.pusher && state.pusher.username ? state.pusher.username : null),
+ host: state.mopidy.host,
+ port: state.mopidy.port,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ coreActions: bindActionCreators(coreActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(InitialSetup)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(InitialSetup);
diff --git a/src/js/views/modals/KioskMode.js b/src/js/views/modals/KioskMode.js
index 4f58a7b7..3717fcec 100755
--- a/src/js/views/modals/KioskMode.js
+++ b/src/js/views/modals/KioskMode.js
@@ -1,8 +1,8 @@
import React from 'react';
import { connect } from 'react-redux';
-import Link from '../../components/Link'
import { createStore, bindActionCreators } from 'redux';
+import Link from '../../components/Link';
import Modal from './Modal';
import Thumbnail from '../../components/Thumbnail';
@@ -15,89 +15,84 @@ import * as helpers from '../../helpers';
import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
-class KioskMode extends React.Component{
+class KioskMode extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props)
- }
+ componentDidMount() {
+ this.setWindowTitle();
+ }
- componentDidMount(){
- this.setWindowTitle();
- }
+ componentWillReceiveProps(nextProps) {
+ if (!this.props.current_track && nextProps.current_track) {
+ this.setWindowTitle(nextProps.current_track);
+ }
+ }
- componentWillReceiveProps(nextProps){
- if (!this.props.current_track && nextProps.current_track){
- this.setWindowTitle(nextProps.current_track);
- }
- }
+ setWindowTitle(current_track = this.props.current_track) {
+ if (current_track) {
+ let artists = '';
+ for (let i = 0; i < current_track.artists.length; i++) {
+ if (artists != '') {
+ artists += ', ';
+ }
+ artists += current_track.artists[i].name;
+ }
+ this.props.uiActions.setWindowTitle(`${current_track.name} by ${artists} (now playing)`);
+ } else {
+ this.props.uiActions.setWindowTitle('Now playing');
+ }
+ }
- setWindowTitle(current_track = this.props.current_track){
- if (current_track){
- var artists = "";
- for (var i = 0; i < current_track.artists.length; i++){
- if (artists != ""){
- artists += ", ";
- }
- artists += current_track.artists[i].name;
- }
- this.props.uiActions.setWindowTitle(current_track.name+" by "+artists+" (now playing)");
- } else{
- this.props.uiActions.setWindowTitle("Now playing");
- }
- }
+ togglePlay(e) {
+ if (this.props.play_state == 'playing') {
+ this.props.mopidyActions.pause();
+ } else {
+ this.props.mopidyActions.play();
+ }
+ }
- togglePlay(e){
- if (this.props.play_state == 'playing'){
- this.props.mopidyActions.pause();
- } else {
- this.props.mopidyActions.play();
- }
- }
+ render() {
+ if (this.props.current_track && this.props.current_track.images) {
+ var { images } = this.props.current_track;
+ } else {
+ var images = [];
+ }
- render(){
- if (this.props.current_track && this.props.current_track.images){
- var images = this.props.current_track.images
- } else {
- var images = []
- }
+ return (
+
- return (
-
-
-
+
- this.togglePlay(e)}>
-
- {this.props.play_state == 'playing' ? : }
-
+ this.togglePlay(e)}>
+
+ {this.props.play_state == 'playing' ? : }
+
-
-
-
{ this.props.current_track ? this.props.current_track.name : - }
- { this.props.current_track ?
:
}
-
+
+
+
{ this.props.current_track ? this.props.current_track.name : - }
+ { this.props.current_track ?
:
}
+
-
-
-
- )
- }
+
+
+
+ );
+ }
}
-const mapStateToProps = (state) => {
- return {
- play_state: state.mopidy.play_state,
- current_track: (state.core.current_track && state.core.tracks[state.core.current_track.uri] !== undefined ? state.core.tracks[state.core.current_track.uri] : null),
- }
-}
+const mapStateToProps = (state) => ({
+ play_state: state.mopidy.play_state,
+ current_track: (state.core.current_track && state.core.tracks[state.core.current_track.uri] !== undefined ? state.core.tracks[state.core.current_track.uri] : null),
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ uiActions: bindActionCreators(uiActions, dispatch),
+ mopidyActions: bindActionCreators(mopidyActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(KioskMode)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(KioskMode);
diff --git a/src/js/views/modals/Modal.js b/src/js/views/modals/Modal.js
index fb622edf..f2bfee4d 100755
--- a/src/js/views/modals/Modal.js
+++ b/src/js/views/modals/Modal.js
@@ -3,55 +3,51 @@ import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
-import * as helpers from '../../helpers'
-import Icon from '../../components/Icon'
+import * as helpers from '../../helpers';
+import Icon from '../../components/Icon';
-class Modal extends React.Component{
+class Modal extends React.Component {
+ constructor(props) {
+ super(props);
+ }
- constructor(props){
- super(props);
- }
+ componentWillMount() {
+ $('body').addClass('modal-open');
+ }
- componentWillMount(){
- $('body').addClass('modal-open');
- }
+ componentWillUnmount() {
+ $('body').removeClass('modal-open');
+ }
- componentWillUnmount(){
- $('body').removeClass('modal-open');
- }
+ render() {
+ let className = 'modal';
+ if (this.props.className) {
+ className += ` ${this.props.className}`;
+ }
- render(){
+ return (
+
- var className = "modal";
- if (this.props.className){
- className += " "+this.props.className;
- }
+
+ {this.props.noclose ? null : (
+
window.history.back()}>
+
+
+ ) }
+
- return (
-
-
-
- {this.props.noclose ? null :
window.history.back()}>
-
-
}
-
-
-
- {this.props.children}
-
-
- );
- }
+
+ {this.props.children}
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- shortkeys_enabled: state.ui.shortkeys_enabled
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ shortkeys_enabled: state.ui.shortkeys_enabled,
+});
-const mapDispatchToProps = (dispatch) => {
- return {}
-}
+const mapDispatchToProps = (dispatch) => ({});
-export default connect(mapStateToProps, mapDispatchToProps)(Modal)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Modal);
diff --git a/src/js/views/modals/ShareConfiguration.js b/src/js/views/modals/ShareConfiguration.js
index d50659df..186e7175 100755
--- a/src/js/views/modals/ShareConfiguration.js
+++ b/src/js/views/modals/ShareConfiguration.js
@@ -1,8 +1,8 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import Link from '../../components/Link'
-import { createStore, bindActionCreators } from 'redux'
+import React from 'react';
+import { connect } from 'react-redux';
+import { createStore, bindActionCreators } from 'redux';
+import Link from '../../components/Link';
import Modal from './Modal';
import Icon from '../../components/Icon';
@@ -11,208 +11,221 @@ import * as uiActions from '../../services/ui/actions';
import * as pusherActions from '../../services/pusher/actions';
import * as helpers from '../../helpers';
-class ShareConfiguration extends React.Component {
+class ShareConfiguration extends React.Component {
+ constructor(props) {
+ super(props);
- constructor(props){
- super(props);
+ this.state = {
+ recipients: [],
+ spotify: false,
+ lastfm: false,
+ genius: false,
+ ui: false,
+ };
+ }
- this.state = {
- recipients: [],
- spotify: false,
- lastfm: false,
- genius: false,
- ui: false
- };
- }
+ componentDidMount() {
+ this.props.uiActions.setWindowTitle('Share configuration');
+ }
- componentDidMount(){
- this.props.uiActions.setWindowTitle("Share configuration");
- }
+ toggleRecipient(id) {
+ const { recipients } = this.state;
+ if (recipients.includes(id)) {
+ const index = recipients.indexOf(id);
+ recipients.splice(index, 1);
+ } else {
+ recipients.push(id);
+ }
+ this.setState({ recipients });
+ }
- toggleRecipient(id){
- var recipients = this.state.recipients;
- if (recipients.includes(id)){
- var index = recipients.indexOf(id);
- recipients.splice(index,1);
- } else {
- recipients.push(id);
- }
- this.setState({recipients: recipients});
- }
+ handleSubmit(e) {
+ e.preventDefault();
- handleSubmit(e){
- e.preventDefault();
+ const configuration = {};
+ if (this.state.spotify) {
+ configuration.spotify = {
+ authorization: this.props.spotify_authorization,
+ me: this.props.spotify_me,
+ };
+ }
+ if (this.state.genius) {
+ configuration.genius = {
+ authorization: this.props.genius_authorization,
+ me: this.props.genius_me,
+ };
+ }
+ if (this.state.lastfm) {
+ configuration.lastfm = {
+ authorization: this.props.lastfm_authorization,
+ me: this.props.lastfm_me,
+ };
+ }
+ if (this.state.ui) {
+ configuration.ui = this.props.ui;
+ }
- var configuration = {};
- if (this.state.spotify){
- configuration.spotify = {
- authorization: this.props.spotify_authorization,
- me: this.props.spotify_me
- }
- }
- if (this.state.genius){
- configuration.genius = {
- authorization: this.props.genius_authorization,
- me: this.props.genius_me
- }
- }
- if (this.state.lastfm){
- configuration.lastfm = {
- authorization: this.props.lastfm_authorization,
- me: this.props.lastfm_me
- }
- }
- if (this.state.ui){
- configuration.ui = this.props.ui;
- }
+ for (const recipient of this.state.recipients) {
+ this.props.pusherActions.deliverMessage(
+ recipient,
+ 'share_configuration_received',
+ configuration,
+ );
+ }
- for (var recipient of this.state.recipients){
- this.props.pusherActions.deliverMessage(
- recipient,
- 'share_configuration_received',
- configuration
- );
- }
+ window.history.back();
+ }
- window.history.back();
- return;
- }
+ render() {
+ const connections = [];
+ for (const connection_id in this.props.connections) {
+ if (this.props.connections.hasOwnProperty(connection_id) && connection_id != this.props.connection_id) {
+ connections.push(this.props.connections[connection_id]);
+ }
+ }
- render(){
- var connections = []
- for (var connection_id in this.props.connections){
- if (this.props.connections.hasOwnProperty(connection_id) && connection_id != this.props.connection_id){
- connections.push(this.props.connections[connection_id])
- }
- }
-
- if (connections.length > 0){
- var recipients = (
-
- {
- connections.map((connection, index) => {
- return (
-
- this.toggleRecipient(connection.connection_id)}
- />
-
- { connection.username }
-
- ({ connection.ip })
-
-
-
- );
- })
+ if (connections.length > 0) {
+ var recipients = (
+
+ {
+ connections.map((connection, index) => (
+
+ this.toggleRecipient(connection.connection_id)}
+ />
+
+ { connection.username }
+
+ (
+ { connection.ip }
+)
+
+
+
+ ))
}
-
- );
- } else {
- var recipients = (
-
-
+
+ );
+ } else {
+ var recipients = (
+
+
No peer connections
-
-
- );
- }
+
+
+ );
+ }
- return (
-
-
- Share configuration
- Push your authorizations and interface settings to another, connected user
+ return (
+
- this.handleSubmit(e)}>
-
-
Recipients
- {recipients}
-
+ Share configuration
+ Push your authorizations and interface settings to another, connected user
-
-
Configurations
-
-
- this.setState({ ui: !this.state.ui })} />
-
- UI customisation (theme, sorting, filters)
-
-
+
this.handleSubmit(e)}>
+
+
Recipients
+ {recipients}
+
- {this.props.spotify_me && this.props.spotify_authorization ?
- this.setState({ spotify: !this.state.spotify })} />
-
- Spotify authorization
- Logged in as {this.props.spotify_me.name}
-
- : null}
+
+ {this.props.lastfm_me && this.props.lastfm_authorization ? (
+
+ this.setState({ lastfm: !this.state.lastfm })}
+ />
+
+ LastFM authorization
+
+Logged in as
+ {this.props.lastfm_me.name}
+
+
+
+ ) : null}
-
- {this.state.recipients.length > 0 ? this.handleSubmit(e)}>Send : this.handleSubmit(e)}>Send }
-
-
-
- )
- }
+ {this.props.genius_me && this.props.genius_authorization ? (
+
+ this.setState({ genius: !this.state.genius })}
+ />
+
+ Genius authorization
+
+Logged in as
+ {this.props.genius_me.name}
+
+
+
+ ) : null}
+
+
+
+
+ {this.state.recipients.length > 0 ? this.handleSubmit(e)}>Send : this.handleSubmit(e)}>Send }
+
+
+
+ );
+ }
}
-const mapStateToProps = (state, ownProps) => {
- return {
- spotify_authorization: state.spotify.authorization,
- spotify_me: state.spotify.me,
- genius_authorization: state.genius.authorization,
- genius_me: state.genius.me,
- lastfm_authorization: state.lastfm.authorization,
- lastfm_me: state.lastfm.me,
- ui: state.ui,
- connection_id: state.pusher.connection_id,
- connections: state.pusher.connections
- }
-}
+const mapStateToProps = (state, ownProps) => ({
+ spotify_authorization: state.spotify.authorization,
+ spotify_me: state.spotify.me,
+ genius_authorization: state.genius.authorization,
+ genius_me: state.genius.me,
+ lastfm_authorization: state.lastfm.authorization,
+ lastfm_me: state.lastfm.me,
+ ui: state.ui,
+ connection_id: state.pusher.connection_id,
+ connections: state.pusher.connections,
+});
-const mapDispatchToProps = (dispatch) => {
- return {
- pusherActions: bindActionCreators(pusherActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch)
- }
-}
+const mapDispatchToProps = (dispatch) => ({
+ pusherActions: bindActionCreators(pusherActions, dispatch),
+ uiActions: bindActionCreators(uiActions, dispatch),
+});
-export default connect(mapStateToProps, mapDispatchToProps)(ShareConfiguration)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(ShareConfiguration);
diff --git a/src/service-worker.js b/src/service-worker.js
index 8f91feb7..93becd36 100755
--- a/src/service-worker.js
+++ b/src/service-worker.js
@@ -1,3 +1,3 @@
self.addEventListener('fetch', (event) => {
- // Nothing doing!
-});
\ No newline at end of file
+ // Nothing doing!
+});