Merge pull request #741 from auouymous/show-dialog-when-error-updating-feed

Better feed update error feedback:
 - remove common stacktraces
 - always show feeds in error
 - error emblem on feed cover
 - error message in description
This commit is contained in:
Eric Le Lay 2020-04-01 09:35:59 +02:00 committed by GitHub
commit 400ee8e9d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 16 deletions

View File

@ -1327,7 +1327,9 @@ class gPodder(BuilderWidget, dbus.service.Object):
box.add(Gtk.HSeparator())
if len(channel.description) < 500:
if channel._update_error is not None:
description = _('ERROR: %s') % channel._update_error
elif len(channel.description) < 500:
description = channel.description
else:
pos = channel.description.find('\n\n')
@ -2610,6 +2612,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.pbFeedUpdate.set_text(progression)
try:
channel._update_error = None
util.idle_add(indicate_updating_podcast, channel)
channel.update(max_episodes=self.config.max_episodes_per_feed)
self._update_cover(channel)
@ -2617,10 +2620,19 @@ class gPodder(BuilderWidget, dbus.service.Object):
d = {'title': html.escape(channel.title), 'url': html.escape(channel.url), 'message': html.escape(str(e))}
if d['message']:
message = _('Error while updating %(title)s at %(url)s: %(message)s')
channel._update_error = str(e)
else:
message = _('The %(title)s feed at %(url)s could not be updated.')
channel._update_error = '?'
self.notification(message % d, _('Error while updating feed'), widget=self.treeChannels)
logger.error('Error: %s', str(e), exc_info=True)
logger.error('Error: %s', str(e), exc_info=(e.__class__ not in [
gpodder.feedcore.BadRequest,
gpodder.feedcore.AuthenticationRequired,
gpodder.feedcore.Unsubscribe,
gpodder.feedcore.NotFound,
gpodder.feedcore.InternalServerError,
gpodder.feedcore.UnknownStatusCode,
]))
updated_channels.append(channel)

View File

@ -497,6 +497,8 @@ class PodcastChannelProxy(object):
self.cover_thumb = None
self.auto_archive_episodes = False
self._update_error = None
def get_statistics(self):
# Get the total statistics for all channels from the database
return self._db.get_podcast_statistics()
@ -538,12 +540,15 @@ class PodcastListModel(Gtk.ListStore):
self._max_image_side = 40
self._cover_downloader = cover_downloader
self.ICON_DISABLED = 'gtk-media-pause'
self.ICON_DISABLED = 'media-playback-pause'
self.ICON_ERROR = 'dialog-warning'
def _filter_visible_func(self, model, iter, misc):
channel = model.get_value(iter, self.C_CHANNEL)
# If searching is active, set visibility based on search text
if self._search_term is not None:
if model.get_value(iter, self.C_CHANNEL) == SectionMarker:
if channel == SectionMarker:
return True
key = self._search_term.lower()
columns = (model.get_value(iter, c) for c in self.SEARCH_COLUMNS)
@ -551,6 +556,8 @@ class PodcastListModel(Gtk.ListStore):
if model.get_value(iter, self.C_SEPARATOR):
return True
elif getattr(channel, '_update_error', None) is not None:
return True
elif self._view_mode == EpisodeListModel.VIEW_ALL:
return model.get_value(iter, self.C_HAS_EPISODES)
elif self._view_mode == EpisodeListModel.VIEW_UNDELETED:
@ -687,20 +694,31 @@ class PodcastListModel(Gtk.ListStore):
channel.cover_thumb = bytes(b''.join(bufs))
channel.save()
def _get_cover_image(self, channel, add_overlay=False):
def _get_cover_image(self, channel, add_overlay=False, pixbuf_overlay=None):
""" get channel's cover image. Callable from gtk thread.
:param channel: channel model
:param bool add_overlay: True to add a pause/error overlay
:param GdkPixbuf.Pixbux pixbuf_overlay: existing pixbuf if already loaded, as an optimization
:return GdkPixbuf.Pixbux: channel's cover image as pixbuf
"""
if self._cover_downloader is None:
return None
return pixbuf_overlay
pixbuf_overlay = self._get_cached_thumb(channel)
if pixbuf_overlay is None: # optimization: we can pass existing pixbuf
pixbuf_overlay = self._get_cached_thumb(channel)
if pixbuf_overlay is None:
# load cover if it's not in cache
pixbuf = self._cover_downloader.get_cover(channel, avoid_downloading=True)
pixbuf_overlay = self._resize_pixbuf(channel.url, pixbuf)
self._save_cached_thumb(channel, pixbuf_overlay)
if add_overlay and channel.pause_subscription:
pixbuf_overlay = self._overlay_pixbuf(pixbuf_overlay, self.ICON_DISABLED)
pixbuf_overlay.saturate_and_pixelate(pixbuf_overlay, 0.0, False)
if add_overlay:
if getattr(channel, '_update_error', None) is not None:
pixbuf_overlay = self._overlay_pixbuf(pixbuf_overlay, self.ICON_ERROR)
elif channel.pause_subscription:
pixbuf_overlay = self._overlay_pixbuf(pixbuf_overlay, self.ICON_DISABLED)
pixbuf_overlay.saturate_and_pixelate(pixbuf_overlay, 0.0, False)
return pixbuf_overlay
@ -713,7 +731,9 @@ class PodcastListModel(Gtk.ListStore):
def _format_description(self, channel, total, deleted,
new, downloaded, unplayed):
title_markup = html.escape(channel.title)
if not channel.pause_subscription:
if channel._update_error is not None:
description_markup = html.escape(_('ERROR: %s') % channel._update_error)
elif not channel.pause_subscription:
description_markup = html.escape(util.get_first_line(channel.description) or ' ')
else:
description_markup = html.escape(_('Subscription paused'))
@ -724,7 +744,9 @@ class PodcastListModel(Gtk.ListStore):
if new:
d.append('</span>')
if description_markup.strip():
if channel._update_error is not None:
return ''.join(d + ['\n', '<span weight="bold">', description_markup, '</span>'])
elif description_markup.strip():
return ''.join(d + ['\n', '<small>', description_markup, '</small>'])
else:
return ''.join(d)
@ -877,6 +899,7 @@ class PodcastListModel(Gtk.ListStore):
self.set(iter,
self.C_TITLE, channel.title,
self.C_DESCRIPTION, description,
self.C_COVER, self._get_cover_image(channel, True),
self.C_SECTION, channel.section,
self.C_ERROR, self._format_error(channel),
self.C_PILL, pill_image,
@ -902,9 +925,7 @@ class PodcastListModel(Gtk.ListStore):
pixbuf = self._resize_pixbuf(channel.url, pixbuf)
self._save_cached_thumb(channel, pixbuf)
if channel.pause_subscription:
pixbuf = self._overlay_pixbuf(pixbuf, self.ICON_DISABLED)
pixbuf.saturate_and_pixelate(pixbuf, 0.0, False)
pixbuf = self._get_cover_image(channel, add_overlay=True, pixbuf_overlay=pixbuf)
for row in self:
if row[self.C_URL] == channel.url:

View File

@ -762,7 +762,7 @@ class PodcastEpisode(PodcastModelObject):
class PodcastChannel(PodcastModelObject):
__slots__ = schema.PodcastColumns + ('_common_prefix',)
__slots__ = schema.PodcastColumns + ('_common_prefix', '_update_error',)
UNICODE_TRANSLATE = {ord('ö'): 'o', ord('ä'): 'a', ord('ü'): 'u'}
@ -814,6 +814,8 @@ class PodcastChannel(PodcastModelObject):
self.children = self.db.load_episodes(self, self.episode_factory)
self._determine_common_prefix()
self._update_error = None
@property
def model(self):
return self.parent