Adds CoverageRollup type, getCoverageRollup() against
/api/admin/library/coverage, and createCoverageQuery() with the same
3s/30s pacing used by scan-status. New qk.coverage() key follows the
existing zero-arg tuple pattern. Vitest covers the GET path and the
empty-library zero-state plus the with_art + pending + settled = total
invariant.
Adds getScanStatus/triggerScan helpers, createScanStatusQuery factory
(3s poll), qk.scanStatus(), and a Library Scan section on the admin
overview page with per-stage tallies and inline Run scan button.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire shapes mirror the server's snake_case envelope. URL helpers use
the existing apiFetch + ApiError surface so error codes (not_found,
not_authorized, bad_request, server_error) propagate via the same
copyForCode chain as everything else.
Persists the operator's metadata-profile choice alongside quality
profile + root folder. Defaults to the first profile Lidarr returns
(usually 'Standard' on a vanilla install) so the common case is
zero-click; operators with custom profiles like 'Singles only' can pick
explicitly.
Backend:
- Migration 0013: adds nullable default_metadata_profile_id to
lidarr_config. Existing rows get NULL and the service falls back to
fetch-and-pick-first until they save.
- Updated lidarr_config queries + sqlc + lidarrconfig.Config + admin
view/put body to round-trip the new field.
- handlePutLidarrConfig requires it (along with QP and root folder)
when enabled=true — matches the existing missing_defaults gate.
- New GET /api/admin/lidarr/metadata-profiles handler + lidarr.Client
ListMetadataProfiles (GET /api/v1/metadataprofile, same shape as
the quality-profile endpoint).
- lidarrrequests.Approve prefers cfg.DefaultMetadataProfileID; falls
back to the fetch-list path only when 0 (back-compat for upgraders).
Frontend:
- LidarrConfig type + LidarrMetadataProfile type + qk.lidarrMetadataProfiles.
- listMetadataProfiles + createMetadataProfilesQuery client helpers.
- Integrations page: third <select> picker, auto-defaults to first
profile when the saved value is 0, sends the new field on save and
clears it on disconnect.
- Updated test fixtures + the duplicate 'Standard' option string in
the dropdown-populates assertion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds sort_name/cover_url to ArtistRef, sort_title to AlbumRef (matching
backend Task 5 wire shape), HomePayload type, and qk.home/albumsAlpha/
artistTracks query keys. Updates existing test fixtures to satisfy the
new required fields.
Verified clean via 'npm run check' (0 errors, only pre-existing warnings).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- qk.adminRequests defaults to status='all' when no filter is set; the unfiltered
endpoint returns every status, so caching it as 'pending' was a latent mismatch.
- 60s staleTime on lidarrConfig + myRequests — both are session-stable enough
that refetching on every consumer-page mount produced needless flicker.
T13 of the M5a Lidarr plan. Three new client modules wrap api.get/post/put/del
helpers and the existing TanStack Query qk namespace:
lidarr.ts - searchLidarr() + createLidarrSearchQuery()
requests.ts - createRequest, listMyRequests, getRequest, cancelRequest;
createMyRequestsQuery(); cancel goes through apiFetch
directly because the backend returns the cancelled row body
(api.del's return type is fixed to null).
admin.ts - getLidarrConfig, putLidarrConfig, testLidarrConnection,
listQualityProfiles, listRootFolders, listAdminRequests,
approveRequest, rejectRequest; query factories for each
read; quality profiles + root folders take an enabled prop
so the call site decides when Lidarr is configured.
Shared LidarrRequestStatus / LidarrRequestKind enums and request/config/
search-result shapes added to types.ts. Per-module helpers (CreateRequestParams)
stay in their module files. testLidarrConnection returns a discriminated union
({ok:true,version} | {ok:false,error}) and never throws on ok:false so the
SPA can render either branch.
qk extended with lidarrSearch, myRequests, lidarrConfig,
lidarrQualityProfiles, lidarrRootFolders, adminRequests.
Tests mirror likes.test.ts (vi.mock('./client')) and cover URL construction,
query-param encoding, body shapes, the not-ok testLidarrConnection branch,
and qk additions. 32 new tests, 217 total passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
createLikedIdsQuery is the single source for heart-button state across
the app (track_ids/album_ids/artist_ids Sets). likeEntity / unlikeEntity
do optimistic setQueryData updates with rollback on error. Per-entity
infinite queries back the /library/liked sections.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
createSearchQuery hits /api/search with limit=10 (the main /search
page summary). createSearchArtistsInfiniteQuery /
createSearchAlbumsInfiniteQuery / createSearchTracksInfiniteQuery each
hit /api/search with limit=50 and project to their own facet, used by
the per-facet overflow pages. All four are gated by q.length > 0 so
empty queries don't fire.
qk.{artists,artist,album} key generators and create*Query wrappers
with shared page size, sort-aware keys, and infinite-query plumbing
for /api/artists.