From 9c147cf980f40e5dd8c46a4a0dc16efb51db53ed Mon Sep 17 00:00:00 2001 From: Thomas Perl Date: Sun, 11 Mar 2012 09:37:49 +0100 Subject: [PATCH] Extensions: Various fixes and clean-ups from review --- share/gpodder/extensions/flv2mp4.py | 209 +++++++++++------------- share/gpodder/extensions/m4a_converter.py | 201 ++++++++++------------- share/gpodder/extensions/mp3gain.py | 170 +++++++++---------- share/gpodder/extensions/normalize_audio.py | 70 ++++---- share/gpodder/extensions/notification.py | 2 - share/gpodder/extensions/rename_download.py | 36 ++-- share/gpodder/extensions/rm_ogg_cover.py | 64 ++++---- share/gpodder/extensions/rockbox_convert2mp4.py | 26 ++- share/gpodder/extensions/tagging.py | 18 +- share/gpodder/extensions/tfh_shownotes.py | 6 +- src/gpodder/extensions.py | 14 +- 11 files changed, 362 insertions(+), 454 deletions(-) rewrite share/gpodder/extensions/flv2mp4.py (63%) rewrite share/gpodder/extensions/m4a_converter.py (73%) rewrite share/gpodder/extensions/mp3gain.py (65%) diff --git a/share/gpodder/extensions/flv2mp4.py b/share/gpodder/extensions/flv2mp4.py dissimilarity index 63% index e2fae41e..21891eb6 100644 --- a/share/gpodder/extensions/flv2mp4.py +++ b/share/gpodder/extensions/flv2mp4.py @@ -1,115 +1,94 @@ -# -*- coding: utf-8 -*- -# Put FLV files from YouTube into a MP4 container after download -# This requires ffmpeg to be installed. Also works as a context -# menu item for already-downloaded files. This does not convert -# the files in reality, but just swaps the container format. -# -# (c) 2011-08-05 Thomas Perl -# Released under the same license terms as gPodder itself. - -import os -import shlex -import subprocess - -import gpodder -from gpodder import util -from gpodder import youtube - -import logging -logger = logging.getLogger(__name__) - -_ = gpodder.gettext - -__title__ = _('Convert FLV to MP4') -__description__ = _('Put FLV files from YouTube into a MP4 container after download') -__author__ = 'Thomas Perl , Bernd Schlapsi ' - -DefaultConfig = { - 'extensions': { - 'flv2mp4': { - 'context_menu': True, - } - } -} - -FFMPEG_CMD = 'ffmpeg -i "%(infile)s" -vcodec copy -acodec copy "%(outfile)s"' - - -class gPodderExtension: - def __init__(self, container): - self.container = container - - self.cmd = FFMPEG_CMD - program = shlex.split(self.cmd)[0] - if not util.find_command(program): - raise ImportError("Couldn't find program '%s'" % program) - - def on_load(self): - logger.info('Extension "%s" is being loaded.' % __title__) - - def on_unload(self): - logger.info('Extension "%s" is being unloaded.' % __title__) - - def on_episode_downloaded(self, episode): - self._convert_episode(episode) - - def on_episodes_context_menu(self, episodes): - if not self.container.config.context_menu: - return None - - if 'video/x-flv' not in [e.mime_type for e in episodes if e.file_exists()]: - return None - - return [(self.container.metadata.title, self._convert_episodes)] - - def _convert_episode(self, episode): - retvalue = self._run_conversion(episode) - - if retvalue == 0: - logger.info('FLV conversion successful.') - self.rename_episode_file(episode, basename+'.mp4') - os.remove(filename) - else: - logger.info('Error converting file. FFMPEG installed?') - try: - os.remove(target) - except OSError: - pass - - def _run_conversion(self, episode): - if not youtube.is_video_link(episode.url): - logger.debug('Not a YouTube video. Ignoring.') - return - - filename = episode.local_filename(create=False) - dirname = os.path.dirname(filename) - basename, ext = os.path.splitext(os.path.basename(filename)) - - if open(filename, 'rb').read(3) != 'FLV': - logger.debug('Not a FLV file. Ignoring.') - return - - if ext == '.mp4': - # Move file out of place for conversion - newname = os.path.join(dirname, basename+'.flv') - os.rename(filename, newname) - filename = newname - - target = os.path.join(dirname, basename+'.mp4') - cmd = FFMPEG_CMD % { - 'infile': filename, - 'outfile': target - } - - # Prior to Python 2.7.3, this module (shlex) did not support Unicode input. - cmd = util.sanitize_encoding(cmd) - - ffmpeg = subprocess.Popen(shlex.split(cmd), - stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - stdout, stderr = ffmpeg.communicate() - return ffmpeg.returncode - - def _convert_episodes(self, episodes): - for episode in episodes: - self._convert_episode(episode) +# -*- coding: utf-8 -*- +# Put FLV files from YouTube into a MP4 container after download +# This requires ffmpeg to be installed. Also works as a context +# menu item for already-downloaded files. This does not convert +# the files in reality, but just swaps the container format. +# +# (c) 2011-08-05 Thomas Perl +# Released under the same license terms as gPodder itself. + +import os +import subprocess + +import gpodder + +from gpodder import util +from gpodder import youtube + +import logging +logger = logging.getLogger(__name__) + +_ = gpodder.gettext + +__title__ = _('Convert .flv files from YouTube to .mp4') +__description__ = _('Useful for playing downloaded videos on hardware players') +__author__ = 'Thomas Perl , Bernd Schlapsi ' + +DefaultConfig = { + 'context_menu': True, # Show the conversion option in the context menu +} + + +class gPodderExtension: + MIME_TYPE = 'video/x-flv' + + def __init__(self, container): + self.container = container + self.config = self.container.config + + # Dependency checks + self.container.require_command('ffmpeg') + + def on_episode_downloaded(self, episode): + if youtube.is_video_link(episode.url): + self._convert_episode(episode) + + def on_episodes_context_menu(self, episodes): + if not self.config.context_menu: + return None + + if not all(e.was_downloaded(and_exists=True) for e in episodes): + return None + + if not any(e.mime_type == self.MIME_TYPE for e in episodes): + return None + + return [(_('Convert FLV to MP4'), self._convert_episodes)] + + + def _convert_episode(self, episode): + old_filename = episode.local_filename(create=False) + filename, ext = os.path.splitext(filename) + new_filename = filename + '.mp4' + + if open(old_filename, 'rb').read(3) != 'FLV': + logger.debug('Not a FLV file. Ignoring.') + return + + if ext.lower() == '.mp4': + # Move file out of place for conversion + tmp_filename = filename + '.flv' + os.rename(old_filename, tmp_filename) + old_filename = tmp_filename + + cmd = ['ffmpeg', + '-i', old_filename, + '-vcodec', 'copy', + '-acodec', 'copy', + new_filename] + + ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = ffmpeg.communicate() + + if ffmpeg.returncode == 0: + logger.info('FLV conversion successful.') + util.rename_episode_file(episode, new_filename) + os.remove(old_filename) + else: + logger.warn('Error converting file: %s / %s', stdout, stderr) + + def _convert_episodes(self, episodes): + for episode in episodes: + self._convert_episode(episode) + diff --git a/share/gpodder/extensions/m4a_converter.py b/share/gpodder/extensions/m4a_converter.py dissimilarity index 73% index b82e57a5..07e5acab 100644 --- a/share/gpodder/extensions/m4a_converter.py +++ b/share/gpodder/extensions/m4a_converter.py @@ -1,114 +1,87 @@ -# -*- coding: utf-8 -*- -# Convertes m4a audio files to mp3 -# This requires ffmpeg to be installed. Also works as a context -# menu item for already-downloaded files. -# -# (c) 2011-11-23 Bernd Schlapsi -# Released under the same license terms as gPodder itself. - -import os -import shlex -import subprocess - -import gpodder -from gpodder import util - -import logging -logger = logging.getLogger(__name__) - -_ = gpodder.gettext - -__title__ = _('Converts M4A audio') -__description__ = _('Converts m4a audio files to mp3') -__author__ = 'Bernd Schlapsi ' - - -DefaultConfig = { - 'extensions': { - 'm4a_converter': { - 'file_format': [ True, False ], - 'context_menu': True, - } - } -} - -FILE_FORMATS = ( 'mp3', 'ogg' ) -FFMPEG_CMD = 'ffmpeg -i "%(infile)s" -sameq "%(outfile)s"' -MIME_TYPES = ['audio/x-m4a', 'audio/mp4'] - - -class gPodderExtension: - def __init__(self, container): - self.container = container - - program = shlex.split(FFMPEG_CMD)[0] - if not util.find_command(program): - raise ImportError("Couldn't find program '%s'" % program) - - def on_load(self): - logger.info('Extension "%s" is being loaded.' % __title__) - - def on_unload(self): - logger.info('Extension "%s" is being unloaded.' % __title__) - - def on_episode_downloaded(self, episode): - self._convert_episode(episode) - - def on_episodes_context_menu(self, episodes): - if not self.container.config.context_menu: - return None - - if not [e for e in episodes if e.mime_type in MIME_TYPES and e.file_exists()]: - return None - - return [(self.container.metadata.title, self._convert_episodes)] - - def _convert_episode(self, episode): - retvalue = self._run_conversion(episode) - - if retvalue == 0: - logger.info('m4a -> %s conversion successful.', extension) - gpodder.user_extensions.on_notification_show("Converting finished", episode) - if not self.container.manager.testrun: - self.rename_episode_file(episode, target) - os.remove(filename) - else: - logger.info('Error converting file. FFMPEG installed?') - gpodder.user_extensions.on_notification_show("Converting finished with errors", episode) - try: - os.remove(target) - except OSError: - pass - - def _run_conversion(self, episode): - choices = zip(FILE_FORMATS, self.container.config.file_format) - extension = '.' + [ext for ext, state in choices if state][0] - - filename = episode.local_filename(create=False) - dirname = os.path.dirname(filename) - basename, ext = os.path.splitext(os.path.basename(filename)) - new_filename = basename + extension - - if episode.mime_type not in MIME_TYPES: - return - - gpodder.user_extensions.on_notification_show("Converting", episode) - - target = os.path.join(dirname, new_filename) - cmd = FFMPEG_CMD % { - 'infile': filename, - 'outfile': target - } - - # Prior to Python 2.7.3, this module (shlex) did not support Unicode input. - cmd = util.sanitize_encoding(cmd) - - ffmpeg = subprocess.Popen(shlex.split(cmd), - stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - stdout, stderr = ffmpeg.communicate() - return ffmpeg.returncode - - def _convert_episodes(self, episodes): - for episode in episodes: - self._convert_episode(episode) +# -*- coding: utf-8 -*- +# Convertes m4a audio files to mp3 +# This requires ffmpeg to be installed. Also works as a context +# menu item for already-downloaded files. +# +# (c) 2011-11-23 Bernd Schlapsi +# Released under the same license terms as gPodder itself. + +import os +import subprocess + +import gpodder + +import logging +logger = logging.getLogger(__name__) + +_ = gpodder.gettext + +__title__ = _('Convert M4A audio to MP3 or OGG') +__description__ = _('Transcode .m4a files to .mp3 or .ogg using ffmpeg') +__author__ = 'Bernd Schlapsi , Thomas Perl ' + + +DefaultConfig = { + 'use_ogg': False, # Set to True to convert to .ogg (otherwise .mp3) + 'context_menu': True, # Show the conversion option in the context menu +} + +class gPodderExtension: + MIME_TYPES = ['audio/x-m4a', 'audio/mp4'] + + def __init__(self, container): + self.container = container + self.config = self.container.config + + # Dependency checks + self.container.require_command('ffmpeg') + + def on_episode_downloaded(self, episode): + self._convert_episode(episode) + + def on_episodes_context_menu(self, episodes): + if not self.config.context_menu: + return None + + if not all(e.was_downloaded(and_exists=True) for e in episodes): + return None + + if not any(e.mime_type in self.MIME_TYPES for e in episodes): + return None + + target_format = ('OGG' if self.config.use_ogg else 'MP3') + menu_item = _('Convert to %(format)s') % {'format': target_format} + + return [(menu_item, self._convert_episodes)] + + def _convert_episode(self, episode): + if episode.mime_type not in self.MIME_TYPES: + return + + if self.config.use_ogg: + extension = '.ogg' + else: + extension = '.mp3' + + old_filename = episode.local_filename(create=False) + filename, _ = os.path.splitext(old_filename) + new_filename = filename + extension + + cmd = ['ffmpeg', '-i', old_filename, '-sameq', new_filename] + ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = ffmpeg.communicate() + + if ffmpeg.returncode == 0: + logger.info('Converted M4A file.') + gpodder.user_extensions.on_notification_show(_('File converted'), + episode) + else: + logger.warn('Error converting file: %s / %s', stdout, stderr) + gpodder.user_extensions.on_notification_show(_('Conversion failed'), + episode) + + def _convert_episodes(self, episodes): + for episode in episodes: + self._convert_episode(episode) + diff --git a/share/gpodder/extensions/mp3gain.py b/share/gpodder/extensions/mp3gain.py dissimilarity index 65% index b9d4b329..782c6e27 100644 --- a/share/gpodder/extensions/mp3gain.py +++ b/share/gpodder/extensions/mp3gain.py @@ -1,94 +1,76 @@ -# -*- coding: utf-8 -*- -# This extension adjusts mp3s so that they all have the same volume -# -# Requires: mp3gain -# -# (c) 2011-11-06 Bernd Schlapsi -# Released under the same license terms as gPodder itself. -import os -import platform -import shlex -import subprocess - -import gpodder -from gpodder import util - -import logging -logger = logging.getLogger(__name__) - -_ = gpodder.gettext - -__title__ = _('mp3gain') -__description__ = _('This hook adjusts mp3s so that they all have the same volume. It don\'t decode and re-encode the audio file') -__author__ = 'Bernd Schlapsi ' - - -DefaultConfig = { - 'extensions': { - 'mp3gain': { - 'context_menu': True, - } - } -} - -CMD = { - 'Linux': 'mp3gain -c "%s"', - 'Windows': 'mp3gain.exe -c "%s"' -} - - -class gPodderExtension: - def __init__(self, container): - self.container = container - - self.cmd = CMD[platform.system()] - program = shlex.split(self.cmd)[0] - if not util.find_command(program): - raise ImportError("Couldn't find program '%s'" % program) - - def on_load(self): - logger.info('Extension "%s" is being loaded.' % __title__) - - def on_unload(self): - logger.info('Extension "%s" is being unloaded.' % __title__) - - def on_episode_downloaded(self, episode): - self._convert_episode(episode) - - def on_episodes_context_menu(self, episodes): - if not self.container.config.context_menu: - return None - - if 'audio/mpeg' not in [e.mime_type for e in episodes - if e.mime_type is not None and e.file_exists()]: - return None - - return [(self.container.metadata.title, self._convert_episodes)] - - def _convert_episode(self, episode): - filename = episode.local_filename(create=False, check_only=True) - if filename is None: - return - - (basename, extension) = os.path.splitext(filename) - if episode.file_type() == 'audio' and extension.lower().endswith('mp3'): - - cmd = self.cmd % filename - - # Prior to Python 2.7.3, this module (shlex) did not support Unicode input. - cmd = util.sanitize_encoding(cmd) - - p = subprocess.Popen(shlex.split(cmd), - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - - if p.returncode == 0: - logger.info('mp3gain processing successfull.') - - else: - logger.info('mp3gain processing not successfull.') - logger.debug(stdout + stderr) - - def _convert_episodes(self, episodes): - for episode in episodes: - self._convert_episode(episode) +# -*- coding: utf-8 -*- +# This extension adjusts mp3s so that they all have the same volume +# +# Requires: mp3gain +# +# (c) 2011-11-06 Bernd Schlapsi +# Released under the same license terms as gPodder itself. + +import os +import subprocess + +import gpodder +from gpodder import util + +import logging +logger = logging.getLogger(__name__) + +_ = gpodder.gettext + +__title__ = _('mp3gain Volume Normalizer') +__description__ = _('Normalize the volume of MP3 files without re-encoding') +__author__ = 'Bernd Schlapsi ' + + +DefaultConfig = { + 'context_menu': True, +} + + +class gPodderExtension: + MIME_TYPE = 'audio/mpeg' + + def __init__(self, container): + self.container = container + self.config = self.container.config + + self.mp3gain = self.container.require_command('mp3gain') + + def on_episode_downloaded(self, episode): + self._convert_episode(episode) + + def on_episodes_context_menu(self, episodes): + if not self.config.context_menu: + return None + + if not all(e.was_downloaded(and_exists=True) for e in episodes): + return None + + if not any(e.mime_type == self.MIME_TYPE for e in episodes): + return None + + return [(_('Normalize volume (mp3gain)'), self._convert_episodes)] + + def _convert_episode(self, episode): + if episode.mime_type != self.MIME_TYPE: + return + + filename = episode.local_filename(create=False) + if filename is None: + return + + cmd = [self.mp3gain, '-c', filename] + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + + if p.returncode == 0: + logger.info('mp3gain processing successful.') + else: + logger.warn('mp3gain failed: %s / %s', stdout, stderr) + + def _convert_episodes(self, episodes): + for episode in episodes: + self._convert_episode(episode) + diff --git a/share/gpodder/extensions/normalize_audio.py b/share/gpodder/extensions/normalize_audio.py index 170f9ffb..58eb41ee 100644 --- a/share/gpodder/extensions/normalize_audio.py +++ b/share/gpodder/extensions/normalize_audio.py @@ -6,8 +6,8 @@ # # (c) 2011-11-06 Bernd Schlapsi # Released under the same license terms as gPodder itself. + import os -import shlex import subprocess import gpodder @@ -18,38 +18,29 @@ logger = logging.getLogger(__name__) _ = gpodder.gettext -__title__ = _('Normalize audio') -__description__ = _('This hook adjusts mp3s/oggs so that they all have the same volume. It decode and re-encode the audio file') +__title__ = _('Normalize audio with re-encoding') +__description__ = _('Normalize the volume of audio files with normalize-audio') __author__ = 'Bernd Schlapsi ' DefaultConfig = { - 'extensions': { - 'normalize_audio': { - 'context_menu': True, - } - } + 'context_menu': True, # Show action in the episode list context menu } # a tuple of (extension, command) -SUPPORTED = (('ogg', 'normalize-ogg "%s"'), ('mp3', 'normalize-mp3 "%s"')) - -#TODO: add setting to use normalize-audio instead of normalizie-mp3 for mp3 files if wanted -# http://normalize.nongnu.org/README.html FAQ #5 -#MP3_CMD = 'normalize-audio "%s"' - -CMDS_TO_TEST = ('normalize-ogg', 'normalize-mp3', 'normalize-audio', - 'lame', 'mpg123', 'oggenc', 'oggdec') - +CONVERT_COMMANDS = { + 'ogg': 'normalize-ogg', + 'mp3': 'normalize-mp3', +} class gPodderExtension: def __init__(self, container): self.container = container - for cmd in CMDS_TO_TEST: - program = shlex.split(cmd)[0] - if not util.find_command(program): - raise ImportError("Couldn't find program '%s'" % program) + # Dependency check + self.container.require_command('normalize-ogg') + self.container.require_command('normalize-mp3') + self.container.require_command('normalize-audio') def on_load(self): logger.info('Extension "%s" is being loaded.' % __title__) @@ -72,34 +63,29 @@ class gPodderExtension: return [(self.container.metadata.title, self._convert_episodes)] def _convert_episode(self, episode): - filename = episode.local_filename(create=False, check_only=True) - if filename is None: + if episode.file_type() != 'audio': return - formats, commands = zip(*SUPPORTED) - (basename, extension) = os.path.splitext(filename) - extension = extension.lstrip('.').lower() - if episode.file_type() == 'audio' and extension in formats: - gpodder.user_extensions.on_notification_show("Normalizing", episode) - - cmd = commands[formats.index(extension)] % filename + filename = episode.local_filename(create=False) + if filename is None: + return - # Prior to Python 2.7.3, this module (shlex) did not support Unicode input. - cmd = util.sanitize_encoding(cmd) + basename, extension = os.path.splitext(filename) - p = subprocess.Popen(shlex.split(cmd), - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = p.communicate() + cmd = [CONVERT_COMMANDS.get(extension, 'normalize-audio'), filename] - if p.returncode == 0: - logger.info('normalize-audio processing successfull.') - gpodder.user_extensions.on_notification_show("Normalizing finished successfully", episode) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = p.communicate() - else: - logger.info('normalize-audio processing not successfull.') - gpodder.user_extensions.on_notification_show("Normalizing finished not successfully", episode) - logger.debug(stderr) + if p.returncode == 0: + logger.info('normalize-audio processing successful.') + gpodder.user_extensions.on_notification_show(_('File normalized'), + episode) + else: + logger.warn('normalize-audio failed: %s / %s', stdout, stderr) def _convert_episodes(self, episodes): for episode in episodes: self._convert_episode(episode) + diff --git a/share/gpodder/extensions/notification.py b/share/gpodder/extensions/notification.py index f8b89b59..debe18d8 100644 --- a/share/gpodder/extensions/notification.py +++ b/share/gpodder/extensions/notification.py @@ -45,10 +45,8 @@ else: def on_load(self): pynotify.init('gPodder') - logger.info('PyNotify initialized.') def on_unload(self): - logger.info('Uninitializing PyNotify.') pynotify.uninit() def on_notification_show(self, title, message): diff --git a/share/gpodder/extensions/rename_download.py b/share/gpodder/extensions/rename_download.py index 46639bde..5fcf0c7d 100644 --- a/share/gpodder/extensions/rename_download.py +++ b/share/gpodder/extensions/rename_download.py @@ -13,34 +13,38 @@ logger = logging.getLogger(__name__) _ = gpodder.gettext -__title__ = _('Rename after download') -__description__ = _('rename files after download based on the episode title') -__author__ = 'Bernd Schlapsi ' +__title__ = _('Rename episodes after download') +__description__ = _('Rename episodes to "." on download') +__author__ = 'Bernd Schlapsi , Thomas Perl ' class gPodderExtension: def __init__(self, container): self.container = container - def on_load(self): - logger.info('Extension "%s" is being loaded.' % __title__) - - def on_unload(self): - logger.info('Extension "%s" is being unloaded.' % __title__) - def on_episode_downloaded(self, episode): current_filename = episode.local_filename(create=False) - new_filename = self.rename_file(current_filename, episode.title) - logger.info('Renaming %s -> %s:', current_filename, new_filename) + new_filename = self.make_filename(current_filename, episode.title) - os.rename(current_filename, new_filename) - util.rename_episode_file(episode, new_filename) + if new_filename != current_filename: + logger.info('Renaming: %s -> %s', current_filename, new_filename) + os.rename(current_filename, new_filename) + util.rename_episode_file(episode, new_filename) - def rename_file(self, current_filename, title): + def make_filename(self, current_filename, title): dirname = os.path.dirname(current_filename) filename = os.path.basename(current_filename) basename, ext = os.path.splitext(filename) - new_filename = util.sanitize_encoding(title) + ext - return os.path.join(dirname, new_filename) + new_basename = util.sanitize_encoding(title) + ext + new_filename = os.path.join(dirname, new_basename) + + if new_filename == current_filename: + return current_filename + + for filename in util.generate_names(new_filename): + # Avoid filename collisions + if not os.path.exists(filename): + return filename + diff --git a/share/gpodder/extensions/rm_ogg_cover.py b/share/gpodder/extensions/rm_ogg_cover.py index 7473f8e3..62824570 100644 --- a/share/gpodder/extensions/rm_ogg_cover.py +++ b/share/gpodder/extensions/rm_ogg_cover.py @@ -30,75 +30,67 @@ import gpodder import logging logger = logging.getLogger(__name__) -try: - from mutagen.oggvorbis import OggVorbis -except: - logger.error( '(remove ogg cover extension) Could not find mutagen') +from mutagen.oggvorbis import OggVorbis _ = gpodder.gettext -__title__ = _('Remove Coverart from OGG') +__title__ = _('Remove cover art from OGG files') __description__ = _('removes coverart from all downloaded ogg files') __author__ = 'Bernd Schlapsi ' DefaultConfig = { - 'extensions': { - 'rm_ogg_cover': { - 'context_menu': True, - } - } + 'context_menu': True, # Show item in context menu } class gPodderExtension: def __init__(self, container): self.container = container - - def on_load(self): - logger.info('Extension "%s" is being loaded.' % __title__) - - def on_unload(self): - logger.info('Extension "%s" is being unloaded.' % __title__) + self.config = self.container.config def on_episode_downloaded(self, episode): self.rm_ogg_cover(episode) def on_episodes_context_menu(self, episodes): - if not self.container.config.context_menu: + if not self.config.context_menu: return None if 'audio/ogg' not in [e.mime_type for e in episodes if e.mime_type is not None and e.file_exists()]: return None - return [(self.container.metadata.title, self._rm_ogg_covers)] + return [(_('Remove cover art'), self._rm_ogg_covers)] def _rm_ogg_covers(self, episodes): for episode in episodes: self.rm_ogg_cover(episode) def rm_ogg_cover(self, episode): - filename = episode.local_filename(create=False, check_only=True) + filename = episode.local_filename(create=False) if filename is None: return - (basename, extension) = os.path.splitext(filename) - if episode.file_type() == 'audio' and extension.lower().endswith('ogg'): - logger.info(u'trying to remove cover from %s' % filename) + basename, extension = os.path.splitext(filename) + + if episode.file_type() != 'audio': + return + + if extension.lower() != '.ogg'): + return + + try: + ogg = OggVorbis(filename) + found = False + for key in ogg.keys(): + if key.startswith('cover'): + found = True + ogg.pop(key) + + if found: + logger.info('Removed cover art from OGG file: %s', filename) + ogg.save() + except Exception, e: + logger.warn('Failed to remove OGG cover: %s', e, exc_info=True) - try: - ogg = OggVorbis(filename) - for key in ogg.keys(): - if key.startswith('cover'): - found = True - ogg.pop(key) - - if found: - logger.info(u'removed cover from the ogg file successfully') - ogg.save() - else: - logger.info(u'there was no cover to remove in the ogg file') - except: - None diff --git a/share/gpodder/extensions/rockbox_convert2mp4.py b/share/gpodder/extensions/rockbox_convert2mp4.py index 6d3511de..8675ecec 100644 --- a/share/gpodder/extensions/rockbox_convert2mp4.py +++ b/share/gpodder/extensions/rockbox_convert2mp4.py @@ -23,23 +23,19 @@ logger = logging.getLogger(__name__) _ = gpodder.gettext -__title__ = _('Convert to MP4') -__description__ = _('Converts Files to MP4 to use on Rockbox devices') -__author__ = 'Guy Sheffer , Thomas Perl , Bernd Schlapsi ' +__title__ = _('Convert video files to MP4 for Rockbox') +__description__ = _('Converts all videos to a Rockbox-compatible format') +__author__ = 'Guy Sheffer , Thomas Perl , Bernd Schlapsi ' DefaultConfig = { - 'extensions': { - 'rockbox_convert2mp4': { - "device_height": 176.0, - "device_width": 224.0, - "ffmpeg_options": u'-vcodec mpeg2video -b 500k -ab 192k -ac 2 -ar 44100 -acodec libmp3lame', - } - } + 'device_height': 176.0, + 'device_width': 224.0, + 'ffmpeg_options': '-vcodec mpeg2video -b 500k -ab 192k -ac 2 -ar 44100 -acodec libmp3lame', } -ROCKBOX_EXTENTION = "mpg" -EXTENTIONS_TO_CONVERT = ['.mp4',"." + ROCKBOX_EXTENTION] +ROCKBOX_EXTENSION = "mpg" +EXTENTIONS_TO_CONVERT = ['.mp4',"." + ROCKBOX_EXTENSION] FFMPEG_CMD = 'ffmpeg -y -i "%(from)s" -s %(width)sx%(height)s %(options)s "%(to)s"' @@ -79,10 +75,10 @@ class gPodderExtension: logger.info("Ignore file with file-extension %s." % ext) return None - if filename.endswith(ROCKBOX_EXTENTION): - new_filename = "%s-convert.%s" % (basename, ROCKBOX_EXTENTION) + if filename.endswith(ROCKBOX_EXTENSION): + new_filename = "%s-convert.%s" % (basename, ROCKBOX_EXTENSION) else: - new_filename = "%s.%s" % (basename, ROCKBOX_EXTENTION) + new_filename = "%s.%s" % (basename, ROCKBOX_EXTENSION) return os.path.join(dirname, new_filename) diff --git a/share/gpodder/extensions/tagging.py b/share/gpodder/extensions/tagging.py index c522eccd..86faf339 100644 --- a/share/gpodder/extensions/tagging.py +++ b/share/gpodder/extensions/tagging.py @@ -40,18 +40,14 @@ except: _ = gpodder.gettext -__title__ = _('Tagging') -__description__ = _('adds episode title and podcast title to the audio file') +__title__ = _('Tag downloaded files using Mutagen') +__description__ = _('Add episode and podcast titles to MP3/OGG tags') __author__ = 'Bernd Schlapsi ' DefaultConfig = { - 'extensions': { - 'tagging': { - "strip_album_from_title": True, - "genre_tag": u'Podcast', - } - } + 'strip_album_from_title': True, + 'genre_tag': 'Podcast', } @@ -59,12 +55,6 @@ class gPodderExtension: def __init__(self, container): self.container = container - def on_load(self): - logger.info('Extension "%s" is being loaded.' % __title__) - - def on_unload(self): - logger.info('Extension "%s" is being unloaded.' % __title__) - def on_episode_downloaded(self, episode): # exit if mutagen is not installed if not mutagen_installed: diff --git a/share/gpodder/extensions/tfh_shownotes.py b/share/gpodder/extensions/tfh_shownotes.py index 13b26c31..e9b9cd65 100644 --- a/share/gpodder/extensions/tfh_shownotes.py +++ b/share/gpodder/extensions/tfh_shownotes.py @@ -45,11 +45,7 @@ __author__ = 'Bernd Schlapsi ' DefaultConfig = { - 'extensions': { - 'tfh_shownotes': { - 'context_menu': True, - } - } + 'context_menu': True, } TFH_TITLE = 'Tin Foil Hat' diff --git a/src/gpodder/extensions.py b/src/gpodder/extensions.py index d07e7ae7..28275fd6 100644 --- a/src/gpodder/extensions.py +++ b/src/gpodder/extensions.py @@ -130,6 +130,7 @@ class ExtensionMetadata(object): uis = filter(None, [x.strip() for x in self.only_for.split(',')]) return any(getattr(gpodder.ui, ui.lower(), False) for ui in uis) +class MissingDependency(Exception): pass class ExtensionContainer(object): """An extension container wraps one extension module""" @@ -147,6 +148,12 @@ class ExtensionContainer(object): self.parameters = None self.metadata = ExtensionMetadata(self, self._load_metadata(filename)) + def require_command(self, command): + result = util.find_command(command) + if result is None: + raise MissingDependency(command) + return result + def _load_metadata(self, filename): if not filename or not os.path.exists(filename): return {} @@ -204,7 +211,12 @@ class ExtensionContainer(object): util.delete_file(self.filename + 'c') self.default_config = getattr(module_file, 'DefaultConfig', {}) - self.manager.core.config.register_defaults(self.default_config) + if self.default_config: + self.manager.core.config.register_defaults({ + 'extensions': { + self.name: self.default_config, + } + }) self.config = getattr(self.manager.core.config.extensions, self.name) self.module = module_file.gPodderExtension(self) -- 2.11.4.GIT