api: BooruClient virtual _post_view_url + _tag_api_url + category_fetcher attr

Three additions to the base class, all default-inactive:

  _post_view_url(post) -> str | None
    Override to provide the post-view HTML URL for the per-post
    category scrape path. Default None (Danbooru/e621 skip it).

  _tag_api_url() -> str | None
    Override to provide the batch tag DAPI base URL for the fast
    path in CategoryFetcher. Default None. Only Gelbooru proper
    benefits — the fetcher's probe-and-cache determines at runtime
    whether the endpoint actually honors the names= parameter.

  self.category_fetcher = None
    Set externally by the factory (client_for_type) when db and
    site_id are available. Gelbooru-shape and Moebooru clients use
    it; Danbooru/e621 leave it None.

No behavior change at this commit. Existing clients inherit the
defaults and continue working identically.
This commit is contained in:
pax 2026-04-09 19:13:21 -05:00
parent e00d88e1ec
commit 8f298e51fc

View File

@ -85,6 +85,11 @@ class BooruClient(ABC):
self.base_url = base_url.rstrip("/")
self.api_key = api_key
self.api_user = api_user
# Set externally by client_for_type when db + site_id are
# available. Gelbooru-shape and Moebooru clients use it to
# populate post.tag_categories via HTML scrape / batch API.
# Danbooru and e621 leave it None (inline categorization).
self.category_fetcher = None # CategoryFetcher | None
@property
def client(self) -> httpx.AsyncClient:
@ -176,6 +181,28 @@ class BooruClient(ABC):
"""Tag autocomplete. Override in subclasses that support it."""
return []
def _post_view_url(self, post: Post) -> str | None:
"""Return the URL for a post's HTML detail page, or None.
Override in subclasses whose booru exposes tag categories in
the post-view HTML via ``class="tag-type-X"`` markup.
CategoryFetcher.fetch_post uses this to scrape categories.
Returning None means "no HTML scrape path" the default for
Danbooru and e621 which categorize inline via JSON.
"""
return None
def _tag_api_url(self) -> str | None:
"""Return the base URL for the batch tag DAPI, or None.
Override in Gelbooru-shaped subclasses to enable the fast
path in CategoryFetcher.fetch_via_tag_api. The fetcher
appends ``?page=dapi&s=tag&q=index&...`` query params.
Returning None disables the fast path; the fetcher falls
back to per-post HTML scrape.
"""
return None
async def test_connection(self) -> tuple[bool, str]:
"""Test connection. Returns (success, detail_message).