I enjoy having my life broadcast on the net and one essential part of that is music. A few weeks ago, I started working on a ruby library for accessing the audioscrobbler web services.

Last night I put the finishing touches on the first release so I thought I would say something here. If you have a last.fm profile and are logging your tunes, you can now access them using ruby with my scrobbler gem.

So how easy is it? Below are a few examples of how to work with users, artists, albums and tracks.

# get recent tracks for a user
user = Scrobbler::User.new('jnunemaker')
user.recent_tracks.each { |t| puts t.name }

# get all the tracks for an album
album = Scrobbler::Album.new('Carrie Underwood', 'Some Hearts', :include_info => true)
album.tracks.each { |t| puts t.name }

# get similar artists
artist = Scrobbler::Artist.new('Carrie Underwood')
artist.similar.each { |a| puts "(#{a.match}%) #{a.name}" }

# top albums for a tag
tag = Scrobbler::Tag.new('country')
tag.top_albums.each { |a| puts "(#{a.count}) #{a.name} by #{a.artist}" }

# top fans for a track
track = Scrobbler::Track.new('Carrie Underwood', 'Before He Cheats')
track.fans.each { |u| puts "(#{u.weight}) #{u.username}" }

I implemented pretty much everything but the group stuff. I don’t use groups so I didn’t feel like throwing it together. It probably would have been pretty easy and patches are welcome (svn repo).

This is my fifth gem and it’s really fun for me to look back and see how far I’ve come in ruby. The first was Magnolia (June 2, 2006) which had 0 tests. Yep, back then I hadn’t even heard of tests. Each gem since then has had more tests and I really feel that Scrobbler is my best to date. I mocked the class that hits audioscrobbler to instead read an xml fixture file which is kind of cool. If the services change in the future, I just have to put in a new xml file and get my tests passing again. I’m thinking in the next web service gem I’ll do something along the lines of this Scott Raymond comment. I really don’t know how I survived without tests back in my PHP and ColdFusion days.

At any rate, enjoy the gem and let me know if you do anything cool with it.

20 Responses to “Scrobbler: Last.fm For Ruby”

  1. William H. Harle Jr. Says:

    I can’t wait to use this John. Well done sir.

  2. sol Says:

    thanks very much!

  3. jeroen Says:

    sweet

  4. Christian Dalager Says:

    Cool! I’ll just throw away my inferior wrapper ;-)

  5. Konstantin Tumalevich Says:

    ooops … i have error.

    ruby album.rb /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:404:in `to_constant_name’: Anonymous modules have no name to be referenced by (ArgumentError) from /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:214:in `qualified_name_for’ from /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:476:in `const_missing’ from /usr/local/lib/site_ruby/1.8/scrobbler/base.rb:9:in `connection’ from /usr/local/lib/site_ruby/1.8/scrobbler/base.rb:13:in `fetch_and_parse’ from /usr/local/lib/site_ruby/1.8/scrobbler/album.rb:107:in `load_info’ from /usr/local/lib/site_ruby/1.8/scrobbler/album.rb:99:in `initialize’ from album.rb:4

  6. John Nunemaker Says:

    @Konstantin – What are you calling to when you get that error. Can you paste the code in?

  7. Jason Says:

    I removed my dependency on xmlsimple, I stopped parsing out the recenttracks.xml file powering my dynamic “Most Recently Played” sig, and just moved to a call with your library.

    It’s down to 34 lines (down from 43 in PHP w/ GD IIRC).

    http://vxjasonxv.com/images/lastfm.png

    The image uses Ruby (duh), RMagick for all the text annotation and image rendering, and your lib. Hey, I can get rid of my net/http dependency too.

    33 lines :).

    I do need to work something in in order to see if I should even get the xml file / regenerate the image or not. (I guess this means I have to go curl -I’ing it and see if AudioScrobbler puts out reliable “Last-Modified” headers.)

  8. John Nunemaker Says:

    @Jason – Sweet. Nice work. Fun to see people using my libs.

  9. Konstantin Tumalevich Says:

    i`m executing example from gem on Ubuntu Linux.

  10. Jason Says:

    John,

    I believe I may have found an HTML entity problem. I left a static copy of the image on Webshots:

    Take a look at Huey Lewis & the News http://aycu34.webshots.com/image/22313/2006317658898393236_rs.jpg

    I don’t think you mean for that literal & to be appearing.

    I’m assuming that the library isn’t converting the XML character data to the single character entities?

  11. Jason Says:

    Clearly I meant XML entity, or perhaps character entity, by the way.

  12. Ray Says:

    Were you able to generate the flash player for the music? Thanks.

  13. Nikola Says:

    Hi, thanks for your work…

    I’ve found that if profile isn’t complete load_profile() script breakes.

    So I modified it: :)

    def load_profile
      doc = self.class.fetch_and_parse("#{api_path}/profile.xml")
      @id = (doc).at(:profile)['id']
      @cluster = (doc).at(:profile)['cluster']
      @url = (doc).at(:url).inner_html
      if ((doc).at(:realname)) : @realname = (doc).at(:realname).inner_html end
      if ((doc).at(:mbox_sha1sum)) : @mbox_sha1sum = (doc).at(:mbox_sha1sum).inner_html end
      @registered = (doc).at(:registered).inner_html
      @registered_unixtime = (doc).at(:registered)['unixtime']
      if ((doc).at(:age)) : @age = (doc).at(:age).inner_html end
      if ((doc).at(:gender)) : @gender = (doc).at(:gender).inner_html end
      if ((doc).at(:country)) : @country = (doc).at(:country).inner_html end
      @playcount = (doc).at(:playcount).inner_html
      if ((doc).at(:avatar)) : @avatar = (doc).at(:avatar).inner_html end
    end

    ...but I have another problem, constant timeout… I can’t do more that few requests (I’m sleep()-ing as a real gentleman), how can I solve this?

    Thanks again, Nikola

  14. josh Says:

    Awesome John. I started writing this myself until I came to my senses and googled it. Very, very nice implementation!

    thx

  15. John Nunemaker Says:

    Glad I could help. Hopefully I’ll get to use it some day. :)

  16. sanjay Says:

    Hiya. Is there a way to see if a band is actually in the scrobbler system?

    I can ask for their top albums, to see if anything comes back, but that seems kinda silly.

    thanks, sanj

  17. John Nunemaker Says:

    @sanjay – Nope. Scrobbler doesn’t have an API method for that purpose, at least not that they have documented.

  18. Georg Wacker Says:

    I made a little addition to Scrobbler::Artist that will enable getting the artist cover from which you are referencing.

    bc. def image doc = self.class.fetch_and_parse(”#{api_path}/similar.xml”) return (doc).at(:similarartists)[‘picture’] end

  19. Leon Bogaert Says:

    Is it also possible to add a song to you “Recently Listened Tracks” with this library?

    Thanks in advance!

  20. John Nunemaker Says:

    @Leon – Nope. Only read, no write.

Leave a Reply


(textile enabled)