Loving track; Investigating scrobbling
This commit is contained in:
@ -37,7 +37,7 @@ class FollowButton extends React.Component{
|
||||
|
||||
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){
|
||||
} else if (this.props.is_loved && this.props.is_loved !== "0"){
|
||||
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>
|
||||
|
||||
@ -33,21 +33,32 @@ const sendRequest = (dispatch, getState, params, signed = false) => {
|
||||
|
||||
$.ajax(config).then(
|
||||
response => {
|
||||
dispatch(uiActions.stopLoading(loader_key))
|
||||
resolve(response)
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
if (response.error){
|
||||
reject({
|
||||
config: config,
|
||||
error: response
|
||||
});
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
},
|
||||
(xhr, status, error) => {
|
||||
dispatch(uiActions.stopLoading(loader_key))
|
||||
dispatch(coreActions.handleException(
|
||||
'LastFM: '+xhr.responseText,
|
||||
{
|
||||
config: config,
|
||||
error: error,
|
||||
status: status,
|
||||
xhr: xhr
|
||||
}
|
||||
));
|
||||
reject(error)
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
|
||||
// Snatch a more meaningful error
|
||||
var description = null;
|
||||
if (xhr.responseJSON.message){
|
||||
description = xhr.responseJSON.message;
|
||||
}
|
||||
|
||||
reject({
|
||||
config: config,
|
||||
error: error,
|
||||
description: description,
|
||||
status: status,
|
||||
xhr: xhr
|
||||
});
|
||||
}
|
||||
)
|
||||
})
|
||||
@ -64,8 +75,18 @@ const sendRequest = (dispatch, getState, params, signed = false) => {
|
||||
const sendSignedRequest = (dispatch, getState, params) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
// Not authorized
|
||||
if (!getState().lastfm.session){
|
||||
reject({
|
||||
params: params,
|
||||
error: "No active LastFM session"
|
||||
});
|
||||
}
|
||||
|
||||
var loader_key = helpers.generateGuid()
|
||||
dispatch(uiActions.startLoading(loader_key, 'lastfm_'+params))
|
||||
dispatch(uiActions.startLoading(loader_key, 'lastfm_'+params));
|
||||
|
||||
params += "&sk="+getState().lastfm.session.key;
|
||||
|
||||
var config = {
|
||||
method: 'GET',
|
||||
@ -75,33 +96,33 @@ const sendSignedRequest = (dispatch, getState, 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];
|
||||
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)
|
||||
}
|
||||
);
|
||||
|
||||
dispatch(uiActions.stopLoading(loader_key))
|
||||
sendRequest(dispatch, getState, signed_params, true)
|
||||
.then(
|
||||
response => {
|
||||
resolve(response);
|
||||
},
|
||||
error => {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
(xhr, status, error) => {
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
reject(error)
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
@ -164,7 +185,6 @@ export function loveTrack(uri, artist, track){
|
||||
sendSignedRequest(dispatch, getState, params)
|
||||
.then(
|
||||
response => {
|
||||
console.log(response);
|
||||
dispatch({
|
||||
type: 'TRACK_LOADED',
|
||||
key: uri,
|
||||
@ -277,11 +297,13 @@ export function getAlbum(artist, album, mbid = false){
|
||||
export function getTrack(track, artist_name = null, track_name = null){
|
||||
return (dispatch, getState) => {
|
||||
if (track){
|
||||
artist_name = track.artist[0].name;
|
||||
track_name = track.name;
|
||||
if (track.artists){
|
||||
artist_name = track.artists[0].name;
|
||||
}
|
||||
}
|
||||
artist_name = encodeURIComponent(artist_name);
|
||||
var params = 'method=track.getInfo&track='+track+'&artist='+artist;
|
||||
var params = 'method=track.getInfo&track='+track_name+'&artist='+artist_name;
|
||||
if (getState().lastfm.session){
|
||||
params += '&username='+getState().lastfm.session.name;
|
||||
}
|
||||
@ -296,7 +318,7 @@ export function getTrack(track, artist_name = null, track_name = null){
|
||||
);
|
||||
dispatch({
|
||||
type: 'TRACK_LOADED',
|
||||
key: uri,
|
||||
key: merged_track.uri,
|
||||
track: merged_track
|
||||
});
|
||||
}
|
||||
@ -305,3 +327,32 @@ export function getTrack(track, artist_name = null, track_name = null){
|
||||
}
|
||||
}
|
||||
|
||||
export function scrobble(track){
|
||||
return (dispatch, getState) => {
|
||||
var track_name = track.name;
|
||||
var artist_name = "Unknown";
|
||||
if (track.artists){
|
||||
artist_name = track.artists[0].name;
|
||||
}
|
||||
var artist_name = encodeURIComponent(artist_name);
|
||||
|
||||
var params = 'method=track.scrobble';
|
||||
params += '&track='+track_name+'&artist='+artist_name;
|
||||
params += '×tamp='+Date.now();
|
||||
|
||||
sendSignedRequest(dispatch, getState, params)
|
||||
.then(
|
||||
response => {
|
||||
console.log("Scrobbled", response);
|
||||
},
|
||||
error => {
|
||||
dispatch(coreActions.handleException(
|
||||
'Could not scrobble track',
|
||||
error,
|
||||
(error.description ? error.description : null)
|
||||
));
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,6 +32,16 @@ const LastfmMiddleware = (function(){
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'MOPIDY_CURRENTTLTRACK':
|
||||
if (action.data && action.data.track){
|
||||
if (state.lastfm.session){
|
||||
store.dispatch(lastfmActions.scrobble(action.data.track));
|
||||
}
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
|
||||
@ -178,6 +178,17 @@ const localstorageMiddleware = (function(){
|
||||
);
|
||||
localStorage.setItem('lastfm', JSON.stringify(lastfm));
|
||||
break;
|
||||
|
||||
case 'LASTFM_AUTHORIZATION_REVOKED':
|
||||
var lastfm = JSON.parse(localStorage.getItem('lastfm') );
|
||||
lastfm = Object.assign(
|
||||
{},
|
||||
{
|
||||
session: null
|
||||
}
|
||||
);
|
||||
localStorage.setItem('lastfm', JSON.stringify(lastfm));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -52,9 +52,18 @@ class Track extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have lyrics, and we have just received our artists
|
||||
if (!nextProps.track.lyrics_results && !this.props.track.artists && nextProps.track.artists){
|
||||
this.props.geniusActions.findTrackLyrics(nextProps.track);
|
||||
// We have just received our full track info (with artists)
|
||||
if (!this.props.track.artists && nextProps.track.artists){
|
||||
|
||||
// Ready to load LastFM
|
||||
if (nextProps.lastfm_authorized){
|
||||
this.props.lastfmActions.getTrack(nextProps.track);
|
||||
}
|
||||
|
||||
// Ready to load lyrics
|
||||
if (!nextProps.track.lyrics_results){
|
||||
this.props.geniusActions.findTrackLyrics(nextProps.track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,14 +100,18 @@ 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 have artist info already
|
||||
if (props.track && props.track.artists){
|
||||
|
||||
// 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);
|
||||
// Get the LastFM version of this track (provided we have artist info)
|
||||
if (props.lastfm_authorized){
|
||||
this.props.lastfmActions.getTrack(props.track);
|
||||
}
|
||||
|
||||
// Ready for lyrics
|
||||
if (props.track && !props.track.lyrics_results){
|
||||
this.props.geniusActions.findTrackLyrics(props.track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,7 +231,7 @@ class Track extends React.Component{
|
||||
|
||||
<div className="actions">
|
||||
<button className="primary" onClick={e => this.play()}>Play</button>
|
||||
<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} />
|
||||
<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.track.userloved} />
|
||||
<ContextMenuTrigger onTrigger={e => this.handleContextMenu(e)} />
|
||||
</div>
|
||||
|
||||
@ -248,7 +261,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,
|
||||
lastfm_authorized: state.lastfm.session,
|
||||
spotify_authorized: state.spotify.authorization,
|
||||
mopidy_connected: state.mopidy.connected
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user