FLAC to MP3 Conversion
Here is my custom Python script to convert FLAC files to MP3 files.
In addition to the obligatory audio conversion, it also handles tag conversion. Because of this, the external eyeD3 module is required.
Take a look:
#!/usr/bin/python import subprocess import eyed3 import os import os.path import re import struct import getopt temp_tags = r"/tmp/___TAGS___.utf8" temp_cover = r"/tmp/___COVER___.jpg" def apic_from_unicode_to_latin1(filename): data = open(filename, "rb").read() match = re.search('APIC(......)\x01image/jpeg\x00\x03\xff\xfe\x00\x00', data) if match: header = match.group(1) # Just inject FIX as picture description to keep same frame size! old = 'APIC' + header + '\x01image/jpeg\x00\x03\xff\xfe\x00\x00' new = 'APIC' + header + '\x00image/jpeg\x00\x03FIX\x00' data = data.replace(old, new) fh = open(filename, "wb") fh.write(data) fh.close() class TagData(object): def __init__(self): self.title = None self.album = None self.track_num = None self.artist = None self.genre = None self.date = None self.album_artist = None def read_flac_tags(self, filename): subprocess.call(["metaflac", "--no-utf8-convert", "--export-tags-to=" + temp_tags, filename]) fh = open(temp_tags, "rb") for line in fh: match = re.match(r'^TITLE=(.*)', line.decode('UTF-8'), re.IGNORECASE) if match: self.title = match.group(1) match = re.match(r'^ALBUM=(.*)', line.decode('UTF-8'), re.IGNORECASE) if match: self.album = match.group(1) match = re.match(r'^TRACKNUMBER=(\d*)', line.decode('UTF-8'), re.IGNORECASE) if match: self.track_num = int(match.group(1)) match = re.match(r'^ARTIST=(.*)', line.decode('UTF-8'), re.IGNORECASE) if match: self.artist = match.group(1) match = re.match(r'^GENRE=(.*)', line.decode('UTF-8'), re.IGNORECASE) if match: self.genre = match.group(1) match = re.match(r'^DATE=(\d*)', line.decode('UTF-8'), re.IGNORECASE) if match: self.date = int(match.group(1)) fh.close() def write_mp3_tags(self, filename): audiofile = eyed3.load(filename) audiofile.tag = eyed3.id3.Tag() # Create NEW! if self.title: audiofile.tag.title = self.title if self.album: audiofile.tag.album = self.album if self.track_num: audiofile.tag.track_num = self.track_num if self.artist: audiofile.tag.artist = self.artist if self.genre: audiofile.tag.genre = self.genre if self.date: audiofile.tag.recording_date = self.date # Works if version 2.3 if self.album_artist: audiofile.tag.album_artist = self.album_artist audiofile.tag.save(filename, eyed3.id3.ID3_V2_3) def print_usage(progname): print "Usage: %s " % (progname) print "-f <FLAC File>" print "-a [AlbumArtist]" print "-c [Cover Image Path]" print "-n [Album Name Override]" if __name__ == "__main__": import sys tagdata = TagData() # NOTE: Need to filter out empty strings from sys.argv. # If not, the parser thinks parsing finishes early. try: opts, args = getopt.getopt(filter(None, sys.argv[1:]), "hf:a:c:n:", ["help", "flacfile=", "albumartist=", "cover=", "albumname="]) except getopt.GetoptError as err: print str(err) print_usage(sys.argv[0]) sys.exit(1) print "Opts:", opts print "Args:", args filename = None album_artist = None cover_override = None album_name_override = None for o, a in opts: if o in ("-h", "--help"): print_usage(sys.argv[0]) sys.exit(1) elif o in ("-f", "--flacfile"): filename = a print "FLAC File:", filename elif o in ("-a", "--albumartist"): album_artist = a print "AlbumArtist:", album_artist elif o in ("-c", "--cover"): cover_override = a print "Cover Image Path:", cover_override elif o in ("-n", "--albumname"): album_name_override = a print "Album Name Override:", album_name_override if filename == None: print_usage(sys.argv[0]) sys.exit(1) # Set optional AlbumArtist. if album_artist: tagdata.album_artist = unicode(album_artist) # Read old tags from FLAC. tagdata.read_flac_tags(filename) # Set optional album name override, AFTER reading default tags. if album_name_override: tagdata.album = unicode(album_name_override) # Decode FLAC, encode MP3. subprocess.call(["flac", "-d", filename, "-o", filename + ".wav"]) subprocess.call(["lame", "-b", "320", "-h", filename + ".wav", filename + ".mp3"]) # Write new tags to MP3. tagdata.write_mp3_tags(filename + ".mp3") # Get cover image from argument, or... if cover_override: cover_file = cover_override else: # ...attempt to extract cover image from FLAC file... subprocess.call(["metaflac", "--export-picture-to=" + temp_cover, filename]) cover_file = temp_cover # ...then apply it. if os.path.isfile(cover_file): imagedata = open(cover_file, "rb").read() if imagedata.startswith("\xff\xd8\xff"): audiofile = eyed3.load(filename + ".mp3") audiofile.tag.images.set(3, imagedata, "image/jpeg") audiofile.tag.save() else: print "Warning: Image data is not JPEG." # iTunes APIC fix, encoding must be changed to latin1. apic_from_unicode_to_latin1(filename + ".mp3") # Remove ".flac" part of final MP3 file. if os.path.isfile(filename + ".mp3"): os.rename(filename + ".mp3", filename.replace(".flac", "") + ".mp3") # Remove temporary files. if os.path.isfile(filename + ".wav"): os.remove(filename + ".wav") if os.path.isfile(temp_tags): os.remove(temp_tags) if os.path.isfile(temp_cover): os.remove(temp_cover)