Using online music services with Ruby

[Or : Streaming Rhapsody or with Ruby]

Ruby has excellent libraries (HTTP, SSL, SOAP, XML, etc.) that can be used to write your own music player for streaming music from online services like Rhapsody or – so why not use them? Here are code snippets to help you getting started! They show you…

  • …how to make a HTTPS GET or POST request using SSL (https://…)
  • …how to easily parse the XML response of such a request
  • …how to stream music data (e.g. MP3) from some HTTP URL and how to pipe that stream data to another process (e.g. mplayer) for playing it back while streaming
  • …how to use SOAP requests with custom SSL certificates (https://…)
  • …how to encrypt/decrypt 64-bit DES ECB data

My own Ruby (1.8)-based Rhapsody player has 400 lines of Ruby code, my player has 200 lines of Ruby code  –   Do you think other languages can do better 😉 ?

Using HTTPS POST and SSL (HTTPS GET works similar using the Net::HTTP::Get class)

require 'net/http'
require 'net/https'

dict['api_key'] = @apikey
url = "https://someurl"

uri = URI.parse(url)
sock =, uri.port)
sock.use_ssl = true

req =
res = sock.start{|http| http.request(req) }
puts res.body

Parsing XML response data

require 'rexml/document'
res = http_post( {'method'=> 'radio.getPlaylist', 'sk' => @sk })

doc =

printf("%-30s %-50s %-40sn", "title", "album", "creator")
doc.elements.each("*/*/*/track") do |element|
  title    = element.elements["title"].text
  album    = element.elements["album"].text
  creator  = element.elements["creator"].text
  location = element.elements["location"].text
  image    = element.elements["image"].text
  printf("%-30s %-50s %-40sn", title, album, creator)

Streaming HTTP music data  (e.g. MP3) and piping it to another process (e.g. mplayer)

    uri = URI.parse(url)
    Net::HTTP.start( do |http|
      http.request_get(uri.path) do |resp|
        pipe = IO.popen("mplayer -cache 256 -", "w")
        resp.read_body do |segment|
          if segment.length > 0

Of course, you can always pipe using bash..

macbook-pro:~ nero$ lastfm.rb | mplayer -cache 64 -

...however this wouldn't allow you to write something else to STDOUT except the music data.

Using SOAP requests and custom SSL certificates

require 'openssl'
require "rubygems"
gem "httpclient", ""
gem 'soap4r'
require 'soap/rpc/driver'

driverPlay ='https://someurl', 'urn:someurn')
driverPlay.options["protocol.http.ssl_config.verify_mode"] = nil
driverPlay.options["protocol.http.ssl_config.client_cert"] = File.join(@dir, "somefile.cert.pem")
driverPlay.options["protocol.http.ssl_config.client_key"] = File.join(@dir, "somefile.key.pem")
driverPlay.return_response_as_xml = true
# define some method
driverPlay.add_method('startPlaybackSession', 'developerKey', 'cobrandId', 'logon', 'password', 'clientType')

Using 64-bit DES ECB encryption
(the key is to use ‘cipher.padding = 0’  – it took me 2 hours to figure that out …)

  require 'openssl'
  def testDES
    puts '*** TESTDES ***'
    key         = "x01x23x45x67x89xabxcdxef"
    plain       = "x01x23x45x67x89xabxcdxe7"
    cryptdata   = "xc9x57x44x25x6ax5exd3x1d"

    puts "key      = " + key.unpack("H*").to_s
    puts "plain    = " + plain.unpack("H*").to_s
    #puts OpenSSL::Cipher.ciphers

    puts "encrypt..."
    cipher ='des-ecb')
    cipher.key = key
    cipher.padding = 0
    res = cipher.update(plain)
    puts "res      = " + res.unpack("H*").to_s
    puts "crypted  = " + cryptdata.unpack("H*").to_s

    puts "decrypt..."
    res = cipher.update(res) +
    puts "res      = " + res.unpack("H*").to_s
    puts "plain    = " + plain.unpack("H*").to_s

    puts "triple..."
    plain = cipher.update(plain) +
    cipher.key = plain
    plain = cipher.update(plain)
    cipher.key = key
    res = cipher.update(plain) +
    puts "res      = " + res.unpack("H*").to_s