package server import ( "music-server/internal/backend" "music-server/internal/logging" "net/http" "os" "strconv" "github.com/labstack/echo/v5" "go.uber.org/zap" ) type MusicHandler struct { } func NewMusicHandler() *MusicHandler { return &MusicHandler{} } // GetSong godoc // @Summary Get a specific song // @Description Returns a specific song by name // @Tags music // @Accept json // @Produce audio/mpeg // @Param song query string true "Song name" // @Success 200 {file} file // @Failure 400 {string} string "song can't be empty" // @Failure 404 {string} string "Not Found" // @Failure 423 {string} string "Syncing is in progress" // @Router /music [get] func (m *MusicHandler) GetSong(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } song := ctx.QueryParam("song") if song == "" { return ctx.String(http.StatusBadRequest, "song can't be empty") } songPath := backend.GetSong(song) file, err := os.Open(songPath) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() return ctx.Stream(http.StatusOK, "audio/mpeg", file) } // GetSoundCheckSong godoc // @Summary Get sound check song // @Description Returns the sound check song // @Tags music // @Produce audio/mpeg // @Success 200 {file} file // @Failure 404 {string} string "Not Found" // @Failure 423 {string} string "Syncing is in progress" // @Router /music/soundTest [get] func (m *MusicHandler) GetSoundCheckSong(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } songPath := backend.GetSoundCheckSong() file, err := os.Open(songPath) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() return ctx.Stream(http.StatusOK, "audio/mpeg", file) } // ResetMusic godoc // @Summary Reset music state // @Description Resets the music state // @Tags music // @Accept json // @Success 204 // @Failure 423 {string} string "Syncing is in progress" // @Router /music/reset [get] func (m *MusicHandler) ResetMusic(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } backend.Reset() return ctx.NoContent(http.StatusOK) } // GetRandomSong godoc // @Summary Get random song // @Description Returns a random song // @Tags music // @Produce audio/mpeg // @Success 200 {file} file // @Failure 404 {string} string "Not Found" // @Failure 423 {string} string "Syncing is in progress" // @Router /music/rand [get] func (m *MusicHandler) GetRandomSong(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } songPath := backend.GetRandomSong() file, err := os.Open(songPath) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() return ctx.Stream(http.StatusOK, "audio/mpeg", file) } // GetRandomSongLowChance godoc // @Summary Get random song with low chance // @Description Returns a random song with low chance selection // @Tags music // @Produce audio/mpeg // @Success 200 {file} file // @Failure 404 {string} string "Not Found" // @Failure 423 {string} string "Syncing is in progress" // @Router /music/rand/low [get] func (m *MusicHandler) GetRandomSongLowChance(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } songPath := backend.GetRandomSongLowChance() file, err := os.Open(songPath) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() return ctx.Stream(http.StatusOK, "audio/mpeg", file) } // GetRandomSongClassic godoc // @Summary Get random classic song // @Description Returns a random song from the classic selection // @Tags music // @Produce audio/mpeg // @Success 200 {file} file // @Failure 404 {string} string "Not Found" // @Failure 423 {string} string "Syncing is in progress" // @Router /music/rand/classic [get] func (m *MusicHandler) GetRandomSongClassic(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } songPath := backend.GetRandomSongClassic() file, err := os.Open(songPath) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() return ctx.Stream(http.StatusOK, "audio/mpeg", file) } // GetSongInfo godoc // @Summary Get current song info // @Description Returns information about the current song // @Tags music // @Accept json // @Produce json // @Success 200 {object} map[string]interface{} // @Router /music/info [get] func (m *MusicHandler) GetSongInfo(ctx *echo.Context) error { song := backend.GetSongInfo() return ctx.JSON(http.StatusOK, song) } // GetPlayedSongs godoc // @Summary Get played songs list // @Description Returns a list of played songs // @Tags music // @Accept json // @Produce json // @Success 200 {array} map[string]interface{} // @Router /music/list [get] func (m *MusicHandler) GetPlayedSongs(ctx *echo.Context) error { songList := backend.GetPlayedSongs() return ctx.JSON(http.StatusOK, songList) } // GetNextSong godoc // @Summary Get next song // @Description Returns the next song in the queue // @Tags music // @Produce audio/mpeg // @Success 200 {file} file // @Failure 404 {string} string "Not Found" // @Failure 423 {string} string "Syncing is in progress" // @Router /music/next [get] func (m *MusicHandler) GetNextSong(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } songPath := backend.GetNextSong() file, err := os.Open(songPath) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() return ctx.Stream(http.StatusOK, "audio/mpeg", file) } // GetPreviousSong godoc // @Summary Get previous song // @Description Returns the previous song in the queue // @Tags music // @Produce audio/mpeg // @Success 200 {file} file // @Failure 404 {string} string "Not Found" // @Failure 423 {string} string "Syncing is in progress" // @Router /music/previous [get] func (m *MusicHandler) GetPreviousSong(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } songPath := backend.GetPreviousSong() file, err := os.Open(songPath) if err != nil { return echo.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() return ctx.Stream(http.StatusOK, "audio/mpeg", file) } // GetAllSoundtracks godoc // @Summary Get all soundtracks // @Description Returns a list of all games in order // @Tags music // @Accept json // @Produce json // @Success 200 {array} map[string]interface{} // @Failure 423 {string} string "Syncing is in progress" // @Router /music/all/order [get] func (m *MusicHandler) GetAllSoundtracks(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } soundtrackList := backend.GetAllSoundtracks() return ctx.JSON(http.StatusOK, soundtrackList) } // GetAllSoundtracksRandom godoc // @Summary Get all soundtracks random // @Description Returns a list of all games in random order // @Tags music // @Accept json // @Produce json // @Success 200 {array} map[string]interface{} // @Failure 423 {string} string "Syncing is in progress" // @Router /music/all/random [get] func (m *MusicHandler) GetAllSoundtracksRandom(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } soundtrackList := backend.GetAllSoundtracksRandom() return ctx.JSON(http.StatusOK, soundtrackList) } // PutPlayed godoc // @Summary Mark song as played // @Description Marks a song as played by its ID // @Tags music // @Accept json // @Produce json // @Param song query int true "Song ID" // @Success 204 // @Failure 400 {string} string "Bad Request" // @Failure 423 {string} string "Syncing is in progress" // @Router /music/played [put] func (m *MusicHandler) PutPlayed(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } song, err := strconv.Atoi(ctx.QueryParam("song")) if err != nil { return ctx.JSON(http.StatusBadRequest, err.Error()) } logging.GetLogger().Info("Marking song as played", zap.Int("song_id", song)) backend.SetPlayed(song) return ctx.NoContent(http.StatusOK) } // AddLatestToQue godoc // @Summary Add latest to queue // @Description Adds the latest song to the queue // @Tags music // @Accept json // @Success 204 // @Failure 423 {string} string "Syncing is in progress" // @Router /music/addQue [get] func (m *MusicHandler) AddLatestToQue(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } backend.AddLatestToQue() return ctx.NoContent(http.StatusOK) } // AddLatestPlayed godoc // @Summary Add latest to played // @Description Adds the latest song to the played list // @Tags music // @Accept json // @Success 204 // @Failure 423 {string} string "Syncing is in progress" // @Router /music/addPlayed [get] func (m *MusicHandler) AddLatestPlayed(ctx *echo.Context) error { if backend.Syncing { logging.GetLogger().Info("Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress") } backend.AddLatestPlayed() return ctx.NoContent(http.StatusOK) }