Commit Graph

14 Commits

Author SHA1 Message Date
bvandeusen b7f8136502 fix(server): wire real Lidarr clientFn for requests + quarantine services
Both lidarrrequests.Approve and lidarrquarantine.DeleteViaLidarr need a
working client factory; the previous nil clientFn made them always return
ErrLidarrDisabled even when /admin/integrations had a valid Lidarr config
saved. Per-call factory re-reads config so admin saves take effect without
restart, matching the Service contract.
2026-04-30 20:23:07 -04:00
bvandeusen 6fedd495be feat(api): /api/quarantine user + admin endpoints + Service wiring
User-facing /api/quarantine handlers (POST flag, DELETE unflag, GET mine)
plus the five /api/admin/quarantine endpoints (queue, resolve, delete-file,
delete-via-lidarr, actions). Mount() and the handlers struct now accept the
lidarrquarantine.Service, constructed in server.go alongside the existing
lidarrrequests wiring.
2026-04-30 20:19:39 -04:00
bvandeusen 03cbd4d0c1 feat(api): add /api/requests user-facing CRUD
Implements POST/GET/GET:id/DELETE /api/requests handlers delegating to
lidarrrequests.Service; wires routes in RequireUser group and threads
the service through Mount and server.go.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 17:40:49 -04:00
bvandeusen 905e27a988 feat(api): add /api/lidarr/search proxy with library/request enrichment
Implements GET /api/lidarr/search?q=&kind=artist|album|track. Validates
kind and q, loads lidarr_config per-request, calls the matching Lidarr
Lookup* method, enriches each result with in_library (EXISTS by MBID
against artists/albums/tracks) and requested (HasNonTerminalRequestForMBID),
and returns a normalized JSON array. Adds lidarrCfg field to handlers struct
and threads lidarrconfig.Service through Mount and server.Router.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 17:35:00 -04:00
bvandeusen 4492826354 feat(auth): add RequireAdmin middleware for /api/admin/* routes
Replaces the old X-API-Token-based RequireAdmin in middleware.go with a
context-aware RequireAdmin() that runs after RequireUser, checks
user.IsAdmin, and returns 403 {"error":"not_authorized"} for non-admins
or 500 {"error":"internal_error"} if RequireUser was bypassed. Updates
server.go to mount RequireUser then RequireAdmin on the /api/admin group.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 17:27:47 -04:00
bvandeusen 08591debee feat(api): rewrite /api/radio with weighted shuffle v1
Validates seed_track + optional limit (default cfg.Recommendation.RadioSize,
clamped to RadioSizeMax). Calls recommendation.LoadCandidates +
recommendation.Shuffle. Prepends seed to result. Server seeds a
math/rand source at startup; handlers package threads that as a
func() float64 so tests inject deterministic RNGs.

Mount + server.New gain a RecommendationConfig parameter.
2026-04-27 08:08:10 -04:00
bvandeusen 599a19f780 feat(subsonic): wire /rest/scrobble into playevents.Writer
submission=false → play_started (replaces in-memory nowPlayingMap).
submission=true (default) → synthetic completed play. The nowPlayingMap
struct + factory + the nowPlaying field on mediaHandlers are deleted;
play_events WHERE ended_at IS NULL is now the source of truth for
'currently playing,' reachable from M3+ work.

api.Mount now takes the shared *playevents.Writer instead of cfg so
the same writer instance feeds both surfaces.
2026-04-26 00:23:20 -04:00
bvandeusen f4e73b81b4 feat(api): add POST /api/events handler
Discriminated-union JSON over three event types: play_started,
play_ended, play_skipped. Auth via existing RequireUser. play_started
returns play_event_id + session_id; the other two return { ok: true }.
Validates ownership: play_ended/play_skipped on another user's row
returns 403. Mount signature now takes EventsConfig and constructs
the playevents.Writer; server.New propagates it through.
2026-04-26 00:12:06 -04:00
bvandeusen 75ce65c80e feat(server): serve embedded SPA at root with /api,/rest carve-out
- NotFound wrapper routes unknown /api/* and /rest/* to a JSON 404
- Everything else falls through to the embedded web handler, which
  resolves static assets or returns index.html for SPA deep links
2026-04-22 10:31:30 -04:00
bvandeusen 06a1fe16e0 feat(server): mount /api/* (login, logout, me)
Wires the native JSON surface alongside the existing /api/admin
and /rest/* routes. Subsonic compatibility remains untouched.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 22:19:59 -04:00
bvandeusen 5288e9d5df feat(server): wire subsonic.Mount under /rest 2026-04-19 17:40:05 +00:00
bvandeusen 8e91235b88 M1/#293: add /api/admin/scan route gated on X-API-Token 2026-04-19 15:16:15 +00:00
bvandeusen 4c5b4d1790 fix(server): rename unused request param to _ for revive/unused-parameter 2026-04-18 21:47:52 +00:00
bvandeusen 16f2fc2ce4 feat(skel): chi router with RequestID/Recoverer middleware and /healthz 2026-04-18 21:20:17 +00:00