Files
silo-server/internal/audiobooks/abs/me_handler.go
T
RXWatcherandClaude Opus 4.7 dd876338e3 refactor(abs): plugin-parity /me and library wire shapes
/me returns the minimal {id, username, defaultLibraryId} envelope
emitted by continuum-plugin-audiobooks. ABS clients already have the
rich user object from /login and /authorize; /me is a session-resume
probe in real-ABS, and the previous rich envelope (mediaProgress,
librariesAccessible, permissions) could confuse clients that pattern-
match on the minimal shape.

Library map also trims folders / displayOrder / icon / settings /
createdAt / lastUpdate down to {id, name, mediaType} — real ABS
clients ignore the extra fields and emitting them risks behavior
drift from the plugin reference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 16:16:32 +02:00

63 lines
1.9 KiB
Go

package abs
import (
"net/http"
"strconv"
"strings"
)
// handleMe — GET /abs/api/me (and /api/me)
//
// Minimal {id, username, defaultLibraryId} envelope — matches the
// continuum-plugin-audiobooks shape exactly. ABS clients already
// have the full user object from /login and /authorize; /me is just
// a session-resume probe in real-ABS, so returning the rich user
// envelope here is unnecessary and can confuse clients that pattern-
// match on the minimal shape.
func (h *Handler) handleMe(w http.ResponseWriter, r *http.Request) {
a, ok := absAuthFrom(r)
if !ok || a.UserID == "" {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
defaultLibID := VirtualLibraryID
libs, err := h.deps.MediaStore.ListAudiobookLibraries(r.Context())
if err == nil && len(libs) > 0 {
defaultLibID = audiobookLibraryID(libs[0])
}
writeJSON(w, http.StatusOK, map[string]any{
"id": a.UserID,
"username": a.UserID,
"defaultLibraryId": defaultLibID,
})
}
// audiobookLibraryID returns the ABS-wire library ID string for an
// AudiobookLibrary. Numeric IDs are formatted as decimal strings; when
// the ID is 0 we fall back to the virtual constant.
func audiobookLibraryID(lib AudiobookLibrary) string {
if lib.ID > 0 {
return strconv.FormatInt(lib.ID, 10)
}
return VirtualLibraryID
}
// audiobookLibraryMap builds the minimal ABS library object shared by
// /libraries (list) and /libraries/{id} (detail). Plugin parity:
// {id, name, mediaType} only — the extra folders/displayOrder/icon
// fields some servers emit are ignored by real ABS clients and adding
// them risks behaviour drift.
func audiobookLibraryMap(lib AudiobookLibrary) map[string]any {
name := strings.TrimSpace(lib.Name)
if name == "" {
name = VirtualLibraryName
}
return map[string]any{
"id": audiobookLibraryID(lib),
"name": name,
"mediaType": LibraryMediaType,
}
}