I've always found it easier to organize my music hierarchally in directories with categories and subcategories than to use playlists. Unfortunately, iTunes and the iPod ignores the disk layout and only work with playlists
This is a small ruby script to bridge the gap. It traverses a directory structure and generates playlists for all directories and subdirectories. It then imports all these generated playlists into iTunes.
The script has not been cleaned up enough to be "click-and-go", you probably have to tweak it slightly to use it on your system. Note that:
# Generates m3u playlists from directory structure. A playlist is generated
# for each folder with the name of that folder.
VOLUME = "Macintosh HD"
require 'find'
require 'iconv'
def is_sound_file?(path)
exts = %w(.mp3 .wav .aiff .m4a)
ext = File.extname(path).downcase
return exts.include?(ext)
end
def sound_files_in_dir(dir)
files = []
Find.find(dir) {|file| files << file if is_sound_file?(file)}
return files.sort
end
def unix_path_to_mac_path(path)
if path[0,1] == "/"
path = File.join(VOLUME, path[1,path.size])
else
path = "/#{path}"
end
path = path.gsub("/", ":")
return path
end
def utf_to_roman(path)
# Replace separated characters with joined
# ä
path = path.gsub("a\314\210", "\303\244")
path = path.gsub("o\314\210", "\303\266")
path = path.gsub("u\314\210", "\303\274")
path = path.gsub("A\314\210", "\303\204")
path = path.gsub("O\314\210", "\303\226")
path = path.gsub("U\314\210", "\303\234")
# å
path = path.gsub("a\314\212", "\303\245")
path = path.gsub("A\314\212", "\303\205")
# á
path = path.gsub("a\314\201", "\303\241")
path = path.gsub("e\314\201", "\303\251")
path = path.gsub("i\314\201", "\303\255")
# à
path = path.gsub("a\314\200", "\303\240")
path = path.gsub("c\314\247", "\303\247")
begin
path = Iconv.conv("MacRoman", "UTF-8", path)
rescue
puts "ERROR -- CANNOT CONVERT PATH"
puts path
raise
end
return path
end
def generate_playlist_for_dir(dir)
result = ""
sound_files_in_dir(dir).each { |file|
path = unix_path_to_mac_path(file)
path = utf_to_roman(path)
result << path << "\n"
}
return result
end
def playlist_name(dir, root)
dir = dir.clone
dir[root] = "" if dir[root]
dir = dir[1,dir.size] if dir[0,1] == "/"
dir[-1,1] = "" if dir[-1,1] == "/"
dir = dir.gsub("/", " - ")
return dir + ".m3u"
end
def add_playlist_to_itunes(playlist)
path = utf_to_roman(unix_path_to_mac_path(File.expand_path(playlist)))
name = utf_to_roman(File.basename(playlist, ".*"))
out = <<ENDOF
tell application "iTunes"
set pl to make new playlist
set name of pl to "#{name}"
add "#{path}" to pl
end tell
ENDOF
`osascript -e '#{out}'`
end
# add #{unix_path_to_mac_path(playlist)} to play
def generate_playlists_for_root(root)
Find.find(root) {|file|
Find.prune if File.basename(file)[0,1] == "_"
next unless File.directory?(file)
next if file == root
files = Dir.glob(File.join(file, "*"))
next if files.size == 0 || (files.size == 1 && !is_sound_file?(files[0]))
name = playlist_name(file, root)
playlist = generate_playlist_for_dir(file)
if playlist.size > 0
puts name
File.open(name, "w") {|f| f.write(playlist)}
add_playlist_to_itunes(name)
end
}
end
def clear_playlists
script = <<SCRIPT
tell application "iTunes"
repeat while (count of playlists) >= 3
set pl to item 3 of playlists
delete playlist (name of pl)
end repeat
end tell
SCRIPT
`osascript -e '#{script}'`
end
clear_playlists
generate_playlists_for_root(ARGV[0])
© 2012, Niklas Frykholm, administrator@frykholm.se