Gracefully handle download errors in texture browser

This commit is contained in:
Sybren A. Stüvel 2018-03-22 14:21:09 +01:00
parent 0a99b9e22e
commit 79dc5c91f7
3 changed files with 42 additions and 21 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -632,7 +632,11 @@ async def download_texture_thumbnail(texture_node, desired_size: str,
# Cached headers are stored next to thumbnails in sidecar files. # Cached headers are stored next to thumbnails in sidecar files.
header_store = '%s.headers' % thumb_path header_store = '%s.headers' % thumb_path
await download_to_file(thumb_url, thumb_path, header_store=header_store, future=future) try:
await download_to_file(thumb_url, thumb_path, header_store=header_store, future=future)
except requests.exceptions.HTTPError as ex:
log.error('Unable to download %s: %s', thumb_url, ex)
thumb_path = 'ERROR'
loop.call_soon_threadsafe(thumbnail_loaded, texture_node, file_desc, thumb_path) loop.call_soon_threadsafe(thumbnail_loaded, texture_node, file_desc, thumb_path)

View File

@ -82,6 +82,7 @@ class MenuItem:
DEFAULT_ICONS = { DEFAULT_ICONS = {
'FOLDER': os.path.join(library_icons_path, 'folder.png'), 'FOLDER': os.path.join(library_icons_path, 'folder.png'),
'SPINNER': os.path.join(library_icons_path, 'spinner.png'), 'SPINNER': os.path.join(library_icons_path, 'spinner.png'),
'ERROR': os.path.join(library_icons_path, 'error.png'),
} }
FOLDER_NODE_TYPES = {'group_texture', 'group_hdri', UpNode.NODE_TYPE, ProjectNode.NODE_TYPE} FOLDER_NODE_TYPES = {'group_texture', 'group_hdri', UpNode.NODE_TYPE, ProjectNode.NODE_TYPE}
@ -99,6 +100,7 @@ class MenuItem:
self.node = node # pillarsdk.Node, contains 'node_type' key to indicate type self.node = node # pillarsdk.Node, contains 'node_type' key to indicate type
self.file_desc = file_desc # pillarsdk.File object, or None if a 'folder' node. self.file_desc = file_desc # pillarsdk.File object, or None if a 'folder' node.
self.label_text = label_text self.label_text = label_text
self.small_text = self._small_text_from_node()
self._thumb_path = '' self._thumb_path = ''
self.icon = None self.icon = None
self._is_folder = node['node_type'] in self.FOLDER_NODE_TYPES self._is_folder = node['node_type'] in self.FOLDER_NODE_TYPES
@ -118,6 +120,26 @@ class MenuItem:
self.width = 0 self.width = 0
self.height = 0 self.height = 0
def _small_text_from_node(self) -> str:
"""Return the components of the texture (i.e. which map types are available)."""
if not self.node:
return ''
try:
node_files = self.node.properties.files
except AttributeError:
# Happens for nodes that don't have .properties.files.
return ''
if not node_files:
return ''
map_types = {f.map_type for f in node_files if f.map_type}
map_types.discard('color') # all textures have colour
if not map_types:
return ''
return ', '.join(sorted(map_types))
def sort_key(self): def sort_key(self):
"""Key for sorting lists of MenuItems.""" """Key for sorting lists of MenuItems."""
return self._order, self.label_text return self._order, self.label_text
@ -159,6 +181,11 @@ class MenuItem:
if label_text is not None: if label_text is not None:
self.label_text = label_text self.label_text = label_text
if thumb_path == 'ERROR':
self.small_text = 'This open is broken'
else:
self.small_text = self._small_text_from_node()
@property @property
def is_folder(self) -> bool: def is_folder(self) -> bool:
return self._is_folder return self._is_folder
@ -185,15 +212,17 @@ class MenuItem:
bgl.glRectf(self.x, self.y, self.x + self.width, self.y + self.height) bgl.glRectf(self.x, self.y, self.x + self.width, self.y + self.height)
texture = self.icon texture = self.icon
err = texture.gl_load(filter=bgl.GL_NEAREST, mag=bgl.GL_NEAREST) if texture:
assert not err, 'OpenGL error: %i' % err err = texture.gl_load(filter=bgl.GL_NEAREST, mag=bgl.GL_NEAREST)
assert not err, 'OpenGL error: %i' % err
bgl.glColor4f(0.0, 0.0, 1.0, 0.5) bgl.glColor4f(0.0, 0.0, 1.0, 0.5)
# bgl.glLineWidth(1.5) # bgl.glLineWidth(1.5)
# ------ TEXTURE ---------# # ------ TEXTURE ---------#
bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode[0]) if texture:
bgl.glEnable(bgl.GL_TEXTURE_2D) bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode[0])
bgl.glEnable(bgl.GL_TEXTURE_2D)
bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA) bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA)
bgl.glColor4f(1, 1, 1, 1) bgl.glColor4f(1, 1, 1, 1)
@ -210,7 +239,8 @@ class MenuItem:
bgl.glDisable(bgl.GL_TEXTURE_2D) bgl.glDisable(bgl.GL_TEXTURE_2D)
bgl.glDisable(bgl.GL_BLEND) bgl.glDisable(bgl.GL_BLEND)
texture.gl_free() if texture:
texture.gl_free()
# draw some text # draw some text
font_id = 0 font_id = 0
@ -221,24 +251,11 @@ class MenuItem:
blf.size(font_id, self.text_size, text_dpi) blf.size(font_id, self.text_size, text_dpi)
blf.draw(font_id, self.label_text) blf.draw(font_id, self.label_text)
# Draw the components of the texture (i.e. which map types are available) # draw the small text
try:
node_files = self.node.properties.files
except AttributeError:
# Happens for nodes that don't have .properties.files.
node_files = None
if not node_files:
return
map_types = {f.map_type for f in node_files if f.map_type}
map_types.discard('color') # all textures have colour
if not map_types:
return
bgl.glColor4f(1.0, 1.0, 1.0, 0.5) bgl.glColor4f(1.0, 1.0, 1.0, 0.5)
blf.size(font_id, self.text_size_small, text_dpi) blf.size(font_id, self.text_size_small, text_dpi)
blf.position(font_id, text_x, self.y + 0.5 * self.text_size_small, 0) blf.position(font_id, text_x, self.y + 0.5 * self.text_size_small, 0)
blf.draw(font_id, ', '.join(sorted(map_types))) blf.draw(font_id, self.small_text)
def hits(self, mouse_x: int, mouse_y: int) -> bool: def hits(self, mouse_x: int, mouse_y: int) -> bool:
return self.x < mouse_x < self.x + self.width and self.y < mouse_y < self.y + self.height return self.x < mouse_x < self.x + self.width and self.y < mouse_y < self.y + self.height