LastFM love button, API failing
This commit is contained in:
62
src/js/components/LastfmLoveButton.js
Executable file
62
src/js/components/LastfmLoveButton.js
Executable file
@ -0,0 +1,62 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link } from 'react-router'
|
||||
import { createStore, bindActionCreators } from 'redux'
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
|
||||
import * as helpers from '../helpers'
|
||||
import * as uiActions from '../services/ui/actions'
|
||||
import * as lastfmActions from '../services/lastfm/actions'
|
||||
|
||||
class FollowButton extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
remove(){
|
||||
this.props.lastfmActions.loveTrack(this.props.uri, this.props.artist, this.props.track);
|
||||
}
|
||||
|
||||
add(){
|
||||
this.props.lastfmActions.unloveTrack(this.props.uri, this.props.artist, this.props.track);
|
||||
}
|
||||
|
||||
render(){
|
||||
if (!this.props.uri){
|
||||
return false;
|
||||
}
|
||||
|
||||
var className = '';
|
||||
|
||||
// Inherit passed-down classes
|
||||
if (this.props.className){
|
||||
className += ' '+this.props.className;
|
||||
}
|
||||
|
||||
if (!this.props.lastfm_authorized){
|
||||
return <button className={className+' disabled'} onClick={e => this.props.uiActions.createNotification('You must authorize LastFM first','warning')}>{this.props.addText}</button>
|
||||
} else if (this.props.loved === true){
|
||||
return <button className={className+' destructive'} onClick={e => this.remove()}>{this.props.removeText}</button>
|
||||
} else {
|
||||
return <button className={className} onClick={e => this.add()}>{this.props.addText}</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
load_queue: state.ui.load_queue,
|
||||
lastfm_authorized: state.lastfm.session
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
lastfmActions: bindActionCreators(lastfmActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(FollowButton)
|
||||
@ -9,19 +9,26 @@ var helpers = require('../../helpers')
|
||||
* @param dispatch = obj
|
||||
* @param getState = obj
|
||||
* @param params = string, the url params to send
|
||||
* @param signed = boolean
|
||||
* @params signed = boolean, whether we've got a signed request with baked-in api_key
|
||||
**/
|
||||
const sendRequest = (dispatch, getState, params, signed) => {
|
||||
const sendRequest = (dispatch, getState, params, signed = false) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
var loader_key = helpers.generateGuid()
|
||||
dispatch(uiActions.startLoading(loader_key, 'lastfm_'+params))
|
||||
var loader_key = helpers.generateGuid();
|
||||
dispatch(uiActions.startLoading(loader_key, 'lastfm_'+params));
|
||||
|
||||
var config = {
|
||||
method: 'GET',
|
||||
cache: true,
|
||||
timeout: 30000,
|
||||
url: '//ws.audioscrobbler.com/2.0/?format=json&api_key=4320a3ef51c9b3d69de552ac083c55e3&'+params
|
||||
url: '//ws.audioscrobbler.com/2.0/?format=json&'+params
|
||||
}
|
||||
|
||||
// Signed requests don't need our api_key as the proxy has it's own
|
||||
if (!signed){
|
||||
config.url += '&api_key=4320a3ef51c9b3d69de552ac083c55e3';
|
||||
} else {
|
||||
config.method = 'POST';
|
||||
}
|
||||
|
||||
$.ajax(config).then(
|
||||
@ -46,6 +53,58 @@ const sendRequest = (dispatch, getState, params, signed) => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a SIGNED ajax request to the LastFM API
|
||||
*
|
||||
* @param dispatch = obj
|
||||
* @param getState = obj
|
||||
* @param params = string, the url params to send
|
||||
* @param signed = boolean
|
||||
**/
|
||||
const sendSignedRequest = (dispatch, getState, params) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
var loader_key = helpers.generateGuid()
|
||||
dispatch(uiActions.startLoading(loader_key, 'lastfm_'+params))
|
||||
|
||||
var config = {
|
||||
method: 'GET',
|
||||
cache: false,
|
||||
timeout: 30000,
|
||||
url: getState().lastfm.authorization_url+"?action=sign_request&"+params
|
||||
}
|
||||
|
||||
$.ajax(config).then(
|
||||
response => {
|
||||
var signed_params = "";
|
||||
for (var key in response){
|
||||
if (response.hasOwnProperty(key)){
|
||||
if (signed_params != ""){
|
||||
signed_params += "&"
|
||||
}
|
||||
signed_params += key+'='+response[key];
|
||||
}
|
||||
}
|
||||
dispatch(uiActions.stopLoading(loader_key))
|
||||
return sendRequest(dispatch, getState, signed_params, true)
|
||||
},
|
||||
(xhr, status, error) => {
|
||||
dispatch(uiActions.stopLoading(loader_key))
|
||||
dispatch(coreActions.handleException(
|
||||
'LastFM: '+xhr.responseText,
|
||||
{
|
||||
config: config,
|
||||
error: error,
|
||||
status: status,
|
||||
xhr: xhr
|
||||
}
|
||||
));
|
||||
reject(error)
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function set(data){
|
||||
return {
|
||||
@ -98,16 +157,38 @@ export function connect(){
|
||||
* TODO
|
||||
**/
|
||||
|
||||
export function loveTrack(artist, track){
|
||||
export function loveTrack(uri, artist, track){
|
||||
return (dispatch, getState) => {
|
||||
var params = 'method=track.love&artist='+artist+'&track='+track
|
||||
sendRequest(dispatch, getState, params, true)
|
||||
artist = encodeURIComponent(artist);
|
||||
var params = 'method=track.love&track='+track+'&artist='+artist;
|
||||
sendSignedRequest(dispatch, getState, params)
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
type: 'LASTFM_TRACK_LOVED',
|
||||
artist: artist,
|
||||
track: track
|
||||
type: 'TRACK_LOADED',
|
||||
key: uri,
|
||||
track: {
|
||||
userloved: true
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function unloveTrack(uri, artist, track){
|
||||
return (dispatch, getState) => {
|
||||
artist = encodeURIComponent(artist);
|
||||
var params = 'method=track.unlove&track='+track+'&artist='+artist;
|
||||
sendSignedRequest(dispatch, getState, params)
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
type: 'TRACK_LOADED',
|
||||
key: uri,
|
||||
track: {
|
||||
userloved: false
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
@ -192,19 +273,30 @@ export function getAlbum(artist, album, mbid = false){
|
||||
}
|
||||
}
|
||||
|
||||
export function getTrack(artist, track){
|
||||
export function getTrack(track, artist_name = null, track_name = null){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'LASTFM_TRACK_LOADED', data: false });
|
||||
|
||||
artist = encodeURIComponent(artist );
|
||||
sendRequest(dispatch, getState, 'method=track.getInfo&track='+track+'&artist='+artist)
|
||||
if (track){
|
||||
artist_name = track.artist[0].name;
|
||||
track_name = track.name;
|
||||
}
|
||||
artist_name = encodeURIComponent(artist_name);
|
||||
var params = 'method=track.getInfo&track='+track+'&artist='+artist;
|
||||
if (getState().lastfm.session){
|
||||
params += '&username='+getState().lastfm.session.name;
|
||||
}
|
||||
sendRequest(dispatch, getState, params)
|
||||
.then(
|
||||
response => {
|
||||
if (response.track){
|
||||
var merged_track = Object.assign(
|
||||
{},
|
||||
response.track,
|
||||
track
|
||||
);
|
||||
dispatch({
|
||||
type: 'LASTFM_TRACK_LOADED',
|
||||
data: response.track
|
||||
type: 'TRACK_LOADED',
|
||||
key: uri,
|
||||
track: merged_track
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,11 +264,7 @@ export function getMe(){
|
||||
**/
|
||||
export function getTrack(uri){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// flush out the previous store value
|
||||
dispatch({ type: 'SPOTIFY_TRACK_LOADED', data: false });
|
||||
|
||||
sendRequest(dispatch, getState, 'tracks/'+ helpers.getFromUri('trackid', uri) )
|
||||
sendRequest(dispatch, getState, 'tracks/'+ helpers.getFromUri('trackid', uri))
|
||||
.then(
|
||||
response => {
|
||||
let track = Object.assign(
|
||||
@ -677,6 +673,13 @@ export function following(uri, method = 'GET'){
|
||||
var asset_name = helpers.uriType(uri);
|
||||
var endpoint, data
|
||||
switch(asset_name){
|
||||
case 'track':
|
||||
if (method == 'GET'){
|
||||
endpoint = 'me/tracks/contains/?ids='+ helpers.getFromUri('trackid', uri)
|
||||
} else {
|
||||
endpoint = 'me/tracks/?ids='+ helpers.getFromUri('trackid', uri)
|
||||
}
|
||||
break
|
||||
case 'album':
|
||||
if (method == 'GET'){
|
||||
endpoint = 'me/albums/contains/?ids='+ helpers.getFromUri('albumid', uri)
|
||||
@ -709,7 +712,7 @@ export function following(uri, method = 'GET'){
|
||||
break
|
||||
}
|
||||
|
||||
sendRequest(dispatch, getState, endpoint, method, data )
|
||||
sendRequest(dispatch, getState, endpoint, method, data)
|
||||
.then(
|
||||
response => {
|
||||
if (response ) is_following = response
|
||||
|
||||
@ -11,6 +11,7 @@ import Thumbnail from '../components/Thumbnail'
|
||||
import ArtistSentence from '../components/ArtistSentence'
|
||||
import ArtistGrid from '../components/ArtistGrid'
|
||||
import FollowButton from '../components/FollowButton'
|
||||
import LastfmLoveButton from '../components/LastfmLoveButton'
|
||||
import Dater from '../components/Dater'
|
||||
import LazyLoadListener from '../components/LazyLoadListener'
|
||||
import ContextMenuTrigger from '../components/ContextMenuTrigger'
|
||||
@ -19,6 +20,7 @@ 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 lastfmActions from '../services/lastfm/actions'
|
||||
import * as geniusActions from '../services/genius/actions'
|
||||
|
||||
class Track extends React.Component{
|
||||
@ -39,13 +41,13 @@ class Track extends React.Component{
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
|
||||
// if our URI has changed, fetch new album
|
||||
// if our URI has changed, fetch new track
|
||||
if (nextProps.params.uri != this.props.params.uri){
|
||||
this.loadTrack(nextProps )
|
||||
this.loadTrack(nextProps)
|
||||
|
||||
// if mopidy has just connected AND we're a local album, go get
|
||||
// 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.params.uri ) != 'spotify'){
|
||||
if (helpers.uriSource(this.props.params.uri) != 'spotify'){
|
||||
this.loadTrack(nextProps);
|
||||
}
|
||||
}
|
||||
@ -89,6 +91,11 @@ class Track extends React.Component{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the LastFM version of this track
|
||||
if (props.lastfm_authorized){
|
||||
//this.props.lastfmActions.getTrack(this.props.track);
|
||||
}
|
||||
|
||||
// We don't have lyrics, but the track (and artists) is already loaded
|
||||
if (props.track && !props.track.lyrics_results && props.track.artists){
|
||||
this.props.geniusActions.findTrackLyrics(props.track);
|
||||
@ -211,7 +218,8 @@ class Track extends React.Component{
|
||||
|
||||
<div className="actions">
|
||||
<button className="primary" onClick={e => this.play()}>Play</button>
|
||||
{this.props.slim_mode ? null : <ContextMenuTrigger onTrigger={e => this.handleContextMenu(e)} />}
|
||||
<LastfmLoveButton uri={this.props.params.uri} artist={this.props.track.artists[0].name} track={this.props.track.name} addText="Love" removeText="Unlove" is_loved={this.props.userloved} />
|
||||
<ContextMenuTrigger onTrigger={e => this.handleContextMenu(e)} />
|
||||
</div>
|
||||
|
||||
{this.renderLyricsSelector()}
|
||||
@ -240,6 +248,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
albums: state.core.albums,
|
||||
spotify_library_albums: state.spotify.library_albums,
|
||||
local_library_albums: state.mopidy.library_albums,
|
||||
lastfm_authorized: state.spotify.session,
|
||||
spotify_authorized: state.spotify.authorization,
|
||||
mopidy_connected: state.mopidy.connected
|
||||
};
|
||||
@ -250,6 +259,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
lastfmActions: bindActionCreators(lastfmActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
geniusActions: bindActionCreators(geniusActions, dispatch)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user