Web UI: setup wizard, auth pages, library browsing, player, admin, streaming, cover art
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.noroutes.net/NoRoutes/vibetunes/internal/auth"
|
||||
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
|
||||
)
|
||||
|
||||
func (h *Web) handlePlaylists(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
playlists, err := database.ListPlaylistsVisibleToUser(h.DB, user.ID)
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
h.page(w, r, "playlists", "playlists", "Playlists", playlists)
|
||||
}
|
||||
|
||||
func (h *Web) handlePlaylistCreate(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
name := r.FormValue("name")
|
||||
if name == "" {
|
||||
http.Redirect(w, r, "/playlists", http.StatusFound)
|
||||
return
|
||||
}
|
||||
if _, err := database.CreatePlaylist(h.DB, user.ID, name, "", false); err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/playlists", http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *Web) handlePlaylist(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
id := r.PathValue("id")
|
||||
playlist, err := database.GetPlaylist(h.DB, id)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if playlist.OwnerID != user.ID && !playlist.IsPublic {
|
||||
http.Error(w, "403 Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
entries, err := database.ListPlaylistEntries(h.DB, id)
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var rows []SongRow
|
||||
for _, e := range entries {
|
||||
song, err := database.GetSong(h.DB, e.SongID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
rows = append(rows, toSongRow(h.DB, song, albumOf(h.DB, song), user.ID))
|
||||
}
|
||||
h.page(w, r, "playlist", "playlists", playlist.Name, struct {
|
||||
Playlist *database.Playlist
|
||||
Songs []SongRow
|
||||
Owned bool
|
||||
}{playlist, rows, playlist.OwnerID == user.ID})
|
||||
}
|
||||
|
||||
func (h *Web) handlePlaylistDelete(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
id := r.PathValue("id")
|
||||
playlist, err := database.GetPlaylist(h.DB, id)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if playlist.OwnerID != user.ID {
|
||||
http.Error(w, "403 Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if err := database.DeletePlaylist(h.DB, id); err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/playlists", http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *Web) handleFavorites(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
|
||||
artistIDs, _ := database.ListStarredIDs(h.DB, user.ID, "artist")
|
||||
var artists []ArtistView
|
||||
for _, id := range artistIDs {
|
||||
if a, err := database.GetArtist(h.DB, id); err == nil {
|
||||
artists = append(artists, toArtistView(a))
|
||||
}
|
||||
}
|
||||
|
||||
albumIDs, _ := database.ListStarredIDs(h.DB, user.ID, "album")
|
||||
var albums []AlbumView
|
||||
for _, id := range albumIDs {
|
||||
if a, err := database.GetAlbum(h.DB, id); err == nil {
|
||||
albums = append(albums, toAlbumView(h.DB, a))
|
||||
}
|
||||
}
|
||||
|
||||
songIDs, _ := database.ListStarredIDs(h.DB, user.ID, "song")
|
||||
var songs []SongRow
|
||||
for _, id := range songIDs {
|
||||
if s, err := database.GetSong(h.DB, id); err == nil {
|
||||
songs = append(songs, toSongRow(h.DB, s, albumOf(h.DB, s), user.ID))
|
||||
}
|
||||
}
|
||||
|
||||
h.page(w, r, "favorites", "favorites", "Favorites", struct {
|
||||
Artists []ArtistView
|
||||
Albums []AlbumView
|
||||
Songs []SongRow
|
||||
}{artists, albums, songs})
|
||||
}
|
||||
|
||||
func (h *Web) handleFavoriteStar(w http.ResponseWriter, r *http.Request) { h.setFavorite(w, r, true) }
|
||||
func (h *Web) handleFavoriteUnstar(w http.ResponseWriter, r *http.Request) {
|
||||
h.setFavorite(w, r, false)
|
||||
}
|
||||
|
||||
func (h *Web) setFavorite(w http.ResponseWriter, r *http.Request, star bool) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
itemType := r.FormValue("item_type")
|
||||
itemID := r.FormValue("item_id")
|
||||
next := r.FormValue("next")
|
||||
if next == "" || next[0] != '/' {
|
||||
next = "/"
|
||||
}
|
||||
switch itemType {
|
||||
case "song", "album", "artist":
|
||||
default:
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var err error
|
||||
if star {
|
||||
err = database.Star(h.DB, user.ID, itemType, itemID)
|
||||
} else {
|
||||
err = database.Unstar(h.DB, user.ID, itemType, itemID)
|
||||
}
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, next, http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *Web) handleRecent(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
history, err := database.ListRecentlyPlayed(h.DB, user.ID, 100)
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var rows []SongRow
|
||||
seen := map[string]bool{}
|
||||
for _, entry := range history {
|
||||
if seen[entry.SongID] {
|
||||
continue
|
||||
}
|
||||
seen[entry.SongID] = true
|
||||
song, err := database.GetSong(h.DB, entry.SongID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
rows = append(rows, toSongRow(h.DB, song, albumOf(h.DB, song), user.ID))
|
||||
}
|
||||
h.page(w, r, "recent", "recent", "Recently Played", rows)
|
||||
}
|
||||
Reference in New Issue
Block a user