Revamp of backend method structure; Proxy for any URL
This commit is contained in:
@ -78,15 +78,20 @@ class IrisCore(object):
|
||||
return {"clientid": clientid, "connection_id": connection_id, "username": username, "generated": generated}
|
||||
|
||||
|
||||
def send_message(self, to, data):
|
||||
def send_message(self, *args, **kwargs):
|
||||
connection_id = kwargs.get('connection_id', None)
|
||||
data = kwargs.get('data', {})
|
||||
|
||||
try:
|
||||
self.connections[to]['connection'].write_message( json_encode(data) )
|
||||
self.connections[connection_id]['connection'].write_message( json_encode(data) )
|
||||
except:
|
||||
self.raven_client.captureException()
|
||||
logger.error('Failed to send message to '+ to)
|
||||
logger.error('Failed to send message to '+ connection_id)
|
||||
|
||||
|
||||
def broadcast(self, data):
|
||||
def broadcast(self, *args, **kwargs):
|
||||
data = kwargs.get('data', None)
|
||||
|
||||
for connection in self.connections.itervalues():
|
||||
connection['connection'].write_message( json_encode(data) )
|
||||
return {
|
||||
@ -102,7 +107,7 @@ class IrisCore(object):
|
||||
# to all current connections
|
||||
##
|
||||
|
||||
def get_connections(self, data):
|
||||
def get_connections(self, *args, **kwargs):
|
||||
connections = []
|
||||
for connection in self.connections.itervalues():
|
||||
connections.append(connection['client'])
|
||||
@ -112,7 +117,11 @@ class IrisCore(object):
|
||||
'connections': connections
|
||||
}
|
||||
|
||||
def add_connection(self, connection_id, connection, client):
|
||||
def add_connection(self, *args, **kwargs):
|
||||
connection_id = kwargs.get('connection_id', None)
|
||||
connection = kwargs.get('connection', None)
|
||||
client = kwargs.get('client', None)
|
||||
|
||||
new_connection = {
|
||||
'client': client,
|
||||
'connection': connection
|
||||
@ -120,39 +129,48 @@ class IrisCore(object):
|
||||
self.connections[connection_id] = new_connection
|
||||
|
||||
self.send_message(
|
||||
connection_id, {
|
||||
connection_id=connection_id,
|
||||
data={
|
||||
'type': 'connected',
|
||||
'connection_id': connection_id,
|
||||
'username': client['username']
|
||||
}
|
||||
)
|
||||
|
||||
self.broadcast({
|
||||
'type': 'connection_added',
|
||||
'connection': client
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'connection_added',
|
||||
'connection': client
|
||||
}
|
||||
)
|
||||
|
||||
def remove_connection(self, connection_id):
|
||||
if connection_id in self.connections:
|
||||
try:
|
||||
client = self.connections[connection_id]['client']
|
||||
del self.connections[connection_id]
|
||||
self.broadcast({
|
||||
'type': 'connection_removed',
|
||||
'connection': client
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'connection_removed',
|
||||
'connection': client
|
||||
}
|
||||
)
|
||||
except:
|
||||
self.raven_client.captureException()
|
||||
logger.error('Failed to close connection to '+ connection_id)
|
||||
|
||||
def set_username(self, data):
|
||||
def set_username(self, *args, **kwargs):
|
||||
connection_id = data['connection_id']
|
||||
data = kwargs.get('data', None)
|
||||
|
||||
if connection_id in self.connections:
|
||||
self.connections[connection_id]['client']['username'] = data['username']
|
||||
self.broadcast({
|
||||
'type': 'connection_updated',
|
||||
'connection': self.connections[connection_id]['client']
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'connection_updated',
|
||||
'connection': self.connections[connection_id]['client']
|
||||
}
|
||||
)
|
||||
return {
|
||||
'status': 1,
|
||||
'connection_id': connection_id,
|
||||
@ -168,14 +186,14 @@ class IrisCore(object):
|
||||
'message': error
|
||||
}
|
||||
|
||||
def deliver_message(self, data):
|
||||
to = data['to']
|
||||
if to in self.connections:
|
||||
|
||||
self.send_message(to, data['message'])
|
||||
def deliver_message(self, *args, **kwargs):
|
||||
data = kwargs.get('data', "{}")
|
||||
|
||||
if data['connection_id'] in self.connections:
|
||||
self.send_message(connection_id=data['connection_id'], data=data['message'])
|
||||
return {
|
||||
'status': 1
|
||||
'status': 1,
|
||||
'message': 'Sent message to '+data['connection_id']
|
||||
}
|
||||
|
||||
else:
|
||||
@ -196,7 +214,7 @@ class IrisCore(object):
|
||||
# Faciitates upgrades and configuration fetching
|
||||
##
|
||||
|
||||
def get_config(self, data):
|
||||
def get_config(self, *args, **kwargs):
|
||||
|
||||
# handle config setups where there is no username/password
|
||||
# Iris won't work properly anyway, but at least we won't get server errors
|
||||
@ -215,7 +233,7 @@ class IrisCore(object):
|
||||
'config': config
|
||||
}
|
||||
|
||||
def get_version(self, data):
|
||||
def get_version(self, *args, **kwargs):
|
||||
|
||||
url = 'https://pypi.python.org/pypi/Mopidy-Iris/json'
|
||||
req = urllib2.Request(url)
|
||||
@ -264,13 +282,14 @@ class IrisCore(object):
|
||||
# recommendations limit low to avoid timeouts and slow UI
|
||||
##
|
||||
|
||||
def get_radio(self, data):
|
||||
def get_radio(self, *args, **kwargs):
|
||||
return {
|
||||
'status': 1,
|
||||
'radio': self.radio
|
||||
}
|
||||
|
||||
def change_radio(self, data):
|
||||
def change_radio(self, *args, **kwargs):
|
||||
data = kwargs.get('data', None)
|
||||
|
||||
# figure out if we're starting or updating radio mode
|
||||
if data['update'] and self.radio['enabled']:
|
||||
@ -301,15 +320,19 @@ class IrisCore(object):
|
||||
if added.get():
|
||||
if starting:
|
||||
self.core.playback.play()
|
||||
self.broadcast({
|
||||
'type': 'radio_started',
|
||||
'radio': self.radio
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'radio_started',
|
||||
'radio': self.radio
|
||||
}
|
||||
)
|
||||
else:
|
||||
self.broadcast({
|
||||
'type': 'radio_changed',
|
||||
'radio': self.radio
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'radio_changed',
|
||||
'radio': self.radio
|
||||
}
|
||||
)
|
||||
|
||||
return self.get_radio({})
|
||||
|
||||
@ -322,7 +345,7 @@ class IrisCore(object):
|
||||
}
|
||||
|
||||
|
||||
def stop_radio(self, data):
|
||||
def stop_radio(self, *args, **kwargs):
|
||||
|
||||
self.radio = {
|
||||
"enabled": 0,
|
||||
@ -336,10 +359,12 @@ class IrisCore(object):
|
||||
self.core.tracklist.set_consume(self.initial_consume)
|
||||
self.core.playback.stop()
|
||||
|
||||
self.broadcast({
|
||||
'type': 'radio_stopped',
|
||||
'radio': self.radio
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'radio_stopped',
|
||||
'radio': self.radio
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
'status': 1
|
||||
@ -359,11 +384,13 @@ class IrisCore(object):
|
||||
error = 'IrisFrontend: access_token missing or invalid'
|
||||
self.raven_client.captureMessage(error)
|
||||
logger.error(error)
|
||||
self.broadcast({
|
||||
'type': 'error',
|
||||
'message': 'Could not get radio tracks: access_token missing or invalid',
|
||||
'source': 'load_more_tracks'
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'error',
|
||||
'message': 'Could not get radio tracks: access_token missing or invalid',
|
||||
'source': 'load_more_tracks'
|
||||
}
|
||||
)
|
||||
|
||||
try:
|
||||
url = 'https://api.spotify.com/v1/recommendations/'
|
||||
@ -387,17 +414,19 @@ class IrisCore(object):
|
||||
except:
|
||||
self.raven_client.captureException()
|
||||
logger.error('IrisFrontend: Failed to fetch Spotify recommendations')
|
||||
self.broadcast({
|
||||
'type': 'error',
|
||||
'message': 'Could not get radio tracks',
|
||||
'source': 'load_more_tracks'
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'error',
|
||||
'message': 'Could not get radio tracks',
|
||||
'source': 'load_more_tracks'
|
||||
}
|
||||
)
|
||||
return []
|
||||
|
||||
|
||||
def check_for_radio_update( self ):
|
||||
tracklistLength = self.core.tracklist.length.get()
|
||||
if( tracklistLength < 3 and self.radio['enabled'] == 1 ):
|
||||
if (tracklistLength < 3 and self.radio['enabled'] == 1):
|
||||
|
||||
# Grab our loaded tracks
|
||||
uris = self.radio['results']
|
||||
@ -423,13 +452,14 @@ class IrisCore(object):
|
||||
# added_by and from_uri.
|
||||
##
|
||||
|
||||
def get_queue_metadata(self, data):
|
||||
def get_queue_metadata(self, *args, **kwargs):
|
||||
return {
|
||||
'status': 1,
|
||||
'queue_metadata': self.queue_metadata
|
||||
}
|
||||
|
||||
def add_queue_metadata(self, data):
|
||||
def add_queue_metadata(self, *args, **kwargs):
|
||||
data = kwargs.get('data', None)
|
||||
|
||||
for tlid in data['tlids']:
|
||||
item = {
|
||||
@ -439,10 +469,12 @@ class IrisCore(object):
|
||||
}
|
||||
self.queue_metadata['tlid_'+str(tlid)] = item
|
||||
|
||||
self.broadcast({
|
||||
'type': 'queue_metadata_changed',
|
||||
'queue_metadata': self.queue_metadata
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'queue_metadata_changed',
|
||||
'queue_metadata': self.queue_metadata
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
'status': 1
|
||||
@ -459,10 +491,12 @@ class IrisCore(object):
|
||||
|
||||
self.queue_metadata = cleaned_queue_metadata
|
||||
|
||||
self.broadcast({
|
||||
'type': 'queue_metadata_changed',
|
||||
'queue_metadata': self.queue_metadata
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'queue_metadata_changed',
|
||||
'queue_metadata': self.queue_metadata
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
'status': 1
|
||||
@ -477,12 +511,12 @@ class IrisCore(object):
|
||||
# passing token to frontend for javascript requests without use of the Authorization Code Flow.
|
||||
##
|
||||
|
||||
def get_spotify_token(self, data):
|
||||
def get_spotify_token(self, *args, **kwargs):
|
||||
return {
|
||||
'spotify_token': self.spotify_token
|
||||
}
|
||||
|
||||
def refresh_spotify_token(self, data):
|
||||
def refresh_spotify_token(self, *args, **kwargs):
|
||||
|
||||
# Use client_id and client_secret from config
|
||||
# This was introduced in Mopidy-Spotify 3.1.0
|
||||
@ -497,14 +531,16 @@ class IrisCore(object):
|
||||
req = urllib2.Request(url, data_encoded)
|
||||
|
||||
try:
|
||||
response = urllib2.urlopen(req, timeout=30).read()
|
||||
response = urllib2.urlopen(req, timeout=15).read()
|
||||
response_dict = json.loads(response)
|
||||
self.spotify_token = response_dict
|
||||
|
||||
self.broadcast({
|
||||
'type': 'spotify_token_changed',
|
||||
'spotify_token': self.spotify_token
|
||||
})
|
||||
self.broadcast(
|
||||
data={
|
||||
'type': 'spotify_token_changed',
|
||||
'spotify_token': self.spotify_token
|
||||
}
|
||||
)
|
||||
|
||||
return self.get_spotify_token({})
|
||||
|
||||
@ -517,3 +553,81 @@ class IrisCore(object):
|
||||
'message': 'Could not refresh token: '+error['error_description'],
|
||||
'source': 'refresh_spotify_token'
|
||||
}
|
||||
|
||||
|
||||
##
|
||||
# Proxy a request to an external provider
|
||||
#
|
||||
# This is required when requesting to non-CORS providers. We simply make the request
|
||||
# server-side and pass that back. All we change is the response's Access-Control-Allow-Origin
|
||||
# to prevent CORS-blocking by the browser.
|
||||
##
|
||||
|
||||
def proxy_request(self, *args, **kwargs):
|
||||
|
||||
data = kwargs.get('data', None)
|
||||
origin_request = kwargs.get('request', None)
|
||||
|
||||
# Our request includes data, so make sure we POST the data
|
||||
if 'url' not in data:
|
||||
self.raven_client.captureException()
|
||||
return {
|
||||
'type': 'error',
|
||||
'message': 'Could not complete proxy request',
|
||||
'source': 'proxy_request',
|
||||
'error': "Missing URL property",
|
||||
'original_request': data
|
||||
}
|
||||
|
||||
# Construct request headers
|
||||
# If we have an original request, pass through it's headers
|
||||
if origin_request:
|
||||
target_request_headers = origin_request.headers
|
||||
else:
|
||||
target_request_headers = {}
|
||||
|
||||
# Adjust headers
|
||||
target_request_headers["Accept-Encoding"] = "deflate"
|
||||
if "Content-Type" in target_request_headers:
|
||||
del target_request_headers["Content-Type"]
|
||||
|
||||
# Our request includes data, so make sure we POST the data
|
||||
if ('data' in data and data['data']):
|
||||
target_request = urllib2.Request(data['url'], data=urllib.urlencode(data['data']), headers=target_request_headers)
|
||||
|
||||
# No data, so just a simple GET request
|
||||
else:
|
||||
target_request = urllib2.Request(data['url'], headers=target_request_headers)
|
||||
|
||||
try:
|
||||
target_response = urllib2.urlopen(target_request, timeout=15)
|
||||
target_response_body = target_response.read()
|
||||
|
||||
try:
|
||||
response = json.loads(target_response_body)
|
||||
return {
|
||||
'response': response
|
||||
}
|
||||
except:
|
||||
return {
|
||||
'response': target_response_body
|
||||
}
|
||||
|
||||
except urllib2.HTTPError as e:
|
||||
self.raven_client.captureException()
|
||||
return {
|
||||
'type': 'error',
|
||||
'message': 'Could not complete proxy request',
|
||||
'source': 'proxy_request',
|
||||
'response': e.read(),
|
||||
'original_request': data
|
||||
}
|
||||
|
||||
except urllib2.URLError as e:
|
||||
self.raven_client.captureException()
|
||||
return {
|
||||
'type': 'error',
|
||||
'message': 'Could not complete proxy request',
|
||||
'source': 'proxy_request',
|
||||
'original_request': data
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
|
||||
}
|
||||
|
||||
# add to connections
|
||||
mem.iris.add_connection(connection_id, self, client)
|
||||
mem.iris.add_connection(connection_id=connection_id, connection=self, client=client)
|
||||
|
||||
|
||||
def on_message(self, message):
|
||||
@ -87,11 +87,11 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
|
||||
if hasattr(mem.iris, message['method']):
|
||||
|
||||
# make the call, and return it's response
|
||||
response = getattr(mem.iris, message['method'])(data)
|
||||
response = getattr(mem.iris, message['method'])(data=data)
|
||||
|
||||
if response:
|
||||
response['request_id'] = request_id
|
||||
mem.iris.send_message(self.connection_id, response)
|
||||
mem.iris.send_message(connection_id=self.connection_id, data=response)
|
||||
else:
|
||||
mem.iris.raven_client.captureMessage("Method "+message['method']+" does not exist")
|
||||
response = {
|
||||
@ -99,7 +99,7 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
|
||||
'message': 'Method "'+message['method']+'" does not exist',
|
||||
'request_id': request_id
|
||||
}
|
||||
mem.iris.send_message(self.connection_id, response)
|
||||
mem.iris.send_message(connection_id=self.connection_id, data=response)
|
||||
else:
|
||||
mem.iris.raven_client.captureMessage("Method key missing from request")
|
||||
response = {
|
||||
@ -107,11 +107,11 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
|
||||
'message': 'Method key missing from request',
|
||||
'request_id': request_id
|
||||
}
|
||||
mem.iris.send_message(self.connection_id, response)
|
||||
mem.iris.send_message(connection_id=self.connection_id, data=response)
|
||||
|
||||
|
||||
def on_close(self):
|
||||
mem.iris.remove_connection(self.connection_id)
|
||||
mem.iris.remove_connection(connection_id=self.connection_id)
|
||||
|
||||
|
||||
|
||||
@ -133,7 +133,30 @@ class HttpHandler(tornado.web.RequestHandler):
|
||||
if hasattr(mem.iris, slug):
|
||||
|
||||
# make the call, and return it's response
|
||||
self.write(getattr(mem.iris, slug)({}))
|
||||
self.write(getattr(mem.iris, slug)(data={}, request=self.request))
|
||||
else:
|
||||
mem.iris.raven_client.captureMessage("Method "+slug+" does not exist")
|
||||
self.write({
|
||||
'error': 'Method "'+slug+'" does not exist'
|
||||
})
|
||||
|
||||
def post(self, slug=None):
|
||||
|
||||
# make sure the method exists
|
||||
if hasattr(mem.iris, slug):
|
||||
|
||||
try:
|
||||
data = json.loads(self.request.body.decode('utf-8'))
|
||||
|
||||
# make the call, and return it's response
|
||||
self.write(getattr(mem.iris, slug)(data=data, request=self.request))
|
||||
|
||||
except urllib2.HTTPError as e:
|
||||
self.raven_client.captureException()
|
||||
self.write({
|
||||
'error': 'Invalid JSON payload'
|
||||
})
|
||||
|
||||
else:
|
||||
mem.iris.raven_client.captureMessage("Method "+slug+" does not exist")
|
||||
self.write({
|
||||
|
||||
10
src/js/bootstrap.js
vendored
10
src/js/bootstrap.js
vendored
@ -7,6 +7,7 @@ import pusher from './services/pusher/reducer'
|
||||
import mopidy from './services/mopidy/reducer'
|
||||
import lastfm from './services/lastfm/reducer'
|
||||
import spotify from './services/spotify/reducer'
|
||||
import genius from './services/genius/reducer'
|
||||
|
||||
import thunk from 'redux-thunk'
|
||||
import coreMiddleware from './services/core/middleware'
|
||||
@ -22,6 +23,7 @@ let reducers = combineReducers({
|
||||
pusher,
|
||||
mopidy,
|
||||
lastfm,
|
||||
genius,
|
||||
spotify
|
||||
});
|
||||
|
||||
@ -61,10 +63,10 @@ var initialState = {
|
||||
}
|
||||
},
|
||||
lastfm: {
|
||||
connected: false,
|
||||
album: {},
|
||||
artist: {},
|
||||
track: {}
|
||||
connected: false
|
||||
},
|
||||
genius: {
|
||||
connected: false
|
||||
},
|
||||
spotify: {
|
||||
connected: false,
|
||||
|
||||
@ -16,12 +16,14 @@ import SearchURISchemesModal from './SearchURISchemesModal'
|
||||
import VolumeModal from './VolumeModal'
|
||||
import AuthorizationModal_Send from './AuthorizationModal_Send'
|
||||
import AuthorizationModal_Receive from './AuthorizationModal_Receive'
|
||||
import TrackInfoModal from './TrackInfoModal'
|
||||
|
||||
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 geniusActions from '../../services/genius/actions'
|
||||
|
||||
class Modal extends React.Component{
|
||||
|
||||
@ -58,6 +60,7 @@ class Modal extends React.Component{
|
||||
{ this.props.modal.name == 'kiosk_mode' ? <KioskModeModal uiActions={this.props.uiActions} data={this.props.modal.data} current_track={this.props.current_track} /> : null }
|
||||
{ this.props.modal.name == 'search_uri_schemes' ? <SearchURISchemesModal uiActions={this.props.uiActions} coreActions={this.props.coreActions} search_uri_schemes={this.props.search_uri_schemes} available_uri_schemes={this.props.uri_schemes} data={this.props.modal.data} /> : null }
|
||||
{ this.props.modal.name == 'volume' ? <VolumeModal uiActions={this.props.uiActions} mopidyActions={this.props.mopidyActions} volume={this.props.volume} mute={this.props.mute} /> : null }
|
||||
{ this.props.modal.name == 'track_info' ? <TrackInfoModal uiActions={this.props.uiActions} geniusActions={this.props.geniusActions} current_track={this.props.current_track} /> : null }
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -92,7 +95,8 @@ const mapDispatchToProps = (dispatch) => {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch)
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
geniusActions: bindActionCreators(geniusActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
32
src/js/components/Modal/TrackInfoModal.js
Executable file
32
src/js/components/Modal/TrackInfoModal.js
Executable file
@ -0,0 +1,32 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
|
||||
import Icon from '../Icon'
|
||||
import ArtistSentence from '../ArtistSentence'
|
||||
import * as helpers from '../../helpers'
|
||||
|
||||
export default class TrackInfoModal extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if (this.props.current_track && !this.props.current_track.annotations){
|
||||
this.props.geniusActions.getTrackInfo(this.props.current_track);
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
var track = this.props.current_track;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Track info</h1>
|
||||
<h2 className="grey-text">{track.name} by <ArtistSentence artists={track.artists} /></h2>
|
||||
{track.annotations ? track.annotations.id : "No annotations"}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
|
||||
import ReactGA from 'react-ga'
|
||||
|
||||
var coreActions = require('./actions.js')
|
||||
var uiActions = require('../ui/actions.js')
|
||||
var pusherActions = require('../pusher/actions.js')
|
||||
var mopidyActions = require('../mopidy/actions.js')
|
||||
var spotifyActions = require('../spotify/actions.js')
|
||||
var lastfmActions = require('../lastfm/actions.js')
|
||||
var helpers = require('../../helpers.js')
|
||||
var coreActions = require('./actions.js');
|
||||
var uiActions = require('../ui/actions.js');
|
||||
var pusherActions = require('../pusher/actions.js');
|
||||
var mopidyActions = require('../mopidy/actions.js');
|
||||
var spotifyActions = require('../spotify/actions.js');
|
||||
var lastfmActions = require('../lastfm/actions.js');
|
||||
var geniusActions = require('../genius/actions.js');
|
||||
var helpers = require('../../helpers.js');
|
||||
|
||||
const CoreMiddleware = (function(){
|
||||
|
||||
@ -71,9 +72,8 @@ const CoreMiddleware = (function(){
|
||||
break;
|
||||
|
||||
case 'CORE_START_SERVICES':
|
||||
store.dispatch(mopidyActions.connect())
|
||||
store.dispatch(pusherActions.connect())
|
||||
store.dispatch(lastfmActions.connect())
|
||||
store.dispatch(mopidyActions.connect());
|
||||
store.dispatch(pusherActions.connect());
|
||||
|
||||
next(action)
|
||||
break
|
||||
|
||||
73
src/js/services/genius/actions.js
Executable file
73
src/js/services/genius/actions.js
Executable file
@ -0,0 +1,73 @@
|
||||
|
||||
var coreActions = require('../core/actions')
|
||||
var uiActions = require('../ui/actions')
|
||||
var helpers = require('../../helpers')
|
||||
|
||||
/**
|
||||
* Send an ajax request to the Spotify API
|
||||
*
|
||||
* @param dispatch obj
|
||||
* @param getState obj
|
||||
* @param endpoint params = the url params to send
|
||||
**/
|
||||
const sendRequest = (dispatch, getState, endpoint) => {
|
||||
return new Promise( (resolve, reject) => {
|
||||
|
||||
var loader_key = helpers.generateGuid();
|
||||
dispatch(uiActions.startLoading(loader_key, 'genius_'+endpoint));
|
||||
|
||||
var config = {
|
||||
method: 'GET',
|
||||
cache: false,
|
||||
url: 'https://api.genius.com/'+endpoint+'&access_token=2AGP9sfzKQcxfKSZuGa_3lqsDIpuOiTGT7-vhJYcKaaDjHIIA2HICsxXCiC30Xxi'
|
||||
};
|
||||
|
||||
$.ajax(config).then(
|
||||
response => {
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
resolve(response.response);
|
||||
},
|
||||
(xhr, status, error) => {
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
reject({
|
||||
config: config,
|
||||
xhr: xhr,
|
||||
status: status,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function getTrackInfo(track){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
var query = '';
|
||||
for (var i = 0; i < track.artists.length; i++){
|
||||
query += track.artists[i].name+' ';
|
||||
}
|
||||
query += track.name;
|
||||
|
||||
sendRequest(dispatch, getState, 'search?q='+query)
|
||||
.then(
|
||||
response => {
|
||||
if (response.hits && response.hits.length > 0){
|
||||
dispatch({
|
||||
type: 'TRACK_LOADED',
|
||||
key: track.uri,
|
||||
track: {
|
||||
annotations: response.hits[0].result
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error => {
|
||||
dispatch(coreActions.handleException(
|
||||
'Could not get track info',
|
||||
error
|
||||
));
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
18
src/js/services/genius/reducer.js
Executable file
18
src/js/services/genius/reducer.js
Executable file
@ -0,0 +1,18 @@
|
||||
|
||||
export default function reducer(genius = {}, action){
|
||||
switch (action.type) {
|
||||
|
||||
case 'GENIUS_CONNECT':
|
||||
case 'GENIUS_CONNECTING':
|
||||
return Object.assign({}, genius, { connected: false, connecting: true });
|
||||
|
||||
case 'GENIUS_CONNECTED':
|
||||
return Object.assign({}, genius, { connected: true, connecting: false });
|
||||
|
||||
default:
|
||||
return genius
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1685,10 +1685,14 @@ const MopidyMiddleware = (function(){
|
||||
if (action.data && action.data.track){
|
||||
|
||||
// Fire off our universal track index loader
|
||||
store.dispatch({ type: 'TRACK_LOADED', key: action.data.track.uri, track: action.data.track })
|
||||
store.dispatch({
|
||||
type: 'TRACK_LOADED',
|
||||
key: action.data.track.uri,
|
||||
track: action.data.track
|
||||
});
|
||||
|
||||
// We've got Spotify running, and it's a spotify track - go straight to the source!
|
||||
if (helpers.uriSource(action.data.track.uri) == 'spotify' && store.getState().spotify.access != 'none'){
|
||||
if (helpers.uriSource(action.data.track.uri) == 'spotify' && store.getState().spotify.enabled){
|
||||
store.dispatch(spotifyActions.getTrack(action.data.track.uri))
|
||||
|
||||
// Some other source, rely on Mopidy backends to do their work
|
||||
|
||||
@ -24,7 +24,9 @@ const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false
|
||||
|
||||
// prepend the API baseurl, unless the endpoint already has it (ie pagination requests)
|
||||
var url = 'https://api.spotify.com/v1/'+endpoint
|
||||
if (endpoint.startsWith('https://api.spotify.com/')) url = endpoint;
|
||||
if (endpoint.startsWith('https://api.spotify.com/')){
|
||||
url = endpoint;
|
||||
}
|
||||
|
||||
// create our ajax request config
|
||||
var config = {
|
||||
|
||||
@ -174,6 +174,7 @@ class Debug extends React.Component{
|
||||
<option value='{"method":"set_username","data":{"connection_id":"CONNECTION_ID_HERE","username":"NewUsername"}}'>Change username</option>
|
||||
<option value='{"method":"refresh_spotify_token"}'>Refresh Spotify token</option>
|
||||
<option value='{"method":"perform_upgrade"}'>Perform upgrade (beta)</option>
|
||||
<option value='{"method":"proxy_request","data":{"url":"https://jsonplaceholder.typicode.com/posts/1"}}'>Proxy request</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -120,6 +120,7 @@ class Queue extends React.Component{
|
||||
{ this.renderArtwork(image) }
|
||||
<div className="title">
|
||||
{this.props.current_track ? this.props.current_track.name : <span>-</span>}
|
||||
<FontAwesome name="info-circle" onClick={e => this.props.uiActions.openModal('track_info')} />
|
||||
</div>
|
||||
{this.props.current_track ? <ArtistSentence artists={ this.props.current_track.artists } /> : <ArtistSentence />}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user