The queue lived in memory and was shared by all clients, so a restart or a finished sync cleared it. Every client now has its own queue in the new queue and queue_song tables (added to the undeployed migration 000006). The music endpoints return the queue ID in the X-Queue-Id header and expect it back. A request without an ID, or with an ended one, starts a new queue. /music/reset ends the queue and returns a new ID, and a sync ends all running queues. Ended queues are kept as history. The deprecated legacy routes without the /api/v1 prefix are removed.
77 lines
3.3 KiB
Go
77 lines
3.3 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"music-server/internal/backend"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
)
|
|
|
|
const maxStatsLimit = 100
|
|
|
|
type limitInput struct {
|
|
Limit int `query:"limit" default:"10" minimum:"1" doc:"Number of results. Values above 100 are capped to 100."`
|
|
}
|
|
|
|
func (in *limitInput) capped() int32 {
|
|
return int32(min(in.Limit, maxStatsLimit))
|
|
}
|
|
|
|
func (s *Server) registerStatistics(a huma.API) {
|
|
st := s.stats
|
|
op := func(id, path, summary, description string) route {
|
|
return route{op: huma.Operation{
|
|
OperationID: id,
|
|
Method: http.MethodGet,
|
|
Path: "/statistics" + path,
|
|
Summary: summary,
|
|
Description: description,
|
|
Tags: []string{"statistics"},
|
|
}}
|
|
}
|
|
soundtracks := func(id, path, summary, description string,
|
|
query func(context.Context, int32) ([]backend.SoundtrackWithSongs, error)) {
|
|
register(s, a, op(id, path, summary, description),
|
|
func(ctx context.Context, in *limitInput) (*jsonBody[[]backend.SoundtrackWithSongs], error) {
|
|
return ok(query(ctx, in.capped()))
|
|
})
|
|
}
|
|
songs := func(id, path, summary, description string,
|
|
query func(context.Context, int32) ([]backend.SongInfoForStats, error)) {
|
|
register(s, a, op(id, path, summary, description),
|
|
func(ctx context.Context, in *limitInput) (*jsonBody[[]backend.SongInfoForStats], error) {
|
|
return ok(query(ctx, in.capped()))
|
|
})
|
|
}
|
|
|
|
soundtracks("get-most-played-soundtracks", "/soundtracks/most-played", "Most played soundtracks",
|
|
"Returns the most played soundtracks with their songs.", st.MostPlayedSoundtracks)
|
|
soundtracks("get-least-played-soundtracks", "/soundtracks/least-played", "Least played soundtracks",
|
|
"Returns the least played soundtracks with their songs.", st.LeastPlayedSoundtracks)
|
|
soundtracks("get-last-played-soundtracks", "/soundtracks/last-played", "Recently played soundtracks",
|
|
"Returns the most recently played soundtracks with their songs.", st.LastPlayedSoundtracks)
|
|
soundtracks("get-oldest-played-soundtracks", "/soundtracks/oldest-played", "Least recently played soundtracks",
|
|
"Returns the soundtracks played longest ago (played at least once) with their songs.", st.OldestPlayedSoundtracks)
|
|
songs("get-most-played-songs", "/songs/most-played", "Most played songs",
|
|
"Returns the most played songs with their soundtrack.", st.MostPlayedSongs)
|
|
songs("get-least-played-songs", "/songs/least-played", "Least played songs",
|
|
"Returns the least played songs with their soundtrack.", st.LeastPlayedSongs)
|
|
|
|
register(s, a, op("get-all-soundtrack-statistics", "/soundtracks", "All soundtracks with statistics",
|
|
"Returns every soundtrack with its songs and play counts, sorted by name."),
|
|
func(ctx context.Context, _ *struct{}) (*jsonBody[[]backend.SoundtrackWithSongs], error) {
|
|
return ok(st.AllSoundtracks(ctx))
|
|
})
|
|
register(s, a, op("get-never-played-soundtracks", "/soundtracks/never-played", "Never played soundtracks",
|
|
"Returns all soundtracks that have never been played, with their songs."),
|
|
func(ctx context.Context, _ *struct{}) (*jsonBody[[]backend.SoundtrackWithSongs], error) {
|
|
return ok(st.NeverPlayedSoundtracks(ctx))
|
|
})
|
|
register(s, a, op("get-statistics-summary", "/summary", "Statistics summary", "Returns overall play statistics."),
|
|
func(ctx context.Context, _ *struct{}) (*jsonBody[backend.StatisticsSummary], error) {
|
|
return ok(st.Summary(ctx))
|
|
})
|
|
}
|