1️⃣🌓🌎
(📃),(🖼️)

🌞 The Sun is currently in 'Twilight Poetry' phase! 🌒
Gregorian: 08/26/2025
Julian: 2460914 -> 08/13/2025
AE Calendar: AE 1, Month 6, Day 14 (Tuesday)

Moon Phase: First Quarter 🌓
Species: Aardwolf 🐾
Were-Form: WereAardwolf 🐾
Consciousness: 2.1263122248558224/20 (10.631561124279113%)
Miade-Score/Infini-Vaeria Consciousness: 0.8936843887572089% (1.8987470369116275%)

120🕰️11:72 PST



🏷️last.fm

Accessing the last.fm API

🔗(19)
📅 2025-07-12 23:53:17 -0700
⏲️🔐 2025-07-12 23:53:40 -0700
✍️ infinivaeria
🏷️[last.fm] [api access] [rustby-c] 
(🪟)

🖥️...⌨️

Retrieving the Current “Now Playing” Track from Last.fm API in Rust, Ruby, and Crystal

Last.fm’s API allows you to fetch a user’s currently scrobbling song (“now playing” track) if available. In this guide, we’ll walk through obtaining an API key, calling the Last.fm API for the latest track, and writing the output to a text file. We demonstrate the process in three languages – Rust, Ruby, and Crystal (the “Rustby-C” paradigm) – with step-by-step instructions and code examples for each.


Last.fm API Setup and Key Registration

Before coding, you need to sign up for Last.fm’s API and get an API key:

  1. Create a Last.fm Account: If you don’t have one, register on Last.fm (or log in if you already have an account).
  2. Apply for an API Key: Visit the Last.fm API page and click “Get an API account”. Fill out the “Create an API account” form with a name and description for your application (you can use any name/description), and you can leave the callback URL blank. Submit the form.
  3. Copy Your API Key: After submission, Last.fm will display your new API Key (a string of letters and numbers) on the screen. Copy this key – you’ll use it in your API calls (Last.fm also provides a secret, but for reading public data like now-playing tracks, only the key is needed).

Your API key is essential for authenticating requests to Last.fm’s API. Keep it secure and do not share it publicly.


Identifying the Correct API Method (Now Playing Track)

Last.fm’s API method to retrieve a user’s recent tracks (including the current track) is user.getRecentTracks. This REST endpoint returns a list of a user’s recently scrobbled tracks. If the user is currently listening to a song, the first track in the list will be marked with a special attribute indicating it’s now playing. Specifically, the JSON/XML includes nowplaying="true" on that track entry.

  • Endpoint: https://ws.audioscrobbler.com/2.0/
  • Method: user.getRecentTracks
  • Required Parameters:
    user – the Last.fm username whose track you want to fetch.
    api_key – your API key obtained earlier.
    format – set to json for JSON response (easier to parse in code).

For example, a GET request URL looks like:

https://ws.audioscrobbler.com/2.0/?method=user.getRecentTracks&user=LASTFM_USERNAME&api_key=YOUR_API_KEY&format=json

Replace LASTFM_USERNAME with the target username and YOUR_API_KEY with the key you obtained. You can test this URL in a web browser or with a tool like curl. The response will be a JSON object containing the recent tracks. The currently playing track (if any) will appear as the first track entry with a @attr.nowplaying flag set to "true". If the user isn’t playing anything at the moment, the first entry will just be the last played track (with a timestamp).

Response structure: The JSON will look roughly like:

{
  "recenttracks": {
    "track": [
      {
        "artist": { "#text": "Artist Name", ... },
        "name": "Song Title",
        "album": { "#text": "Album Name", ... },
        "url": "https://www.last.fm/music/Artist+Name/_/Song+Title",
        "@attr": { "nowplaying": "true" }
      },
      {
        "artist": { "#text": "Previous Artist", ... },
        "name": "Previous Song",
        "date": { "uts": "1699478400", "#text": "08 Nov 2023, 10:00" }
      },
      ...
    ]
  }
}

In the above, the first track has "nowplaying": "true" indicating it’s currently being scrobbled. Our code will need to check for this attribute and retrieve that track’s name and artist. According to Last.fm’s docs, user.getRecentTracks does not require user authentication for public profiles, so the API key alone is sufficient.

💡 Note: The now playing attribute will only be present if the user’s scrobbler updates Last.fm in real-time. Some music players (or scrobbling apps) update “currently listening” status continuously, while others (like certain older scrobblers) only submit tracks after they finish. If you don’t see a nowplaying flag in the response even when music is playing, it could be due to the scrobbler’s behavior rather than an API limitation.


Implementing the Solution in Rust

In Rust, we can use the reqwest crate to handle the HTTP GET request and serde_json to parse the JSON response. This approach lets us easily fetch the data and extract the track information without writing a lot of low-level code. We’ll also use Rust’s file I/O from the standard library to write the output to a text file.

Setting up the Rust Environment

Make sure you have Rust installed (via rustup) and set up a new project (cargo new lastfm_nowplaying). In your Cargo.toml, add dependencies for reqwest (with the json feature) and serde_json for JSON parsing, as well as tokio if using async. For example, you can run:

cargo add tokio -F full
cargo add reqwest -F json
cargo add serde_json

This will include the necessary crates. The reqwest crate’s JSON feature allows directly parsing the response as JSON. We’ll use the synchronous API here for simplicity (via reqwest::blocking) to avoid dealing with async in the example.

Rust Code: Fetching and Writing Now Playing Track

Below is a Rust code snippet that retrieves the current track and writes “Artist - Title” to nowplaying.txt:

use reqwest::blocking;
use serde_json::Value;
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = "YOUR_LASTFM_API_KEY";
    let user = "LASTFM_USERNAME";
    // Construct the API URL
    let url = format!(
        "https://ws.audioscrobbler.com/2.0/?method=user.getRecentTracks&user={}&api_key={}&format=json",
        user, api_key
    );

    // Send GET request to Last.fm API
    let resp_text = blocking::get(&url)?.text()?;
    // Parse the JSON response
    let data: Value = serde_json::from_str(&resp_text)?;
    // Navigate to the first track in the JSON structure
    let tracks = &data["recenttracks"]["track"];
    if tracks.is_null() {
        eprintln!("No tracks found for user {}", user);
        return Ok(());
    }
    // Handle case where recenttracks.track might be an object or array
    let first_track = if tracks.is_array() {
        &tracks[0]
    } else {
        // If only one track, the API might return a single object instead of an array
        tracks
    };
    // Extract track name and artist
    let track_name = first_track["name"].as_str().unwrap_or("Unknown Track");
    let artist_name = first_track["artist"]["#text"].as_str().unwrap_or("Unknown Artist");
    // Check the nowplaying attribute
    let nowplaying_attr = first_track.get("@attr").and_then(|attr| attr.get("nowplaying"));
    let is_now_playing = nowplaying_attr.map_or(false, |v| v == "true");

    // Prepare output string
    let output_line = format!("{} - {}", artist_name, track_name);
    // Write to text file
    fs::write("nowplaying.txt", &output_line)?;
    println!("{}", if is_now_playing {
        format!("Currently playing: {}", output_line)
    } else {
        format!("Last played: {}", output_line)
    });
    Ok(())
}

How it works: This Rust program builds the request URL with your provided user and api_key, then uses reqwest::blocking::get to fetch the data. The response body (in JSON text) is parsed into a serde_json::Value structure for easy querying. We then access data["recenttracks"]["track"][0] to get the first track entry. We retrieve the "name" and the artist’s "#text" field (the artist name) from the JSON. We also look for the optional @attr.nowplaying flag. If nowplaying is "true", we know this track is currently being played. Finally, we format “Artist - Track” as a single line and write it to nowplaying.txt using Rust’s std::fs::write function, which conveniently creates/overwrites the file and writes the given text in one call.

The Rust code uses safe unwrapping (unwrap_or) in case fields are missing, and it checks for both array and object cases for recenttracks["track"] because Last.fm’s JSON can return either an array of tracks or a single track object if there’s exactly one recent track. We handle both for robustness. Writing to the file is done via fs::write, but you could also manually use File::create and write_all if preferred.

Run the program: Build and run (cargo run --release). The console should print out the track it found, and you should see a new file nowplaying.txt with the content “Artist - Title” corresponding to the user’s current or last track.


Implementing the Solution in Ruby

Ruby has very convenient built-in libraries for making HTTP requests and handling JSON. We don’t even need an external gem to call the Last.fm API. We’ll use OpenURI (an easy wrapper over Net::HTTP) to fetch the URL and Ruby’s JSON library to parse the response. Then, we use Ruby’s file I/O to save the result.

Ruby Code: Fetching and Writing Now Playing Track

Make sure you have Ruby installed (any recent version 2.x or 3.x). The following script demonstrates the process:

require 'open-uri'   # allows opening URLs like files
require 'json'       # JSON parsing

api_key = "YOUR_LASTFM_API_KEY"
user    = "LASTFM_USERNAME"
url     = "https://ws.audioscrobbler.com/2.0/?method=user.getRecentTracks&user=#{user}&api_key=#{api_key}&format=json"

# Fetch the JSON data from Last.fm API
response = URI.open(url).read  # OpenURI treats the URL like a file and reads it
data = JSON.parse(response)

# Extract the first track from the response
tracks = data.dig("recenttracks", "track")
first_track = tracks.is_a?(Array) ? tracks.first : tracks  # handle array or single object
if first_track.nil?
  puts "No track info found for user #{user}"
  exit
end

track_name = first_track["name"] || "Unknown Track"
artist_name = first_track.dig("artist", "#text") || "Unknown Artist"
nowplaying = first_track.dig("@attr", "nowplaying") == "true"

output_line = "#{artist_name} - #{track_name}"
File.write("nowplaying.txt", output_line)  # writes the string to file (overwrites if exists)

if nowplaying
  puts "Currently playing: #{output_line}"
else
  puts "Last played: #{output_line}"
end

Explanation: We use URI.open (from OpenURI) to send a GET request to the Last.fm API endpoint. OpenURI makes it trivial to retrieve the contents of a URL as if it were a local file – the URI.open(...).read call returns the response body as a string. We then parse that string into a Ruby hash using JSON.parse. The current track data is nested under ["recenttracks"]["track"]. In Ruby, this might be either an Array (if multiple recent tracks) or a Hash (if only one track in history), so we check is_a?(Array) and take the first element if it’s an array. We then pull out the "name" and "artist"]["#text"] fields for the track title and artist. To see if it’s now playing, we look for the optional ["@attr"]["nowplaying"] flag and compare it to "true".

Finally, we use File.write to write the output to a text file. The File.write method in Ruby is a simple one-liner that opens (or creates) the file, writes the given content, and closes the file automatically. In our case, it will create/overwrite nowplaying.txt with a line like Artist Name - Song Title. We also print a message to the console indicating whether it’s the current track or just the last played track.

Note: OpenURI is part of Ruby’s standard library and conveniently handles HTTP redirects and SSL. It’s suitable for simple use cases. For more complex needs or to handle errors, you might use Net::HTTP directly or a gem like HTTParty. Here, OpenURI keeps the code concise.

Run the script: Save it as lastfm_nowplaying.rb and run ruby lastfm_nowplaying.rb. The script will create/update nowplaying.txt in the current directory with the now-playing info.

Alternative Ruby approach: Instead of manual requests, you could use the community-provided ruby-lastfm gem, which wraps Last.fm API methods in Ruby objects. Using that gem, you would initialize a client with your API key and secret, then call something like lastfm.user.get_recent_tracks(user: "name") to get a Ruby array/hash of tracks. Under the hood it’s doing the same HTTP call. For a short script, using the standard libraries as shown is straightforward and avoids extra dependencies.


Implementing the Solution in Crystal

Crystal is a language with Ruby-like syntax, compiled for performance. It has a standard library that includes an HTTP client and JSON parsing, making the task very similar to the Ruby approach. We’ll use Crystal’s built-in HTTP::Client for the GET request and JSON.parse for parsing.

Crystal Code: Fetching and Writing Now Playing Track

Make sure Crystal is installed on your system. Create a file lastfm_nowplaying.cr with the following content:

require "http/client"
require "json"

api_key = "YOUR_LASTFM_API_KEY"
user    = "LASTFM_USERNAME"
url     = "https://ws.audioscrobbler.com/2.0/?method=user.getRecentTracks&user=#{user}&api_key=#{api_key}&format=json"

# Send GET request to Last.fm API
response = HTTP::Client.get(url)                        # perform HTTP GET and get a Response
if response.status_code != 200
  puts "HTTP request failed with code #{response.status_code}"
  exit
end

# Parse JSON response body into a dynamic structure (JSON::Any)
data = JSON.parse(response.body)

# Access the recenttracks.track data
tracks = data["recenttracks"]["track"]
first_track = tracks.is_a?(Array) ? tracks[0] : tracks   # Crystal JSON::Any allows .is_a?(Array)
if first_track.nil?
  puts "No track info found for user #{user}"
  exit
end

track_name = first_track["name"].as_s || "Unknown Track"
artist_name = first_track["artist"]["#text"].as_s || "Unknown Artist"
now_playing_attr = first_track["@attr"]?["nowplaying"]?  # use nil-safe navigation
is_now_playing = now_playing_attr.as_s? == "true"

output_line = "#{artist_name} - #{track_name}"
File.write("nowplaying.txt", output_line)               # write output to file (creates or truncates)

if is_now_playing
  puts "Currently playing: #{output_line}"
else
  puts "Last played: #{output_line}"
end

Explanation: After requiring http/client and json, we construct the request URL similarly to the other languages. We then call HTTP::Client.get(url), which returns an HTTP::Client::Response object synchronously. We check that the status_code is 200 (OK). The response body is accessible via response.body as a String. Crystal’s JSON.parse returns a JSON::Any (a type that can hold any JSON structure). We navigate through this JSON structure by keys: data["recenttracks"]["track"]. This returns another JSON::Any which could be an Array or single object. We check tracks.is_a?(Array) to decide how to extract the first track (Crystal’s JSON library provides type query methods like is_a?(Array) on JSON::Any).

Once we have first_track, we pull the "name" and nested "artist"]["#text"] values. In Crystal, JSON::Any provides methods like .as_s to convert to string, and returns nil if the value is not present or not a string. We use || "Unknown Track" to default in case of nil. To check the now playing flag, we safely navigate to first_track["@attr"] and then ["nowplaying"] using the ? operator (which yields nil if any part is missing). We then get the string value and compare to "true". The logic is similar to the Ruby version.

Finally, we use File.write("nowplaying.txt", output_line) to write the result to a file. Crystal’s File.write is analogous to Ruby’s: it opens (creates if needed) the file, writes the given content, and closes it, in one call. We print out a message indicating whether it’s currently playing or just last played.

Compile and run: Compile the Crystal program with crystal build --release lastfm_nowplaying.cr. Running the resulting binary will create/update the nowplaying.txt file with the song info.

Because Crystal compiles to a native binary, this tool can be very fast and suitable for command-line use or cron jobs (e.g., to periodically update a “now playing” text file for a streaming overlay or a website).


Alternate Approaches and Libraries

The above sections show how to directly use the Last.fm REST API in three languages. If the official API did not meet your needs or you prefer not to handle HTTP/JSON manually, there are a few alternatives and third-party libraries to consider:

  • Higher-level API Wrappers: Many community libraries simplify interactions with Last.fm. For example, in Rust you could use the lastfm crate, which provides a Client abstraction and even a now_playing() method to get the current track directly. In Ruby, the ruby-lastfm gem (by Youpy) offers methods corresponding to each API call (e.g., lastfm.user.get_recent_tracks) and handles the HTTP under the hood. Using these can reduce boilerplate; however, adding a dependency is only worth it if you plan to use many API features. In our simple scenario, the raw HTTP approach is fairly straightforward in each language.

  • Alternate Data Sources: If Last.fm’s API didn’t provide the now playing song, one could consider other means. For instance, some users embed now playing info by using the Spotify API (if they listen via Spotify) or by reading from a local music player’s API/IPC (like MPD or iTunes integrations). Another option is using an open scrobbling service like ListenBrainz which has its own API. Fortunately, Last.fm’s user.getRecentTracks does support retrieving the current track as we’ve demonstrated, so usually you won’t need these workarounds.

  • Automation and Integration: With the above code, you can periodically run the script/binary (using a scheduler or cron job) to update the text file whenever you want. If you are displaying this on a website, ensure the site reads the latest contents of nowplaying.txt or set up a small server to serve this info. For example, a simple approach could be to have a job update an HTML snippet or JSON file that your webpage can fetch. On a desktop (e.g., streaming setup), you might just load the text file contents directly into your overlay tool.

Remember that the Last.fm API is rate-limited (typically 1 request per second, and a few hundred calls per day for free accounts). For a “currently playing” display, updating once every 60 seconds is more than enough in most cases (or even less frequently, as tracks usually last a few minutes).


Summary of Steps and Tools

The table below summarizes the key steps to achieve this and the tools or libraries used in each language:

Step Rust Implementation Ruby Implementation Crystal Implementation
1. Get API Key Register via Last.fm website to obtain API key. Same process (API key is language-agnostic). Same process (API key is language-agnostic).
2. Construct API Request Use reqwest to build and send GET request (REST URL with query params). Use OpenURI (URI.open) to fetch the URL as text. Use HTTP::Client.get from stdlib to send GET request.
3. Parse JSON Response Use serde_json to parse into Value (dynamic JSON) and traverse to track info. Use built-in JSON.parse to get Ruby Hash/Array. Use JSON.parse to get JSON::Any and navigate keys.
4. Identify Now-Playing Track Check Value for recenttracks.track[0].@attr.nowplaying == "true" to confirm current track. Check first track Hash for "@attr"]["nowplaying"] == "true". Check first track JSON::Any for ["@attr"]["nowplaying"] == "true".
5. Extract Song & Artist Extract track["name"] and track["artist"]["#text"] from JSON Value. Extract hash["name"] and hash["artist"]["#text"] from parsed Hash. Extract any["name"].as_s and any["artist"]["#text"].as_s from JSON::Any.
6. Write to Text File Use Rust std::fs::write or File::create + write_all to save output. Use File.write to create/overwrite file with content. Use File.write (Crystal) to write string to file.
Tools/Libraries Used reqwest HTTP client, serde_json for JSON, Rust std fs for file I/O. Ruby stdlib (OpenURI, JSON, File class), no extra gem required. Crystal stdlib (HTTP::Client, JSON, File class), no extra shard required.
Optional: Third-Party Lib lastfm crate provides a higher-level API (e.g. now_playing() method). ruby-lastfm gem wraps the API methods (e.g. user.get_recent_tracks). (No dedicated Last.fm shard known; use HTTP/JSON as above.)

Each implementation follows the same basic flow: get API key → call Last.fm API → parse JSON → find current track → write to file. By leveraging each language’s strengths (Rust’s type safety and speed, Ruby’s elegance and brevity with open-uri, Crystal’s convenient syntax with compiled performance), you can achieve the goal in whichever environment you prefer. The resulting nowplaying.txt will contain the track info, ready to be used wherever needed (website, overlay, etc.), updating whenever the script is run.

I'll start researching how to interact with the Last.fm API to fetch the current scrobbling song and write it to a text file, using Rust, Ruby, and Crystal as part of the Rustby-C paradigm. This will include a step-by-step guide for signing up for the API, making the necessary API calls, and implementing the functionality. If the Last.fm API doesn't support this directly, I'll explore alternative methods or third-party libraries that can achieve the same goal. This will take me some time, so feel free to step away—I’ll keep working in the background and save the report in this conversation for you to review later!


📐 0.00099s [0.99087ms]


♾️75,422 -- (c)Miaed-Score -- (v#️⃣15.0.0.3):[ 🏗️May 26, 2025 - "Muskium Source 👃🩲🍆⚽⚽🦨" ]

August, 25, 2025 - 06:33:09 PM SLT/PST




🏘️[🌐216.73.216.133]

[➕🔒]|[➖🔒]





    # The 23 fabled moon rotations with emojis:
        MOON_ROTATIONS = [
          'New Moon 🌑',            # 0
          'Waxing Crescent 🌒',     # 1
          'First Quarter 🌓',       # 2
          'Waxing Gibbous 🌔', # 3
          'Full Moon 🌕',           # 4
          'Waning Gibbous 🌖',      # 5
          'Last Quarter 🌗',        # 6
          'Waning Crescent 🌘',     # 7
          'Supermoon 🌝',           # 8
          'Blue Moon 🔵🌙',         # 9
          'Blood Moon 🩸🌙',        # 10
          'Harvest Moon 🍂🌕',      # 11
          "Hunter's Moon 🌙🔭",     # 12
          'Wolf Moon 🐺🌕',         # 13
          'Pink Moon 🌸🌕',
          'Snow Moon 🌨️',          # 14
          'Snow Moon Snow 🌨️❄️',    # 15
          'Avian Moon 🦅',          # 16
          'Avian Moon Snow 🦅❄️',    # 17
          'Skunk Moon 🦨',           # 18
          'Skunk Moon Snow 🦨❄️',    # 19
        ]

        # Define 23 corresponding species with emojis.
        SPECIES = [
          'Dogg 🐶', # New Moon
          'Folf 🦊🐺', # Waxing Crescent
          'Aardwolf 🐾',                 # First Quarter
          'Spotted Hyena 🐆',            # Waxing Gibbous
          'Folf Hybrid 🦊✨',             # Full Moon
          'Striped Hyena 🦓',            # Waning Gibbous
          'Dogg Prime 🐕⭐',              # Last Quarter
          'WolfFox 🐺🦊', # Waning Crescent
          'Brown Hyena 🦴',              # Supermoon
          'Dogg Celestial 🐕🌟',          # Blue Moon
          'Folf Eclipse 🦊🌒',            # Blood Moon
          'Aardwolf Luminous 🐾✨', # Harvest Moon
          'Spotted Hyena Stellar 🐆⭐', # Hunter's Moon
          'Folf Nova 🦊💥', # Wolf Moon
          'Brown Hyena Cosmic 🦴🌌', # Pink Moon
          'Snow Leopard 🌨️', # New Moon
          'Snow Leopard Snow Snep 🌨️❄️', # Pink Moon
          'Avian 🦅', # New Moon
          'Avian Snow 🦅❄️', # Pink Moon
          'Skunk 🦨', # New Moon
          'Skunk Snow 🦨❄️', # New Moon
        ]

        # Define 23 corresponding were-forms with emojis.
        WERE_FORMS = [
          'WereDogg 🐶🌑',                     # New Moon
          'WereFolf 🦊🌙',                     # Waxing Crescent
          'WereAardwolf 🐾',                   # First Quarter
          'WereSpottedHyena 🐆',               # Waxing Gibbous
          'WereFolfHybrid 🦊✨',                # Full Moon
          'WereStripedHyena 🦓',               # Waning Gibbous
          'WereDoggPrime 🐕⭐',                 # Last Quarter
          'WereWolfFox 🐺🦊', # Waning Crescent
          'WereBrownHyena 🦴',                 # Supermoon
          'WereDoggCelestial 🐕🌟',             # Blue Moon
          'WereFolfEclipse 🦊🌒',               # Blood Moon
          'WereAardwolfLuminous 🐾✨',          # Harvest Moon
          'WereSpottedHyenaStellar 🐆⭐',       # Hunter's Moon
          'WereFolfNova 🦊💥', # Wolf Moon
          'WereBrownHyenaCosmic 🦴🌌', # Pink Moon
          'WereSnowLeopard 🐆❄️',
          'WereSnowLeopardSnow 🐆❄️❄️', # Pink Moon
          'WereAvian 🦅', # New Moon
          'WereAvianSnow 🦅❄️', # Pink Moon
          'WereSkunk 🦨', # New Moon
          'WereSkunkSnow 🦨❄️' # New Moon

        ]