Entries Tagged 'Ruby' ↓

Aruduino ethernet shield and Rails

I just wrote an article on the GumboLabs blog about using the Arduino Ethernet shield. Be sure to check it out.

Rails app turns seedbox into mediacenter

Well, it has been a while since a post. I am glad to get something back up here. I am just coming coming up for air from a long stretch of work. I wanted to waste a little time so I decided to make an improvement on my custom seedbox / media center. If you want to read a little about it, check this post.

Anyway, what I wanted to do is have a webpage served from my seedbox that displays all the movies on the system with a link to imdb and a link to play the movie. The link to play the movie would create a ‘vlcrc’ subprocess and open up a new window with the controls. This way, anyone on my network, using a laptop or phone, could open up the page and choose a movie and it would play on my TV.

This initially seemed really complicated when I came up with the idea last year and I had started writing a pretty thorough Rails app to do it. Then I got tired of it and forgot about it. Like most code I write, I realized that unless money was involved I am too lazy to do it right and usually settle for a hack.

The hack resulted in this python cgi script:

#!/usr/bin/env python
import cgi
import cgitb
import os, subprocess
cgitb.enable()

MOVIE_DIRECTORY = "/media/MEDIA/media_backup/videos/films"
MY_IP = "192.168.0.100"
VLC_HTTP_LINK = "http://" + MY_IP + ":8080"

form = cgi.FieldStorage()
movie_to_play = form.getvalue('movie')

print "Content-type: text/html"
print

movies = [mov for mov in
os.listdir(MOVIE_DIRECTORY) if (mov[-3:] == 'avi' or mov[-3:] == 'mov' or mov[-3:] == 'mpg')]

# print
print """
<html><head><title>Ben's Movies</title></head><body>
<font size="4" face="Verdana">"""

if movie_to_play:
    command = "vlcrc %s" % MOVIE_DIRECTORY+'/'+movie_to_play
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
    #print process.communicate()
    #retval = subprocess.call(command, 0, None, None, outptr, errptr)
    print """
             <script>
                  window.open('%s','%s','width=400,height=200');
             </script>
          """ % (VLC_HTTP_LINK, movie_to_play)
    print "Playing: "+ movie_to_play

print """
</center><table border="1">
<tr>
<th></th>
<th>Title</th>
<th></th>
<th></th>
</tr>
"""

base_play_link = "http://" + MY_IP + "/cgi-bin/movies.py?movie=%s"
base_imdb_link = 'http://www.imdb.com/find?s=all&q=%s'

i = 1

for mov in movies:
    nice_mov = mov[:-4] #get rid of extension
    nice_mov = nice_mov.replace('_', ' ') #make it more human readble
    imdb_link = base_imdb_link % nice_mov.replace(' ', '+')
    play_link = base_play_link % mov
    print """
          <tr>
              <td>%d</td>
              <td>%s</td>
              <td><a target="_blank" href="%s">IMDB Info</a></td>
              <td><a href="%s">Play</a></td>
          </tr>
          """ % (i, nice_mov, imdb_link, play_link)
    i += 1

print """
</table></center></font></body></html>
"""

For some reason handling the vlc subprocess was not working for me. I am guessing that it has something to do with the permissions that the cgi script have when trying to execute a subprocess? I don’t know and I didn’t fight it too hard. So instead of fixing it, I just wrote a Rails app. You can download it here.

It basically works exactly the same way. First let’s look at the main controller [BTW, please don't make fun of my ruby, it has been a while :) ]. Also, my source code viewer adds IO twice!!??!?! Should just be IO.popen

class MainController < ApplicationController

    MOVIE_DIRECTORY = "/media/MEDIA/media_backup/videos/films"
    MY_IP = "192.168.0.100"
    VLC_HTTP_LINK = "http://" + MY_IP + ":8080"
    BASE_IMDB_LINK  = "http://www.imdb.com/find?s=all&q="

    def index
        @ip = MY_IP
        @vlc_link = VLC_HTTP_LINK
    	@movies = Dir.new(MOVIE_DIRECTORY).entries.find_all{|item| item =~ /.avi$/ or item =~ /.mpg$/ or item =~ /.wmv$/ or item =~ /.mp4$/}
        @movie_to_play = params[:movie]
         if @movie_to_play
	     system("killall vlc")
	     vlcpipe = IO.popen("vlcrc "+MOVIE_DIRECTORY+"/"+@movie_to_play)
         end
    end

end

This is the only controller. It pulls all the movies from the ‘films’ folder on my hard-drive. I name all my movie files by the title with underscores instead of spaces, for example 2001_A_Space_Odyssey.avi. After it gets all the movies, it checks the request for a parameter named ‘movie’. If there is a movie, it kills any instances of vlc, if there are any running, it then runs my little vlcrc bash script. That script ensures the DISPLAY is set to my TV and starts up vlc using the http interface. Once again, refer to my last post.

Next let’s look at the view. First the helper file:

module MainHelper

    def nice_name(movie)
    	movie[0..movie.length-5].gsub('_', ' ')
    end

    def imdb_link(movie)
        link = "http://www.imdb.com/find?s=all&q="+movie.gsub('_', '+')[0..movie.length-5]
    	return "<a href='"+link+"' target='_blank'>IMDB Info</a>"
    end

    def play_link(movie)
    	"<a href='/main/index?movie="+movie+"'>Play</a>"
    end

end

Then the index.html.erb template:

<html>
  <head>
    <title>Ben's Movies</title>
  </head>
  <body>
  <font size="4" face="Verdana">

   <center>
     <h2> There are currently <%= @movies.length %> movies on this machine </h2>
    <% if @movie_to_play %>
	   <div style="background-color:#9ACD32; color:#FFFFFF; visibility: visible"><p>Now Playing <b><%= @movie_to_play %></b></p></div>
           <script>
                 function open_vlc_window() {
                    window.open('<%= @vlc_link %>','<%= @movie_to_play %>','width=600,height=385');
                 }
                 setTimeout("open_vlc_window()",1250);//slight delay, vlc needs a second to start up
           </script>
        <% end %>
        <table border=1>

          <% @movies.each do |movie| %>
              <tr>
                 <td><%= nice_name(movie) %></td>
                 <td><%= imdb_link(movie) %></td>
                 <td><%= play_link(movie) %></td>
              </tr>
          <% end %>

        </table>
        </center>
      </font>
    </body>
</html>

Ugh, ugly code, useless declarations, poor ruby practices, oh well. Anyways, how it works should be pretty obvious. I had previously written a service to pull down the synopsis info for a movie but all that was too complicated so i just made the link a search on imdb. If the movie name is unique, it will jump straight to the page, if not, it will ask you to choose between movies with the same or similar names by just executing a standard search.

Here is the home page:

Home Page

Home Page

Then we click play on Adaptation:

Play button pushed

Play button pushed

It informs us of the movie that is playing with the green status bar and the ajax remote control box pop up. It is sized to be as small as needed:

vlc control interface

vlc control interface

You can play, stop, pause, toggle fullscreen, change the volume, and there is even a seek bar. The best thing about it is that this is all javascript so it works pretty well on all browsers, even phone browsers. It fits nicely on my G1 :)

If you click on another movie, the vlc instance is killed as expected and a new one is started. All that is left to do is create an init.d bash script to start up the mongrel server on port 80 on boot up and maybe map your ip to a name if you have the means.