New `absdy` crate mounted at `/abs`: browse, search, and play audiobooks
from a self-hosted audiobookshelf server. Shaped on the fyyd provider --
an `Abs` reqwest seam faked in tests (14 unit tests, no network), an
in-memory per-library search-term store, and a `library -> book -> tracks`
tree with a per-library `search` subtree.
audiobookshelf-specific decisions:
- Credentials + a secret. A missing/incomplete abs.toml (no base_url or
api_key) disables `/abs` non-fatally. The api_key and the `?token=`
stream URL are secrets: Settings and AbsApi have manual redacting Debug,
and the token is built only in `Abs::stream_url` -- never logged, never
handed to a reqwest call in absdy (browse auth is a bearer header).
- Playback needs no API call: a track's stream URL is fully derivable from
its path (item id + ino) plus the token. Verified live that `?token=`
auth returns 200 and the file endpoint honors HTTP range (206), so the
windowed-HTTP player streams it directly.
- Per-library search (ABS search is per-library); the reserved `search`
segment splits the search branch from item ids. A book's queueability
comes from the summary's numAudioFiles, so ebook-only items show but are
not queueable. Root lists only book libraries.
Wired through the orchestrator and settings exactly like the other
providers (dispatch arms, root child, ALL_PROVIDERS, ProviderToggles).
An `#[ignore]`d live test (absdy/tests/live.rs) validates the DTOs against
a real server end-to-end. Docs: architecture/, quality/, plan/, READMEs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>