From: yomguy <> Date: Mon, 16 Apr 2007 20:55:38 +0000 (+0000) Subject: Added the ExportCore, OggExporter, FlacExporter, WavExporter and a test tool with... X-Git-Tag: 1.1~989 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=e08ddbe518c39f7771c49604c13fde97042f3988;p=telemeta.git Added the ExportCore, OggExporter, FlacExporter, WavExporter and a test tool with a free sample. Modified several info files. Migrates COPYING to BSD Licence. --- diff --git a/AUTHORS b/AUTHORS index 3f9cf612..4ece8504 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,2 @@ Guillaume Pellerin +Olivier Guilyardi diff --git a/telemeta/__init__.py b/telemeta/__init__.py index 6fd5b8d0..e515d48c 100644 --- a/telemeta/__init__.py +++ b/telemeta/__init__.py @@ -1,3 +1,52 @@ +# -*- coding: utf-8 -*- + +""" +Telemeta +Parisson SARL + +U{http://svn.parisson.org/telemeta} + +@author: Guillaume Pellerin +@author: Olivier Guilyardi +""" + +__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() diff --git a/telemeta/export/__init__.py b/telemeta/export/__init__.py index e69de29b..38998772 100644 --- a/telemeta/export/__init__.py +++ b/telemeta/export/__init__.py @@ -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 * diff --git a/telemeta/export/api.py b/telemeta/export/api.py index 6cce485a..ac5a1ab3 100644 --- a/telemeta/export/api.py +++ b/telemeta/export/api.py @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2007 Olivier Guilyardi +# Copyright (c) 2007 Guillaume Pellerin +# 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 +# Guillaume Pellerin 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 index 00000000..16caff7d --- /dev/null +++ b/telemeta/export/core.py @@ -0,0 +1,282 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2006-2007 Guillaume Pellerin +# 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 + +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 index 00000000..f8ec9297 --- /dev/null +++ b/telemeta/export/default.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2006-2007 Guillaume Pellerin +# 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 + +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 index 00000000..e2c57877 --- /dev/null +++ b/telemeta/export/flac.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2006-2007 Guillaume Pellerin +# 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 + +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 index 00000000..424a1a8f --- /dev/null +++ b/telemeta/export/ogg.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2006-2007 Guillaume Pellerin +# 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 + +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 index 00000000..d30871b4 --- /dev/null +++ b/telemeta/export/wav.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2006-2007 Guillaume Pellerin +# 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 + +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 index 00000000..cf643cbf --- /dev/null +++ b/tests/export_test.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2006-2007 Guillaume Pellerin +# 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 + +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 index 00000000..aa1e9df8 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 index 00000000..a000a0b8 --- /dev/null +++ b/tests/telemeta @@ -0,0 +1 @@ +../telemeta/ \ No newline at end of file