4.6 KiB
4.6 KiB
Quality gates — audiobookshelf provider
Criteria an implementation of absdy (architecture/audiobookshelf-provider.md)
must satisfy. Each is pass/fail by reading/reasoning; automated coverage lives
in absdy/src/tests.rs (unit, no network) and absdy/tests/live.rs (ignored,
real server).
Secrets (hard rule — highest priority)
- G1 —
api_keynever inDebug.SettingsandClientDebugoutput redact the key. (test:settings_debug_redacts_the_api_key.) - G2 — The token never reaches a log or error. The
?token=stream URL is built only inAbs::stream_urland returned; it is never passed todebug!/warn!/error!, and never to areqwestcall insideabsdy(so it cannot appear in areqwesterror). Browse URLs (logged atdebug) carry auth in the bearer header, not the URL. - G3 —
AbsApi::Debugredacts the token (manual impl, not derived).
Errors and robustness (hard rule: no panics on input/network)
- G4 — No panics on bad input or network failures. All backend
failures map to a typed
ProviderError(FetchErrorfor fetches,MalformedPathfor bad paths,InvalidInputfor empty titles,Configfor missing creds). Nounwrap/expect/panic!on request, path, or response data. (tests:backend_failures_are_typed_never_panics,foreign_and_malformed_paths_are_rejected,track_metadata_picks_the_file_by_ino.) - G5 — Defensive decoding. Wire DTOs use
#[serde(default)]; missing fields degrade (empty string /None/ dropped entry), never error the whole call. Items/files without an id/ino are dropped, not panicked on. - G6 — Timeouts on every external call.
AbsApisets a per-callreqwesttimeout fromcall_timeout_secs(default 30).
Tree and path contract
- G7 — Path parsing is total and reserved-word safe. Every
/abs/...shape maps to a variant orMalformedPath; the literalsearchsegment routes to the search branch and never collides with a (UUID) item id. Empty segments (/abs//x) areMalformedPath. - G8 — Root lists only book libraries. Podcast libraries are filtered
(D6). (test:
root_lists_only_book_libraries.) - G9 — Queueability reflects audio. A book child is queueable iff
num_audio_files > 0; an ebook is shown but not queueable/downloadable; an audio-less book node is empty and non-queueable. (tests:a_library_lists_search_then_books_with_audio_gating_queueability,an_audio_less_book_is_empty_and_not_queueable.) - G10 — Download blessing matches the other providers. A node is
downloadable iff it is queueable or holds tracks; a child is downloadable iff
it is queueable. The
searchchild is neither. - G11 — Search terms mirror tidal/youtube/fyyd and are per-library.
searchis creatable; terms are editable + deletable, deduped, recreated implicitly on stale paths, isolated per library id, and rename/delete are idempotent. (tests:search_terms_list_books_and_are_per_library,search_terms_rename_and_delete.)
Playback
- G12 — Stream URL is derivable with no API call.
get_urls_for_trackbuilds the URL from the path (item id + ino) plus the token, making no network request; the direct and search branches yield the same URL. (test:track_stream_url_embeds_the_token_and_path_ids_without_a_call.) - G13 — Track metadata.
artist= author,album= book title,title= file title,duration= seconds (Nonewhen absent),provider_item_id="<item>:<ino>". (test:a_book_lists_its_files_as_tracks.)
Wiring and lifecycle
- G14 — Non-fatal init. Missing/incomplete
abs.toml(nobase_url/api_key) disables/abswith a warning; it never aborts startup. (test:init_requires_base_url_and_api_key; orchestrator build block mirrors fyyd.) - G15 — Orchestrator parity.
absis wired at every dispatch point (is_track_path,get_urls_for_track,get_metadata_for_track,get_lib_node,create/rename/delete,resolve_tracks_into, root child) and in settings (ALL_PROVIDERS,ProviderToggles,all,provider_toggles). - G16 — Bounded listings.
items_per_libraryandsearch_resultscap every listing; truncation to the cap islog-ged, not silent.
Live validation (drift gate)
- G17 — DTOs decode the real server.
absdy/tests/live.rs(#[ignore]) exercises libraries → items → search → detail against a real server and confirms the shapes. Verified during implementation against the provided test server.