Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Fetching contributors…
Cannot retrieve contributors at this time
79 lines (70 sloc) 3.56 KB
require 'rubygems'
require 'builder'
require 'mp3info'
# First off, where do you want to look?
root = "/Users/tom/Downloads/"
feed_title = "My Downloads"
port = 3000
# Now, are you interested only in audio files, or do you want videos too?
# I exclude PDFs because the whole concept of 'PDFcasting' is stupid and ugly and needs to die in a fire.
audio_only = true
# make our comparator - using
comparator = case audio_only
when true; lambda {|i| !(i.match(/\.mp3$/i) || i.match(/\.m4a$/i)) }
when false; lambda {|i| !(i.match(/\.mp3$/i) || i.match(/\.m4a$/i) || i.match(/\.mp4$/i) || i.match(/\.mov$/i) || i.match(/\.m4v$/i)) }
# Yeah, if this were LISP and not Ruby, we'd use a magical macro function to merge and Not Repeat Myself.
# But it isn't, so this will have to do. Still, I get points for lambdas right? ;)
files = `find .`.split(/\n/).delete_if(&comparator)
# Note for scaredy-cats: delete_if isn't deleting the file - rather, it is part of the inherent crapness
# of Ruby. Rather than calling it 'filter' like Scala would or 'Where' like .NET does, Ruby calls it delete_if.
# It doesn't actually delete your files, it filters the list of files using the comparator function we've just defined.
# Next we need to expand all the paths, get the file data and sort them by mtime.! {|i| File.expand_path(i, root)}! {|i| {:name => i, :mtime =>, :size => File.size(i)}}
files = files.sort_by {|x| x[:mtime]}.reverse
# Now we need to extract all the metadata and turn it into an RSS item.
builder = => STDOUT, :indent => 2)
builder.rss("version" => "2.0", "xmlns:itunes" => "") do |rss| do
rss.title(feed_title)"") # doesn't actually matter but ought to be there for validation's sake.
description = "Stuff I've recently downloaded to ~/Downloads"
rss.itunes :subtitle, description #weird syntax for xmlns in builder 2.0
rss.language('en-US') # whatever
files.each do |file|
if file[:name].match(/\.mp3$/)
id3tag =[:name])
id3tag = nil
rss.item do
rss.title(id3tag.tag.title || file[:name])
# if the mp3 has a Comment tag in the ID3, we should just use that as the rss Description. otherwise
# cobble one together from a ragtag bag of ID3 crapola so you've got something interesting to read on
# yer iPod.
unless id3tag.tag.COMM.nil? || id3tag.tag.COMM.empty?
rss.description("#{id3tag.tag.artist} #{id3tag.tag.composer} #{id3tag.tag.album} #{id3tag.tag.track}")
rss.pubDate(file[:mtime].to_s) # damn RSS 2.0 for RFC 822. If you ever think about writing a data format,
# read up on ISO 8601. It is the date-time format of sane people.
# see
uri = "http://localhost:#{port.to_s}" + file[:name]
ftype = case file[:name]
when /\.mp3$/; "audio/mpeg"
when /\.m4a$/; "audio/mp4"
when /\.mp4$/; "video/mp4"
when /\.mov$/; "video/quicktime"
when /\.m4v$/; "video/mp4"
when /\.pdf$/; "application/pdf"
rss.enclosure("url" => uri, "length" => file[:size].to_s, "type" => ftype)
rss.guid(uri) # never got the point of guid's in RSS - URIs should be unique enough for everything.
Jump to Line
Something went wrong with that request. Please try again.