[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