feat: add album management endpoints (sections 2.1, 2.2, 2.3)

This commit is contained in:
Alexander
2026-04-29 13:34:20 +02:00
parent ff49403fd5
commit c307c68d88
6 changed files with 1275 additions and 0 deletions
+206
View File
@@ -9,6 +9,7 @@ import (
"github.com/fujin/music-agregator/internal/metadata"
"github.com/fujin/music-agregator/internal/services"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
)
type Handlers struct {
@@ -371,6 +372,211 @@ func (h *Handlers) EditArtist(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, artist)
}
func (h *Handlers) GetAlbum(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
albumIDStr := chi.URLParam(r, "id")
albumID, err := parseUUID(albumIDStr)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid album ID")
return
}
album, err := h.DB.GetAlbumDetailByID(r.Context(), albumID)
if err != nil {
writeError(w, http.StatusNotFound, "album not found")
return
}
writeJSON(w, http.StatusOK, album)
}
func (h *Handlers) EditAlbum(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
albumIDStr := chi.URLParam(r, "id")
albumID, err := parseUUID(albumIDStr)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid album ID")
return
}
var update struct {
Monitored *bool `json:"monitored"`
}
if err := json.NewDecoder(r.Body).Decode(&update); err != nil {
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
if update.Monitored != nil {
if err := h.DB.UpdateAlbumMonitored(r.Context(), albumID, *update.Monitored); err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
if *update.Monitored {
hasFiles, _ := h.DB.HasTrackFiles(r.Context(), albumID)
if !hasFiles {
h.DB.AddToWantedAlbums(r.Context(), albumID)
}
} else {
h.DB.RemoveFromWantedAlbums(r.Context(), albumID)
}
}
album, err := h.DB.GetAlbumDetailByID(r.Context(), albumID)
if err != nil {
writeError(w, http.StatusNotFound, "album not found")
return
}
writeJSON(w, http.StatusOK, album)
}
func (h *Handlers) SearchAlbum(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
albumIDStr := chi.URLParam(r, "id")
albumID, err := parseUUID(albumIDStr)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid album ID")
return
}
result, err := services.SearchAlbum(r.Context(), albumID, h.DB, h.IndexerService)
if err != nil {
writeError(w, http.StatusNotFound, "album not found")
return
}
writeJSON(w, http.StatusOK, result)
}
func (h *Handlers) BulkMonitorArtistAlbums(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
artistID := chi.URLParam(r, "id")
if artistID == "" {
writeError(w, http.StatusBadRequest, "artist ID required")
return
}
var req struct {
Monitored bool `json:"monitored"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
artist, err := h.DB.GetArtistMetadataByForeignID(r.Context(), artistID)
if err != nil {
writeError(w, http.StatusNotFound, "artist not found")
return
}
updatedCount, err := h.DB.BulkUpdateAlbumsMonitored(r.Context(), artist.ID, req.Monitored)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
albums, _ := h.DB.ListAlbumsByArtist(r.Context(), artist.ID)
for _, album := range albums {
if req.Monitored {
hasFiles, _ := h.DB.HasTrackFiles(r.Context(), album.ID)
if !hasFiles {
h.DB.AddToWantedAlbums(r.Context(), album.ID)
}
} else {
h.DB.RemoveFromWantedAlbums(r.Context(), album.ID)
}
}
writeJSON(w, http.StatusOK, map[string]any{
"updated_count": updatedCount,
"monitored": req.Monitored,
})
}
func (h *Handlers) SearchArtistAlbums(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
artistID := chi.URLParam(r, "id")
if artistID == "" {
writeError(w, http.StatusBadRequest, "artist ID required")
return
}
result, err := services.SearchArtistAlbums(r.Context(), artistID, h.DB, h.IndexerService)
if err != nil {
writeError(w, http.StatusNotFound, "artist not found")
return
}
writeJSON(w, http.StatusOK, result)
}
func (h *Handlers) AddToBlocklist(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
var req struct {
AlbumID string `json:"album_id"`
SourceTitle string `json:"source_title"`
GUID *string `json:"guid"`
TorrentHash *string `json:"torrent_hash"`
Indexer *string `json:"indexer"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
albumID, err := parseUUID(req.AlbumID)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid album_id")
return
}
artistID, err := h.DB.GetArtistIDByAlbum(r.Context(), albumID)
if err != nil {
writeError(w, http.StatusNotFound, "album not found")
return
}
if err := h.DB.AddToBlocklist(r.Context(), *artistID, albumID, req.SourceTitle, req.TorrentHash, req.Indexer); err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
writeJSON(w, http.StatusOK, map[string]any{
"added": true,
})
}
func parseUUID(s string) (uuid.UUID, error) {
return uuid.Parse(s)
}
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)