Aug 162012
 

Ever since apple came out with their new standard airplay I have been very jelly
of it. It allows for a user to stream videos, music, and photos to a device, in
their design the appletv. XBMC, Totem, and many others though have implemented
the receiver protocol allowing for them to be airplay endpoints to be driven by
iphones and macbooks etc. Which is cool but doesn’t get me any love for my
gnu/linux thinkpad.
When the rasberry pi came out I decided I wanted to build a little xbmc box that I
could carry with me to do remote video playback. I found a ruby library that allows
for pushing airplay video, and images to airplay devices like the appletv and the pi.
I downloaded and got it working, but it didn’t support streaming files locally, only
via http. So I learned me a little ruby and wrote the script below. It takes an
http/s url or a local file url and serves them up for the airplay receiver. It
works great. give it a try

#!/usr/bin/ruby
#code is written by Matthew O'Gorman 2012 Licensed Gplv3
require 'webrick'
require 'airplay'
require 'uri'
require 'socket'

class Streamer < WEBrick::HTTPServlet::FileHandler
  def initialize(server, v, f, l)
    super(server, l)
    @valid_ip = v
    @valid_file = f
    @local_path = l
  end

def prevent_caching(res)
    res['ETag']          = nil
    res['Last-Modified'] = Time.now + 100**4
    res['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
    res['Pragma']        = 'no-cache'
    res['Expires']       = Time.now - 100**4
  end

def do_GET(req, res)
  super
  print "yup \n" + req.remote_ip + "\n" + req.path + "\n"
  print "uh hu " + @valid_ip + " " + @valid_file + "\n"
  path = req.path.slice!(0)
  if (req.remote_ip != @valid_ip) then
    if (path != @valid_file) then
      print "invalid request\n"
      res.status = 403
      res['Content-Type'] = "text/html"
      res.body = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><html><head><title>403 Forbidden</title></head><body><h1>Forbidden</h1><p>You are not the airplay server we are looking for!</p><hr><address>WEBrick airplay server 0.1</address></body></html>"
      return res
    end
  end
    prevent_caching(res)
end

end

def Local_ip
  orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true  # turn off reverse DNS resolution temporarily

  UDPSocket.open do |s|
    s.connect '64.233.187.99', 1
    s.addr.last
  end
ensure
  Socket.do_not_reverse_lookup = orig
end


client = Airplay::Client.new
client.browse

if (ARGV[0] =~ URI::regexp) then
  print "playing url " + ARGV[0] + "\n"
  player = client.send_video(ARGV[0])
  # Correct URL
elsif (File.readable?(ARGV[0])) then
  print "playing file " + ARGV[0] + "\n"
  dir = File.dirname(ARGV[0])
  Dir.chdir(dir)
  

  s = WEBrick::HTTPServer.new(:IP => "0.0.0.0", :Port => 3000)
  valid_ip = client.servers[0].ip
  valid_file = File.basename(ARGV[0])
  s.mount "/", Streamer, valid_ip, valid_file, Dir.pwd
  trap('INT') { s.shutdown }
  child = fork do
    sleep 2
    url =  "http://" + Local_ip() + ":3000/" + valid_file
    print url
    print "\n"
    player = client.send_video(url)
  end
    s.start
    exit
else
       print "Not a uri or a readable file.  nothing to do\n"
end

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>