It goes without saying that if you want to learn to program (in a particular language) you should not rely too much on books. The only way is to find a task you want to have automated, and then code it using your language of choice. Surely, you must pick the task (or the language) carefully, since not all languages are suitable for all tasks.
One of the things which Oliver has struggled with was organizing all of his podcasts in his player, sorted neatly by directories of author and title. Having found both a hammer and a nail, we were ready to start pounding.
After a bit of research we found the mp3info and id3tag Ruby libraries. id3tag had different fields for ID3v1 and ID3v2 data and didn't have write support (not that we needed it). mp3info didn't have ID3v2.2 support, but I found an interesting link about ID3 internals- the format of the fields was something that could be useful.
After a while our pair programming session has reached a milestone- our script works. It doesn't seem very modular though, so we spend some time making classes and discussing what is the responsibility of each class. Should there be a manager-class? Or should the objects manage themselves? I go with the second approach, and here's the result:
# Class for handling information of the mp3 file
class Mp3File
attr_reader :title, :artist, :album
def initialize filename
@artist = @album = "unknown"
@filename = filename
@title = File.basename(filename, ".mp3")
read_attributes
end
def title
sanitize(@title)
if @title == "unknown" then @title = File.basename(@filename, ".mp3") end
@title
end
def read_attributes
begin
Mp3Info.open(@filename) do |mp3info|
(@title, @artist, @album) = %w{title artist album}.collect { |attrib|
begin
(result = mp3info.tag.send(attrib)).empty? ? "unknown" : result
rescue
"unknown"
end
}
end
rescue
end
end
def sanitize str
str.tr_s!("?'","_")
end
def transfer(newPath)
newPath = eval('"' + newPath + '"')
FileUtils.mkdir_p File.dirname(newPath)
FileUtils.cp @filename, newPath
end
end
This is the class which is initialized with the location of the file and then extracts information about the artist, title and track name. The read_attributes method is meant to show off our new knowledge about the dynamic nature of Ruby- we build a list of methods to invoke on the Mp3Info object, and if no meaningful result, return "unknown". Finally, as the class knows about the current location and mp3 meta-info, it has a method for copying the file to a new location. The new path is passed as a template, where the
#@artist
, #@album
, #@title
are substituted with the value of these fields.
class Mp3List
attr_reader :files
def files
@files.map {|file| Mp3File.new(file) }
end
def initialize(sourcePath, days = 7)
@sourcePath = sourcePath
@days = days
@files = read_new
end
def read_new
Dir["#@sourcePath/**/*.mp3"].find_all do |path|
test(?M, path) > (Time.now - (@days * 60 * 60 * 24))
end
end
def to_s
@files.inspect
end
end
Here comes the class, which represents a list of mp3 files in a certain directory (and subdirectories), which satisfies some criteria- in this case, how long ago the files were created (modified). Could it be made more general? Certainly, but in a 80-line script? Maybe next time.
list = Mp3List.new("/home/whoami/Music", 730)
list.files.each do |mp3|
#~ puts "Processing #{filename}"
mp3.transfer('/tmp/music/#@artist/#@album/#@title.mp3')
end
What's left was an example of how to use these classes. Seems good to me- and best of all, it works.
The only thing left was to prepare a patch for the mp3info library for ID3v2.2 support. I actually implemented one (still not incorporated in base), and it also initializes the common fields with either the v2 or v1 data, whatever present (v2 still has precedence, if both are present).
Conclusions from our short session:
- Ruby is neat for quick hack jobs
- mp3info does not provide an exhaustive ID3 handling support, but is good enough and workable
- Pair programming might not be smooth from the start, but you will learn a lot about yourself
- Organizing your music can sometimes take longer than total time spent looking for your tracks
- You should choose your business trip accomodation place carefully if you can
1 comment:
Those were the days my friend:) Still doing some Ruby development? I didn't find the time and look more into Python or Groovy.
Cheers, Oliver
Post a Comment