package web import ( "database/sql" "git.noroutes.net/NoRoutes/vibetunes/internal/database" ) // View-model structs shape database rows for templates, keeping SQL // scanning details (sql.Null*) out of the .html files. type ArtistView struct { ID string Name string Bio string CoverArtID string } type AlbumView struct { ID string Title string ArtistName string Year int64 CoverArtID string } type SongRow struct { ID string Title string ArtistName string ArtistID string AlbumTitle string AlbumID string CoverArtID string TrackNumber int64 DurationSeconds float64 Starred bool IsAdmin bool } func toArtistView(a *database.Artist) ArtistView { v := ArtistView{ID: a.ID, Name: a.Name, Bio: a.Bio} if a.CoverArtID.Valid { v.CoverArtID = a.CoverArtID.String } return v } func toAlbumView(db *sql.DB, a *database.Album) AlbumView { v := AlbumView{ID: a.ID, Title: a.Title} if a.Year.Valid { v.Year = a.Year.Int64 } if a.CoverArtID.Valid { v.CoverArtID = a.CoverArtID.String } if a.PrimaryAlbumArtistID.Valid { if artist, err := database.GetArtist(db, a.PrimaryAlbumArtistID.String); err == nil { v.ArtistName = artist.Name } } return v } // toSongRow builds a display row for a song, given its owning album (may // be nil for albumless tracks) and the current user (for the starred // flag; pass "" userID to skip that lookup, and isAdmin=false to hide // the row's "Edit" link). func toSongRow(db *sql.DB, s *database.Song, album *database.Album, userID string, isAdmin bool) SongRow { row := SongRow{ ID: s.ID, Title: s.Title, DurationSeconds: 0, IsAdmin: isAdmin, } if s.TrackNumber.Valid { row.TrackNumber = s.TrackNumber.Int64 } if names, err := database.ListSongArtistNames(db, s.ID); err == nil && len(names) > 0 { row.ArtistName = names[0] for _, n := range names[1:] { row.ArtistName += ", " + n } } if id, err := database.PrimarySongArtistID(db, s.ID); err == nil { row.ArtistID = id } if album != nil { row.AlbumTitle = album.Title row.AlbumID = album.ID if album.CoverArtID.Valid { row.CoverArtID = album.CoverArtID.String } } if mf, err := database.GetMediaFile(db, s.MediaFileID); err == nil { row.DurationSeconds = mf.DurationSeconds } if userID != "" { if starred, err := database.IsStarred(db, userID, "song", s.ID); err == nil { row.Starred = starred } } return row } // albumOf loads a song's album, tolerating albumless songs. func albumOf(db *sql.DB, s *database.Song) *database.Album { if !s.AlbumID.Valid { return nil } album, err := database.GetAlbum(db, s.AlbumID.String) if err != nil { return nil } return album }