MelanciaUK MelanciaUK - 2 months ago 18
Javascript Question

Can't scrobble tracks (batch) to Last.fm API. Invalid method signature

I've been trying this for a while now, but I can't get my head around what's wrong. Maybe I've tried so many ways that I'm not even sure this piece of code is right anymore.

Basically I'm trying to use the

track.scrobble
method from the Last.fm API, sending a batch of tracks.

That's the code I have, and it's always returning
Invalid method signature
. Does anyone can give me some help here, please?

UPDATE

Based on mccannf answer, I've changed the code, but am still getting the error:

var apiUrl = "http://ws.audioscrobbler.com/2.0/";
var apiMethod = "track.scrobble";
var apiKey = "MY_API_KEY";
var apiSecret = "MY_API_SECRET";
var key = "MY_SESSION_KEY";
var apiSig = "";

var lastfmScrobble = function (data) {
var dataToScrobble = setTiming(data);

var albums = [];
var artists = [];;
var timestamps = [];
var tracks = [];
var dataToHash = "";

for (var i = 0; i < dataToScrobble.tracks.length; i++) {
albums["album["+ i.toString() + "]"] = dataToScrobble.album;
artists["artist[" + i.toString() + "]"] = dataToScrobble.artist;
timestamps["timestamp[" + i.toString() + "]"] = dataToScrobble.tracks[i].split("|")[1];
tracks["track[" + i.toString() + "]"] = dataToScrobble.tracks[i].split("|")[0];
}

dataToHash += albums.sort().join("");
dataToHash += "api_key" + apiKey;
dataToHash += artists.sort().join("");
dataToHash += "method" + apiMethod;
dataToHash += "sk" + key;
dataToHash += timestamps.sort().join("");
dataToHash += tracks.sort().join("");
dataToHash += apiSecret;

apiSig = $.md5(unescape(encodeURIComponent(dataToHash)));

var songsToScrobble = {};

$.extend(songsToScrobble,
albums.sort(),
{ api_key: apiKey },
{ api_sig: apiSig },
artists.sort(),
{ method: apiMethod },
{ sk: key },
timestamps.sort(),
tracks.sort());

$.ajax({
url: apiUrl,
type: "POST",
data: songsToScrobble,
success: function (data) {
console.log(data);
}
});
}


Now the object sent has the correct format (JSON). What can still be wrong?

Answer

I did a quick sample JS Fiddle of your code.

The dataToHash is like this:

 album[0]Achtung Babyalbum[1]Achtung Babyapi_keyxxxBLAHxxxartist[0]U2artist[1]U2methodtrack.scrobbleskkkkFOOkkktimestamp[0]1379368800timestamp[1]1379369000track[0]Onetrack[1]The FlymmmySecrettt 

The songsToScrobble variable in the code above looked like this:

 { "album": [ 
              "album[0]Achtung Baby",
              "album[1]Achtung Baby"
            ], 
   "api_key":"xxxBLAHxxx",
   "api_sig":"8dbc147e533411a41ba9169f59e65b3a",
   "artist":["artist[0]U2","artist[1]U2"],          
   "method": "track.scrobble", 
   "sk":"kkkFOOkkk" 
   "timestamp": [
                  "timestamp[0]1379368800",
                  "timestamp[1]1379369000"
                ],
   "track": [ 
              "track[0]One",
              "track[1]The Fly"
            ]
  } 

I believe songsToScrobble should look like this:

 { "album[0]": "Achtung Baby",
   "album[1]": "Achtung Baby",
   "api_key":"xxxBLAHxxx",
   "api_sig":"8dbc147e533411a41ba9169f59e65b3a",
   "artist[0]": "U2",
   "artist[1]": "U2",          
   "method": "track.scrobble", 
   "sk":"kkkFOOkkk" 
   "timestamp[0]": "1379368800",
   "timestamp[1]": "1379369000",
   "track[0]": "One",
   "track[1]": "The Fly"
  } 

Only other minor point is to make sure dataToHash is UTF-8 encoded before you convert to MD5 hash.

Edit

This is how I created the data for the ajax call. NOTE: this is untested - I don't have a last.fm account.

var songsToScrobble = {};

function addDataToScrobble(parentElement, inputData) {
    if ($.isArray(inputData)) {
      $.each(inputData, function(index ,element) {
         songsToScrobble[parentElement + "[" + index + "]"] = element;
         dataToHash += parentElement + "[" + index + "]" + element;
      });
    } else {
      songsToScrobble[parentElement] = inputData;
      dataToHash += parentElement + inputData;
    }
}

for (var i = 0; i < data.tracks.length; i++) {
     albums.push(data.album);
     artists.push(data.artist);
     // The tracks are coming in the format: title|timestamp
     timestamps.push(data.tracks[i].split("|")[1]);
     tracks.push(data.tracks[i].split("|")[0]);     
}

addDataToScrobble("album", albums);
addDataToScrobble("api_key", apiKey);
addDataToScrobble("artist", artists);
addDataToScrobble("method", apiMethod);
addDataToScrobble("sk", key);
addDataToScrobble("timestamp", timestamps);
addDataToScrobble("track", tracks);

apiSig = $.md5(unescape(encodeURIComponent(dataToHash+apiSecret)));

songsToScrobble["api_sig"] = apiSig;

$.ajax({
    url: apiUrl,
    type: "POST",
    data: songsToScrobble,
    success: function (data) { 
        console.log(data);
    }
});
Comments