1# -*- coding: utf-8 -*- 2# This extension adjusts the volume of audio files to a standard level 3# Supported file formats are mp3 and ogg 4# 5# Requires: normalize-audio, mpg123 6# 7# (c) 2011-11-06 Bernd Schlapsi <brot@gmx.info> 8# Released under the same license terms as gPodder itself. 9 10import logging 11import os 12import subprocess 13 14import gpodder 15from gpodder import util 16 17logger = logging.getLogger(__name__) 18 19_ = gpodder.gettext 20 21__title__ = _('Normalize audio with re-encoding') 22__description__ = _('Normalize the volume of audio files with normalize-audio') 23__authors__ = 'Bernd Schlapsi <brot@gmx.info>' 24__doc__ = 'https://gpodder.github.io/docs/extensions/normalizeaudio.html' 25__payment__ = 'https://flattr.com/submit/auto?user_id=BerndSch&url=http://wiki.gpodder.org/wiki/Extensions/NormalizeAudio' 26__category__ = 'post-download' 27 28 29DefaultConfig = { 30 'context_menu': True, # Show action in the episode list context menu 31} 32 33# a tuple of (extension, command) 34CONVERT_COMMANDS = { 35 '.ogg': 'normalize-ogg', 36 '.mp3': 'normalize-mp3', 37} 38 39 40class gPodderExtension: 41 MIME_TYPES = ('audio/mpeg', 'audio/ogg', ) 42 EXT = ('.mp3', '.ogg', ) 43 44 def __init__(self, container): 45 self.container = container 46 47 # Dependency check 48 self.container.require_command('normalize-ogg') 49 self.container.require_command('normalize-mp3') 50 self.container.require_command('normalize-audio') 51 52 def on_load(self): 53 logger.info('Extension "%s" is being loaded.' % __title__) 54 55 def on_unload(self): 56 logger.info('Extension "%s" is being unloaded.' % __title__) 57 58 def on_episode_downloaded(self, episode): 59 self._convert_episode(episode) 60 61 def on_episodes_context_menu(self, episodes): 62 if not self.container.config.context_menu: 63 return None 64 65 if not any(self._check_source(episode) for episode in episodes): 66 return None 67 68 return [(self.container.metadata.title, self.convert_episodes)] 69 70 def _check_source(self, episode): 71 if not episode.file_exists(): 72 return False 73 74 if episode.mime_type in self.MIME_TYPES: 75 return True 76 77 if episode.extension() in self.EXT: 78 return True 79 80 return False 81 82 def _convert_episode(self, episode): 83 if episode.file_type() != 'audio': 84 return 85 86 filename = episode.local_filename(create=False) 87 if filename is None: 88 return 89 90 basename, extension = os.path.splitext(filename) 91 92 cmd = [CONVERT_COMMANDS.get(extension, 'normalize-audio'), filename] 93 94 if gpodder.ui.win32: 95 p = util.Popen(cmd) 96 p.wait() 97 stdout, stderr = ("<unavailable>",) * 2 98 else: 99 p = util.Popen(cmd, stdout=subprocess.PIPE, 100 stderr=subprocess.PIPE) 101 stdout, stderr = p.communicate() 102 103 if p.returncode == 0: 104 logger.info('normalize-audio processing successful.') 105 gpodder.user_extensions.on_notification_show(_('File normalized'), 106 episode.title) 107 else: 108 logger.warn('normalize-audio failed: %s / %s', stdout, stderr) 109 110 def convert_episodes(self, episodes): 111 for episode in episodes: 112 self._convert_episode(episode) 113