Files
Iris/src/js/services/lastfm/actions.js

462 lines
15 KiB
JavaScript
Raw Normal View History

2016-11-07 21:21:15 +13:00
2017-11-10 15:56:01 +13:00
var coreActions = require('../core/actions');
var uiActions = require('../ui/actions');
var helpers = require('../../helpers');
2016-11-07 21:21:15 +13:00
/**
2017-11-04 14:03:59 +13:00
* Send an ajax request to the LastFM API
2016-11-07 21:21:15 +13:00
*
2017-11-04 14:03:59 +13:00
* @param dispatch = obj
* @param getState = obj
* @param params = string, the url params to send
2017-11-04 22:09:51 +13:00
* @params signed = boolean, whether we've got a signed request with baked-in api_key
2016-11-07 21:21:15 +13:00
**/
2017-11-04 22:09:51 +13:00
const sendRequest = (dispatch, getState, params, signed = false) => {
2017-10-10 13:05:28 +13:00
return new Promise((resolve, reject) => {
2016-11-07 21:21:15 +13:00
2017-11-04 22:09:51 +13:00
var loader_key = helpers.generateGuid();
var method = params.substring(params.indexOf("method=")+7, params.length);
method = method.substring(0, method.indexOf("&"));
dispatch(uiActions.startLoading(loader_key, 'lastfm_'+method));
2017-03-27 14:23:38 +13:00
var config = {
method: 'GET',
cache: true,
timeout: 30000,
2017-11-04 22:09:51 +13:00
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';
}
2017-10-10 13:05:28 +13:00
$.ajax(config).then(
2017-03-27 14:23:38 +13:00
response => {
2017-11-06 16:59:21 +13:00
dispatch(uiActions.stopLoading(loader_key));
if (response.error){
reject({
config: config,
error: response
});
} else {
resolve(response);
}
2017-03-27 14:23:38 +13:00
},
2016-11-07 21:21:15 +13:00
(xhr, status, error) => {
2017-11-06 16:59:21 +13:00
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
});
2016-11-07 21:21:15 +13:00
}
)
})
}
2017-11-04 22:09:51 +13:00
/**
* 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) => {
2017-11-06 16:59:21 +13:00
// Not authorized
if (!getState().lastfm.session){
reject({
params: params,
error: "No active LastFM session"
});
}
var loader_key = helpers.generateGuid();
var method = params.substring(params.indexOf("method=")+7, params.length);
method = method.substring(0, method.indexOf("&"));
dispatch(uiActions.startLoading(loader_key, 'lastfm_'+method));
2017-11-06 16:59:21 +13:00
params += "&sk="+getState().lastfm.session.key;
2017-11-04 22:09:51 +13:00
var config = {
method: 'GET',
cache: false,
timeout: 30000,
url: getState().lastfm.authorization_url+"?action=sign_request&"+params
}
// Get our server proxy to sign our request
2017-11-04 22:09:51 +13:00
$.ajax(config).then(
2017-11-06 16:59:21 +13:00
response => {
dispatch(uiActions.stopLoading(loader_key));
2017-11-06 16:59:21 +13:00
// Now we have signed params, we can make the actual request
sendRequest(dispatch, getState, response.params, true)
2017-11-06 16:59:21 +13:00
.then(
response => {
resolve(response);
},
error => {
reject(error);
}
);
},
(xhr, status, error) => {
dispatch(uiActions.stopLoading(loader_key));
reject(error)
}
);
2017-11-04 22:09:51 +13:00
})
}
2017-11-02 21:20:56 +13:00
export function set(data){
return {
type: 'LASTFM_SET',
data: data
}
}
/**
* Handle authorization process
**/
export function authorizationGranted(data){
data.session.expiry = new Date().getTime() + 3600;
return {
type: 'LASTFM_AUTHORIZATION_GRANTED',
data: data
}
2017-11-02 21:20:56 +13:00
}
export function revokeAuthorization(){
return { type: 'LASTFM_AUTHORIZATION_REVOKED' }
}
2017-11-04 14:03:59 +13:00
2017-11-04 14:03:59 +13:00
/**
* Non-signed requests
2017-11-04 14:03:59 +13:00
**/
export function getMe(){
2017-11-04 14:03:59 +13:00
return (dispatch, getState) => {
var params = 'method=user.getInfo&user='+getState().lastfm.session.name
sendRequest(dispatch, getState, params)
2017-11-04 14:03:59 +13:00
.then(
response => {
if (response.user){
dispatch({
type: 'LASTFM_USER_LOADED',
user: response.user
});
dispatch({ type: 'LASTFM_CONNECTED' })
}
2017-11-04 22:09:51 +13:00
}
)
}
}
export function getTrack(uri){
2017-11-04 22:09:51 +13:00
return (dispatch, getState) => {
if (getState().core.tracks[uri] !== undefined){
var track = getState().core.tracks[uri];
if (!track.artists){
dispatch(coreActions.handleException(
"Could not get track",
{},
"Track has no artists"
));
return;
}
} else {
dispatch(coreActions.handleException(
"Could not get track",
{},
"Could not find track in index"
));
return;
}
2017-11-04 14:03:59 +13:00
2017-11-10 15:56:01 +13:00
var track_name = track.name;
var artist_name = encodeURIComponent(track.artists[0].name);
var params = 'method=track.getInfo&track='+track_name+'&artist='+artist_name;
if (getState().lastfm.session){
params += '&username='+getState().lastfm.session.name;
2017-11-10 15:56:01 +13:00
}
sendRequest(dispatch, getState, params)
.then(
response => {
if (response.track){
var merged_track = Object.assign(
{},
{
uri: track.uri
},
response.track,
track
);
dispatch({
type: 'TRACK_LOADED',
track: merged_track
});
}
}
)
}
}
2017-10-10 13:05:28 +13:00
export function getArtist(uri, artist, mbid = false){
2018-02-20 16:59:32 +13:00
2016-11-07 21:21:15 +13:00
return (dispatch, getState) => {
2017-10-10 13:05:28 +13:00
if (mbid){
2016-11-07 21:21:15 +13:00
var params = 'method=artist.getInfo&mbid='+mbid
} else {
2018-02-20 16:59:32 +13:00
artist = artist.replace("&","and");
artist = encodeURIComponent(artist);
2016-11-07 21:21:15 +13:00
var params = 'method=artist.getInfo&artist='+artist
}
sendRequest(dispatch, getState, params)
.then(
response => {
2017-10-10 13:05:28 +13:00
if (response.artist){
2016-11-07 21:21:15 +13:00
dispatch({
2017-01-15 21:06:24 +13:00
type: 'ARTIST_LOADED',
artist: {
2017-11-09 09:12:23 +13:00
uri: uri,
2017-01-15 21:06:24 +13:00
images: response.artist.image,
2017-02-08 20:05:37 +13:00
bio: response.artist.bio,
listeners: parseInt(response.artist.stats.listeners),
play_count: parseInt(response.artist.stats.playcount),
on_tour: response.artist.stats.ontour
2017-01-15 21:06:24 +13:00
}
2016-11-07 21:21:15 +13:00
});
}
}
)
}
}
2017-10-10 13:05:28 +13:00
export function getAlbum(artist, album, mbid = false){
2016-11-07 21:21:15 +13:00
return (dispatch, getState) => {
2017-10-10 13:05:28 +13:00
if (mbid){
var params = 'method=album.getInfo&mbid='+mbid;
} else {
artist = encodeURIComponent(artist);
album = encodeURIComponent(album);
var params = 'method=album.getInfo&album='+album+'&artist='+artist;
2016-11-07 21:21:15 +13:00
}
sendRequest(dispatch, getState, params)
.then(
response => {
2017-10-10 13:05:28 +13:00
if (response.album){
dispatch(coreActions.albumsLoaded([response.album]));
2016-11-07 21:21:15 +13:00
}
}
);
}
}
export function getImages(context, uri){
return (dispatch, getState) => {
var record = getState().core[context][uri];
if (record){
switch (context){
case "tracks":
if (record.mbid){
var params = 'method=album.getInfo&mbid='+record.mbid;
} else if (record.artists && record.artists.length > 0 && record.album){
var artist = encodeURIComponent(record.artists[0].name);
var album = encodeURIComponent(record.album.name);
var params = 'method=album.getInfo&album='+album+'&artist='+artist;
}
if (params){
sendRequest(dispatch, getState, params)
.then(
response => {
if (response.album){
record = Object.assign({}, record, {images: response.album.image});
dispatch(coreActions.tracksLoaded([record]));
dispatch(coreActions.albumsLoaded([response.album]));
}
}
);
}
break;
case "albums":
if (record.mbid){
var params = 'method=album.getInfo&mbid='+record.mbid;
} else if (record.artists && record.artists.length > 0){
var artist = encodeURIComponent(record.artists[0].name);
var album = encodeURIComponent(record.name);
var params = 'method=album.getInfo&album='+album+'&artist='+artist;
}
if (params){
sendRequest(dispatch, getState, params)
.then(
response => {
if (response.album){
record = Object.assign({}, record, {images: response.album.image});
dispatch(coreActions.albumsLoaded([record]));
}
}
);
}
break;
}
}
2016-11-07 21:21:15 +13:00
}
}
/**
* Signed requests
**/
export function loveTrack(uri){
2016-11-07 21:21:15 +13:00
return (dispatch, getState) => {
if (getState().core.tracks[uri] !== undefined){
var track = getState().core.tracks[uri];
if (!track.artists){
dispatch(coreActions.handleException(
"Could not love track",
track,
"Track has no artists"
));
return;
2017-11-06 16:59:21 +13:00
}
} else {
dispatch(coreActions.handleException(
"Could not love track",
track,
"Could not find track in index"
));
return;
2017-11-04 22:09:51 +13:00
}
var artist = encodeURIComponent(track.artists[0].name);
var params = 'method=track.love&track='+track.name+'&artist='+artist;
sendSignedRequest(dispatch, getState, params)
.then(
response => {
track = Object.assign(
{},
track,
{
userloved: true
}
);
dispatch({
type: 'TRACKS_LOADED',
tracks: [track]
});
}
);
}
}
export function unloveTrack(uri){
return (dispatch, getState) => {
if (getState().core.tracks[uri] !== undefined){
var track = getState().core.tracks[uri];
if (!track.artists){
dispatch(coreActions.handleException(
"Could not unlove track",
track,
"Track has no artists"
));
return;
}
} else {
dispatch(coreActions.handleException(
"Could not unlove track",
track,
"Could not find track in index"
));
return;
2017-11-04 22:09:51 +13:00
}
var artist = encodeURIComponent(track.artists[0].name);
var params = 'method=track.unlove&track='+track.name+'&artist='+artist;
sendSignedRequest(dispatch, getState, params)
2016-11-07 21:21:15 +13:00
.then(
response => {
track = Object.assign(
{},
track,
{
userloved: false
}
);
dispatch({
type: 'TRACKS_LOADED',
tracks: [track]
});
2016-11-07 21:21:15 +13:00
}
);
2016-11-07 21:21:15 +13:00
}
}
2017-11-14 21:02:33 +13:00
/**
* TODO: Currently scrobbling client-side would result in duplicated scrobbles
* if the user was authorized across multiple connections. Ideally this would
* be handled server-side. Mopidy-Scrobbler currently achieves this.
**/
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='+Math.floor(Date.now() / 1000);
sendSignedRequest(dispatch, getState, params)
.then(
response => {
console.log("Scrobbled", response);
},
error => {
dispatch(coreActions.handleException(
'Could not scrobble track',
error,
(error.description ? error.description : null)
));
}
)
}
}