• v0.2.8 8eba84a63a

    v0.2.8 Stable

    pax released this 2026-08-19 22:26:14 -05:00 | 39 commits to main since this release

    v0.2.8

    Added

    • Settings → Cache: Clear Tag Cache button — wipes the per-site tag_types rows (including the __batch_api_probe__ sentinel) so Gelbooru/Moebooru backends re-probe and re-populate tag categories from scratch. Useful when a stale cache from an earlier build leaves some category types mis-labelled or missing

    Changed

    • Windows installer now ships licenses\LGPL-2.1.txt and licenses\THIRD-PARTY-NOTICES.txt alongside the app, naming the exact libmpv build, its source and checksum, and how to swap the DLL — the attribution and relink terms LGPL section 6 asks for when redistributing the library
    • Windows installer now bundles the LGPL build of libmpv instead of the GPL build. booru-viewer decodes video and never encodes it, so the GPL-only x264/x265 encoders were unused weight in an MIT-licensed app; H.264/HEVC/AV1/VP9 decoding is unaffected
    • Thumbnail drag-start threshold raised from 10px to 30px to match the rubber band's gate — small mouse wobbles on a thumb no longer trigger a file drag
    • Settings → Cache layout: Clear Tag Cache moved into row 1 alongside Clear Thumbnails and Clear Image Cache as a 3-wide non-destructive row; destructive Clear Everything + Evict stay in row 2

    Fixed

    • rule34.xxx misdetected as danbooru, then failing Test Connection with HTTP 403 Forbidden. rule34 now serves a WAF HTML block page (403) at /posts.json, and detect_site_type read any 401/403 there as "Danbooru behind auth". The Danbooru and Moebooru probes now only treat 401/403 as conclusive when the body is actually JSON, so WAF-guarded Gelbooru-family hosts fall through to the Gelbooru probe. Behavior change: rule34.xxx detects as gelbooru
    • Gelbooru-shape sites answering HTTP 200 with a bare JSON string were reported as a search with zero results. rule34 now requires api_key + user_id and replies "Missing authentication..." at 200, which raise_for_status() cannot see; GelbooruClient now raises BooruAuthError instead, and the Gelbooru probe treats that shape as a positive match. Behavior change: a missing or rejected API key surfaces as an error rather than an empty grid
    • Grid blanked out after splitter drag or tile/float toggle until the next scroll — ThumbnailGrid.resizeEvent now re-runs _recycle_offscreen against the new geometry so thumbs whose pixmap was evicted by a column-count shift get refreshed into view. Behavior change: no more blank grid after resize
    • Status bar overwrote the per-post info set by _on_post_selected with "N results — Loaded" the moment the image finished downloading, hiding tag counts / post ID until the user re-clicked; on_image_done now preserves the incoming info string
    • category_fetcher._do_ensure no longer permanently flips _batch_api_works to False when a transient network error drops a tag-API request mid-call; the unprobed path now routes through _probe_batch_api, which distinguishes clean 200-with-zero-matches (structurally broken, flip) from timeout/HTTP-error (transient, retry next call)
    • Bookmark→library save and bookmark Save As now plumb the active site's CategoryFetcher through to the filename template, so %artist%/%character% tokens render correctly instead of silently dropping out when saving a post that wasn't previewed first
    • Info panel no longer silently drops tags that failed to land in a cached category — any tag from post.tag_list not rendered under a known category section now appears in an "Other" bucket, so partial cache coverage can't make individual tags invisible
    • BooruClient._request retries now cover httpx.RemoteProtocolError and httpx.ReadError in addition to the existing timeout/connect/network set — an overloaded booru that drops the TCP connection mid-response no longer fails the whole search on the first try
    • VRAM retained when no video is playing — stop() now frees the GL render context (textures + FBOs) instead of just dropping the hwdec surface pool. Context is recreated lazily on next play_file() via ensure_gl_init() (~5ms, invisible behind network fetch)

    Refactored

    • category_fetcher batch tag-API params are now built by a shared _build_tag_api_params helper instead of duplicated across fetch_via_tag_api and _probe_batch_api
    • detect.detect_site_type — removed the leftover if True: indent marker; no behavior change
    • core.http.make_client — single constructor for the three httpx.AsyncClient instances (cache download pool, API pool, detect probe). Each call site still keeps its own singleton and connection pool; only the construction is shared
    • Silent except: pass sites in popout/window, video_player, and window_state now carry one-line comments naming the absorbed failure and the graceful fallback (or were downgraded to log.debug(..., exc_info=True)). No behavior change
    • Popout docstrings purged of in-flight-refactor commit markers (skeleton, 14a, 14b, future commit) that referred to now-landed state-machine extraction; load-bearing commit 14b reference kept in _dispatch_and_apply as it still protects against reintroducing the bug
    • core/cache.py tempfile cleanup: BaseException catch now documents why it's intentionally broader than Exception
    • api/e621 and api/moebooru JSON parse guards narrowed from bare except to ValueError
    • gui/media/video_player.pyimport time hoisted to module top
    • gui/post_actions.is_in_library — dead try/except stripped

    Removed

    • Unused Favorite alias in core/db.py — callers migrated to Bookmark in 0.2.5, nothing referenced the fallback anymore
    Downloads