song.go (1382B)
1 package server 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "lyrics/internal/db" 8 "lyrics/internal/domain" 9 "lyrics/internal/server/htmx" 10 "lyrics/internal/server/routes" 11 "lyrics/internal/server/ui/views/song" 12 "net/http" 13 "strconv" 14 ) 15 16 func (ss *ServerState) Song(w http.ResponseWriter, r *http.Request) { 17 logger := ss.logger.With("handler", "Song") 18 19 idStr := r.PathValue("id") 20 id, err := strconv.Atoi(idStr) 21 if err != nil { 22 logger.Error("failed to convert song id to integer", "id", idStr, "err", err) 23 htmx.HxError(w, http.StatusBadRequest, err.Error()) 24 return 25 } 26 27 slug := r.PathValue("slug") 28 logger = logger.With("id", id, "slug", slug) 29 30 s, err := db.Song(ss.db, domain.SongID(id)) 31 if err != nil { 32 logger.Error("failed to get song", "err", err) 33 htmx.HxError(w, http.StatusInternalServerError, fmt.Sprintf("failed to query for song '%s'", slug)) 34 return 35 } 36 37 songTitle := s.Title 38 if s.LatinTitle != nil { 39 songTitle = *s.LatinTitle 40 } 41 42 if domain.Slug(songTitle) != slug { 43 htmx.HxRedirect(w, http.StatusMovedPermanently, routes.SongPath(domain.SongID(id), songTitle)) 44 return 45 } 46 47 err = song.Song(song.SongParams{Song: s}).Render(r.Context(), w) 48 if err != nil { 49 if errors.Is(err, context.Canceled) { 50 return 51 } 52 53 logger.Error("failed to render song page", "err", err) 54 http.Error(w, "Internal Server Error", http.StatusInternalServerError) 55 return 56 } 57 }