Even after almost 6 months of getting paid to code in Ruby (and loving it) I can’t get over the fact that I can produce working programs with such ease and speed.
The latest example is a very simple thing I used to do by hand: Renaming my mp3 files according to their ID3 tags.
I actually used EAC’s renaming feature, but it only works with v1 tags (with their famous fixed size fields), so I ended up with some chopped up filenames (Christmas Card from a Hooker in Min.mp3 comes to mind as a good example – a prize to anyone who names the full title and the artist).
Renaming everything by hand is out of the question obviously – it’s enough having to fill in ID3 Tag information per hand when the CDDB does not have an entry for your CD (something that happens repeatedly for greek music cds) or some wiseguy has used all capitals for their CDDB entry. A mistyped CDDB entry gets on my nerves a lot worse than a missing entry.
So when after a long time I decided to put to order my mp3 collection I quickly realized that it was in the mess I left it simply because I had no inclination of spending a man-month “beautifying” it. Such realizations help you achieve ‘coding critical mass’. So, Ruby to the rescue.
The first step is to look for a ready made ID3 library. The first (and only) stop for this purpose is the Ruby Application Archive. If it doesn’t have it, you don’t want it.
Of the 3 choices (id3tag,mp3taglib,mp3info) I chose mp3info mostly because there’s a gem and it’s the library most recently updated.
mp3taglib depends on id3lib so that ruled it out very quickly (I tend to prefer pure Ruby solutions).
id3tag looks more complete, but it’s been sometime since it was updated and there was no gem in sight.
So armed, it took me about fifteen minutes and 85 lines of naive code (no golfing, first draft type of code with comments and everything) to write a small CLI utility that renames mp3 files using the pattern
‘Tracknumber. Artist – Title.mp3’.
The interesting thing is, that it is a very small step from these 85 lines that only generate filenames according to a single naming convention to having a mini “naming format language” (I seem to come back to DSLs again and again).
EAC has exactly this type of mini language in the settings:
%A is a placeholder for Artist, %T the placeholder for Title, %N is the track number etc.
I am tempted to implement it, but for the time being the fifteen minutes invested are more than enough: It works like I intended and that’s that.
The ‘juice’ of the app. A couple of checks are missing, i.e. empty tags give pretty bad results.
require "mp3info"
def rename_mp3_file filename
title=""
artist=""
number=""
Mp3Info.open(filename) do |mp3info|
#for some reason we get C strings
title=mp3info.tag.title.chomp("\0")
artist=mp3info.tag.artist.chomp("\0")
num=mp3info.tag.tracknum.chomp("\0")
#this in case the track number is in the #/total format
number=num.split("/")[0]
#single digit to double digit
number="0#{number}" if number.size==1
end
new_name="#{number}. #{artist} - #{title}.mp3"
sanitize(new_name)
@logger.info("New name: #{new_name}")
begin
FileUtils.mv(filename,File.join(File.dirname(filename),new_name))
rescue
@logger.warn("#{$!}")
end
end
#removes any characters that create problems (like ?)
def sanitize str
str.gsub!("?","")
end