Extensions: Various fixes and clean-ups from review
[gpodder.git] / share / gpodder / extensions / rockbox_convert2mp4.py
blob8675ecec5f2f3e327a0678a3e64304cc3bc61830
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 # Requirements: apt-get install python-kaa-metadata ffmpeg python-dbus
4 # To use, copy it as a Python script into ~/.config/gpodder/extensions/rockbox_mp4_convert.py
5 # See the module "gpodder.extensions" for a description of when each extension
6 # gets called and what the parameters of each extension are.
7 #Based on Rename files after download based on the episode title
8 #And patch in Bug https://bugs.gpodder.org/show_bug.cgi?id=1263
9 # Copyright (c) 2011-04-06 Guy Sheffer <guysoft at gmail.com>
10 # Copyright (c) 2011-04-04 Thomas Perl <thp.io>
11 # Licensed under the same terms as gPodder itself
13 import kaa.metadata
14 import os
15 import shlex
16 import subprocess
18 import gpodder
19 from gpodder import util
21 import logging
22 logger = logging.getLogger(__name__)
24 _ = gpodder.gettext
26 __title__ = _('Convert video files to MP4 for Rockbox')
27 __description__ = _('Converts all videos to a Rockbox-compatible format')
28 __author__ = 'Guy Sheffer <guysoft@gmail.com>, Thomas Perl <thp@gpodder.org>, Bernd Schlapsi <brot@gmx.info>'
31 DefaultConfig = {
32 'device_height': 176.0,
33 'device_width': 224.0,
34 'ffmpeg_options': '-vcodec mpeg2video -b 500k -ab 192k -ac 2 -ar 44100 -acodec libmp3lame',
37 ROCKBOX_EXTENSION = "mpg"
38 EXTENTIONS_TO_CONVERT = ['.mp4',"." + ROCKBOX_EXTENSION]
39 FFMPEG_CMD = 'ffmpeg -y -i "%(from)s" -s %(width)sx%(height)s %(options)s "%(to)s"'
42 class gPodderExtension:
43 def __init__(self, container):
44 self.container = container
46 program = shlex.split(FFMPEG_CMD)[0]
47 if not util.find_command(program):
48 raise ImportError("Couldn't find program '%s'" % program)
50 def on_load(self):
51 logger.info('Extension "%s" is being loaded.' % __title__)
53 def on_unload(self):
54 logger.info('Extension "%s" is being unloaded.' % __title__)
56 def on_episode_downloaded(self, episode):
57 current_filename = episode.local_filename(False)
58 converted_filename = self._convert_mp4(episode, current_filename)
60 if converted_filename is not None:
61 self.rename_episode_file(episode, converted_filename)
62 os.remove(current_filename)
63 logger.info('Conversion for %s was successfully' % current_filename)
65 def _get_rockbox_filename(self, origin_filename):
66 if not os.path.exists(origin_filename):
67 logger.info("File '%s' don't exists." % origin_filename)
68 return None
70 dirname = os.path.dirname(origin_filename)
71 filename = os.path.basename(origin_filename)
72 basename, ext = os.path.splitext(filename)
74 if ext not in EXTENTIONS_TO_CONVERT:
75 logger.info("Ignore file with file-extension %s." % ext)
76 return None
78 if filename.endswith(ROCKBOX_EXTENSION):
79 new_filename = "%s-convert.%s" % (basename, ROCKBOX_EXTENSION)
80 else:
81 new_filename = "%s.%s" % (basename, ROCKBOX_EXTENSION)
82 return os.path.join(dirname, new_filename)
85 def _calc_resolution(self, video_width, video_height, device_width, device_height):
86 if video_height is None:
87 return None
89 width_ratio = device_width / video_width
90 height_ratio = device_height / video_height
92 dest_width = device_width
93 dest_height = width_ratio * video_height
95 if dest_height > device_height:
96 dest_width = height_ratio * video_width
97 dest_height = device_height
99 return (int(round(dest_width)), round(int(dest_height)))
102 def _convert_mp4(self, episode, from_file):
103 """Convert MP4 file to rockbox mpg file"""
105 # generate new filename and check if the file already exists
106 to_file = self._get_rockbox_filename(from_file)
107 if to_file is None:
108 return None
109 if os.path.isfile(to_file):
110 return to_file
112 logger.info("Converting: %s", from_file)
113 gpodder.user_extensions.on_notification_show("Converting", episode)
115 # calculationg the new screen resolution
116 info = kaa.metadata.parse(from_file)
117 resolution = self._calc_resolution(
118 info.video[0].width,
119 info.video[0].height,
120 self.container.config.device_width,
121 self.container.config.device_height
123 if resolution is None:
124 logger.error("Error calculating the new screen resolution")
125 return None
127 convert_command = FFMPEG_CMD % {
128 'from': from_file,
129 'to': to_file,
130 'width': str(resolution[0]),
131 'height': str(resolution[1]),
132 'options': self.container.config.ffmpeg_options
135 # Prior to Python 2.7.3, this module (shlex) did not support Unicode input.
136 convert_command = util.sanitize_encoding(convert_command)
138 process = subprocess.Popen(shlex.split(convert_command),
139 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
140 stdout, stderr = process.communicate()
141 if process.returncode != 0:
142 logger.error(stderr)
143 return None
145 gpodder.user_extensions.on_notification_show("Converting finished", episode)
147 return to_file