Vimeo: Support for selecting file format (bug 1954)

This commit is contained in:
Thomas Perl 2014-09-30 13:35:23 +02:00
parent 5693551766
commit e215a5d5a3
7 changed files with 127 additions and 28 deletions

View File

@ -52,7 +52,7 @@
<object class="GtkTable" id="table_players">
<property name="column_spacing">6</property>
<property name="n_columns">3</property>
<property name="n_rows">3</property>
<property name="n_rows">4</property>
<property name="row_spacing">6</property>
<property name="visible">True</property>
<child>
@ -136,11 +136,11 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="label_preferred_video_format">
<object class="GtkLabel" id="label_preferred_youtube_format">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Preferred video format:</property>
<property name="label" translatable="yes">Preferred YouTube format:</property>
</object>
<packing>
<property name="top_attach">2</property>
@ -149,10 +149,10 @@
</packing>
</child>
<child>
<object class="GtkComboBox" id="combobox_preferred_video_format">
<object class="GtkComboBox" id="combobox_preferred_youtube_format">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="on_combobox_preferred_video_format_changed" swapped="no"/>
<signal name="changed" handler="on_combobox_preferred_youtube_format_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
@ -161,6 +161,32 @@
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_preferred_vimeo_format">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Preferred Vimeo format:</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">fill</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="combobox_preferred_vimeo_format">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="on_combobox_preferred_vimeo_format_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>

View File

@ -193,6 +193,10 @@ defaults = {
'preferred_fmt_ids': [], # for advanced uses (custom fallback sequence)
},
'vimeo': {
'fileformat': 'hd', # preferred file format (hd, sd, mobile)
},
'extensions': {
'enabled': [],
},

View File

@ -751,7 +751,7 @@ class DownloadTask(object):
# Resolve URL and start downloading the episode
fmt_ids = youtube.get_fmt_ids(self._config.youtube)
url = youtube.get_real_download_url(self.__episode.url, fmt_ids)
url = vimeo.get_real_download_url(url)
url = vimeo.get_real_download_url(url, self._config.vimeo.fileformat)
url = escapist_videos.get_real_download_url(url)
downloader = DownloadURLOpener(self.__episode.channel)

View File

@ -32,6 +32,7 @@ N_ = gpodder.ngettext
from gpodder import util
from gpodder import youtube
from gpodder import vimeo
from gpodder.gtkui.interface.common import BuilderWidget
from gpodder.gtkui.interface.common import TreeViewHelper
@ -139,23 +140,28 @@ class gPodderFlattrSignIn(BuilderWidget):
def on_btn_close_clicked(self, widget):
util.idle_add(self.main_window.destroy)
class VideoFormatList(gtk.ListStore):
class YouTubeVideoFormatListModel(gtk.ListStore):
C_CAPTION, C_ID = range(2)
def __init__(self, config):
gtk.ListStore.__init__(self, str, int)
self._config = config
self.custom_fmt_ids = self._config.youtube.preferred_fmt_ids
if self._config.youtube.preferred_fmt_ids:
caption = _('Custom (%(format_ids)s)') % {
'format_ids': ', '.join(self.custom_format_ids),
'format_ids': ', '.join(str(x) for x in self.custom_fmt_ids),
}
self.append((caption, -1))
else:
for id, (fmt_id, path, description) in youtube.formats:
self.append((description, id))
for id, (fmt_id, path, description) in youtube.formats:
self.append((description, id))
def get_index(self):
if self._config.youtube.preferred_fmt_ids:
return 0
for index, row in enumerate(self):
if self._config.youtube.preferred_fmt_id == row[self.C_ID]:
return index
@ -165,6 +171,36 @@ class VideoFormatList(gtk.ListStore):
value = self[index][self.C_ID]
if value > 0:
self._config.youtube.preferred_fmt_id = value
# If we set a value, we need to unset the custom one, so that
# the single value (preferred_fmt_id) gets used instead
self._config.youtube.preferred_fmt_ids = []
else:
# If the user selects the -1 value, it's our custom one, and
# we need to restore the value for preferred_fmt_ids
self._config.youtube.preferred_fmt_ids = self.custom_fmt_ids
class VimeoVideoFormatListModel(gtk.ListStore):
C_CAPTION, C_ID = range(2)
def __init__(self, config):
gtk.ListStore.__init__(self, str, str)
self._config = config
for fileformat, description in vimeo.FORMATS:
self.append((description, fileformat))
def get_index(self):
for index, row in enumerate(self):
if self._config.vimeo.fileformat == row[self.C_ID]:
return index
return 0
def set_index(self, index):
value = self[index][self.C_ID]
if value > 0:
self._config.vimeo.fileformat = value
class gPodderPreferences(BuilderWidget):
C_TOGGLE, C_LABEL, C_EXTENSION, C_SHOW_TOGGLE = range(4)
@ -190,12 +226,19 @@ class gPodderPreferences(BuilderWidget):
index = self.video_player_model.get_index(self._config.videoplayer)
self.combo_video_player_app.set_active(index)
self.preferred_video_format_model = VideoFormatList(self._config)
self.combobox_preferred_video_format.set_model(self.preferred_video_format_model)
self.preferred_youtube_format_model = YouTubeVideoFormatListModel(self._config)
self.combobox_preferred_youtube_format.set_model(self.preferred_youtube_format_model)
cellrenderer = gtk.CellRendererText()
self.combobox_preferred_video_format.pack_start(cellrenderer, True)
self.combobox_preferred_video_format.add_attribute(cellrenderer, 'text', self.preferred_video_format_model.C_CAPTION)
self.combobox_preferred_video_format.set_active(self.preferred_video_format_model.get_index())
self.combobox_preferred_youtube_format.pack_start(cellrenderer, True)
self.combobox_preferred_youtube_format.add_attribute(cellrenderer, 'text', self.preferred_youtube_format_model.C_CAPTION)
self.combobox_preferred_youtube_format.set_active(self.preferred_youtube_format_model.get_index())
self.preferred_vimeo_format_model = VimeoVideoFormatListModel(self._config)
self.combobox_preferred_vimeo_format.set_model(self.preferred_vimeo_format_model)
cellrenderer = gtk.CellRendererText()
self.combobox_preferred_vimeo_format.pack_start(cellrenderer, True)
self.combobox_preferred_vimeo_format.add_attribute(cellrenderer, 'text', self.preferred_vimeo_format_model.C_CAPTION)
self.combobox_preferred_vimeo_format.set_active(self.preferred_vimeo_format_model.get_index())
self._config.connect_gtk_togglebutton('podcast_list_view_all',
self.checkbutton_show_all_episodes)
@ -482,9 +525,13 @@ class gPodderPreferences(BuilderWidget):
index = self.combo_video_player_app.get_active()
self._config.videoplayer = self.video_player_model.get_command(index)
def on_combobox_preferred_video_format_changed(self, widget):
index = self.combobox_preferred_video_format.get_active()
self.preferred_video_format_model.set_index(index)
def on_combobox_preferred_youtube_format_changed(self, widget):
index = self.combobox_preferred_youtube_format.get_active()
self.preferred_youtube_format_model.set_index(index)
def on_combobox_preferred_vimeo_format_changed(self, widget):
index = self.combobox_preferred_vimeo_format.get_active()
self.preferred_vimeo_format_model.set_index(index)
def on_button_audio_player_clicked(self, widget):
result = self.show_text_edit_dialog(_('Configure audio player'), \

View File

@ -1873,9 +1873,10 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.mygpo_client.on_playback([episode])
fmt_ids = youtube.get_fmt_ids(self.config.youtube)
vimeo_fmt = self.config.vimeo.fileformat
allow_partial = (player != 'default')
filename = episode.get_playback_url(fmt_ids, allow_partial)
filename = episode.get_playback_url(fmt_ids, vimeo_fmt, allow_partial)
# Determine the playback resume position - if the file
# was played 100%, we simply start from the beginning

View File

@ -466,7 +466,7 @@ class PodcastEpisode(PodcastModelObject):
self.set_state(gpodder.STATE_DELETED)
def get_playback_url(self, fmt_ids=None, allow_partial=False):
def get_playback_url(self, fmt_ids=None, vimeo_fmt=None, allow_partial=False):
"""Local (or remote) playback/streaming filename/URL
Returns either the local filename or a streaming URL that
@ -484,7 +484,7 @@ class PodcastEpisode(PodcastModelObject):
if url is None or not os.path.exists(url):
url = self.url
url = youtube.get_real_download_url(url, fmt_ids)
url = vimeo.get_real_download_url(url)
url = vimeo.get_real_download_url(url, vimeo_fmt)
url = escapist_videos.get_real_download_url(url)
return url

View File

@ -25,6 +25,8 @@
import gpodder
_ = gpodder.gettext
from gpodder import util
import logging
@ -44,13 +46,19 @@ MOOGALOOP_RE = re.compile(r'http://vimeo\.com/moogaloop\.swf\?clip_id=(\d+)$', r
SIGNATURE_RE = re.compile(r'"timestamp":(\d+),"signature":"([^"]+)"')
DATA_CONFIG_RE = re.compile(r'data-config-url="([^"]+)"')
# List of qualities, from lowest to highest
FILEFORMAT_RANKING = ['mobile', 'sd', 'hd']
FORMATS = (
('mobile', _('Mobile')),
('sd', _('SD')),
('hd', _('HD')),
)
class VimeoError(BaseException): pass
def get_real_download_url(url):
quality = 'sd'
codecs = 'H264,VP8,VP6'
def get_real_download_url(url, preferred_fileformat=None):
video_id = get_vimeo_id(url)
if video_id is None:
@ -78,8 +86,21 @@ def get_real_download_url(url):
yield (fileformat, keys['url'])
for quality, url in get_urls(data_config_url):
return url
fileformat_to_url = dict(get_urls(data_config_url))
if preferred_fileformat is not None and preferred_fileformat in fileformat_to_url:
logger.debug('Picking preferred format: %s', preferred_fileformat)
return fileformat_to_url[preferred_fileformat]
def fileformat_sort_key_func(fileformat):
if fileformat in FILEFORMAT_RANKING:
return FILEFORMAT_RANKING.index(fileformat)
return 0
for fileformat in sorted(fileformat_to_url, key=fileformat_sort_key_func, reverse=True):
logger.debug('Picking best format: %s', fileformat)
return fileformat_to_url[fileformat]
def get_vimeo_id(url):
result = MOOGALOOP_RE.match(url)