#!/usr/bin/python """ This script converts Vorbis OGG and mp3 files to low-bitrate mp3 files. Requires at least the following Debian packages: python, python-pyvorbis, python-eyed3, vorbis-tools Also required; lame, version 3.92 or newer """ import sys, os, ogg, ogg.vorbis, eyeD3 import getopt, re usage = """Usage: %s [options] [...]"""%(os.path.basename(sys.argv[0])) help = """ -h --help this help -n --simple-names Remove non-alnum chars from filename -d --single-directory Do not create "artist - album" directory source File or directory, directories are searched for ogg and mp3 -files. Found files are converted to 96kbps mp3-files, "-lbr" is appended to the filename. By default the files are placed in a "artist - album" directory. """ def escape(s): return s.replace("'", "\\'") class Config(object): def __init__(self, args=[]): self.keep_filenames = 1 self.single_directory = 0 opts, args=getopt.getopt(sys.argv[1:], "hnd", ("help", "simple-names", "single-directory")) self.sources=args for name, value in opts: if name in ("-h", "--help"): print usage print help sys.exit(0) elif name in ("-n", "--simple-names"): self.keep_filenames=0 elif name in ("-d", "--single-directory"): self.single_directory=1 if not args: print usage sys.exit(0) def files(self): for source in self.sources: if os.path.isdir(source): for file in self.__subfiles(source): yield file elif os.path.isfile(source): yield source else: print>>sys.stderr, "ERROR:"\ "'%s' is not a file or a directory."%source def __subfiles(self, path): for dirpath, dirnames, filenames in os.walk(path): for filename in filenames: fn=os.path.join(dirpath, filename) if os.path.isfile(fn) and\ filename[-4:].lower() in (".ogg", ".mp3"): yield fn else: print >>sys.stderr, "ERROR: ignoring '%s'"%(filename) class AudioStream(object): def __init__(self, filename): self.fn = filename if filename[-4:].lower() == ".ogg": self.mode="ogg" self.get_ogg_tags() elif filename[-4:].lower() == ".mp3": self.mode="mp3" self.get_mp3_tags() else: raise Exception, "Unknown extension '%s'"%filename[-3:] self.lame_opts="--lowpass 14 --preset 96" def get_ogg_tags(self): stream = ogg.vorbis.VorbisFile(self.fn) comments = stream.comment().as_dict() self.artist = comments.get("ARTIST", [""])[0].encode("latin_1") self.album = comments.get("ALBUM", [""])[0].encode("latin_1") self.track = comments.get("TRACKNUMBER", [""])[0].encode("latin_1") self.title = comments.get("TITLE", [""])[0].encode("latin_1") def get_mp3_tags(self): tags = eyeD3.Mp3AudioFile(self.fn).getTag() self.artist = tags.getArtist() or "unknown" self.album = tags.getAlbum() or "unknown" self.track = str(tags.getTrackNum()[0] or "") self.title = tags.getTitle() or "unknown" def convert(self, target): path = os.path.dirname(target) if path: if not os.path.exists(path): os.makedirs(path) elif not os.path.isdir(path): print >>sys.stderr, "ERROR:"\ "'%s' exists and is not a directory"%(path) if self.mode == "ogg": self.convert_ogg(target) elif self.mode == "mp3": self.convert_mp3(target) else: raise Exception, "Invalid Mode" def convert_ogg(self, target): tempname = "/tmp/oggconvert-%d.wav"%(os.getpid()) print "Converting %s to wav"%(os.path.basename(self.fn)) os.system('ogg123 -q -d wav -f "%s" "%s"'%( escape(tempname), escape(self.fn))) os.system('lame "%s" %s "%s" --tt "%s" --ta "%s"'%( escape(tempname), self.lame_opts, escape(target), " - ".join(filter(None, (self.track, escape(self.title)))), " - ".join(filter(None, (escape(self.artist), escape(self.album)))))) os.remove(tempname) def convert_mp3(self, target): os.system('lame "%s" %s "%s" --tt "%s" --ta "%s"'%( escape(self.fn), self.lame_opts, escape(target), " - ".join(filter(None, (self.track, escape(self.title)))), " - ".join(filter(None, (escape(self.artist), escape(self.album)))))) def outputname(self, keep_names=1, single_dir=1): if single_dir and keep_names: return os.path.basename(self.fn)[:-4]+"-lbr.mp3" if not keep_names: result = re.sub("\W+", "", os.path.basename(self.fn[:-4]))+"-lbr.mp3" else: result = os.path.basename(self.fn)[:-4]+"-lbr.mp3" if not single_dir: result = "%s - %s%s%s"%(self.artist.replace(os.sep, ""), self.album.replace(os.sep, ""), os.sep, result) return result if __name__ == "__main__": config = Config(sys.argv[1:]) for filename in config.files(): a=AudioStream(filename) result=a.outputname(config.keep_filenames, config.single_directory) a.convert(result)