#!/usr/bin/python import os import os.path import sys import re import shutil from stat import * import pprint MODE = "aac" # change to mp3 to do what the program title # suggests. this should be a command line option, but I'm # too lazy too look up how the getopts module # works. Though apparently not lazy enough to refrain # from writing this comment. IN_DIR = "Z:\\audio\\FLAC" if MODE == "aac": OUT_DIR = "Z:\\audio\\AAC" else: OUT_DIR = "Z:\\audio\\MP3" LAME = "C:\\Documents and Settings\\staffan\\bin\\i386-pc-win32\\lame.exe" FLAC = "C:\\Documents and Settings\\staffan\\bin\\i386-pc-win32\\flac.exe" METAFLAC = "C:\\Documents and Settings\\staffan\\bin\\i386-pc-win32\\metaflac.exe" FAAC = "C:\\Documents and Settings\\staffan\\bin\\i386-pc-win32\\faac.exe" # This path must not contain spaces (it can't be quoted in the # os.system call for some reason), hence the short name (~1) form FLAC = "C:\\PROGRA~1\\FLAC\\flac.exe" METAFLAC = "C:\\PROGRA~1\\FLAC\\metaflac.exe" genres = {} def init_genres(): cmd = '"%s" --genre-list' % LAME print "init_genres: cmd %s" %cmd pipe = os.popen(cmd, "r") for g in pipe.read().splitlines(): m = re.match(r'^ *(\d+)\ +(.*)', g) if m: # print "init_genres: %s has id %s" % (m.group(2),m.group(1)) genres[m.group(2)] = m.group(1) def do_dir(dirname): indir = os.path.abspath(dirname) outdir = indir.replace(IN_DIR,OUT_DIR) assert(indir!=outdir) # print "converting from '%s' to '%s'" % (indir,outdir) if not os.path.exists(outdir): os.mkdir(outdir) # m3ufile = open("%s/playlist.m3u"%outdir, "w") songs = [] for f in os.listdir(indir): if f.endswith(".flac"): song = {} song['filename'] = f song['metadata'] = get_fields(indir,f) songs.append(song) elif f != "playlist.m3u": print "copying %s" % f try: shutil.copy2("%s/%s" % (indir,f), "%s/%s" % (outdir,f)) except IOError: print "Oops, IOError occurred, oh well" fix_tracknumbers(songs) pprint.pprint(songs) for s in songs: if MODE == "aac": flac_to_aac(indir,s['filename'],s['metadata'],outdir) else: flac_to_mp3(indir,s['filename'],s['metadata'],outdir) # m3ufile.close() def get_fields(indir,f): fields = {} cmd = '%s --no-utf8-convert --export-tags-to - "%s%s%s"' % (METAFLAC, indir, os.sep, f) fields_str = unicode(os.popen(cmd, "r").read(),'utf-8').encode('iso-8859-1') for line in fields_str.splitlines(): # print "line: '%s'" % line (key,val) = line.split("=",1) fields[key.lower()] = val fields['tracknumber'] = "%2.2d" % int(fields['tracknumber']) return fields def fix_tracknumbers(songs): for s in songs: fields = s['metadata'] # if the tracnumber has three digits, it means it must be a multi-disc edition if (len(fields['tracknumber']) >= 3): fields['discnumber'] = '%d/%d' % (int(fields['tracknumber'][:1]), int(find_max_discnumber(songs))) fields['formatted_tracknumber'] = "%2.2d/%2.2d" % ( int(fields['tracknumber'][-2:]), int(find_max_tracknumber(s,songs)[-2:])) def find_max_discnumber(songs): maxdiscnum = 0 for s in songs: discnum = s['metadata']['tracknumber'][:-2] if discnum > maxdiscnum: maxdiscnum = discnum return maxdiscnum def find_max_tracknumber(song,songs): maxtracknum = 0 # the simple case, a single-disc edition: if (len(song['metadata']['tracknumber']) <= 2): for s in songs: if s['metadata']['tracknumber'] > maxtracknum: maxtracknum = s['metadata']['tracknumber'] else: discnum = song['metadata']['tracknumber'][:-2] for s in songs: if ((discnum == s['metadata']['tracknumber'][:-2]) and s['metadata']['tracknumber'] > maxtracknum): maxtracknum = s['metadata']['tracknumber'] return maxtracknum def flac_to_aac(indir,filename,fields,outdir): outfile = "%s-%s-%s.m4a" % (fields['tracknumber'], fields['artist'], fields['title']) outfile = re.sub('[\\:/\*\?<>|]','',outfile) # remove characters illegal in NTFS if os.path.exists("%s%s%s" % (outdir, os.sep, outfile)): print "Outfile %s%s%s exists, skipping" % (outdir, os.sep, outfile) return print "outfile is %s" % outfile if (fields['artist'] != "" and fields['title'] != "" and fields['tracknumber'] != "" and fields['album'] != ""): # -q 65 88kbps bitrate, ie not that high, but AAC is supposed to be good at # low bitrates, and my ipod does not have infinite disk space cmd = '%s -s -c -d "%s%s%s" | "%s" -q 60 -w --year %s --artist "%s" --album "%s" --title "%s" --genre "%s" --track %s -o "%s%s%s" ' % ( FLAC, indir, os.sep, filename, FAAC, fields['date'], unicode(fields['artist'],'iso-8859-1').encode('utf-8'), unicode(fields['album'],'iso-8859-1').encode('utf-8'), unicode(fields['title'],'iso-8859-1').encode('utf-8'), unicode(fields['genre'],'iso-8859-1').encode('utf-8'), fields['formatted_tracknumber'], outdir, os.sep, outfile) if 'discnumber' in fields: cmd = cmd + '--disc %s ' % fields['discnumber'] if os.path.exists("%s%s%s" % (indir, os.sep, "folder.jpg")): cmd = cmd + '--cover-art "%s%s%s" ' % (indir,os.sep,"folder.jpg") if "Various - " in indir: cmd = cmd + "--compilation " cmd = cmd + "-" print "executing %s" % cmd os.system(cmd) else: print "%s: couldn't find enough comments in flac file (need artist+title+album+tracknum, skipping this file!" % filename def flac_to_mp3(indir,filename,outdir): # this workaround is only needed for ID3V1 -- but it seems lame # won't let us use other genres even for the ID3V2 field if not fields['genre'] in genres: print "Genre '%s' not recognized" % fields['genre'] fields['genre'] = "Rock" outfile = "%s-%s-%s.mp3" % (fields['tracknumber'], fields['artist'], fields['title']) outfile = re.sub('[\\:/\*\?<>|]','',outfile) # remove characters illegal in NTFS # m3ufile.write("%s\n" % outfile) if os.path.exists("%s%s%s" % (outdir, os.sep, outfile)): print "Outfile %s%s%s exists, skipping" % (outdir, os.sep, outfile) return print "outfile is %s" % outfile if (fields['artist'] != "" and fields['title'] != "" and fields['tracknumber'] != "" and fields['album'] != ""): # if you care about quality as opposed to filesize, use # --preset standard or something instead of -V 6 cmd = '%s -s -c -d "%s%s%s" | "%s" -V 6 --ty %s --ta "%s" --tl "%s" --tt "%s" --tg "%s" --tn %s --add-id3v2 --quiet - "%s%s%s"' % ( FLAC, indir, os.sep, filename, LAME, fields['date'], fields['artist'], fields['album'], fields['title'], fields['genre'], fields['formatted_tracknumber'], outdir, os.sep, outfile) print "executing %s" % cmd os.system(cmd) else: print "%s: couldn't find enough comments in flac file (need artist+title+album+tracknum, skipping this file!" % filename if __name__ == "__main__": init_genres() if len(sys.argv) < 2: dirs = os.listdir(os.getcwd()) else: dirs = sys.argv[1:] for dir in dirs: if not S_ISDIR(os.stat(dir)[ST_MODE]): print "'%s' is not a directory" % dir continue do_dir(dir)