Loving track; Investigating scrobbling

This commit is contained in:
James Barnsley
2017-11-06 16:59:21 +13:00
parent ffba601e4b
commit 2d3d4c351a
5 changed files with 140 additions and 55 deletions

View File

@ -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>

View File

@ -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 += '&timestamp='+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)
));
}
)
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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
};