1
# -*- coding: utf-8 -*-
2
# Convertes video files to avi or mp4
3
# This requires ffmpeg to be installed. Also works as a context
4
# menu item for already-downloaded files.
6
# (c) 2011-08-05 Thomas Perl <thp.io/about>
7
# Released under the same license terms as gPodder itself.
14
from gpodder import util
15
from gpodder import youtube
18
logger = logging.getLogger(__name__)
22
__title__ = _('Convert video files')
23
__description__ = _('Transcode video files to avi/mp4/m4v')
24
__authors__ = 'Thomas Perl <thp@gpodder.org>, Bernd Schlapsi <brot@gmx.info>'
25
__category__ = 'post-download'
28
'output_format': 'mp4', # At the moment we support/test only mp4, m4v and avi
29
'context_menu': True, # Show the conversion option in the context menu
33
class gPodderExtension:
34
MIME_TYPES = ('video/mp4', 'video/m4v', 'video/x-flv', )
35
EXT = ('.mp4', '.m4v', '.flv', )
36
CMD = {'avconv': ['-i', '%(old_file)s', '-codec', 'copy', '%(new_file)s'],
37
'ffmpeg': ['-i', '%(old_file)s', '-codec', 'copy', '%(new_file)s']
40
def __init__(self, container):
41
self.container = container
42
self.config = self.container.config
45
self.command = self.container.require_any_command(['avconv', 'ffmpeg'])
47
# extract command without extension (.exe on Windows) from command-string
48
command_without_ext = os.path.basename(os.path.splitext(self.command)[0])
49
self.command_param = self.CMD[command_without_ext]
51
def on_episode_downloaded(self, episode):
52
self._convert_episode(episode)
54
def _get_new_extension(self):
55
ext = self.config.output_format
56
if not ext.startswith('.'):
61
def _check_source(self, episode):
62
if episode.extension() == self._get_new_extension():
65
if episode.mime_type in self.MIME_TYPES:
68
# Also check file extension (bug 1770)
69
if episode.extension() in self.EXT:
74
def on_episodes_context_menu(self, episodes):
75
if not self.config.context_menu:
78
if not all(e.was_downloaded(and_exists=True) for e in episodes):
81
if not any(self._check_source(episode) for episode in episodes):
84
menu_item = _('Convert to %(format)s') % {'format': self.config.output_format}
86
return [(menu_item, self._convert_episodes)]
88
def _convert_episode(self, episode):
89
if not self._check_source(episode):
92
new_extension = self._get_new_extension()
93
old_filename = episode.local_filename(create=False)
94
filename, old_extension = os.path.splitext(old_filename)
95
new_filename = filename + new_extension
97
cmd = [self.command] + \
98
[param % {'old_file': old_filename, 'new_file': new_filename}
99
for param in self.command_param]
100
ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE,
101
stderr=subprocess.PIPE)
102
stdout, stderr = ffmpeg.communicate()
104
if ffmpeg.returncode == 0:
105
util.rename_episode_file(episode, new_filename)
106
os.remove(old_filename)
108
logger.info('Converted video file to %(format)s.' % {'format': self.config.output_format})
109
gpodder.user_extensions.on_notification_show(_('File converted'), episode.title)
111
logger.warn('Error converting video file: %s / %s', stdout, stderr)
112
gpodder.user_extensions.on_notification_show(_('Conversion failed'), episode.title)
114
def _convert_episodes(self, episodes):
115
for episode in episodes:
116
self._convert_episode(episode)