main_window: pass db+site_id + ensure categories on info panel display

Three changes:

1. _make_client passes db=self._db, site_id=s.id so Gelbooru and
   Moebooru clients get a CategoryFetcher attached via the factory.

2. _on_post_activated calls _ensure_post_categories_async(post)
   after setting up the preview. If the post has empty categories
   (background prefetch hasn't reached it yet, or cache miss),
   this schedules ensure_categories on the async loop. When it
   completes, it emits categories_updated via the Qt signal.

3. _on_categories_updated slot re-renders the info panel and
   preview pane tag display when the currently-selected post's
   categories arrive. Stale updates (user clicked a different post
   before the fill completed) are silently dropped by the post.id
   check.
This commit is contained in:
pax 2026-04-09 19:17:34 -05:00
parent 9a05286f06
commit fa1222a774

View File

@ -149,11 +149,51 @@ class BooruApp(QMainWindow):
s.batch_done.connect(self._on_batch_done, Q) s.batch_done.connect(self._on_batch_done, Q)
s.download_progress.connect(self._on_download_progress, Q) s.download_progress.connect(self._on_download_progress, Q)
s.prefetch_progress.connect(self._on_prefetch_progress, Q) s.prefetch_progress.connect(self._on_prefetch_progress, Q)
s.categories_updated.connect(self._on_categories_updated, Q)
def _on_prefetch_progress(self, index: int, progress: float) -> None: def _on_prefetch_progress(self, index: int, progress: float) -> None:
if 0 <= index < len(self._grid._thumbs): if 0 <= index < len(self._grid._thumbs):
self._grid._thumbs[index].set_prefetch_progress(progress) self._grid._thumbs[index].set_prefetch_progress(progress)
def _ensure_post_categories_async(self, post) -> None:
"""Schedule an async ensure_categories if the post needs it.
No-op if the post already has categories, or if the active
client doesn't have a CategoryFetcher attached.
"""
if post.tag_categories:
return
client = self._make_client()
if client is None or client.category_fetcher is None:
return
fetcher = client.category_fetcher
signals = self._signals
async def _do():
try:
await fetcher.ensure_categories(post)
if post.tag_categories:
signals.categories_updated.emit(post)
except Exception as e:
log.debug(f"ensure_categories failed: {e}")
asyncio.run_coroutine_threadsafe(_do(), self._async_loop)
def _on_categories_updated(self, post) -> None:
"""Background tag-category fill completed for a post.
Re-render the info panel and preview pane if either is
currently showing this post. The post object was mutated in
place by the CategoryFetcher, so we just call the panel's
set_post / set_post_tags again to pick up the new dict.
"""
if not post or not post.tag_categories:
return
idx = self._grid.selected_index
if 0 <= idx < len(self._posts) and self._posts[idx].id == post.id:
self._info_panel.set_post(post)
self._preview.set_post_tags(post.tag_categories, post.tag_list)
def _clear_loading(self) -> None: def _clear_loading(self) -> None:
self._loading = False self._loading = False
@ -516,7 +556,10 @@ class BooruApp(QMainWindow):
if not self._current_site: if not self._current_site:
return None return None
s = self._current_site s = self._current_site
return client_for_type(s.api_type, s.url, s.api_key, s.api_user) return client_for_type(
s.api_type, s.url, s.api_key, s.api_user,
db=self._db, site_id=s.id,
)
def _on_site_changed(self, index: int) -> None: def _on_site_changed(self, index: int) -> None:
if index < 0: if index < 0:
@ -1129,6 +1172,12 @@ class BooruApp(QMainWindow):
self._preview._current_post = post self._preview._current_post = post
self._preview._current_site_id = self._site_combo.currentData() self._preview._current_site_id = self._site_combo.currentData()
self._preview.set_post_tags(post.tag_categories, post.tag_list) self._preview.set_post_tags(post.tag_categories, post.tag_list)
# Kick off async category fill if the post has none yet.
# The background prefetch from search() may not have
# reached this post; ensure_categories is the safety net.
# When it completes, the categories_updated signal fires
# and the slot re-renders both panels.
self._ensure_post_categories_async(post)
site_id = self._preview._current_site_id site_id = self._preview._current_site_id
self._preview.update_bookmark_state( self._preview.update_bookmark_state(
bool(site_id and self._db.is_bookmarked(site_id, post.id)) bool(site_id and self._db.is_bookmarked(site_id, post.id))