Files
MusicServer/internal/server/statistics_handler.go
T
2026-06-29 18:39:09 +02:00

276 lines
9.8 KiB
Go

package server
import (
"net/http"
"strconv"
"music-server/internal/backend"
"music-server/internal/logging"
"github.com/labstack/echo/v5"
"go.uber.org/zap"
)
// StatisticsHandler handles statistics-related HTTP requests
type StatisticsHandler struct {
statsBackend *backend.StatisticsHandler
}
// NewStatisticsHandler creates a new StatisticsHandler
func NewStatisticsHandler() *StatisticsHandler {
return &StatisticsHandler{
statsBackend: backend.NewStatisticsHandler(),
}
}
// GetMostPlayedSoundtracks returns top N most played soundtracks with songs
// GET /api/v1/statistics/soundtracks/most-played
//
// @Summary Get most played soundtracks
// @Description Returns the top N most played soundtracks with their songs
// @Tags statistics
// @Accept json
// @Produce json
// @Param limit query int false "Number of results (default: 10)"
// @Success 200 {array} backend.SoundtrackWithSongs
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/soundtracks/most-played [get]
func (h *StatisticsHandler) GetMostPlayedSoundtracks(ctx *echo.Context) error {
limit := 10 // default
limitStr := ctx.QueryParam("limit")
if limitStr != "" {
var err error
limit, err = strconv.Atoi(limitStr)
if err != nil || limit <= 0 {
return ctx.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid limit parameter"})
}
// Cap at 100 for performance
if limit > 100 {
limit = 100
}
}
soundtracks, err := h.statsBackend.GetMostPlayedSoundtracksWithSongs(int32(limit))
if err != nil {
logging.GetLogger().Error("Failed to get most played soundtracks", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, soundtracks)
}
// GetLeastPlayedSoundtracks returns top N least played soundtracks with songs
// GET /api/v1/statistics/soundtracks/least-played
//
// @Summary Get least played soundtracks
// @Description Returns the top N least played soundtracks with their songs
// @Tags statistics
// @Accept json
// @Produce json
// @Param limit query int false "Number of results (default: 10)"
// @Success 200 {array} backend.SoundtrackWithSongs
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/soundtracks/least-played [get]
func (h *StatisticsHandler) GetLeastPlayedSoundtracks(ctx *echo.Context) error {
limit := 10
limitStr := ctx.QueryParam("limit")
if limitStr != "" {
var err error
limit, err = strconv.Atoi(limitStr)
if err != nil || limit <= 0 {
return ctx.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid limit parameter"})
}
if limit > 100 {
limit = 100
}
}
soundtracks, err := h.statsBackend.GetLeastPlayedSoundtracksWithSongs(int32(limit))
if err != nil {
logging.GetLogger().Error("Failed to get least played soundtracks", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, soundtracks)
}
// GetMostPlayedSongs returns top N most played songs with soundtrack info
// GET /api/v1/statistics/songs/most-played
//
// @Summary Get most played songs
// @Description Returns the top N most played songs with their soundtrack info
// @Tags statistics
// @Accept json
// @Produce json
// @Param limit query int false "Number of results (default: 10)"
// @Success 200 {array} backend.SongInfoForStats
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/songs/most-played [get]
func (h *StatisticsHandler) GetMostPlayedSongs(ctx *echo.Context) error {
limit := 10
limitStr := ctx.QueryParam("limit")
if limitStr != "" {
var err error
limit, err = strconv.Atoi(limitStr)
if err != nil || limit <= 0 {
return ctx.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid limit parameter"})
}
if limit > 100 {
limit = 100
}
}
songs, err := h.statsBackend.GetMostPlayedSongsWithSoundtrack(int32(limit))
if err != nil {
logging.GetLogger().Error("Failed to get most played songs", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, songs)
}
// GetLeastPlayedSongs returns top N least played songs with soundtrack info
// GET /api/v1/statistics/songs/least-played
//
// @Summary Get least played songs
// @Description Returns the top N least played songs with their soundtrack info
// @Tags statistics
// @Accept json
// @Produce json
// @Param limit query int false "Number of results (default: 10)"
// @Success 200 {array} backend.SongInfoForStats
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/songs/least-played [get]
func (h *StatisticsHandler) GetLeastPlayedSongs(ctx *echo.Context) error {
limit := 10
limitStr := ctx.QueryParam("limit")
if limitStr != "" {
var err error
limit, err = strconv.Atoi(limitStr)
if err != nil || limit <= 0 {
return ctx.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid limit parameter"})
}
if limit > 100 {
limit = 100
}
}
songs, err := h.statsBackend.GetLeastPlayedSongsWithSoundtrack(int32(limit))
if err != nil {
logging.GetLogger().Error("Failed to get least played songs", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, songs)
}
// GetNeverPlayedSoundtracks returns soundtracks that have never been played
// GET /api/v1/statistics/soundtracks/never-played
//
// @Summary Get never played soundtracks
// @Description Returns all soundtracks that have never been played (times_played = 0)
// @Tags statistics
// @Accept json
// @Produce json
// @Success 200 {array} backend.SoundtrackWithSongs
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/soundtracks/never-played [get]
func (h *StatisticsHandler) GetNeverPlayedSoundtracks(ctx *echo.Context) error {
soundtracks, err := h.statsBackend.GetNeverPlayedSoundtracks()
if err != nil {
logging.GetLogger().Error("Failed to get never played soundtracks", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, soundtracks)
}
// GetLastPlayedSoundtracks returns most recently played soundtracks
// GET /api/v1/statistics/soundtracks/last-played
//
// @Summary Get last played soundtracks
// @Description Returns the most recently played soundtracks
// @Tags statistics
// @Accept json
// @Produce json
// @Param limit query int false "Number of results (default: 10)"
// @Success 200 {array} backend.SoundtrackWithSongs
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/soundtracks/last-played [get]
func (h *StatisticsHandler) GetLastPlayedSoundtracks(ctx *echo.Context) error {
limit := 10
limitStr := ctx.QueryParam("limit")
if limitStr != "" {
var err error
limit, err = strconv.Atoi(limitStr)
if err != nil || limit <= 0 {
return ctx.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid limit parameter"})
}
if limit > 100 {
limit = 100
}
}
soundtracks, err := h.statsBackend.GetLastPlayedSoundtracks(int32(limit))
if err != nil {
logging.GetLogger().Error("Failed to get last played soundtracks", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, soundtracks)
}
// GetOldestPlayedSoundtracks returns least recently played soundtracks
// GET /api/v1/statistics/soundtracks/oldest-played
//
// @Summary Get oldest played soundtracks
// @Description Returns the least recently played soundtracks (that have been played at least once)
// @Tags statistics
// @Accept json
// @Produce json
// @Param limit query int false "Number of results (default: 10)"
// @Success 200 {array} backend.SoundtrackWithSongs
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/soundtracks/oldest-played [get]
func (h *StatisticsHandler) GetOldestPlayedSoundtracks(ctx *echo.Context) error {
limit := 10
limitStr := ctx.QueryParam("limit")
if limitStr != "" {
var err error
limit, err = strconv.Atoi(limitStr)
if err != nil || limit <= 0 {
return ctx.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid limit parameter"})
}
if limit > 100 {
limit = 100
}
}
soundtracks, err := h.statsBackend.GetOldestPlayedSoundtracks(int32(limit))
if err != nil {
logging.GetLogger().Error("Failed to get oldest played soundtracks", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, soundtracks)
}
// GetStatisticsSummary returns overall statistics
// GET /api/v1/statistics/summary
//
// @Summary Get statistics summary
// @Description Returns overall statistics about the music library
// @Tags statistics
// @Accept json
// @Produce json
// @Success 200 {object} backend.StatisticsSummary
// @Failure 500 {object} map[string]string
// @Router /api/v1/statistics/summary [get]
func (h *StatisticsHandler) GetStatisticsSummary(ctx *echo.Context) error {
summary, err := h.statsBackend.GetStatisticsSummary()
if err != nil {
logging.GetLogger().Error("Failed to get statistics summary", zap.String("error", err.Error()))
return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"})
}
return ctx.JSON(http.StatusOK, summary)
}