Author Topic: Display last.fm scrobble/now playing  (Read 314 times)

Blind Joe

  • Newbie
  • *
  • Posts: 33
    • View Profile
Display last.fm scrobble/now playing
« on: May 07, 2022, 11:36:12 AM »
Perhaps a bit of a long shot but does anyone know if it's possible to display the song I'm currently playing, as fetched from last.fm to which it's being scrobbled, in a layout cell?

I know that it's possible to pull this information from the last.fm api in the form of an html display but I don't know how to use this information in any meaningful way.

Corey Cooper

  • Administrator
  • Hero Member
  • *****
  • Posts: 6064
    • View Profile
Re: Display last.fm scrobble/now playing
« Reply #1 on: May 09, 2022, 10:23:17 AM »
If a simple GET request to a URL returns HTML, then the answer is probably.  I don't use last.fm, but I looked briefly through their API documentation and (a) it looks like it requires authentication (doesn't necessarily rule out use, but makes it more complicated for sure) and (b) I couldn't find anything that returns HTML.  It looks like a typical API which will return data as JSON or XML, which would then have to be processed.  If there's an endpoint that returns HTML, it could be put into an iframe:

<iframe src="http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=USERNAME&limit=1&nowplaying=true&api_key=XXXX&format=html" style="height: 100px; width: 200px"></iframe>

But of course the above won't work because "html" is not a valid format (json and xml are valid formats).  From the above you'll get back something like:

<lfm status="ok">
  <recenttracks user="USERNAME" page="1" perPage="1" totalPages="0" total="0"/>
</lfm>


or

{
  "recenttracks": {
    "track": [],
    "@attr": {
      "user": "USERNAME",
      "totalPages": "0",
      "page": "1",
      "perPage": "1",
      "total": "0"
    }
  }
}


Neither of these you would want to display.  They would require code to process and build HTML.  You might be able to use something like this:

https://github.com/devteaminc/Last.fm-Now-Playing-Widget

With that HTML file and JS file just in a folder on your hard drive.  But I can't say if the security features in Chromium will allow it to reach out to another server or not.  If I get some time I'll try this out.

Corey Cooper

  • Administrator
  • Hero Member
  • *****
  • Posts: 6064
    • View Profile
Re: Display last.fm scrobble/now playing
« Reply #2 on: May 10, 2022, 05:09:27 PM »
OK, so update: this is definitely possible.  The Now Playing widget I referenced is essentially for embedding the currently playing song in a web page, which is very similar but different enough that it wasn't really right for the TD.  I played around with it and got it working.

Here is the cell contents I used:
Code: [Select]
What's Playing?<br>
<iframe src="lastfm.html" style="height: 110px; border: none"></iframe>

And the following code is referenced by the cell contents.  Save this to a file named lastfm.html.  Wherever you save it, you'll need to put the full path to it in the "src" attribute in the cell contents (above).  So if you save it to C:\temp\lastfm.html, the above needs to be <iframe src="C:\temp\lastfm.html" style....  Also update it with your Last.fm API key and user name:

Code: [Select]
<html>
  <head>
  <script
    src="https://code.jquery.com/jquery-3.6.0.js"
    integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
    crossorigin="anonymous">
  </script>

  <script>
  let apiKey = "YOUR-API-KEY-GOES-HERE"
  let username = "YOUR-USERNAME-GOES-HERE"
  let frequency = 3 // check every 3 seconds
  let template = ""

  function update() {
    $.ajax({
      url: "http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=" + username
        + "&limit=1&nowplaying=true&api_key=" + apiKey + "&format=json",
      dataType: "json"
    }).done(data => {
      try {
        let tracks = data.recenttracks.track

        for(let track of tracks) {
          // Check if track is now playing.  It won't have a timestamp so add one.
          if(track.hasOwnProperty("@attr"))
            track.date = Date.now()
          else
            track.date = parseInt(track.date.uts, 10)
        }

        tracks = tracks.sort((a, b) => { return b.date - a.date })

        let track = tracks.length ? tracks[0] : null
        let html = template
          .replace("{track.artist}", track ? track.artist["#text"] : "")
          .replace("{track.title}", track ? track.name : "")
          .replace("{track.album}", track ? track.album["#text"] : "")
        $("#songInfo").html(html)
      } catch(ex) {
      }

      window.setTimeout(update, frequency * 1000)
    })
  }

  $(document).ready(() => {
    template = $("#songInfo").html()
    update()
  })

  </script>
  </head>
  <body style="color: #000; font-family: Segoe UI; font-size: 15pt">
    <div>
      <div id="songInfo">
        <div style="background: #fffc; padding: 5px;">Title: {track.title}</div>
        <div style="background: #fff8; padding: 5px;">Artist: {track.artist}</div>
        <div style="background: #fff4; padding: 5px; color: #fff8;">Album: {track.album}</div>
      </div>
      </div>
  </body>
</html>

This uses jquery because the example I took it from used jquery, but the reliance on jquery could pretty easily be removed.

Basically this code queries the last.fm API every 3 seconds to find your currently playing track.  If one isn't being played, it should display the last played track.  I am brand new to last.fm so there's really very little I know about it, but this seemed to work for the account I created.  There's more data that is returned by the API, including an image, if you want to spruce it up a bit.  With my limited testing, I didn't see any actual album name or album art returned, so your results may vary.

« Last Edit: May 11, 2022, 08:22:39 AM by Corey Cooper »