Rewrites the internal/api comment blocks to rule 32: task, milestone and rule ids gone, the stories behind them restated as the constraint they left, stale references corrected (the stream secret is wired from config, the timezone handler already refreshes the scheduler, the Android app is the native client, the design docs cited are not in the repo). Also rewraps comment lines over 80 columns left by the earlier batches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
55 lines
2.0 KiB
Go
55 lines
2.0 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/apierror"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/library"
|
|
)
|
|
|
|
// maxReplayGainIDs caps one lookup. A player asks for the tracks around the
|
|
// one it is about to play, never a whole library.
|
|
const maxReplayGainIDs = 200
|
|
|
|
// replayGainResp is the wire shape for GET /api/tracks/replay-gain. Tracks
|
|
// with no gain known are absent from items: no adjustment.
|
|
type replayGainResp struct {
|
|
Items map[string]library.ReplayGain `json:"items"`
|
|
}
|
|
|
|
// handleGetReplayGain implements GET /api/tracks/replay-gain?ids=a,b,c:
|
|
// ReplayGain 2.0 values (dB to -18 LUFS, linear peaks) for each track,
|
|
// and for its album when the whole album is measured.
|
|
//
|
|
// A lookup rather than fields on TrackRef. Tracks reach the player through
|
|
// about fifteen surfaces in two wire shapes (TrackRef and playlist entries),
|
|
// and only the player uses the gain. One call from the player, made for the
|
|
// tracks it is about to play, cannot be forgotten by a surface added later,
|
|
// and costs nothing on the pages that never play anything. Android takes the
|
|
// same values from the sync feed instead, so they are there offline.
|
|
func (h *handlers) handleGetReplayGain(w http.ResponseWriter, r *http.Request) {
|
|
raw := strings.TrimSpace(r.URL.Query().Get("ids"))
|
|
if raw == "" {
|
|
writeJSON(w, http.StatusOK, replayGainResp{Items: map[string]library.ReplayGain{}})
|
|
return
|
|
}
|
|
parts := strings.Split(raw, ",")
|
|
if len(parts) > maxReplayGainIDs {
|
|
writeErr(w, apierror.BadRequest("too_many_ids", "at most 200 ids per request"))
|
|
return
|
|
}
|
|
ids := stringsToUUIDs(parts)
|
|
gains, err := library.ReplayGainForTracks(r.Context(), dbq.New(h.pool), ids)
|
|
if err != nil {
|
|
writeErrWithLog(w, h.logger, "replay gain: lookup", apierror.InternalMsg("lookup failed", err))
|
|
return
|
|
}
|
|
items := make(map[string]library.ReplayGain, len(gains))
|
|
for id, g := range gains {
|
|
items[uuidToString(id)] = g
|
|
}
|
|
writeJSON(w, http.StatusOK, replayGainResp{Items: items})
|
|
}
|