From fa1222a774597e778c4c2e11cfb7de886e0994e8 Mon Sep 17 00:00:00 2001 From: pax Date: Thu, 9 Apr 2026 19:17:34 -0500 Subject: [PATCH] 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. --- booru_viewer/gui/main_window.py | 51 ++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/booru_viewer/gui/main_window.py b/booru_viewer/gui/main_window.py index 821ecee..eaf24be 100644 --- a/booru_viewer/gui/main_window.py +++ b/booru_viewer/gui/main_window.py @@ -149,11 +149,51 @@ class BooruApp(QMainWindow): s.batch_done.connect(self._on_batch_done, Q) s.download_progress.connect(self._on_download_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: if 0 <= index < len(self._grid._thumbs): 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: self._loading = False @@ -516,7 +556,10 @@ class BooruApp(QMainWindow): if not self._current_site: return None 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: if index < 0: @@ -1129,6 +1172,12 @@ class BooruApp(QMainWindow): self._preview._current_post = post self._preview._current_site_id = self._site_combo.currentData() 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 self._preview.update_bookmark_state( bool(site_id and self._db.is_bookmarked(site_id, post.id))