diff --git a/mopidy_iris/core.py b/mopidy_iris/core.py
index 89f13016..d9dcb877 100755
--- a/mopidy_iris/core.py
+++ b/mopidy_iris/core.py
@@ -446,27 +446,18 @@ class IrisCore(object):
}
def refresh_spotify_token(self, data):
-
- ## TODO: See if we can use the credentials used by Mopidy-Spotify 3.1.0
- # Currently this returns 'invalid_client' error
# Use client_id and client_secret from config
# This was introduced in Mopidy-Spotify 3.1.0
- #if 'spotify' in self.config and 'client_id' in self.config['spotify']:
- # authorization = str(self.config['spotify']['client_id']+':'+self.config['spotify']['client_secret'])
- # authorization = authorization.encode('base64').replace('\n', '')
-
- # Mopidy-Spotify is old version, so just use basic authorization code
- #else:
- # authorization = 'YTg3ZmI0ZGJlZDMwNDc1YjhjZWMzODUyM2RmZjUzZTI6ZDdjODlkMDc1M2VmNDA2OGJiYTE2NzhjNmNmMjZlZDY='
-
- authorization = 'YTg3ZmI0ZGJlZDMwNDc1YjhjZWMzODUyM2RmZjUzZTI6ZDdjODlkMDc1M2VmNDA2OGJiYTE2NzhjNmNmMjZlZDY='
- url = 'https://accounts.spotify.com/api/token'
- headers = {'Authorization' : 'Basic ' + authorization}
- data = {'grant_type': 'client_credentials'}
+ url = 'https://auth.mopidy.com/spotify/token'
+ data = {
+ 'client_id': self.config['spotify']['client_id'],
+ 'client_secret': self.config['spotify']['client_secret'],
+ 'grant_type': 'client_credentials'
+ }
data_encoded = urllib.urlencode( data )
- req = urllib2.Request(url, data_encoded, headers)
+ req = urllib2.Request(url, data_encoded)
try:
response = urllib2.urlopen(req, timeout=30).read()
diff --git a/src/js/components/Settings/Advanced.js b/src/js/components/Settings/Advanced.js
deleted file mode 100755
index 394727ea..00000000
--- a/src/js/components/Settings/Advanced.js
+++ /dev/null
@@ -1,99 +0,0 @@
-
-import React, { PropTypes } from 'react'
-import { connect } from 'react-redux'
-import { Link, hashHistory } from 'react-router'
-import { bindActionCreators } from 'redux'
-import FontAwesome from 'react-fontawesome'
-
-import ConfirmationButton from '../ConfirmationButton'
-import PusherConnectionList from '../PusherConnectionList'
-import URISchemesList from '../URISchemesList'
-import VersionManager from '../VersionManager'
-
-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 Advanced extends React.Component{
-
- constructor(props) {
- super(props)
- }
-
- render(){
- return (
-
-
-
Pusher
-
-
-
-
Mopidy extensions
-
-
-
Core
-
-
-
Customise behavior
-
-
- this.props.uiActions.set({ clear_tracklist_on_play: !this.props.ui.clear_tracklist_on_play })} />
- Clear tracklist on play of URI(s)
-
-
-
-
-
-
-
-
Reset
-
- this.resetAllSettings()} />
-
-
-
-
- );
- }
-}
-
-
-/**
- * Export our component
- *
- * We also integrate our global store, using connect()
- **/
-
-const mapStateToProps = (state, ownProps) => {
- return {
- ui: state.ui
- }
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(Advanced)
\ No newline at end of file
diff --git a/src/js/components/Settings/Debug.js b/src/js/components/Settings/Debug.js
deleted file mode 100755
index c85c7225..00000000
--- a/src/js/components/Settings/Debug.js
+++ /dev/null
@@ -1,196 +0,0 @@
-
-import React, { PropTypes } from 'react'
-import { connect } from 'react-redux'
-import { Link, hashHistory } from 'react-router'
-import { bindActionCreators } from 'redux'
-import FontAwesome from 'react-fontawesome'
-
-import SpotifyAuthenticationFrame from '../SpotifyAuthenticationFrame'
-
-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{
-
- constructor(props) {
- super(props);
- this.state = {
- mopidy_call: 'playlists.asList',
- mopidy_data: '{}',
- pusher_data: '{"method":"get_config"}',
- access_token: (this.props.access_token ? this.props.access_token : '')
- }
- }
-
- 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) )
- }
-
- render(){
- return (
-
-
User interface
-
-
-
Mopidy
-
-
-
Pusher
-
this.callPusher(e)}>
-
-
Examples
-
- this.setState({ pusher_data: e.target.value })}>
- Get config
- Get version
- Get connections
- Get radio
- Get queue metadata
- Broadcast to all clients
- Broadcast to one client
- Change username
- Refresh Spotify token
- Perform upgrade (beta)
-
-
-
-
-
Data
-
- this.setState({ pusher_data: e.target.value })}
- value={ this.state.pusher_data }>
-
-
-
-
-
-
-
Response
-
- { this.props.debug_response ? JSON.stringify(this.props.debug_response, null, 2) : null }
-
-
-
- );
- }
-}
-
-
-/**
- * Export our component
- *
- * We also integrate our global store, using connect()
- **/
-
-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),
- 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)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(Debug)
\ No newline at end of file
diff --git a/src/js/components/Settings/System.js b/src/js/components/Settings/System.js
deleted file mode 100755
index ecfd7188..00000000
--- a/src/js/components/Settings/System.js
+++ /dev/null
@@ -1,289 +0,0 @@
-
-import React, { PropTypes } from 'react'
-import { connect } from 'react-redux'
-import { Link, hashHistory } from 'react-router'
-import { bindActionCreators } from 'redux'
-import FontAwesome from 'react-fontawesome'
-
-import SpotifyAuthenticationFrame from '../SpotifyAuthenticationFrame'
-import Thumbnail from '../Thumbnail'
-
-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'
-
-class System extends React.Component{
-
- constructor(props) {
- super(props);
- this.state = {
- country: this.props.core.country,
- locale: this.props.core.locale,
- mopidy_host: this.props.mopidy.host,
- mopidy_port: this.props.mopidy.port,
- pusher_username: this.props.pusher.username,
- input_in_focus: null
- }
- }
-
- componentWillReceiveProps(newProps){
- var changed = false
- var state = this.state
-
- if (newProps.pusher.username != this.state.pusher_username && this.state.input_in_focus != 'pusher_username'){
- state.pusher_username = newProps.pusher.username
- changed = true
- }
-
- if (changed){
- this.setState(state)
- }
- }
-
- resetAllSettings(){
- localStorage.clear();
- window.location = '#'
- window.location.reload(true)
- return false;
- }
-
- setMopidyConfig(e){
- this.setState({input_in_focus: null})
- e.preventDefault();
- this.props.mopidyActions.setConfig({ host: this.state.mopidy_host, port: this.state.mopidy_port });
- window.location.reload(true);
- return false;
- }
-
- handleBlur(name, value){
- this.setState({input_in_focus: null})
- var data = {}
- data[name] = value
- this.props.coreActions.set(data)
- }
-
- handleUsernameChange(username){
- this.setState({pusher_username: username.replace(/\W/g, '')})
- }
-
- handleUsernameBlur(e){
- this.setState({input_in_focus: null})
- this.props.pusherActions.setUsername(this.state.pusher_username)
- }
-
- renderApplyButton(){
- if (this.props.mopidy.host == this.state.mopidy_host && this.props.mopidy.port == this.state.mopidy_port) return null
-
- return (
-
-
-
- Apply and reload
-
-
- )
- }
-
- renderStatus(server){
- if (this.props[server].connecting){
- return
- } else if (this.props[server].connected){
- return
- } else {
- return
- }
- }
-
- renderSpotifyUser(){
-
- var user = null
- if (this.props.spotify.me && this.props.spotify.authorization){
- user = this.props.spotify.me
- } else if (this.props.spotify.backend_username){
- if (this.props.core.users && this.props.core.users['spotify:user:'+this.props.spotify.backend_username] !== undefined){
- user = this.props.core.users['spotify:user:'+this.props.spotify.backend_username]
- }
- }
-
- if (user){
- return (
-
-
-
- {user.display_name ? user.display_name : user.id}
-
-
- )
- } else if (this.props.spotify.backend_username){
- return (
-
-
-
- {this.props.spotify.backend_username}
-
-
- )
- } else {
- return (
-
-
-
- Unknown
-
-
- )
- }
- }
-
- renderSendAuthorizationButton(){
- if (!this.props.spotify.authorization) return null
-
- return (
- this.props.uiActions.openModal('send_authorization', {}) }>
- Share authentication
-
- )
- }
-
- render(){
- return (
-
-
-
Servers
-
-
-
Status
-
-
- {this.renderStatus('mopidy')} Mopidy
- {this.renderStatus('pusher')} Pusher
-
-
-
-
-
-
Username
-
- this.handleUsernameChange(e.target.value)}
- onFocus={e => this.setState({input_in_focus: 'pusher_username'})}
- onBlur={e => this.handleUsernameBlur(e)}
- value={this.state.pusher_username } />
-
-
-
-
this.setMopidyConfig(e)}>
-
-
Host
-
- this.setState({mopidy_host: e.target.value})}
- onFocus={e => this.setState({input_in_focus: 'mopidy_host'})}
- onBlur={e => this.setState({input_in_focus: null})}
- value={ this.state.mopidy_host } />
-
-
-
-
Port
-
- this.setState({mopidy_port: e.target.value})}
- onFocus={e => this.setState({input_in_focus: 'mopidy_port'})}
- onBlur={e => this.setState({input_in_focus: null})}
- value={ this.state.mopidy_port } />
-
-
- {this.renderApplyButton()}
-
-
-
Localization
-
-
-
Country
-
- this.setState({country: e.target.value})}
- onFocus={e => this.setState({input_in_focus: 'country'})}
- onBlur={e => this.handleBlur('country',e.target.value)}
- value={ this.state.country } />
-
-
-
-
Locale
-
- this.setState({locale: e.target.value})}
- onFocus={e => this.setState({input_in_focus: 'locale'})}
- onBlur={e => this.handleBlur('locale',e.target.value)}
- value={this.state.locale} />
-
-
-
-
Spotify
-
-
-
Status
-
-
- {!this.props.mopidy.uri_schemes || !this.props.mopidy.uri_schemes.includes('spotify:') ?
Mopidy-Spotify not available
: null}
-
- {this.props.spotify.authorization ?
Authorized All Spotify functionality available :
Limited access Authorize Iris for full functionality}
-
-
-
-
-
Authorization
-
-
- { this.renderSendAuthorizationButton() }
-
-
-
-
Current user
-
-
- { this.renderSpotifyUser() }
-
-
-
-
-
- );
- }
-}
-
-
-/**
- * Export our component
- *
- * We also integrate our global store, using connect()
- **/
-
-const mapStateToProps = (state, ownProps) => {
- return {
- core: state.core,
- ui: state.ui,
- mopidy: state.mopidy,
- pusher: state.pusher,
- spotify: state.spotify
- }
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- coreActions: bindActionCreators(coreActions, dispatch),
- uiActions: bindActionCreators(uiActions, dispatch),
- pusherActions: bindActionCreators(pusherActions, dispatch),
- mopidyActions: bindActionCreators(mopidyActions, dispatch),
- spotifyActions: bindActionCreators(spotifyActions, dispatch)
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(System)
\ No newline at end of file
diff --git a/src/js/components/Sidebar.js b/src/js/components/Sidebar.js
index 595ac8fb..5f24881f 100755
--- a/src/js/components/Sidebar.js
+++ b/src/js/components/Sidebar.js
@@ -68,14 +68,14 @@ class Sidebar extends React.Component{
Playlists
- {this.props.spotify_enabled && this.props.spotify_authorized ?
+
Artists
- : null}
- {this.props.spotify_enabled && this.props.spotify_authorized ?
+
+
Albums
- : null}
+
Browse
diff --git a/src/js/views/Debug.js b/src/js/views/Debug.js
index d6998416..4c05b43d 100755
--- a/src/js/views/Debug.js
+++ b/src/js/views/Debug.js
@@ -117,7 +117,7 @@ class Debug extends React.Component{
this.props.spotifyActions.authorizationGranted({access_token: e.target.value})}
+ onChange={e => this.props.spotifyActions.authorizationGranted({access_token: e.target.value})}
value={this.state.access_token} />
diff --git a/src/js/views/Settings.js b/src/js/views/Settings.js
index 536e0098..4061015e 100755
--- a/src/js/views/Settings.js
+++ b/src/js/views/Settings.js
@@ -212,7 +212,7 @@ class Settings extends React.Component {
return (
-
+
diff --git a/src/scss/global/_core.scss b/src/scss/global/_core.scss
index def1d122..816b9405 100755
--- a/src/scss/global/_core.scss
+++ b/src/scss/global/_core.scss
@@ -264,12 +264,17 @@ button.placeholder {
.pulse { @include pulse(); }
.one-liner { @include one_line_text; }
+.centred-text { text-align: center; }
.grey-text { color: $mid_grey !important; }
.red-text { color: $red !important; }
.green-text { color: $green !important; }
.orange-text { color: $orange !important; }
.dark-text { color: $dark_grey !important; }
-.centred-text { text-align: center; }
+.grey-border { border-color: $mid_grey !important; }
+.red-border { border-color: $red !important; }
+.green-border { border-color: $green !important; }
+.orange-border { border-color: $orange !important; }
+.dark-border { border-color: $dark_grey !important; }
footer {
display: block;
diff --git a/src/scss/views/_settings.scss b/src/scss/views/_settings.scss
index b60cac06..814f7f0a 100755
--- a/src/scss/views/_settings.scss
+++ b/src/scss/views/_settings.scss
@@ -53,8 +53,8 @@
top: 2px;
left: 0;
width: 34px;
- height: 26px;
- padding-top: 8px;
+ height: 25px;
+ padding-top: 9px;
border: 2px solid $grey;
text-align: center;
border-radius: 50%;