Last.FM

Here's some code to submit track information to Last.FM (scrobble).

To use it, first you need to do the handshake, then you get token which you can use to send the "now playing" track (np) or "just played" one (scrobble).

set lastfmtoken [lastfm::handshake $s]

# while the track is playing you should periodically run np:
lastfm::np token $lastfmtoken artist $artist track $track

# to scrobble the track (see details on when to do this on last.fm site)
lastfm::scrobble token $lastfmtoken artist $artist track $track source personal

This code supports both short (as per protocol) and long human-readable sources.

#!/usr/bin/env tclsh

package provide LastFM 0.1

package require http
package require md5

namespace eval lastfm {
    # http://post.audioscrobbler.com/?hs=true&p=1.2.1&c=<client-id>&v=<client-ver>&u=<user>&t=<timestamp>&a=<auth>
    proc handshake {args} {
        set user {}
        set password {}
        if {[llength $args] == 1} {
            lassign $args args
        }
        foreach {k v} $args {
            set $k $v
        }
        set timestamp [clock seconds]
        set authtoken [string tolower [::md5::md5 -hex [string tolower [::md5::md5 -hex $password]]$timestamp]]
        set query [::http::formatQuery hs true p 1.2.1 c tst v 1.0 u $user t $timestamp a $authtoken]
        set r [::http::geturl http://post.audioscrobbler.com/ -query $query]
        set data [::http::data $r]
        ::http::cleanup $r
        return $data
    }

    proc np {args} {
        set sessid {}
        set artist {}
        set track {}
        set album {}
        set length {}
        set trackno {}
        set musicbrainz {}
        if {[llength $args] == 1} {
            lassign $args args
        }
        foreach {k v} $args {
            set $k $v
        }
        lassign $token code sessid npurl
        set query [::http::formatQuery s $sessid a $artist t $track b $album l $length n $trackno m $musicbrainz]
        set r [::http::geturl $npurl -query $query]
        set data [::http::data $r]
        ::http::cleanup $r
        return $data
    }

    proc scrobble {args} {
        set sessid {}
        set artist {}
        set track {}
        set album {}
        set length {}
        set trackno {}
        set musicbrainz {}
        set source personal
        set time [clock seconds]
        if {[llength $args] == 1} {
            lassign $args args
        }
        foreach {k v} $args {
            set $k $v
        }
        set source [string map {personal P radio R recommendation E last.fm L} [string tolower $source]]
        if {$source eq ""} {
            set source P
        }
        lassign $token code sessid -> submissionurl
        set query [::http::formatQuery s $sessid {a[0]} $artist {t[0]} $track {b[0]} $album {l[0]} $length {n[0]} $trackno {m[0]} $musicbrainz {i[0]} $time {o[0]} $source {r[0]} {}]
        set r [::http::geturl $submissionurl -query $query]
        set data [::http::data $r]
        ::http::cleanup $r
        return $data
    }
}