0

I have exchanged a token for a session key that looks like this "UserName 94ag345Sd3452C2ffa3aT 0"

I have the following code: session_key = 'UserName 94ag345Sd3452C2ffa3aT 0'

method = "track.scrobble"
artist = "Muse"
track = "Time Is Running Out"
timestamp = str(time.time())
api_sig = hashlib.md5(
f"api_key{API_KEY}artist{artist}method{method}sk{session_key}timestamp{timestamp}track{track}{API_SECRET}".encode('utf-8')).hexdigest()

header = {"user-agent" : "mediascrobbler/0.1",
      "Content-type": "application/x-www-form-urlencoded"}

# API URL
url = "https://ws.audioscrobbler.com/2.0/"

# Parameters for the POST request
params = {
    "api_key": API_KEY,
    "artist[0]": artist,
    "method": method,
    "sk": session_key,
    "timestamp[0]": timestamp,
    "track[0]": track,
    "api_sig": api_sig,
}

params['api_sig'] = api_sig


# Sending the POST request
try:
    response = requests.post(url, params=params, headers=header)
except requests.exceptions.RequestException as e:
    print(e)
    sys.exit(1)

return response.text

Why does it keep returning Invalid Method Signature? I have utf encoded my params. All required params are there. I've exchanged a token for a session key.

Update: If I set the api sig to look like this:

api_sig = hashlib.md5(
f"api_key{API_KEY}artist[0]{artist}method{method}sk{session_key}timestamp[0]{timestamp}track[0]{track}{API_SECRET}".encode('utf-8')

).hexdigest()

but this is returning Invalid session key - Please re-authenticate with a brand newly generated session key I know to be valid. If I'm not mistaken, those sessions don't expire.

KinsDotNet
  • 1,500
  • 5
  • 25
  • 53
  • I posted an answer suggesting using `pylast`. As to your specific error, I think you need to pass `params` as `params` kwarg: `response = requests.post(url, params=params)` – Tranbi Aug 14 '23 at 08:04
  • @Tranbi I have some project requirements that require me to make manual API calls. I don't want to use a library like lastpy, in fact I started with lastpy and have moved to manual calls. params=params didn't do the trick. Still getting the "Invalid method signature supplied" error. – KinsDotNet Aug 14 '23 at 15:32
  • Not sure if it helps you as I don't know that much about Python and how `requests.post` handles the `data` but from my Java code I can see that I perform a `URLEncoder.encode(val, StandardCharsets.UTF_8)` for every value in the `params` map. So maybe you could check how the body of the POST request is generated. // Maybe also worth trying to scrobble Muse song that only contains letters, e.g. "Animals". – jmizv Aug 16 '23 at 08:20

4 Answers4

1

You forgot to hexdigest your md5 signature in this line:

api_sig = hashlib.md5(
    f"api_key{API_KEY}artist[0]{artist}method{method}sk{session_key}timestamp[0]{timestamp}track[0]{track}{API_SECRET}".encode('utf-8')
)

This should work:

import time, requests, hashlib

# API method and parameters
API_KEY = 'API_KEY'
session_key = 'session_key'
API_SECRET = 'API_SECRET'
method = "track.scrobble"
artist = "Muse"
track = "Time Is Running Out"
timestamp = int(time.time())

api_sig = hashlib.md5(
    f"api_key{API_KEY}artist[0]{artist}method{method}sk{session_key}timestamp[0]{timestamp}track[0]{track}{API_SECRET}".encode('utf-8')
).hexdigest()
# API URL
url = "http://ws.audioscrobbler.com/2.0/"

# Parameters for the POST request
params = {
    "method": method,
    "api_key": API_KEY,
    "api_sig": api_sig,
    "sk": session_key,
    "artist[0]": artist,
    "track[0]": track,
    "timestamp[0]": timestamp,
}

# Sending the POST request
try:
    response = requests.post(url, data=params)
except requests.exceptions.RequestException as e:
    print(e)
    sys.exit(1)

print(response.text)

Response:

<?xml version="1.0" encoding="UTF-8"?>
<lfm status="ok">
  <scrobbles ignored="0" accepted="1">
    <scrobble>
      <track corrected="0">Time Is Running Out</track>
      <artist corrected="0">Muse</artist>
      <album corrected="0" />
      <albumArtist corrected="0"></albumArtist>
      <timestamp>1692987267</timestamp>
      <ignoredMessage code="0"></ignoredMessage>
    </scrobble>
  </scrobbles>
</lfm>
elebur
  • 465
  • 1
  • 5
  • Following this, I added the array indexes to the timestamp track and artist. Now I'm getting Invalid session key - Please re-authenticate with a newly generated session key I know to be valid. – KinsDotNet Aug 25 '23 at 05:03
  • I've updated the answer and added the code example. Before posting I checked it again, and it worked. I don't know the Lasf.fm API very well, but perhaps the "Invalid session key" problem is something that is not related to your initial question? Try calling some other method with this session key to ensure it's working. – elebur Aug 25 '23 at 18:32
  • This answer is correct. The reason that I was getting Invalid session key is because I thought the session key was in the format UserName 29a9d9a9df99aws... because that was returned when I did return response.text. I didn't realize, as I should have, that it was returning xml, and that the alphanumeric section was wrapped in the tag. If anyone sees this, switch to view source for api response calls. – KinsDotNet Aug 27 '23 at 04:33
0

I suggest using pylast. You'll be able to create a connection (code from the doc):

import pylast

# You have to have your own unique two values for API_KEY and API_SECRET
# Obtain yours from https://www.last.fm/api/account/create for Last.fm
API_KEY = "b25b959554ed76058ac220b7b2e0a026"  # this is a sample key
API_SECRET = "425b55975eed76058ac220b7b4e8a054"

# In order to perform a write operation you need to authenticate yourself
username = "your_user_name"
password_hash = pylast.md5("your_password")

network = pylast.LastFMNetwork(
    api_key=API_KEY,
    api_secret=API_SECRET,
    username=username,
    password_hash=password_hash,
)

Then provide artist, track name and timestamp to the scrobble method:

network.scrobble(artist, track, timestamp)
Tranbi
  • 11,407
  • 6
  • 16
  • 33
  • I have some project requirements that require me to make manual API calls. I don't want to use a library like lastpy, in fact I started with lastpy and have moved to manual calls – KinsDotNet Aug 14 '23 at 15:33
0

the order of parameters in params should be the same as they are in md5 hash. and also make sure your system time is ok

ahmadreza130
  • 66
  • 1
  • 5
0

The issue you are facing with the Last.fm API is related to the generation of the API signature. The API signature is used to ensure the integrity and authenticity of the request.

Looking at your code, i found that you are missing a few steps checkout these below i've mentioned.

  1. Ensure that you have the correct values for API_KEY and API_SECRET. Make sure they are valid and correspond to your Last.fm API credentials.

  2. Update the generation of the api_sig variable. The API signature should be an MD5 hash of the concatenated string of all the parameters, sorted alphabetically by parameter name. The parameter values should be URL-encoded. Here's the updated code for generating the api_sig:

api_sig = hashlib.md5(
    f"api_key{API_KEY}artist{artist}method{method}sk{session_key}timestamp{timestamp}track{track}{API_SECRET}".encode('utf-8')
).hexdigest()
  1. Update the params dictionary to include the updated api_sig:
params = {
    "method": method,
    "api_key": API_KEY,
    "api_sig": api_sig,
    "sk": session_key,
    "artist": artist,
    "track": track,
    "timestamp": timestamp,
}
  1. Make sure to use the urlencode from the urllib.parse module to encode the parameters when sending the POST request:
import urllib.parse

# ...

try:
    response = requests.post(url, data=urllib.parse.urlencode(params))
    response.raise_for_status()  # Check for any HTTP errors
except requests.exceptions.RequestException as e:
    print(e)
    sys.exit(1)

Hope that solves your issue there.

Haseeb Mir
  • 928
  • 1
  • 13
  • 22
  • With your changes plus the modifications outlined above, I'm now getting "Invalid session key - Please re-authenticate with a brand newly generated session key I know to be valid. " – KinsDotNet Aug 25 '23 at 05:15