]> git.parisson.com Git - telemeta.git/commitdiff
Added the ExportCore, OggExporter, FlacExporter, WavExporter and a test tool with...
authoryomguy <>
Mon, 16 Apr 2007 20:55:38 +0000 (20:55 +0000)
committeryomguy <>
Mon, 16 Apr 2007 20:55:38 +0000 (20:55 +0000)
12 files changed:
AUTHORS
telemeta/__init__.py
telemeta/export/__init__.py
telemeta/export/api.py
telemeta/export/core.py [new file with mode: 0644]
telemeta/export/default.py [new file with mode: 0644]
telemeta/export/flac.py [new file with mode: 0644]
telemeta/export/ogg.py [new file with mode: 0644]
telemeta/export/wav.py [new file with mode: 0644]
tests/export_test.py [new file with mode: 0644]
tests/samples/wav/Cellar - Show Me - 02.wav [new file with mode: 0755]
tests/telemeta [new symlink]

diff --git a/AUTHORS b/AUTHORS
index 3f9cf612aa1465d8340522830f1ee3435a9fa117..4ece85048ab8c61a6d5b136ef6cc058d0941d981 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,2 @@
 Guillaume Pellerin <yomguy@altern.org>
+Olivier Guilyardi <olivier@samalyse.com>
index 6fd5b8d00ca90b287424623f130da786ba7cfeeb..e515d48c1b7b49d0f562007a0a8ccee2dc68e7de 100644 (file)
@@ -1,3 +1,52 @@
+# -*- coding: utf-8 -*-
+
+"""
+Telemeta
+Parisson SARL
+
+U{http://svn.parisson.org/telemeta}
+
+@author: Guillaume Pellerin <pellerin@parisson.com>
+@author: Olivier Guilyardi <olivier@samalyse.com>
+"""
+
+__docformat__ = 'epytext en'
+__version__ = '0.2.8'
+__url__ = 'http://svn.parisson.org/telemeta'
+__copyright__ = '(C) 2007 Parisson'
+__license__ = 'BSD'
+__license_long__ = """
+ Copyright (C) 2007 Parisson
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The name of the author may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ """
+
+
 from telemeta.util.logger import Logger
 
 logger = Logger()
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..389987720fa51313a136d47fcb09acfd73eda30e 100644 (file)
@@ -0,0 +1,5 @@
+from telemeta.export.api import *
+from telemeta.export.core import *
+from telemeta.export.ogg import *
+from telemeta.export.flac import *
+from telemeta.export.wav import *
index 6cce485a4021f49226bf37c98f18c0afe14abb47..ac5a1ab39bd3cf4ff9a24377854affce5e6d8d61 100644 (file)
@@ -1,3 +1,16 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2007 Olivier Guilyardi <olivier@samalyse.com>
+# Copyright (c) 2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Olivier Guilyardi <olivier@samalyse.com>
+#                Guillaume Pellerin <pellerin@parisson.com>
 
 class IExporter:
     """Export driver interface"""
@@ -24,7 +37,7 @@ class IExporter:
     def get_mime_type():
         """Return the mime type corresponding to this export format"""
 
-    def set_cache_directory(path):
+    def set_cache_dir(path):
         """Set the directory where cached files should be stored. Does nothing
         if the exporter doesn't support caching. 
        
@@ -39,18 +52,17 @@ class IExporter:
         item_id is the media item id that uniquely identifies this audio/video
         resource
 
-        source is the audio/video source file absolute path. For audio that should
-        be a WAV file
+        source is the audio/video source file absolute path. For audio that
+               should be a WAV file
 
         metadata is a dictionary
 
         The returned file path is not meant to be permanent in any way, it 
         should be considered temporary/volatile by the caller.
 
-        It is highly recommended that export drivers implement some sort of cache
-        instead of re-encoding each time process() is called. 
+        It is highly recommended that export drivers implement some sort of
+               cache instead of re-encoding each time process() is called.
 
-        It should be possible to make subsequent calls to process() with different
-        items, using the same driver instance.
+        It should be possible to make subsequent calls to process() with
+               different items, using the same driver instance.
         """
-
diff --git a/telemeta/export/core.py b/telemeta/export/core.py
new file mode 100644 (file)
index 0000000..16caff7
--- /dev/null
@@ -0,0 +1,282 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+
+import os
+import re
+import string
+
+import telemeta.export
+from telemeta.export import *
+from telemeta.export.api import IExporter
+from telemeta.export.default import Tags, Options, Collection
+import xml.dom.minidom
+import xml.dom.ext
+
+class ExporterCore:
+       """Defines the main parts of the exporting tools :
+       paths, formats, metadata..."""
+
+       #implements(IExporter) ?
+
+       def __init__(self):
+               self.source = ''
+               self.collection = ''
+               self.verbose = ''
+               self.dest = ''
+               self.metadata = []
+               self.cache_dir = 'cache'
+
+       def set_cache_dir(self,path):
+               self.cache_dir = path
+
+       def normalize(self):
+               """ Normalize the source and return its path """
+               args = ''
+               if self.verbose == '0':
+                       args = '-q'
+               try:
+                       os.system('normalize-audio '+args+' "'+self.source+'"')
+                       return self.source
+               except IOError:
+                       return 'Exporter error: Cannot normalize, path does not exist.'
+
+                       
+       def create_md5_key(self):
+               """ Create the md5 keys of the dest """
+               try:
+                       os.system('md5sum -b "'+self.dest+'" >"'+self.dest+'.md5"')
+               except IOError:
+                       return 'Exporter error: Cannot create the md5 key...'
+
+       def check_md5_key(self):
+               """ Check if the md5 key is OK and return a boolean """
+               try:
+                       md5_log = os.popen4('md5sum -c "'+self.dest+ \
+                                                               '" "'+self.dest+'.md5"')
+                       return 'OK' in md5_log.split(':')
+               except IOError:
+                       return 'Exporter error: Cannot check the md5 key...'
+       
+       def create_par_key(self):
+               """ Create the par2 keys of the dest """
+               args = 'c -n1 '
+               if self.verbose == '0':
+                       args = args + '-q -q '
+               try:
+                       os.system('par2 '+args+' "'+self.dest+'"')
+               except IOError:
+                       return 'Exporter error: Cannot create the par2 key...'
+
+       def get_file_info(self):
+               """ Return the list of informations of the dest """
+               return self.export.get_file_info()
+
+       def get_wav_length_sec(self) :
+               """ Return the length of the audio source file in seconds """
+               try:
+                       file1, file2 = os.popen4('wavinfo "'+self.source+ \
+                                                                        '" | grep wavDataSize')
+                       for line in file2.readlines():
+                               line_split = line.split(':')
+                               value = int(int(line_split[1])/(4*44100))
+                               return value
+               except IOError:
+                       return 'Exporter error: Cannot get the wav length...'
+
+       def compare_md5_key(self):
+               """ Compare 2 files wih md5 method """
+               in1, in2 = os.popen4('md5sum -b "'+self.source+'"')
+               out1, out2 = os.popen4('md5sum -b "'+self.dest+'"')
+               for line in in2.readlines():
+                       line1 = line.split('*')[0]
+               for line in out2.readlines():
+                       line2 = line.split('*')[0]
+               return line1 == line2
+
+       def write_metadata_xml(self,path):
+               doc = xml.dom.minidom.Document()
+               root = doc.createElement('telemeta')
+               doc.appendChild(root)
+               for tag in self.metadata.keys() :
+                       value = self.metadata[tag]
+                       node = doc.createElement(tag)
+                       node.setAttribute('value', str(value))
+                       #node.setAttribute('type', get_type(value))
+                       root.appendChild(node)
+               xml_file = open(path, "w")
+               xml.dom.ext.PrettyPrint(doc, xml_file)
+               xml_file.close()
+
+       def process(self, item_id, source, metadata):
+               """ Export the source """
+               self.item_id = item_id
+               self.source = source
+               file_name = get_file_name(self.source)
+               file_name_wo_ext, file_ext = split_file_name(file_name)
+
+               self.metadata = metadata
+               self.collection = self.metadata['Collection']
+               self.artist = self.metadata['Artist']
+               self.title = self.metadata['Title']
+               self.verbose = self.metadata['verbose']
+
+               # The Loop
+               for format in self.metadata['export_formats']:
+
+                       # Implement the exporter object with the given format
+                       if format == 'OGG':
+                               self.export = telemeta.export.ogg.OggExporter()
+                       if format == 'FLAC':
+                               self.export = telemeta.export.FlacExporter()
+                       if format == 'WAV':
+                               self.export = telemeta.export.WavExporter()
+
+                       # Decode the source if needed
+                       if os.path.exists(self.source) and not iswav16(self.source):
+                               # TO FIX ! 
+                               self.source = self.export.decode()
+
+                       # Normalize if demanded
+                       if 'normalize' in self.metadata and self.metadata['normalize']:
+                               self.normalize()
+
+                       # Define the cache directory
+                       self.export.set_cache_dir(self.cache_dir)
+                       self.ext = self.export.get_file_extension()
+                       
+                       # Define and create the destination path
+                       # At the moment, the target directory is built with this scheme in
+                       # the cache directory : ./%Format/%Collection/%Artist/
+                       self.dest = self.cache_dir
+                       export_dir = os.path.join(self.ext,self.collection,self.artist)
+
+                       if not os.path.exists(os.path.join(self.dest,export_dir)):
+                               for _dir in export_dir.split(os.sep):
+                                       self.dest = os.path.join(self.dest,_dir)
+                                       if not os.path.exists(self.dest):
+                                               os.mkdir(self.dest)
+                       else:
+                               self.dest = os.path.join(self.dest,export_dir)
+
+                       # Set the target file
+                       target_file = file_name_wo_ext+'.'+self.ext
+                       self.dest = os.path.join(self.dest,target_file)
+                       self.export.dest = self.dest
+                       
+                       # Process
+                       try:
+                               self.export.process(self.item_id,
+                                                                   self.source,
+                                                                       self.metadata)
+                       except IOError:
+                               return 'Encoding failed !'
+
+                       if self.verbose != '0':
+                               print self.dest
+                               print self.export.get_file_info()
+
+
+# External functions
+
+def get_type(value):
+       """ Return a String with the type of value """
+       types = {bool : 'bool', int : 'int', str : 'str'}
+       # 'bool' type must be placed *before* 'int' type, otherwise booleans are
+       # detected as integers
+       for type in types.keys():
+               if isinstance(value, type) :
+                       return types[type]
+       raise TypeError, str(value) + ' has an unsupported type'
+
+def get_cast(value, type) :
+       """ Return value, casted into type """
+       if type == 'bool' :
+               if value == 'True' :
+                       return True
+               return False
+       elif type == 'int' :
+               return int(value)
+       elif type == 'str' :
+               return str(value)
+       raise TypeError, type + ' is an unsupported type'
+
+def get_file_mime_type(path):
+       """ Return the mime type of a file """
+       try:
+               file_out1, file_out2 = os.popen4('file -i "'+path+'"')
+               for line in file_out2.readlines():
+                       line_split = line.split(': ')
+                       mime = line_split[len(line_split)-1]
+                       return mime[:len(mime)-1]
+       except IOError:
+               return 'Exporter error [1]: path does not exist.'
+
+def get_file_type_desc(path):
+       """ Return the type of a file given by the 'file' command """
+       try:
+               file_out1, file_out2 = os.popen4('file "'+path+'"')
+               for line in file_out2.readlines():
+                       description = line.split(': ')
+                       description = description[1].split(', ')
+                       return description
+       except IOError:
+               return 'Exporter error [1]: path does not exist.'
+
+def iswav(path):
+       """ Tell if path is a WAV """
+       try:
+               mime = get_file_mime_type(path)
+               return mime == 'audio/x-wav'
+       except IOError:
+               return 'Exporter error [1]: path does not exist.'
+
+def iswav16(path):
+       """ Tell if path is a 16 bit WAV """
+       try:
+               file_type_desc = get_file_type_desc(path)
+               return iswav(path) and '16 bit' in file_type_desc
+       except IOError:
+               return 'Exporter error [1]: path does not exist.'
+
+def get_file_name(path):
+       """ Return the file name targeted in the path """
+       return os.path.split(path)[1]
+
+def split_file_name(file):
+       """ Return main file name and its extension """
+       try:
+               return os.path.splitext(file)
+       except IOError:
+               return 'Exporter error [1]: path does not exist.'
+
+def clean_word(word) :
+       """ Return the word without excessive blank spaces and underscores """
+       word = re.sub("^[^\w]+","",word)        #trim the beginning
+       word = re.sub("[^\w]+$","",word)        #trim the end
+       #word = string.replace(word,' ','_')
+       word = re.sub("_+","_",word)            #squeeze continuous _ to one _
+       word = re.sub("^[^\w]+","",word)        #trim the beginning _
+       #word = string.capitalize(word)
+       return word
+
+def recover_par_key(path):
+       """ Recover a file with par2 key """
+       os.system('par2 r "'+path+'"')
+
+def verify_par_key(path):
+       """ Verify a par2 key """
+       os.system('par2 v "'+path+'.par2"')
+
+def get_consts_value(self, data):
+       value = self.collection.__dict__[data]
+       value_type = getType(value)
+       return value, value_type
diff --git a/telemeta/export/default.py b/telemeta/export/default.py
new file mode 100644 (file)
index 0000000..f8ec929
--- /dev/null
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+
+import os
+
+class Tags :
+
+       def __init__(self) :
+               self.COLLECTION = 'Unknown'
+               self.ARTIST = 'Unknown'
+               self.TITLE = 'Unknown'
+               self.ALBUM = 'Unknown'
+               self.GENRE = 'Other'
+               self.DATE = '1900'
+               self.SOURCE = 'Here'
+               self.ENCODER = 'me@domain.com'
+               self.COMMENT = 'No comment'
+               self.ORIGINAL_MEDIA = '1/4" tape'
+
+
+class Options :
+
+       def __init__(self) :
+               self.collection = 'Unknown'
+               self.enc_types = 'flac, ogg, mp3'
+               self.ogg_bitrate ='192'
+               self.mp3_bitrate = '192'
+               self.flac_quality = '5'
+               self.audio_marking = False
+               self.auto_audio_marking = True
+               self.audio_marking_file = '/path/to/file'
+               self.audio_marking_timeline = 'b, m, e'
+               self.par_key = True
+               self.normalize = False
+
+
+class Collection :
+
+       def __init__(self) :
+               self.collection_name = 'telemeta_default'
+               self.collection_dir = '/home/'+os.environ["USER"]+'/telemeta_default/'
+               self.user_dir = '/home/'+os.environ["USER"]+'/.telemeta/'
+               self.default_tag_xml = '/home/'+os.environ["USER"]+ \
+                                                          '/.telemeta/default_tags.xml'
+               self.default_collection_xml = '/home/'+os.environ["USER"]+ \
+                                                                         '/.telemeta/default_collection.xml'
+               self.tag_table = 'ARTIST,TITLE,ALBUM,DATE,GENRE,SOURCE,ENCODER,COMMENT'
+               self.type_list = 'mp3,ogg,flac,wav,aiff'
+               self.net_backup_host = 'domain.com'
+               self.net_backup_dir = '/home/'+os.environ["USER"]+'/telemeta/'
+
diff --git a/telemeta/export/flac.py b/telemeta/export/flac.py
new file mode 100644 (file)
index 0000000..e2c5787
--- /dev/null
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+
+import os
+import string
+
+from telemeta.export.core import *
+from mutagen.flac import FLAC
+
+class FlacExporter(ExporterCore):
+       """Defines methods to export to OGG Vorbis"""
+
+       def __init__(self):
+               self.item_id = ''
+               self.metadata = []
+               self.description = ''
+               self.info = []
+               self.source = ''
+               self.dest = ''
+               self.quality_default = '5'
+               
+       def get_format(self):
+               return 'FLAC'
+       
+       def get_file_extension(self):
+               return 'flac'
+
+       def get_mime_type(self):
+               return 'application/flac'
+
+       def get_description(self):
+               return """S00N"""
+
+       def get_file_info(self):
+               try:
+                       file1, file2 = os.popen4('metaflac --list "'+self.dest+'"')
+                       info = []
+                       for line in file2.readlines():
+                               info.append(clean_word(line[:-1]))
+                       self.info = info
+                       return self.info
+               except IOError:
+                       return 'Exporter error [1]: file does not exist.'
+
+       def set_cache_dir(self,path):
+               """Set the directory where cached files should be stored. Does nothing
+        if the exporter doesn't support caching. 
+       
+        The driver shouldn't assume that this method will always get called. A
+        temporary directory should be used if that's not the case.
+        """
+               self.cache_dir = path
+
+       def decode(self):
+               try:
+                       file_name, ext = get_file_name(self.source)
+                       dest = self.cache_dir+os.sep+file_name+'.wav'
+                       os.system('flac -d -o "'+dest+'" "'+self.source+'"')
+                       self.source = dest
+                       return dest
+               except IOError:
+                       return 'ExporterError [2]: decoder not compatible.'
+
+       def write_tags(self):
+               media = FLAC(self.dest)
+               for tag in self.metadata.keys():
+                       if tag == 'COMMENT':
+                               media['DESCRIPTION'] = str(self.metadata[tag])
+                       else:
+                               media[tag] = str(self.metadata[tag])
+               media.save()
+               
+       def process(self, item_id, source, metadata):
+               self.item_id = item_id
+               self.source = source
+               self.metadata = metadata
+
+               if self.metadata['flac_quality'] != '':
+                       args = '-f -V -'+self.metadata['flac_quality']
+               else:
+                       args = '-f -s   -V -'+self.quality_default
+
+               if self.metadata['verbose'] == '0':
+                       args = args+' -s'
+       
+               try:
+                       # Encoding
+                       os.system('flac '+args+' -o "'+self.dest+'" "'+ \
+                                         self.source+'" > /dev/null')
+                       # Write tags
+                       self.write_tags()
+                       return self.dest
+               except IOError:
+                       return 'ExporterError [3]: source file does not exist.'
+
diff --git a/telemeta/export/ogg.py b/telemeta/export/ogg.py
new file mode 100644 (file)
index 0000000..424a1a8
--- /dev/null
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+
+import os
+import string
+
+from telemeta.export.core import *
+from mutagen.oggvorbis import OggVorbis
+
+class OggExporter(ExporterCore):
+       """Defines methods to export to OGG Vorbis"""
+
+       def __init__(self):
+               self.item_id = ''
+               self.metadata = []
+               self.description = ''
+               self.info = []
+               self.source = ''
+               self.dest = ''
+               self.bitrate_default = '192'
+
+       def get_format(self):
+               return 'OGG'
+       
+       def get_file_extension(self):
+               return 'ogg'
+
+       def get_mime_type(self):
+               return 'application/ogg'
+
+       def get_description(self):
+               return """S00N"""
+
+       def get_file_info(self):
+               try:
+                       file_out1, file_out2 = os.popen4('ogginfo "'+self.dest+'"')
+                       info = []
+                       for line in file_out2.readlines():
+                               info.append(clean_word(line[:-1]))
+                       self.info = info
+                       return self.info
+               except IOError:
+                       return 'Exporter error [1]: file does not exist.'
+
+       #def set_cache_dir(self,path):
+       #       self.cache_dir = path
+
+       def decode(self):
+               try:
+                       os.system('oggdec -o "'+self.cache_dir+os.sep+self.item_id+
+                                         '.wav" "'+self.source+'"')
+                       return self.cache_dir+os.sep+self.item_id+'.wav'
+               except IOError:
+                       return 'ExporterError [2]: decoder not compatible.'
+
+       def write_tags(self):
+               media = OggVorbis(self.dest)
+               for tag in self.metadata.keys():
+                       media[tag] = str(self.metadata[tag])
+               media.save()
+               
+       def process(self, item_id, source, metadata):
+               self.item_id = item_id
+               self.source = source
+               self.metadata = metadata
+               self.quality = self.metadata['ogg_quality']
+               self.bitrate = self.metadata['ogg_bitrate']
+
+               if self.bitrate != '':
+                       args = '-b '+self.bitrate
+               elif self.quality != '':
+                       args = '-q '+self.quality
+               else:
+                       args = '-b '+self.bitrate_default
+
+               if self.metadata['verbose'] == '0':
+                       args = args+' -Q'
+
+               if os.path.exists(self.source) and not iswav16(self.source):
+                       self.source = self.decode()
+                       
+               try:
+                       # Encoding
+                       os.system('oggenc '+args+' -o "'+self.dest+
+                                         '" "'+self.source+'"')
+                       # Write tags
+                       self.write_tags()
+                       return self.dest
+               except IOError:
+                       return 'ExporterError [3]: source file does not exist.'
+
diff --git a/telemeta/export/wav.py b/telemeta/export/wav.py
new file mode 100644 (file)
index 0000000..d30871b
--- /dev/null
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+
+import os
+import string
+
+from telemeta.export.core import *
+
+class WavExporter(ExporterCore):
+       """Defines methods to export to OGG Vorbis"""
+
+       def __init__(self):
+               self.item_id = ''
+               self.metadata = []
+               self.description = ''
+               self.info = []
+               self.source = ''
+               self.dest = ''
+               
+               
+       def get_format(self):
+               return 'WAV'
+       
+       def get_file_extension(self):
+               return 'wav'
+
+       def get_mime_type(self):
+               return 'audio/x-wav'
+
+       def get_description(self):
+               return """S00N"""
+
+       def get_file_info(self):
+               try:
+                       file1, file2 = os.popen4('wavinfo "'+self.dest+'"')
+                       info = []
+                       for line in file2.readlines():
+                               info.append(clean_word(line[:-1]))
+                       self.info = info
+                       return self.info
+               except IOError:
+                       return 'Exporter error [1]: file does not exist.'
+
+       def set_cache_dir(self,path):
+               """Set the directory where cached files should be stored. Does nothing
+        if the exporter doesn't support caching. 
+       
+        The driver shouldn't assume that this method will always get called. A
+        temporary directory should be used if that's not the case.
+        """
+               self.cache_dir = path
+
+       def decode(self):
+               try:
+                       file_name, ext = get_file_name(self.source)
+                       dest = self.cache_dir+os.sep+file_name+'.wav'
+                       os.system('sox "'+self.source+'" -w -r 44100 -t wav -c2 "'+ \
+                                         dest+'.wav"')
+                       self.source = dest
+                       return dest
+               except IOError:
+                       return 'ExporterError [2]: decoder not compatible.'
+
+       def write_tags(self):
+               # Create metadata XML file !
+               self.write_metadata_xml(self.dest+'.xml')
+                       
+       def process(self, item_id, source, metadata):
+               self.item_id = item_id
+               self.source = source
+               self.metadata = metadata
+               self.verbose = self.metadata['verbose']
+
+               try:
+                       #if self.compare_md5_key():
+                       os.system('cp -a "'+self.source+'" "'+ self.dest+'"')
+                       #print 'COPIED'
+                       # Write tags
+                       self.write_tags()
+
+                       # Create the md5 key
+                       if 'md5' in self.metadata and self.metadata['md5']:
+                               self.create_md5_key()
+
+                       # Create the par2 key
+                       if 'par2' in self.metadata and self.metadata['par2']:
+                               self.create_par_key()
+                               
+                       return self.dest
+
+               except IOError:
+                       return 'ExporterError [3]: source file does not exist.'
+
diff --git a/tests/export_test.py b/tests/export_test.py
new file mode 100644 (file)
index 0000000..cf643cb
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+
+import os
+from telemeta.export import *
+
+class ExportTest:
+       """Test the 'export' features"""
+       def __init__(self):
+               self.cache_dir = 'cache/'
+               self.source = 'samples/wav/Cellar - Show Me - 02.wav'
+               self.item_id = '1'
+               
+               self.metadata = {'Collection': 'Test_Collection',
+                                                'Title': 'Show Me',
+                                                'Artist': 'Cellar',
+                                                'Encoder': 'Telemeta',
+                                                'Item_id': self.item_id,
+                                                'export_formats': ['WAV','OGG','FLAC'],
+                                                'normalize': True,
+                                                'md5': True,
+                                                'par2': True,
+                                                'ogg_bitrate': '192',
+                                                'ogg_quality': '4',
+                                                'flac_quality': '5',
+                                                'verbose': '1',
+                                                }
+               
+               self.dest = core.ExporterCore()
+               self.dest.set_cache_dir = self.cache_dir
+                                                
+       def process(self):
+               self.dest.process(self.item_id, self.source, self.metadata)
+
+
+media = ExportTest()
+media.process()
\ No newline at end of file
diff --git a/tests/samples/wav/Cellar - Show Me - 02.wav b/tests/samples/wav/Cellar - Show Me - 02.wav
new file mode 100755 (executable)
index 0000000..aa1e9df
Binary files /dev/null and b/tests/samples/wav/Cellar - Show Me - 02.wav differ
diff --git a/tests/telemeta b/tests/telemeta
new file mode 120000 (symlink)
index 0000000..a000a0b
--- /dev/null
@@ -0,0 +1 @@
+../telemeta/
\ No newline at end of file