Support mime type preferences list (bug 995)

Add a new configuration option that controls the
ordering of mime types when multiple enclosures
(file formats) are available in a podcast feed.

Based on an initial patch by Bernd Schlapsi.
This commit is contained in:
Thomas Perl 2010-08-20 23:36:57 +02:00
parent de50c4f065
commit 04b300ad2d
4 changed files with 39 additions and 13 deletions

View File

@ -80,7 +80,8 @@ class Podcast(object):
Downloads the podcast feed (using the feed cache), and
adds new episodes and updated information to the database.
"""
self._podcast.update(self._manager._config.max_episodes_per_feed)
self._podcast.update(self._manager._config.max_episodes_per_feed, \
self._config.mimetype_prefs)
@ -162,7 +163,8 @@ class PodcastClient(object):
podcast = PodcastChannel.load(self._db, url, create=True, \
max_episodes=self._config.max_episodes_per_feed, \
download_dir=self._config.download_dir, \
allow_empty_feeds=self._config.allow_empty_feeds)
allow_empty_feeds=self._config.allow_empty_feeds, \
mimetype_prefs=self._config.mimetype_prefs)
if podcast is not None:
if title is not None:
podcast.set_custom_title(title)

View File

@ -249,6 +249,10 @@ gPodderSettings = {
# Paned position
'paned_position': ( int, 200,
("The width of the channel list.")),
# Preferred mime types for podcasts with multiple content types
'mimetype_prefs': (str, '',
("A comma-separated list of mimetypes, descending order of preference")),
}
# Helper function to add window-specific properties (position and size)

View File

@ -2544,7 +2544,8 @@ class gPodder(BuilderWidget, dbus.service.Object):
authentication_tokens=auth_tokens.get(url, None), \
max_episodes=self.config.max_episodes_per_feed, \
download_dir=self.config.download_dir, \
allow_empty_feeds=self.config.allow_empty_feeds)
allow_empty_feeds=self.config.allow_empty_feeds, \
mimetype_prefs=self.config.mimetype_prefs)
try:
username, password = util.username_password_from_url(url)
@ -2764,7 +2765,8 @@ class gPodder(BuilderWidget, dbus.service.Object):
for updated, channel in enumerate(channels):
if not self.feed_cache_update_cancelled:
try:
channel.update(max_episodes=self.config.max_episodes_per_feed)
channel.update(max_episodes=self.config.max_episodes_per_feed, \
mimetype_prefs=self.config.mimetype_prefs)
self._update_cover(channel)
except Exception, e:
d = {'url': saxutils.escape(channel.url), 'message': saxutils.escape(str(e))}

View File

@ -132,7 +132,8 @@ class PodcastChannel(PodcastModelObject):
@classmethod
def load(cls, db, url, create=True, authentication_tokens=None,\
max_episodes=0, download_dir=None, allow_empty_feeds=False):
max_episodes=0, download_dir=None, allow_empty_feeds=False, \
mimetype_prefs=''):
if isinstance(url, unicode):
url = url.encode('utf-8')
@ -146,7 +147,7 @@ class PodcastChannel(PodcastModelObject):
tmp.username = authentication_tokens[0]
tmp.password = authentication_tokens[1]
tmp.update(max_episodes)
tmp.update(max_episodes, mimetype_prefs)
tmp.save()
db.force_last_new(tmp)
# Subscribing to empty feeds should yield an error (except if
@ -183,7 +184,7 @@ class PodcastChannel(PodcastModelObject):
self.db.purge(max_episodes, self.id)
def _consume_updated_feed(self, feed, max_episodes=0):
def _consume_updated_feed(self, feed, max_episodes=0, mimetype_prefs=''):
self.parse_error = feed.get('bozo_exception', None)
self.title = feed.feed.get('title', self.url)
@ -233,7 +234,7 @@ class PodcastChannel(PodcastModelObject):
# Search all entries for new episodes
for entry in entries:
try:
episode = PodcastEpisode.from_feedparser_entry(entry, self)
episode = PodcastEpisode.from_feedparser_entry(entry, self, mimetype_prefs)
if episode is not None and not episode.title:
episode.title, ext = os.path.splitext(os.path.basename(episode.url))
except Exception, e:
@ -311,7 +312,7 @@ class PodcastChannel(PodcastModelObject):
return updated < one_day_ago or \
(expected < now and updated < lastcheck)
def update(self, max_episodes=0):
def update(self, max_episodes=0, mimetype_prefs=''):
try:
self.feed_fetcher.fetch_channel(self)
except CustomFeed, updated:
@ -320,13 +321,13 @@ class PodcastChannel(PodcastModelObject):
self.save()
except feedcore.UpdatedFeed, updated:
feed = updated.data
self._consume_updated_feed(feed, max_episodes)
self._consume_updated_feed(feed, max_episodes, mimetype_prefs)
self._update_etag_modified(feed)
self.save()
except feedcore.NewLocation, updated:
feed = updated.data
self.url = feed.href
self._consume_updated_feed(feed, max_episodes)
self._consume_updated_feed(feed, max_episodes, mimetype_prefs)
self._update_etag_modified(feed)
self.save()
except feedcore.NotModified, updated:
@ -691,7 +692,7 @@ class PodcastEpisode(PodcastModelObject):
youtube.is_video_link(self.link))
@staticmethod
def from_feedparser_entry(entry, channel):
def from_feedparser_entry(entry, channel, mimetype_prefs=''):
episode = PodcastEpisode(channel)
episode.title = entry.get('title', '')
@ -719,8 +720,25 @@ class PodcastEpisode(PodcastModelObject):
video_available = any(e.get('type', '').startswith('video/') \
for e in enclosures)
# Create the list of preferred mime types
mimetype_prefs = mimetype_prefs.split(',')
def calculate_preference_value(enclosure):
"""Calculate preference value of an enclosure
This is based on mime types and allows users to prefer
certain mime types over others (e.g. MP3 over AAC, ...)
"""
mimetype = enclosure.get('type', None)
try:
# If the mime type is found, return its (zero-based) index
return mimetype_prefs.index(mimetype)
except ValueError:
# If it is not found, assume it comes after all listed items
return len(mimetype_prefs)
# Enclosures
for e in enclosures:
for e in sorted(enclosures, key=calculate_preference_value):
episode.mimetype = e.get('type', 'application/octet-stream')
if episode.mimetype == '':
# See Maemo bug 10036