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:
Then we click play on Adaptation:
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:
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.



0 comments ↓
There are no comments yet...Kick things off by filling out the form below.
Leave a Comment