Matt Price wrote:
convert the files to mp3 one at a time when I want to,
but I wonder if
there's a more fluid way of e.g. converting files when they're uploaded,
or at least converting all files in a particular folder or something.
are there other people out there who have to deal with a similar
situation?
I hacked up this python script to transcode from wav/mp3/ogg/flac to
wav/mp3/flac/ogg.
HTH
R
#!/usr/bin/python
# Copyright Rob Fell, 2007.
import sys
import string
import os
import os.path
import string
import shutil
import tempfile
from subprocess import *
best = False
def GetFlacInfo( meta, f ):
cmd = "metaflac --show-sample-rate --show-tag=artist --show-tag=album
--show-tag=title --show-tag=tracknumber --show-tag=date %s"
p = Popen( cmd % f, shell=True, stdout=PIPE, stderr=PIPE )
artist = album = year = song = tracknum = rate = None
for field in p.communicate()[0].split('\n'):
sep = field.find('=')
if sep > 0:
key = field[0:sep].lower().lstrip()
value = field[sep+1:]
if key == 'artist':
artist = value
if key == 'album':
album = value
if key == 'title':
song = value
if key == 'tracknumber':
tracknum = int( value )
if key == 'date':
year = value
else:
str = ""
for ch in field.lstrip():
if ch.isdigit():
str += ch
else:
break
if str:
rate = int( str )
if song: meta['song'].append( song )
if artist: meta['artist'].append( artist )
if album: meta['album'].append( album )
if tracknum: meta['tracknum'].append( tracknum )
if year: meta['date'].append( year )
if rate: meta['rate'].append( rate )
def GetOggInfo( meta, f ):
p = Popen( "ogginfo %s" % f, shell=True, stdout=PIPE )
artist = album = year = song = tracknum = rate = None
for field in p.communicate()[0].split('\n'):
sep = field.find('=')
if sep > 0:
key = field[0:sep].lower().lstrip()
value = field[sep+1:]
if key == 'artist':
artist = value
if key == 'album':
album = value
if key == 'title':
song = value
if key == 'tracknumber':
tracknum = int( value )
if key == 'date':
year = value
else:
if 'Rate:' in field:
rate = int( field.split(' ')[1] )
if song: meta['song'].append( song )
if artist: meta['artist'].append( artist )
if album: meta['album'].append( album )
if tracknum: meta['tracknum'].append( tracknum )
if year: meta['date'].append( year )
if rate: meta['rate'].append( rate )
def GetID3Info( meta, f ):
p = Popen( "id3info %s" % f, shell=True, stdout=PIPE )
artist = album = year = song = tracknum = rate = None
for field in p.communicate()[0].split('\n'):
if 'Frequency' in field:
freq = field.split(':')[-1].lstrip().lower()
if '44khz' == freq:
rate = 44100
elif '48khz' == freq:
rate = 48000
if not field[0:3] == '===':
continue
key = field[4:8]
if key == 'TIT2':
song = field.split(':')[-1].lstrip()
elif key == 'TPE1':
artist = field.split(':')[-1].lstrip()
elif key == 'TALB':
album = field.split(':')[-1].lstrip()
elif key == 'TRCK':
tracknum = int( field.split(':')[-1] )
elif key == 'TYER':
year = int( field.split(':')[-1] )
if song: meta['song'].append( song )
if artist: meta['artist'].append( artist )
if album: meta['album'].append( album )
if tracknum: meta['tracknum'].append( tracknum )
if year: meta['date'].append( year )
if rate: meta['rate'].append( rate )
def GetMetadata( ftype, f ):
meta = { 'artist' : [],
'album' : [],
'date' : [],
'tracknum' : [],
'song' : [],
'rate' : [] }
if ftype == 'riff':
return None
if ftype == 'flac':
GetFlacInfo( meta, f )
if ftype == 'ogg':
GetOggInfo( meta, f )
GetID3Info( meta, f )
if not meta['tracknum']:
tracknum = ""
for ch in os.path.basename( f ):
if ch.isdigit():
tracknum += ch
else:
break
if tracknum:
meta['tracknum'].append( int( tracknum ))
return meta
def DetermineFileType( f ):
idtable = [ (('MPEG', 'layer III'), ('mp3')),
(('RIFF', 'PCM', 'Microsoft'), ('riff')),
(('Ogg', 'Vorbis'), ('ogg')) ]
# 'file' misidentifies flac files as MP3's, so we use metaflac
# to see if it IS a flac file first
#
is_flac = Popen( "metaflac --list %s" % f, shell=True, stdout=PIPE, stderr=PIPE
).wait() == 0
if is_flac:
ftype = 'flac'
else:
# now fall back to normal 'file' identification
#
p = Popen( "file %s" % f, shell=True, stdout=PIPE )
info = p.communicate()[0]
ftype = None
for rule, tag in idtable:
ftype = tag
for str in rule:
if str not in info:
ftype = None
break
if ftype:
break
return ftype
def Flac2Wav( src, dst ):
return Popen( "flac123 --wav=%s %s" % (dst, src), shell=True, stdout=PIPE
).wait()
def Wav2Flac( src, dst, meta ):
cmd = "flac"
args = ""
if meta:
if meta['song']:
args += ' -T "title=%s"' % meta['song'][0]
if meta['artist']:
args += ' -T "artist=%s"' % meta['artist'][0]
if meta['album']:
args += ' -T "album=%s"' % meta['album'][0]
if meta['date']:
args += ' -T "date=%s"' % meta['date'][0]
if meta['tracknum']:
args += ' -T "tracknumber=%d"' % meta['tracknum'][0]
if args:
cmd += " %s %s %s" % (args, src, dst)
else:
cmd += " %s %s" % (src, dst)
return Popen( cmd , shell=True, stdout=PIPE ).wait()
def Ogg2Wav( src, dst ):
return Popen( "oggdec -o %s %s" % (dst, src), shell=True, stdout=PIPE ).wait()
def Wav2Ogg( src, dst, meta ):
if best:
cmd = "oggenc -q 10"
else:
cmd = "oggenc -q 7"
args = ""
if meta:
if meta['song']:
args += ' -t "%s"' % meta['song'][0]
if meta['artist']:
args += ' -a "%s"' % meta['artist'][0]
if meta['album']:
args += ' -l "%s"' % meta['album'][0]
if meta['date']:
args += ' -d "%s"' % meta['date'][0]
if meta['tracknum']:
args += ' -N %d' % meta['tracknum'][0]
if args:
cmd += " %s -o %s %s" % (args, dst, src)
else:
cmd += " -o %s %s" % (dst, src)
print cmd
return Popen( cmd , shell=True, stdout=PIPE ).wait()
def Mp32Wav( src, dst ):
return Popen( "mpg123 -w %s %s" % (dst, src), shell=True, stdout=PIPE ).wait()
def Wav2Mp3( src, dst, meta ):
if best:
cmd = "lame -V 0 -h "
else:
cmd = "lame -V 4 -h"
args = ""
if meta:
if meta['song']:
args += ' --tt "%s"' % meta['song'][0]
if meta['artist']:
args += ' --ta "%s"' % meta['artist'][0]
if meta['album']:
args += ' --tl "%s"' % meta['album'][0]
if meta['date']:
args += ' --ty "%s"' % meta['date'][0]
if meta['tracknum']:
args += ' --tn %d' % meta['tracknum'][0]
if args:
cmd += " %s %s %s" % (args, src, dst)
else:
cmd += " %s %s" % (src, dst)
return Popen( cmd , shell=True, stdout=PIPE ).wait()
def NewName( f, meta, type ):
types = { 'riff':'wav', 'flac':'flac',
'ogg':'ogg', 'mp3':'mp3' }
if type not in types.keys():
return None
if meta and meta['song']:
if meta['tracknum']:
song = "".join( [ x for x in meta['song'][0].split(' ')] )
name = "%02d%s" % (meta['tracknum'][0], song)
trans = string.maketrans( '', '' )
return ".".join( [string.translate( name, trans,
':,\\/.!\"$%^&*()+=-\'_ ' ), types[type]] )
else:
name = os.path.splitext( os.path.basename( f ))[0]
trans = string.maketrans( '', '' )
return ".".join( [string.translate( name, trans,
':,\\/.!\"$%^&*()+=\' ' ), types[type]] )
def Transcode( src, dst, meta ):
srcFmt, srcFile = src
dstFmt, dstFile = dst
decoders = { 'flac': Flac2Wav,
'ogg' : Ogg2Wav,
'mp3' : Mp32Wav,
'riff': None }
encoders = { 'flac': Wav2Flac,
'ogg' : Wav2Ogg,
'mp3' : Wav2Mp3,
'riff': None }
if os.path.isfile( dstFile ):
raise "refusing to overwrite %s" % dstFile
if not os.path.isdir( os.path.dirname( dstFile )):
raise "directory %s does not exist" % os.path.dirname( dstFile )
if srcFmt == dstFmt:
# only a copy required
#
print "Copying %s to %s" % ( srcFile, dstFile )
shutil.copyfile( srcFile, dstFile )
else:
handle, tempname = tempfile.mkstemp( '.wav', 'pyxcode', '/tmp'
)
os.close(handle)
decode = decoders[srcFmt]
encode = encoders[dstFmt]
if not decode:
shutil.copyfile( srcFile, tempname )
else:
decode( srcFile, tempname )
if not encode:
shutil.copyfile( tempname, dstFile )
else:
encode( tempname, dstFile, meta )
os.remove(tempname)
print "Converted %s" % os.path.basename( srcFile )
def Usage():
print """
exec.py --odir=path --fmt=[flac|wav|riff|ogg|mp3] [--best] file [file...]
"""
sys.exit(1)
if __name__ == "__main__":
files = []
odir = None
fmt = None
args = sys.argv[1:]
for arg in args:
if arg[0:2] == '--':
opt = arg[2:]
sep = opt.find('=')
if sep > 0:
key = opt[0:sep]
value = opt[sep+1:]
if key == 'odir':
odir = value
elif key == 'fmt':
if value == 'wav':
value = 'riff'
fmt = value
else:
Usage()
else:
if opt == 'best':
best = True
else:
Usage()
else:
files.append( arg )
if not odir or not fmt:
Usage()
for f in files:
if os.path.isfile( f ):
ftype = DetermineFileType( f )
if ftype:
meta = GetMetadata( ftype, f )
src = ( ftype, f )
dst = ( fmt, os.path.join( odir, NewName( f, meta, fmt ) ) )
ret = Transcode( src, dst, meta )
if ret:
print ret