def test_transcoder(): ''' Tests AudioTransocder's transcode method ''' transcoder = AudioTranscoder() with create_data_for_test() as (audio_name, result_name): transcoder.transcode(audio_name, result_name, quality=0.3, progress_callback=None) info = discover(result_name) assert len(info.get_audio_streams()) == 1 transcoder.transcode(audio_name, result_name, quality=0.3, mux_name='oggmux', progress_callback=None) info = discover(result_name) assert len(info.get_audio_streams()) == 1
def test_thumbnails(): '''Test thumbnails generation. The code below heavily repeats audio.processing.CommonAudioProcessor.create_spectrogram 1. Create test audio 2. Convert it to OGG source for spectogram using transcoder 3. Create spectogram in jpg ''' thumbnailer = AudioThumbnailer() transcoder = AudioTranscoder() with create_data_for_test() as (audio_name, new_name): transcoder.transcode(audio_name, new_name, mux_name='oggmux') thumbnail = tempfile.NamedTemporaryFile(suffix='.jpg') # fft_size below is copypasted from config_spec.ini thumbnailer.spectrogram(new_name, thumbnail.name, width=100, fft_size=4096) assert imghdr.what(thumbnail.name) == 'jpeg'
class CommonAudioProcessor(MediaProcessor): """ Provides a base for various audio processing steps """ acceptable_files = ['original', 'best_quality', 'webm_audio'] def common_setup(self): """ Setup the workbench directory and pull down the original file, add the audio_config, transcoder, thumbnailer and spectrogram_tmp path """ self.audio_config = mgg \ .global_config['plugins']['mediagoblin.media_types.audio'] # Pull down and set up the processing file self.process_filename = get_process_filename(self.entry, self.workbench, self.acceptable_files) self.name_builder = FilenameBuilder(self.process_filename) self.transcoder = AudioTranscoder() self.thumbnailer = AudioThumbnailer() def copy_original(self): if self.audio_config['keep_original']: copy_original(self.entry, self.process_filename, self.name_builder.fill('{basename}{ext}')) def _keep_best(self): """ If there is no original, keep the best file that we have """ if not self.entry.media_files.get('best_quality'): # Save the best quality file if no original? if not self.entry.media_files.get('original') and \ self.entry.media_files.get('webm_audio'): self.entry.media_files['best_quality'] = self.entry \ .media_files['webm_audio'] def _skip_processing(self, keyname, **kwargs): file_metadata = self.entry.get_file_metadata(keyname) skip = True if not file_metadata: return False if keyname == 'webm_audio': if kwargs.get('quality') != file_metadata.get('quality'): skip = False elif keyname == 'spectrogram': if kwargs.get('max_width') != file_metadata.get('max_width'): skip = False elif kwargs.get('fft_size') != file_metadata.get('fft_size'): skip = False elif keyname == 'thumb': if kwargs.get('size') != file_metadata.get('size'): skip = False return skip def transcode(self, quality=None): if not quality: quality = self.audio_config['quality'] if self._skip_processing('webm_audio', quality=quality): return progress_callback = ProgressCallback(self.entry) webm_audio_tmp = os.path.join( self.workbench.dir, self.name_builder.fill('{basename}{ext}')) self.transcoder.transcode(self.process_filename, webm_audio_tmp, quality=quality, progress_callback=progress_callback) self.transcoder.discover(webm_audio_tmp) self._keep_best() _log.debug('Saving medium...') store_public(self.entry, 'webm_audio', webm_audio_tmp, self.name_builder.fill('{basename}.medium.webm')) self.entry.set_file_metadata('webm_audio', **{'quality': quality}) def create_spectrogram(self, max_width=None, fft_size=None): if not max_width: max_width = mgg.global_config['media:medium']['max_width'] if not fft_size: fft_size = self.audio_config['spectrogram_fft_size'] if self._skip_processing('spectrogram', max_width=max_width, fft_size=fft_size): return wav_tmp = os.path.join(self.workbench.dir, self.name_builder.fill('{basename}.ogg')) _log.info('Creating OGG source for spectrogram') self.transcoder.transcode( self.process_filename, wav_tmp, mux_string='vorbisenc quality={0} ! oggmux'.format( self.audio_config['quality'])) spectrogram_tmp = os.path.join( self.workbench.dir, self.name_builder.fill('{basename}-spectrogram.jpg')) self.thumbnailer.spectrogram(wav_tmp, spectrogram_tmp, width=max_width, fft_size=fft_size) _log.debug('Saving spectrogram...') store_public(self.entry, 'spectrogram', spectrogram_tmp, self.name_builder.fill('{basename}.spectrogram.jpg')) file_metadata = {'max_width': max_width, 'fft_size': fft_size} self.entry.set_file_metadata('spectrogram', **file_metadata) def generate_thumb(self, size=None): if not size: max_width = mgg.global_config['media:thumb']['max_width'] max_height = mgg.global_config['media:thumb']['max_height'] size = (max_width, max_height) if self._skip_processing('thumb', size=size): return thumb_tmp = os.path.join( self.workbench.dir, self.name_builder.fill('{basename}-thumbnail.jpg')) # We need the spectrogram to create a thumbnail spectrogram = self.entry.media_files.get('spectrogram') if not spectrogram: _log.info('No spectrogram found, we will create one.') self.create_spectrogram() spectrogram = self.entry.media_files['spectrogram'] spectrogram_filepath = mgg.public_store.get_local_path(spectrogram) self.thumbnailer.thumbnail_spectrogram(spectrogram_filepath, thumb_tmp, tuple(size)) store_public(self.entry, 'thumb', thumb_tmp, self.name_builder.fill('{basename}.thumbnail.jpg')) self.entry.set_file_metadata('thumb', **{'size': size})
class CommonAudioProcessor(MediaProcessor): """ Provides a base for various audio processing steps """ acceptable_files = ['original', 'best_quality', 'webm_audio'] def common_setup(self): """ Setup the workbench directory and pull down the original file, add the audio_config, transcoder, thumbnailer and spectrogram_tmp path """ self.audio_config = mgg \ .global_config['plugins']['mediagoblin.media_types.audio'] # Pull down and set up the processing file self.process_filename = get_process_filename( self.entry, self.workbench, self.acceptable_files) self.name_builder = FilenameBuilder(self.process_filename) self.transcoder = AudioTranscoder() self.thumbnailer = AudioThumbnailer() def copy_original(self): if self.audio_config['keep_original']: copy_original( self.entry, self.process_filename, self.name_builder.fill('{basename}{ext}')) def _keep_best(self): """ If there is no original, keep the best file that we have """ if not self.entry.media_files.get('best_quality'): # Save the best quality file if no original? if not self.entry.media_files.get('original') and \ self.entry.media_files.get('webm_audio'): self.entry.media_files['best_quality'] = self.entry \ .media_files['webm_audio'] def _skip_processing(self, keyname, **kwargs): file_metadata = self.entry.get_file_metadata(keyname) skip = True if not file_metadata: return False if keyname == 'webm_audio': if kwargs.get('quality') != file_metadata.get('quality'): skip = False elif keyname == 'spectrogram': if kwargs.get('max_width') != file_metadata.get('max_width'): skip = False elif kwargs.get('fft_size') != file_metadata.get('fft_size'): skip = False elif keyname == 'thumb': if kwargs.get('size') != file_metadata.get('size'): skip = False return skip def transcode(self, quality=None): if not quality: quality = self.audio_config['quality'] if self._skip_processing('webm_audio', quality=quality): return progress_callback = ProgressCallback(self.entry) webm_audio_tmp = os.path.join(self.workbench.dir, self.name_builder.fill( '{basename}{ext}')) self.transcoder.transcode( self.process_filename, webm_audio_tmp, quality=quality, progress_callback=progress_callback) self._keep_best() _log.debug('Saving medium...') store_public(self.entry, 'webm_audio', webm_audio_tmp, self.name_builder.fill('{basename}.medium.webm')) self.entry.set_file_metadata('webm_audio', **{'quality': quality}) def create_spectrogram(self, max_width=None, fft_size=None): if not max_width: max_width = mgg.global_config['media:medium']['max_width'] if not fft_size: fft_size = self.audio_config['spectrogram_fft_size'] if self._skip_processing('spectrogram', max_width=max_width, fft_size=fft_size): return wav_tmp = os.path.join(self.workbench.dir, self.name_builder.fill( '{basename}.ogg')) _log.info('Creating OGG source for spectrogram') self.transcoder.transcode(self.process_filename, wav_tmp, mux_name='oggmux') spectrogram_tmp = os.path.join(self.workbench.dir, self.name_builder.fill( '{basename}-spectrogram.jpg')) self.thumbnailer.spectrogram( wav_tmp, spectrogram_tmp, width=max_width, fft_size=fft_size) _log.debug('Saving spectrogram...') store_public(self.entry, 'spectrogram', spectrogram_tmp, self.name_builder.fill('{basename}.spectrogram.jpg')) file_metadata = {'max_width': max_width, 'fft_size': fft_size} self.entry.set_file_metadata('spectrogram', **file_metadata) def generate_thumb(self, size=None): if not size: max_width = mgg.global_config['media:thumb']['max_width'] max_height = mgg.global_config['media:thumb']['max_height'] size = (max_width, max_height) if self._skip_processing('thumb', size=size): return thumb_tmp = os.path.join(self.workbench.dir, self.name_builder.fill( '{basename}-thumbnail.jpg')) # We need the spectrogram to create a thumbnail spectrogram = self.entry.media_files.get('spectrogram') if not spectrogram: _log.info('No spectrogram found, we will create one.') self.create_spectrogram() spectrogram = self.entry.media_files['spectrogram'] spectrogram_filepath = mgg.public_store.get_local_path(spectrogram) self.thumbnailer.thumbnail_spectrogram( spectrogram_filepath, thumb_tmp, tuple(size)) store_public(self.entry, 'thumb', thumb_tmp, self.name_builder.fill('{basename}.thumbnail.jpg')) self.entry.set_file_metadata('thumb', **{'size': size})
def process_audio(entry): audio_config = mgg.global_config['media_type:mediagoblin.media_types.audio'] workbench = mgg.workbench_manager.create_workbench() queued_filepath = entry.queued_media_file queued_filename = workbench.localized_file( mgg.queue_store, queued_filepath, 'source') name_builder = FilenameBuilder(queued_filename) webm_audio_filepath = create_pub_filepath( entry, '{original}.webm'.format( original=os.path.splitext( queued_filepath[-1])[0])) if audio_config['keep_original']: with open(queued_filename, 'rb') as queued_file: original_filepath = create_pub_filepath( entry, name_builder.fill('{basename}{ext}')) with mgg.public_store.get_file(original_filepath, 'wb') as \ original_file: _log.debug('Saving original...') original_file.write(queued_file.read()) entry.media_files['original'] = original_filepath transcoder = AudioTranscoder() with tempfile.NamedTemporaryFile() as webm_audio_tmp: progress_callback = ProgressCallback(entry) transcoder.transcode( queued_filename, webm_audio_tmp.name, quality=audio_config['quality'], progress_callback=progress_callback) transcoder.discover(webm_audio_tmp.name) _log.debug('Saving medium...') mgg.public_store.get_file(webm_audio_filepath, 'wb').write( webm_audio_tmp.read()) entry.media_files['webm_audio'] = webm_audio_filepath # entry.media_data_init(length=int(data.audiolength)) if audio_config['create_spectrogram']: spectrogram_filepath = create_pub_filepath( entry, '{original}-spectrogram.jpg'.format( original=os.path.splitext( queued_filepath[-1])[0])) with tempfile.NamedTemporaryFile(suffix='.ogg') as wav_tmp: _log.info('Creating OGG source for spectrogram') transcoder.transcode( queued_filename, wav_tmp.name, mux_string='vorbisenc quality={0} ! oggmux'.format( audio_config['quality'])) thumbnailer = AudioThumbnailer() with tempfile.NamedTemporaryFile(suffix='.jpg') as spectrogram_tmp: thumbnailer.spectrogram( wav_tmp.name, spectrogram_tmp.name, width=mgg.global_config['media:medium']['max_width'], fft_size=audio_config['spectrogram_fft_size']) _log.debug('Saving spectrogram...') mgg.public_store.get_file(spectrogram_filepath, 'wb').write( spectrogram_tmp.read()) entry.media_files['spectrogram'] = spectrogram_filepath with tempfile.NamedTemporaryFile(suffix='.jpg') as thumb_tmp: thumbnailer.thumbnail_spectrogram( spectrogram_tmp.name, thumb_tmp.name, (mgg.global_config['media:thumb']['max_width'], mgg.global_config['media:thumb']['max_height'])) thumb_filepath = create_pub_filepath( entry, '{original}-thumbnail.jpg'.format( original=os.path.splitext( queued_filepath[-1])[0])) mgg.public_store.get_file(thumb_filepath, 'wb').write( thumb_tmp.read()) entry.media_files['thumb'] = thumb_filepath else: entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg'] mgg.queue_store.delete_file(queued_filepath) # clean up workbench workbench.destroy_self()
def process_audio(proc_state): """Code to process uploaded audio. Will be run by celery. A Workbench() represents a local tempory dir. It is automatically cleaned up when this function exits. """ entry = proc_state.entry workbench = proc_state.workbench audio_config = mgg.global_config['media_type:mediagoblin.media_types.audio'] queued_filepath = entry.queued_media_file queued_filename = workbench.localized_file( mgg.queue_store, queued_filepath, 'source') name_builder = FilenameBuilder(queued_filename) webm_audio_filepath = create_pub_filepath( entry, '{original}.webm'.format( original=os.path.splitext( queued_filepath[-1])[0])) if audio_config['keep_original']: with open(queued_filename, 'rb') as queued_file: original_filepath = create_pub_filepath( entry, name_builder.fill('{basename}{ext}')) with mgg.public_store.get_file(original_filepath, 'wb') as \ original_file: _log.debug('Saving original...') original_file.write(queued_file.read()) entry.media_files['original'] = original_filepath transcoder = AudioTranscoder() with NamedTemporaryFile(dir=workbench.dir) as webm_audio_tmp: progress_callback = ProgressCallback(entry) transcoder.transcode( queued_filename, webm_audio_tmp.name, quality=audio_config['quality'], progress_callback=progress_callback) transcoder.discover(webm_audio_tmp.name) _log.debug('Saving medium...') mgg.public_store.get_file(webm_audio_filepath, 'wb').write( webm_audio_tmp.read()) entry.media_files['webm_audio'] = webm_audio_filepath # entry.media_data_init(length=int(data.audiolength)) if audio_config['create_spectrogram']: spectrogram_filepath = create_pub_filepath( entry, '{original}-spectrogram.jpg'.format( original=os.path.splitext( queued_filepath[-1])[0])) with NamedTemporaryFile(dir=workbench.dir, suffix='.ogg') as wav_tmp: _log.info('Creating OGG source for spectrogram') transcoder.transcode( queued_filename, wav_tmp.name, mux_string='vorbisenc quality={0} ! oggmux'.format( audio_config['quality'])) thumbnailer = AudioThumbnailer() with NamedTemporaryFile(dir=workbench.dir, suffix='.jpg') as spectrogram_tmp: thumbnailer.spectrogram( wav_tmp.name, spectrogram_tmp.name, width=mgg.global_config['media:medium']['max_width'], fft_size=audio_config['spectrogram_fft_size']) _log.debug('Saving spectrogram...') mgg.public_store.get_file(spectrogram_filepath, 'wb').write( spectrogram_tmp.read()) entry.media_files['spectrogram'] = spectrogram_filepath with NamedTemporaryFile(dir=workbench.dir, suffix='.jpg') as thumb_tmp: thumbnailer.thumbnail_spectrogram( spectrogram_tmp.name, thumb_tmp.name, (mgg.global_config['media:thumb']['max_width'], mgg.global_config['media:thumb']['max_height'])) thumb_filepath = create_pub_filepath( entry, '{original}-thumbnail.jpg'.format( original=os.path.splitext( queued_filepath[-1])[0])) mgg.public_store.get_file(thumb_filepath, 'wb').write( thumb_tmp.read()) entry.media_files['thumb'] = thumb_filepath else: entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg'] # Remove queued media file from storage and database. # queued_filepath is in the task_id directory which should # be removed too, but fail if the directory is not empty to be on # the super-safe side. mgg.queue_store.delete_file(queued_filepath) # rm file mgg.queue_store.delete_dir(queued_filepath[:-1]) # rm dir entry.queued_media_file = []
class CommonAudioProcessor(MediaProcessor): """ Provides a base for various audio processing steps """ acceptable_files = ["original", "best_quality", "webm_audio"] def common_setup(self): """ Setup the workbench directory and pull down the original file, add the audio_config, transcoder, thumbnailer and spectrogram_tmp path """ self.audio_config = mgg.global_config["plugins"]["mediagoblin.media_types.audio"] # Pull down and set up the processing file self.process_filename = get_process_filename(self.entry, self.workbench, self.acceptable_files) self.name_builder = FilenameBuilder(self.process_filename) self.transcoder = AudioTranscoder() self.thumbnailer = AudioThumbnailer() def copy_original(self): if self.audio_config["keep_original"]: copy_original(self.entry, self.process_filename, self.name_builder.fill("{basename}{ext}")) def _keep_best(self): """ If there is no original, keep the best file that we have """ if not self.entry.media_files.get("best_quality"): # Save the best quality file if no original? if not self.entry.media_files.get("original") and self.entry.media_files.get("webm_audio"): self.entry.media_files["best_quality"] = self.entry.media_files["webm_audio"] def _skip_processing(self, keyname, **kwargs): file_metadata = self.entry.get_file_metadata(keyname) skip = True if not file_metadata: return False if keyname == "webm_audio": if kwargs.get("quality") != file_metadata.get("quality"): skip = False elif keyname == "spectrogram": if kwargs.get("max_width") != file_metadata.get("max_width"): skip = False elif kwargs.get("fft_size") != file_metadata.get("fft_size"): skip = False elif keyname == "thumb": if kwargs.get("size") != file_metadata.get("size"): skip = False return skip def transcode(self, quality=None): if not quality: quality = self.audio_config["quality"] if self._skip_processing("webm_audio", quality=quality): return progress_callback = ProgressCallback(self.entry) webm_audio_tmp = os.path.join(self.workbench.dir, self.name_builder.fill("{basename}{ext}")) self.transcoder.transcode( self.process_filename, webm_audio_tmp, quality=quality, progress_callback=progress_callback ) self._keep_best() _log.debug("Saving medium...") store_public(self.entry, "webm_audio", webm_audio_tmp, self.name_builder.fill("{basename}.medium.webm")) self.entry.set_file_metadata("webm_audio", **{"quality": quality}) def create_spectrogram(self, max_width=None, fft_size=None): if not max_width: max_width = mgg.global_config["media:medium"]["max_width"] if not fft_size: fft_size = self.audio_config["spectrogram_fft_size"] if self._skip_processing("spectrogram", max_width=max_width, fft_size=fft_size): return wav_tmp = os.path.join(self.workbench.dir, self.name_builder.fill("{basename}.ogg")) _log.info("Creating OGG source for spectrogram") self.transcoder.transcode(self.process_filename, wav_tmp, mux_name="oggmux") spectrogram_tmp = os.path.join(self.workbench.dir, self.name_builder.fill("{basename}-spectrogram.jpg")) self.thumbnailer.spectrogram(wav_tmp, spectrogram_tmp, width=max_width, fft_size=fft_size) _log.debug("Saving spectrogram...") store_public(self.entry, "spectrogram", spectrogram_tmp, self.name_builder.fill("{basename}.spectrogram.jpg")) file_metadata = {"max_width": max_width, "fft_size": fft_size} self.entry.set_file_metadata("spectrogram", **file_metadata) def generate_thumb(self, size=None): if not size: max_width = mgg.global_config["media:thumb"]["max_width"] max_height = mgg.global_config["media:thumb"]["max_height"] size = (max_width, max_height) if self._skip_processing("thumb", size=size): return thumb_tmp = os.path.join(self.workbench.dir, self.name_builder.fill("{basename}-thumbnail.jpg")) # We need the spectrogram to create a thumbnail spectrogram = self.entry.media_files.get("spectrogram") if not spectrogram: _log.info("No spectrogram found, we will create one.") self.create_spectrogram() spectrogram = self.entry.media_files["spectrogram"] spectrogram_filepath = mgg.public_store.get_local_path(spectrogram) self.thumbnailer.thumbnail_spectrogram(spectrogram_filepath, thumb_tmp, tuple(size)) store_public(self.entry, "thumb", thumb_tmp, self.name_builder.fill("{basename}.thumbnail.jpg")) self.entry.set_file_metadata("thumb", **{"size": size})
def process_audio(proc_state): """Code to process uploaded audio. Will be run by celery. A Workbench() represents a local tempory dir. It is automatically cleaned up when this function exits. """ entry = proc_state.entry workbench = proc_state.workbench audio_config = mgg.global_config[ 'media_type:mediagoblin.media_types.audio'] queued_filepath = entry.queued_media_file queued_filename = workbench.localized_file(mgg.queue_store, queued_filepath, 'source') name_builder = FilenameBuilder(queued_filename) webm_audio_filepath = create_pub_filepath( entry, '{original}.webm'.format( original=os.path.splitext(queued_filepath[-1])[0])) if audio_config['keep_original']: with open(queued_filename, 'rb') as queued_file: original_filepath = create_pub_filepath( entry, name_builder.fill('{basename}{ext}')) with mgg.public_store.get_file(original_filepath, 'wb') as \ original_file: _log.debug('Saving original...') original_file.write(queued_file.read()) entry.media_files['original'] = original_filepath transcoder = AudioTranscoder() with NamedTemporaryFile(dir=workbench.dir) as webm_audio_tmp: progress_callback = ProgressCallback(entry) transcoder.transcode(queued_filename, webm_audio_tmp.name, quality=audio_config['quality'], progress_callback=progress_callback) transcoder.discover(webm_audio_tmp.name) _log.debug('Saving medium...') mgg.public_store.get_file(webm_audio_filepath, 'wb').write(webm_audio_tmp.read()) entry.media_files['webm_audio'] = webm_audio_filepath # entry.media_data_init(length=int(data.audiolength)) if audio_config['create_spectrogram']: spectrogram_filepath = create_pub_filepath( entry, '{original}-spectrogram.jpg'.format( original=os.path.splitext(queued_filepath[-1])[0])) with NamedTemporaryFile(dir=workbench.dir, suffix='.ogg') as wav_tmp: _log.info('Creating OGG source for spectrogram') transcoder.transcode( queued_filename, wav_tmp.name, mux_string='vorbisenc quality={0} ! oggmux'.format( audio_config['quality'])) thumbnailer = AudioThumbnailer() with NamedTemporaryFile(dir=workbench.dir, suffix='.jpg') as spectrogram_tmp: thumbnailer.spectrogram( wav_tmp.name, spectrogram_tmp.name, width=mgg.global_config['media:medium']['max_width'], fft_size=audio_config['spectrogram_fft_size']) _log.debug('Saving spectrogram...') mgg.public_store.get_file(spectrogram_filepath, 'wb').write(spectrogram_tmp.read()) entry.media_files['spectrogram'] = spectrogram_filepath with NamedTemporaryFile(dir=workbench.dir, suffix='.jpg') as thumb_tmp: thumbnailer.thumbnail_spectrogram( spectrogram_tmp.name, thumb_tmp.name, (mgg.global_config['media:thumb']['max_width'], mgg.global_config['media:thumb']['max_height'])) thumb_filepath = create_pub_filepath( entry, '{original}-thumbnail.jpg'.format( original=os.path.splitext(queued_filepath[-1])[0])) mgg.public_store.get_file(thumb_filepath, 'wb').write(thumb_tmp.read()) entry.media_files['thumb'] = thumb_filepath else: entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg'] # Remove queued media file from storage and database. # queued_filepath is in the task_id directory which should # be removed too, but fail if the directory is not empty to be on # the super-safe side. mgg.queue_store.delete_file(queued_filepath) # rm file mgg.queue_store.delete_dir(queued_filepath[:-1]) # rm dir entry.queued_media_file = []