Gracefully handle download errors in texture browser
This commit is contained in:
parent
0a99b9e22e
commit
79dc5c91f7
BIN
blender_cloud/icons/error.png
Normal file
BIN
blender_cloud/icons/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user