mkogg.py: Add m4a decoding (using faad2) and bump to version 0.4.
authorW. Trevor King <wking@tremily.us>
Thu, 12 Jul 2012 03:44:25 +0000 (23:44 -0400)
committerW. Trevor King <wking@tremily.us>
Thu, 12 Jul 2012 03:44:25 +0000 (23:44 -0400)
posts/mkogg/mkogg.py

index 174e71260825d5f8e0894e1f4753a932e9f9baf3..cab3e056a0b9b54797ccb3af63d430d65c0ff82d 100755 (executable)
@@ -21,6 +21,7 @@
 Conversion between any of the following formats are supported:
 
 * flac
+* m4a (decoding only)
 * mp3
 * ogg (Vorbis)
 * wav
@@ -28,12 +29,14 @@ Conversion between any of the following formats are supported:
 External packages required for full functionality:
 
 * lame_ (`lame`)
+* faad_ (`faad`)
 * flac_ (`flac`)
 * mpg123_ (`mpg123`)
 * vorbis_ (`ogg123`, `oggenc`)
 * mutagen_ (metadata conversion)
 
 .. _lame: http://lame.sourceforge.net/
+.. _faad: http://www.audiocoding.com/faad2.html
 .. _flac: http://flac.sourceforge.net/
 .. _mpg123: http://www.mpg123.org/
 .. _vorbis: http://www.vorbis.com/
@@ -51,13 +54,14 @@ from tempfile import mkstemp
 try:
     import mutagen.flac
     import mutagen.id3
+    import mutagen.m4a
     import mutagen.mp3
     import mutagen.oggvorbis
 except ImportError, _mutagen_import_error:
     mutagen = None
 
 
-__version__ = '0.3'
+__version__ = '0.4'
 
 
 def invoke(args, stdin=None, expect=(0,)):
@@ -100,11 +104,26 @@ class Converter (object):
         'tyer': 'date',
         }
 
+    m4a_to_vorbis_keys = {
+        '\xa9cmt': 'comment',
+        '\xa9alb': 'album',
+        #'tcom': 'composer',
+        'cprt': 'copyright',
+        '\xa9nam': 'title',
+        '\xa9ART': 'artist',
+        #'tpe2': 'accompaniment',
+        #'tpe3': 'conductor',
+        'disk': 'part of set',
+        #'tpub': 'organization',  # publisher
+        'trkn': 'tracknumber',
+        '\xa9day': 'date',
+        }
+
     def __init__(self, source_dir, target_dir, target_extension='ogg',
                  cache_file=None, hash=True, ignore_function=None):
         self.source_dir = source_dir
         self.target_dir = target_dir
-        self._source_extensions = ['flac', 'mp3', 'ogg', 'wav']
+        self._source_extensions = ['flac', 'm4a', 'mp3', 'ogg', 'wav']
         self._target_extension = target_extension
         self._cache_file = cache_file
         self._cache = self._read_cache()
@@ -304,6 +323,8 @@ class Converter (object):
         invoke(['oggenc', '--quiet', '-q', '3', source, '-o', target])
     convert_flac_to_ogg.handles_metadata = True
 
+    def convert_m4a_to_wav(self, source, target):
+        invoke(['faad', '-o', target, source])
 
     def convert_mp3_to_wav(self, source, target):
         invoke(['mpg123',  '-w', target, source])
@@ -325,6 +346,29 @@ class Converter (object):
             raise _mutagen_import_error
         return mutagen.flac.FLAC(source)
 
+    def get_m4a_metadata(self, source):
+        if mutagen is None:
+            raise _mutagen_import_error
+        m4a = mutagen.m4a.M4A(source)
+        metadata = {}
+        for key,value in m4a.items():
+            try:
+                vorbis_key = self.m4a_to_vorbis_keys[key.lower()]
+            except KeyError:
+                continue
+            if vorbis_key == 'tracknumber':
+                tracknumber,tracktotal = value
+                value = tracknumber
+                if tracktotal:
+                    metadata['tracktotal'] = [str(tracktotal)]
+            elif vorbis_key == 'part of set':
+                disknumber,disktotal = value
+                value = disknumber
+                if disktotal:
+                    metadata['set total'] = [str(disktotal)]
+            metadata[vorbis_key] = [str(value)]
+        return metadata
+
     def get_mp3_metadata(self, source):
         if mutagen is None:
             raise _mutagen_import_error