Using Ruby to Process m3u Playlists
Written By: Nathan Baker
- 06 Apr 2006 -
Description: Programming in Ruby is fun! In this tutorial, we will use Ruby to process the m3u playlists used by a number of media players.
- Introduction
- Part 1: Getting our feet wet
- Part 2: Slowly getting there
- Part 3: I/O, I/O, it's off to work we go
- Part 4: Cleaning up our mess
- Part 5: The extra mile
Section 5: The extra mile
So here's your playlist reader. What to do with it? In this section I take this in two different directions: reading in from the command line and using as a CGI script on your webpage.
Reading in from the command line
Right now, if you want to change the playlist displayed, you have to go in and rename it. What a drag. Instead, what if you could just type "ruby m3uParser.rb MyPlaylist.m3u" and it would use that one? Well, Ruby has a variable ARGV that contains the command line as an array of strings. As the name indicates, this is a constant.
Why didn't I do this to begin with? Well, there's the problem of spaces in filenames. Parsing spaces in filenames isn't hard, but it would be distracting from my main point. Never say I didn't do anything for you, though. Here's a class that will parse filenames for you:
class FilenameParser @ = false def FilenameParser.AllowEscapedSpaces(allow) @ = allow end #Takes an array of strings, returns the filename def FilenameParser.Parse(str = ARGV, idx = 0) retStr = "" if str[idx][0,1]=='"' #Read in double-quoted string retStr << str[idx] while retStr[-1,1]!='"' && idx < str.length-1 retStr << " " << str[idx+=1] end else retStr = str[idx] if(@) #Read in UNIX-style escaped spaces while retStr[-1,1]=='/' && idx < str.length-1 retStr << " " << str[idx+=1] end end end return retStr end end
Note the @ variable. This is a static class variable. All the methods are also prepended with FilenameParser., which indicates that they are static methods. You don't ever have to call FilenameParser.new; just use FilenameParser.Parse when you need to parse something. You can then replace the above top-level code with
p = Playlist.new FilenameParser.AllowEscapedSpaces(true) p.read(FilenameParser.Parse) p.each{|x| puts x}
Note that if you put the parser in a separate file (which I did, since this is the sort of thing you will probably be using a lot), you will need to say
require "FilenameParser.rb"
which will then allow you to reference classes in that file.
Calling as a CGI script
CGI, or common gateway interface, is a way to use pretty much any scripting language to process things like forms from webpages. I personally prefer PHP to this, but to each his (or her) own. Ruby has a cgi class that is useful for this specific purpose. Check out the following code:
require 'cgi' require 'm3uParser.rb' cgi = CGI.new('html4') p = Playlist.new p.read('My Playlist.m3u') playlist = "" p.each{|x| playlist << "\t#{x}#{cgi.br}\n"} cgi.out{ cgi.html{"\n" + cgi.head{"\n\t" + cgi.title{'My playlist is better than yours'} + "\n" } + "\n" + cgi.body{"\n" + playlist} + "\n" } }
cgi.out will send the results over HTTP as a webpage (if you're running this from the command line, it will prompt you for values and then write the output to the screen. Just press Ctrl+Z for EOF when it's asking for input and then look at the output). The other cgi methods will write HTML content using the specified HTML version. This will write a webpage with the songs, one per line. It also tries to format the resulting HTML code fairly neatly. You can also write the HTML code yourself, of course.
It is also to specify the playlist to display via the URL (HTTP GET) or POST. However, this is less useful and might be downright disastrous, since letting users specify things that may or may not be .m3u files isn't a great idea.
Outro
So I hope you learned to appreciate what those young whippersnappers are raving about when they tell you that Ruby makes programming easy 'n' fun. Feel free to check out my sample code, where I include all the code I wrote for this article in one convenient location (well, three source files plus a sample playlist for your parsing pleasure). As always, feel free to drop me a line at [] with questions, comments, insults, amusing banter, etc. Code to live!