Adding structured directories of music into iTunes

I wrote this one for my father as he has several audio tapes worth of MP3s to put into iTunes on Windows. It reads down through a directory structure for music files, using the nested directory names as metadata. It expects a nested directory structure as follows:

Root Dir
 |- Artist Dirs
     |- Album Dirs
          |- Music files

Admittedly, this is my first usage of yield in anger. It hurt – but now my brain has been further fortified with vitamin Ruby.

Code follows…

require 'win32ole'

cwd = `cd`
cwd.gsub! "\\\\", "/"

path = ARGV[0] if not ARGV[0].nil?
path = "." if path.nil?

app = WIN32OLE.new 'iTunes.Application'
exit if app.nil?

$music = app.LibrarySource.Playlists.ItemByName 'Music'

def for_each_in_dir(dir, contained_dir_type, meta={})
  dir.each do |dir_name|
    next if not File.directory? dir_name or dir_name =~ /^\\./
    Dir.open dir_name do |nested_dir|
      Dir.chdir dir_name
      meta[contained_dir_type] = dir_name
      yield nested_dir, meta
      Dir.chdir '..'
    end
  end
end

def read_tracks_for(artist, album, album_dir)
  album_dir.each do |t|
    next if File.directory? t or t =~ /^\\./

    title, junk = t.split '.'
    if title =~ /^(\\d+)\\b(.*)/
      track_number = $1.to_i
      title = $2.strip
    end

    puts "Adding Track '#{title}', Album '#{album}', Artist '#{artist}'"
    file_path = `cd`.chop << "\\\\#{t}"
    $music.AddFile file_path

    # AddFile may fork because sometimes no track is 
    # returned from ItemByName unless I sleep as below.
    # You may need a sleep time greater than 1 depending upon
    # your system's performance.
    sleep 1

    track = $music.Tracks.ItemByName title
    if track.nil?
      next
    end

    track.TrackNumber = track_number if track_number
    track.Name = title
    track.Album = album
    track.Artist = artist
  end
end

Dir.open path do |start_dir|
  Dir.chdir path
  for_each_in_dir start_dir, :artist do |artist_dir, artist_meta|
    for_each_in_dir artist_dir, :album, artist_meta do |album_dir, album_meta|
      read_tracks_for album_meta[:artist], album_meta[:album], album_dir
    end
  end
end

Posted by evan on Tuesday, April 17, 2007

blog comments powered by Disqus