Web UI: setup wizard, auth pages, library browsing, player, admin, streaming, cover art
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.noroutes.net/NoRoutes/vibetunes/internal/auth"
|
||||
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
|
||||
"git.noroutes.net/NoRoutes/vibetunes/internal/streaming"
|
||||
)
|
||||
|
||||
// handleStream serves a song's audio bytes directly (no transcoding in
|
||||
// Phase 1). Authorization happens here, before any file is opened: the
|
||||
// caller must be a signed-in, non-disabled user (enforced by the
|
||||
// RequireUser middleware wrapping this route), and the resolved path is
|
||||
// always re-validated against its music folder root.
|
||||
func (h *Web) handleStream(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
songID := r.PathValue("id")
|
||||
|
||||
song, err := database.GetSong(h.DB, songID)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
mediaFile, err := database.GetMediaFile(h.DB, song.MediaFileID)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
folder, err := database.GetMusicFolder(h.DB, mediaFile.MusicFolderID)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
absPath, err := streaming.ResolvePath(folder.Path, mediaFile.RelativePath)
|
||||
if err != nil {
|
||||
http.Error(w, "403 Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
// Best-effort playback tracking: only record once per playback (on
|
||||
// the request for the start of the file, not every range chunk a
|
||||
// browser issues while seeking/buffering).
|
||||
rangeHeader := r.Header.Get("Range")
|
||||
if rangeHeader == "" || strings.HasPrefix(rangeHeader, "bytes=0-") {
|
||||
_ = database.SetNowPlaying(h.DB, user.ID, song.ID, "web", 0)
|
||||
_ = database.RecordPlayback(h.DB, user.ID, song.ID, 0)
|
||||
}
|
||||
|
||||
if err := streaming.ServeFile(w, r, absPath, mediaFile.RelativePath); err != nil {
|
||||
http.Error(w, "could not read media file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user