mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Assets: download online previews in LIFO fashion
When browsing online assets, download the last-requested preview first. This ensures that, when scrolling through the assets, the previews that are scrolled into view get priority over previews that are scrolled out of view. This introduces an optional keyword-only parameter to `http.BackgroundDownloader.queue_download(queue_side=QueueSide)`, where `QueueSide` is an enum with values `FRONT` and `BACK`. The asset downloader always uses `BACK` for FIFO behaviour, and the preview downloader always uses `FRONT` for LIFO behaviour. This causes preview images in the asset browser to be downloaded bottom-to-top (speaking visually here). This can be adjusted in Blender's C++ code by requesting the thumbnails in the opposite order. As an alternative implementation, a priority queue was discussed. Previews that are scrolled out of view could then get a lower priority. This means that Blender would have to track which previews are requested for download, as well as track how many windows are showing certain previews (because "scrolled out of view in one asset browser" doesn't always mean "no longer visible"). Simply downloading the previews in LIFO order was considerably simpler, and likely sufficient. Pull Request: https://projects.blender.org/blender/blender/pulls/161897
This commit is contained in:
parent
c543fa302a
commit
b9dc2c7ca4
2 changed files with 41 additions and 10 deletions
|
|
@ -71,6 +71,7 @@ def download_asset_file(
|
|||
asset_library_local_path,
|
||||
reporter=AssetReporter(asset_library_url=asset_library_url),
|
||||
on_queue_empty_callback=on_asset_download_queue_empty,
|
||||
queue_side=http_dl.QueueSide.BACK, # FIFO queue.
|
||||
)
|
||||
downloader.start()
|
||||
_asset_downloaders[asset_library_url] = downloader
|
||||
|
|
@ -138,6 +139,7 @@ def download_preview(
|
|||
asset_library_local_path,
|
||||
reporter=PreviewReporter(),
|
||||
on_queue_empty_callback=None,
|
||||
queue_side=http_dl.QueueSide.FRONT, # LIFO queue.
|
||||
)
|
||||
downloader.start()
|
||||
_preview_downloaders[asset_library_url] = downloader
|
||||
|
|
@ -251,6 +253,9 @@ class AssetDownloader:
|
|||
|
||||
_HTTP_METHOD = "GET"
|
||||
|
||||
_queue_side: http_dl.QueueSide
|
||||
"""Previews are queued at the front (LIFO), and assets at the back (FIFO)."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
remote_url: str,
|
||||
|
|
@ -258,6 +263,7 @@ class AssetDownloader:
|
|||
*,
|
||||
reporter: http_dl.DownloadReporter,
|
||||
on_queue_empty_callback: QueueEmptyCallback | None,
|
||||
queue_side: http_dl.QueueSide,
|
||||
) -> None:
|
||||
"""Create a downloader for assets of a specific asset library.
|
||||
|
||||
|
|
@ -285,6 +291,7 @@ class AssetDownloader:
|
|||
)
|
||||
|
||||
self._bg_downloader = None
|
||||
self._queue_side = queue_side
|
||||
|
||||
def _create_bg_downloader(self) -> None:
|
||||
self._bg_downloader = http_dl.BackgroundDownloader(
|
||||
|
|
@ -415,6 +422,7 @@ class AssetDownloader:
|
|||
remote_url,
|
||||
download_to_path,
|
||||
http_method=self._HTTP_METHOD,
|
||||
queue_side=self._queue_side,
|
||||
)
|
||||
return request_descr.url
|
||||
|
||||
|
|
|
|||
|
|
@ -464,6 +464,13 @@ class DownloaderOptions:
|
|||
self.http_headers['user-agent'] = user_agent
|
||||
|
||||
|
||||
class QueueSide(enum.Enum):
|
||||
BACK = 'back'
|
||||
"""Download goes to the back of the queue."""
|
||||
FRONT = 'front'
|
||||
"""Download goes to the front of the queue."""
|
||||
|
||||
|
||||
class BackgroundDownloader:
|
||||
"""Wrapper for a ConditionalDownloader + reporters.
|
||||
|
||||
|
|
@ -539,6 +546,7 @@ class BackgroundDownloader:
|
|||
on_download_done: DownloadDoneCallback | None = None,
|
||||
*,
|
||||
http_method: str = 'GET',
|
||||
queue_side: QueueSide = QueueSide.BACK,
|
||||
) -> RequestDescription:
|
||||
"""Queue up a download of some URL to a location on disk.
|
||||
|
||||
|
|
@ -566,13 +574,21 @@ class BackgroundDownloader:
|
|||
# looking at this dict.
|
||||
self._on_download_done_callbacks[http_req_descr].append(on_download_done)
|
||||
|
||||
if not is_already_queued:
|
||||
if is_already_queued:
|
||||
# Only queue a download once.
|
||||
self._num_pending_downloads += 1
|
||||
self._connection.send(PipeMessage(
|
||||
msgtype=PipeMsgType.QUEUE_DOWNLOAD,
|
||||
payload=(http_req_descr, local_path),
|
||||
))
|
||||
return http_req_descr
|
||||
|
||||
match queue_side:
|
||||
case QueueSide.BACK:
|
||||
msgtype = PipeMsgType.QUEUE_DOWNLOAD
|
||||
case QueueSide.FRONT:
|
||||
msgtype = PipeMsgType.QUEUE_DOWNLOAD_FRONT
|
||||
|
||||
self._num_pending_downloads += 1
|
||||
self._connection.send(PipeMessage(
|
||||
msgtype=msgtype,
|
||||
payload=(http_req_descr, local_path),
|
||||
))
|
||||
|
||||
return http_req_descr
|
||||
|
||||
|
|
@ -846,7 +862,14 @@ class PipeMsgType(enum.Enum):
|
|||
"""Payload: BackgroundDownloader.QueuedDownload
|
||||
|
||||
Main -> Background process.
|
||||
Queue a HTTP request for downloading.
|
||||
Queue a HTTP request for downloading. It will be put at the end of the queue.
|
||||
"""
|
||||
|
||||
QUEUE_DOWNLOAD_FRONT = 'queue-front'
|
||||
"""Payload: BackgroundDownloader.QueuedDownload
|
||||
|
||||
Main -> Background process.
|
||||
Queue a HTTP request for downloading. It will be put at the front of the queue.
|
||||
"""
|
||||
|
||||
CANCEL_DOWNLOAD = 'cancel'
|
||||
|
|
@ -963,11 +986,9 @@ def _download_queued_items(
|
|||
tx_thread.start()
|
||||
|
||||
def unqueue_request(http_req_descr: RequestDescription) -> None:
|
||||
"""Remove the given HTTP request from the download queue."""
|
||||
|
||||
# Reconstruct the download queue, skipping the given HTTP request.
|
||||
# We can't use deque.remove() here, because the RequestDescription
|
||||
# is only part of the objects in the queue.
|
||||
# is only _part_ of the objects in the queue.
|
||||
new_queue = [
|
||||
(queued_req, queued_path)
|
||||
for (queued_req, queued_path) in download_queue
|
||||
|
|
@ -1000,6 +1021,8 @@ def _download_queued_items(
|
|||
do_shutdown.set()
|
||||
case PipeMsgType.QUEUE_DOWNLOAD:
|
||||
download_queue.append(received_msg.payload)
|
||||
case PipeMsgType.QUEUE_DOWNLOAD_FRONT:
|
||||
download_queue.appendleft(received_msg.payload)
|
||||
case PipeMsgType.CANCEL_DOWNLOAD:
|
||||
assert isinstance(received_msg.payload, RequestDescription)
|
||||
request_to_cancel: RequestDescription = received_msg.payload
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue