251 lines
6.5 KiB
Go
251 lines
6.5 KiB
Go
package web
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.noroutes.net/NoRoutes/vibetunes/internal/auth"
|
|
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
|
|
)
|
|
|
|
const pageSize = 60
|
|
|
|
func (h *Web) handleHome(w http.ResponseWriter, r *http.Request) {
|
|
user := auth.UserFromContext(r.Context())
|
|
|
|
albums, err := database.ListAlbums(h.DB, 12, 0)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
var recentlyAdded []AlbumView
|
|
for _, a := range albums {
|
|
recentlyAdded = append(recentlyAdded, toAlbumView(h.DB, a))
|
|
}
|
|
|
|
var recentlyPlayedAlbums []AlbumView
|
|
if user != nil {
|
|
history, err := database.ListRecentlyPlayed(h.DB, user.ID, 30)
|
|
if err == nil {
|
|
seen := map[string]bool{}
|
|
for _, entry := range history {
|
|
song, err := database.GetSong(h.DB, entry.SongID)
|
|
if err != nil || !song.AlbumID.Valid || seen[song.AlbumID.String] {
|
|
continue
|
|
}
|
|
seen[song.AlbumID.String] = true
|
|
album, err := database.GetAlbum(h.DB, song.AlbumID.String)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
recentlyPlayedAlbums = append(recentlyPlayedAlbums, toAlbumView(h.DB, album))
|
|
if len(recentlyPlayedAlbums) >= 12 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
hasLibrary := len(recentlyAdded) > 0
|
|
h.page(w, r, "home", "home", "Home", struct {
|
|
HasLibrary bool
|
|
RecentlyAdded []AlbumView
|
|
RecentlyPlayedAlbums []AlbumView
|
|
}{hasLibrary, recentlyAdded, recentlyPlayedAlbums})
|
|
}
|
|
|
|
func (h *Web) handleArtists(w http.ResponseWriter, r *http.Request) {
|
|
artists, err := database.ListArtists(h.DB)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
var views []ArtistView
|
|
for _, a := range artists {
|
|
views = append(views, toArtistView(a))
|
|
}
|
|
h.page(w, r, "artists", "artists", "Artists", views)
|
|
}
|
|
|
|
func (h *Web) handleArtist(w http.ResponseWriter, r *http.Request) {
|
|
id := r.PathValue("id")
|
|
artist, err := database.GetArtist(h.DB, id)
|
|
if err != nil {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
albums, err := database.ListAlbumsByArtist(h.DB, id)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
var views []AlbumView
|
|
for _, a := range albums {
|
|
views = append(views, toAlbumView(h.DB, a))
|
|
}
|
|
h.page(w, r, "artist", "artists", artist.Name, struct {
|
|
Artist *database.Artist
|
|
Albums []AlbumView
|
|
}{artist, views})
|
|
}
|
|
|
|
func (h *Web) handleAlbums(w http.ResponseWriter, r *http.Request) {
|
|
offset := parseOffset(r)
|
|
albums, err := database.ListAlbums(h.DB, pageSize+1, offset)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
hasMore := len(albums) > pageSize
|
|
if hasMore {
|
|
albums = albums[:pageSize]
|
|
}
|
|
var views []AlbumView
|
|
for _, a := range albums {
|
|
views = append(views, toAlbumView(h.DB, a))
|
|
}
|
|
h.page(w, r, "albums", "albums", "Albums", struct {
|
|
Albums []AlbumView
|
|
HasMore bool
|
|
NextOffset int
|
|
}{views, hasMore, offset + pageSize})
|
|
}
|
|
|
|
func (h *Web) handleAlbum(w http.ResponseWriter, r *http.Request) {
|
|
user := auth.UserFromContext(r.Context())
|
|
id := r.PathValue("id")
|
|
album, err := database.GetAlbum(h.DB, id)
|
|
if err != nil {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
songs, err := database.ListSongsByAlbum(h.DB, id)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
userID := ""
|
|
if user != nil {
|
|
userID = user.ID
|
|
}
|
|
var rows []SongRow
|
|
for _, s := range songs {
|
|
rows = append(rows, toSongRow(h.DB, s, album, userID))
|
|
}
|
|
starred := false
|
|
if user != nil {
|
|
starred, _ = database.IsStarred(h.DB, user.ID, "album", album.ID)
|
|
}
|
|
h.page(w, r, "album", "albums", album.Title, struct {
|
|
Album AlbumView
|
|
Songs []SongRow
|
|
Starred bool
|
|
}{toAlbumView(h.DB, album), rows, starred})
|
|
}
|
|
|
|
func (h *Web) handleSongs(w http.ResponseWriter, r *http.Request) {
|
|
user := auth.UserFromContext(r.Context())
|
|
offset := parseOffset(r)
|
|
songs, err := database.ListSongs(h.DB, pageSize+1, offset)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
hasMore := len(songs) > pageSize
|
|
if hasMore {
|
|
songs = songs[:pageSize]
|
|
}
|
|
userID := ""
|
|
if user != nil {
|
|
userID = user.ID
|
|
}
|
|
var rows []SongRow
|
|
for _, s := range songs {
|
|
rows = append(rows, toSongRow(h.DB, s, albumOf(h.DB, s), userID))
|
|
}
|
|
h.page(w, r, "songs", "songs", "Songs", struct {
|
|
Songs []SongRow
|
|
HasMore bool
|
|
NextOffset int
|
|
}{rows, hasMore, offset + pageSize})
|
|
}
|
|
|
|
func (h *Web) handleGenres(w http.ResponseWriter, r *http.Request) {
|
|
genres, err := database.ListGenres(h.DB)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
h.page(w, r, "genres", "genres", "Genres", genres)
|
|
}
|
|
|
|
func (h *Web) handleSearch(w http.ResponseWriter, r *http.Request) {
|
|
user := auth.UserFromContext(r.Context())
|
|
query := strings.TrimSpace(r.URL.Query().Get("q"))
|
|
|
|
var artistViews []ArtistView
|
|
var albumViews []AlbumView
|
|
var songRows []SongRow
|
|
|
|
if query != "" {
|
|
like := "%" + query + "%"
|
|
|
|
artistRows, _ := h.DB.Query(`SELECT DISTINCT a.id, a.name FROM artists a JOIN album_artists aa ON aa.artist_id = a.id WHERE a.name LIKE ? ORDER BY a.name LIMIT 20`, like)
|
|
if artistRows != nil {
|
|
defer artistRows.Close()
|
|
for artistRows.Next() {
|
|
var id, name string
|
|
if artistRows.Scan(&id, &name) == nil {
|
|
artistViews = append(artistViews, ArtistView{ID: id, Name: name})
|
|
}
|
|
}
|
|
}
|
|
|
|
albumRows, _ := h.DB.Query(`SELECT id FROM albums WHERE title LIKE ? ORDER BY title LIMIT 20`, like)
|
|
if albumRows != nil {
|
|
defer albumRows.Close()
|
|
for albumRows.Next() {
|
|
var id string
|
|
if albumRows.Scan(&id) == nil {
|
|
if album, err := database.GetAlbum(h.DB, id); err == nil {
|
|
albumViews = append(albumViews, toAlbumView(h.DB, album))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
songIDRows, _ := h.DB.Query(`SELECT id FROM songs WHERE title LIKE ? ORDER BY title LIMIT 40`, like)
|
|
if songIDRows != nil {
|
|
defer songIDRows.Close()
|
|
userID := ""
|
|
if user != nil {
|
|
userID = user.ID
|
|
}
|
|
for songIDRows.Next() {
|
|
var id string
|
|
if songIDRows.Scan(&id) == nil {
|
|
if song, err := database.GetSong(h.DB, id); err == nil {
|
|
songRows = append(songRows, toSongRow(h.DB, song, albumOf(h.DB, song), userID))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
h.page(w, r, "search", "search", "Search", struct {
|
|
Query string
|
|
Artists []ArtistView
|
|
Albums []AlbumView
|
|
Songs []SongRow
|
|
}{query, artistViews, albumViews, songRows})
|
|
}
|
|
|
|
func parseOffset(r *http.Request) int {
|
|
n, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
|
if err != nil || n < 0 {
|
|
return 0
|
|
}
|
|
return n
|
|
}
|