• v0.2.1 7d02aa8588

    v0.2.1 Stable

    pax released this 2026-04-07 20:46:52 +00:00 | 357 commits to main since this release

    0.2.1

    A theme + persistence + ricer-friendliness release. The whole stylesheet system was rebuilt around a runtime preprocessor with @palette / ${name} vars, every bundled theme was rewritten end-to-end, and 12 theme variants ship instead of 6. Lots of UI state now survives a restart, and Hyprland ricers get an explicit opt-out for the in-code window management.

    This release does not ship a fresh Windows installer — the previous v0.2.0 installer remains the latest installable binary. Run from source to get 0.2.1, or wait for the next release.

    Changes since v0.2.0

    Theming System

    • @palette / ${name} preprocessor — themes start with a /* @palette */ header block listing color slots, the body uses ${name} placeholders that the app substitutes at load time. Edit the 17-slot palette block at the top of any theme to recolor the entire app — no hunting through hex literals.
    • All 6 bundled themes rewritten with comprehensive Fusion-style QSS covering every widget the app uses, every state (hover, focus, disabled, checked), every control variant
    • Two corner-radius variants per theme*-rounded.qss (4px radius, default Fusion-style look) and *-square.qss (every border-radius stripped except radio buttons, which stay circular)
    • Native Fusion sizing — themed widgets shrunk to match Qt+Fusion defaults, toolbar row height is now ~23px instead of 30px, matching what no-custom.qss renders
    • Bundled themes — catppuccin-mocha, nord, gruvbox, solarized-dark, tokyo-night, everforest. 12 files total (6 themes × 2 variants)

    QSS-Targetable Surfaces

    Many things hardcoded in Python paint code can now be overridden from a custom.qss without touching the source:

    • InfoPanel tag category colorsqproperty-tagArtistColor, tagCharacterColor, tagCopyrightColor, tagSpeciesColor, tagMetaColor, tagLoreColor
    • ThumbnailWidget selection paintqproperty-selectionColor, multiSelectColor, hoverColor, idleColor (in addition to existing savedColor and bookmarkedColor)
    • VideoPlayer letterbox colorqproperty-letterboxColor. mpv paints the area around the video frame in this color instead of hardcoded black. Defaults to QPalette.Window so KDE color schemes, qt6ct, Windows dark/light mode, and any system Qt theme automatically produce a matching letterbox
    • Popout overlay bars — translucent background for the floating top toolbar and bottom controls bar via the overlay_bg palette slot
    • Library count label statesQLabel[libraryCountState="..."] attribute selector distinguishes "N files" / "no items match" / "directory unreachable" with QSS-controlled colors instead of inline red

    Hyprland Integration

    • Two opt-out env vars for users with their own windowrules:
      • BOORU_VIEWER_NO_HYPR_RULES=1 — disables every in-code hyprctl dispatch except the popout's keep_aspect_ratio lock
      • BOORU_VIEWER_NO_POPOUT_ASPECT_LOCK=1 — independently disables the popout's aspect ratio enforcement
    • Popout overlays themed — top toolbar and bottom controls bar now look themed instead of hardcoded translucent black, respect the @palette overlay_bg slot
    • Popout video letterbox tracks the theme's bg color via the new qproperty-letterboxColor
    • Wayland app_id set via setDesktopFileName("booru-viewer") so compositors can target windows by class — windowrule = float, class:^(booru-viewer)$ — instead of by the volatile window title

    State Persistence

    • Main window — geometry, floating mode, tiled mode (Hyprland)
    • Splitter sizes — main splitter (grid vs preview), right splitter (preview vs dl_progress vs info panel)
    • Info panel visibility
    • Cache spinbox auto-derived dialog min height (no more clipping when dragging the settings dialog small)
    • Popout window position, dimensions, and F11 fullscreen state restored via Hyprland floating cache prime

    UX

    • Live debounced search in bookmarks and library tabs — type to filter, press Enter to commit immediately. 150ms debounce on bookmarks (cheap SQLite), 250ms on library (filesystem scan)
    • Search button removed from bookmarks toolbar (live search + Enter)
    • Score field +/- buttons removed from main search bar — type the value directly
    • Embedded preview video controls moved out of the overlay style and into the panel layout, sitting under the media instead of floating on top of it. Popout still uses the floating overlay
    • Next-mode loop wraps to the start of the bookmarks/library list at the end of the last item instead of stopping
    • Splitter handle margins — 4px breathing margin on either side so toolbar buttons don't sit flush against the splitter line

    Performance

    • Page-load thumbnails pre-fetch bookmarks + cache state into set lookups instead of N synchronous SQLite queries per page
    • Animated PNG/WebP conversion off-loaded to a worker thread via asyncio.to_thread so it doesn't block the asyncio event loop during downloads

    Fixes

    • Open in Browser/Default App on the bookmarks tab now opens the bookmark's actual source post (was opening unrelated cached files)
    • Cache settings spinboxes can no longer be vertically clipped at the dialog's minimum size; spinboxes use Python-side setMinimumHeight() to propagate floors up the layout chain
    • Settings dialog uses side-by-side +/- buttons instead of QSpinBox's default vertical arrows for clearer interaction
    • Bookmarks tab BL Tag refreshes correctly when navigating bookmarked posts (was caching stale tags from the first selection)
    • Popout F11 → windowed restores its previous windowed position and dimensions
    • Popout flicker on F11 transitions eliminated via no_anim setprop + deferred fit + dedupe of mpv video-params events
    • Bookmark + saved indicator dots in the thumbnail grid: bookmark star on left, saved dot on right, both vertically aligned in a fixed-size box
    • Selection border on thumbnail cells redrawn pen-aware: square geometry (no rounded corner artifacts), even line width on all sides, no off-by-one anti-aliasing seams
    • Toolbar buttons in narrow slots no longer clip text (Bookmark/Unbookmark, Save/Unsave, BL Tag, BL Post, Popout, + Folder, Refresh) — all bumped to fit "Unbookmark" comfortably under the bundled themes' button padding
    • Toolbar rows on bookmarks/library/preview panels now sit at a uniform 23px height matching the inputs/combos in the same row
    • Score and Page spinbox heights forced to 23px via setFixedHeight to work around QSpinBox reserving vertical space for arrow buttons even when setButtonSymbols(NoButtons) is set
    • Library Open in Default App uses the actual file path instead of routing through cached_path_for (which would return a hash path that doesn't exist for library files)

    Cleanup

    • Deleted unused booru_viewer/gui/theme.py (222 lines of legacy stylesheet template that was never imported)
    • Deleted GREEN/DARK_GREEN/DIM_GREEN/BG/BG_LIGHT etc constants from booru_viewer/core/config.py (only theme.py used them)
    • Removed dead missing-indicator code (set_missing, _missing_color, missingColor Qt Property, the unreachable if not filepath.exists() branch in library.refresh)
    • Removed dead score +/- buttons code path

    28 files changed, ~8400 insertions / ~1200 deletions across 13 commits.

    Downloads