[Or : Streaming Rhapsody or last.fm 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 last.fm – 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 lasm.fm 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 = Net::HTTP.new(uri.host, uri.port)
sock.use_ssl = true
req = Net::HTTP::Post.new(url)
req.set_form_data(dict)
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 = REXML::Document.new(res)
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)
end
Streaming HTTP music data (e.g. MP3) and piping it to another process (e.g. mplayer)
uri = URI.parse(url)
Net::HTTP.start(uri.host) 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
pipe.write(segment)
end
end
pipe.close
end
end
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", "2.1.5.2"
gem 'soap4r'
require 'soap/rpc/driver'
driverPlay = SOAP::RPC::Driver.new('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 = OpenSSL::Cipher::Cipher.new('des-ecb')
cipher.encrypt
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..."
cipher.decrypt
res = cipher.update(res) + cipher.final
puts "res = " + res.unpack("H*").to_s
puts "plain = " + plain.unpack("H*").to_s
puts "triple..."
cipher.decrypt
plain = cipher.update(plain) + cipher.final
cipher.encrypt
cipher.key = plain
plain = cipher.update(plain)
cipher.decrypt
cipher.key = key
res = cipher.update(plain) + cipher.final
puts "res = " + res.unpack("H*").to_s
end