feat(api): GET /api/tracks/{id}/stream with Range support
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -147,3 +147,42 @@ func (h *handlers) handleGetCover(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", imageContentType(path))
|
||||
http.ServeContent(w, r, filepath.Base(path), info.ModTime(), f)
|
||||
}
|
||||
|
||||
// handleGetStream implements GET /api/tracks/{id}/stream. Opens the file on
|
||||
// disk and delegates byte-serving to http.ServeContent, which handles Range,
|
||||
// If-Modified-Since, and ETag based on the file's mod time.
|
||||
func (h *handlers) handleGetStream(w http.ResponseWriter, r *http.Request) {
|
||||
id, ok := parseUUID(chi.URLParam(r, "id"))
|
||||
if !ok {
|
||||
writeErr(w, http.StatusBadRequest, "bad_request", "invalid track id")
|
||||
return
|
||||
}
|
||||
q := dbq.New(h.pool)
|
||||
track, err := q.GetTrackByID(r.Context(), id)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
writeErr(w, http.StatusNotFound, "not_found", "track not found")
|
||||
return
|
||||
}
|
||||
h.logger.Error("api: get track for stream failed", "err", err)
|
||||
writeErr(w, http.StatusInternalServerError, "server_error", "server error")
|
||||
return
|
||||
}
|
||||
f, err := os.Open(track.FilePath)
|
||||
if err != nil {
|
||||
// File vanished (scanner indexed it, filesystem lost it). Treat as
|
||||
// 404 so clients can fall back to the next item in a queue.
|
||||
writeErr(w, http.StatusNotFound, "not_found", "track file not found")
|
||||
return
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
h.logger.Error("api: stat track failed", "err", err)
|
||||
writeErr(w, http.StatusInternalServerError, "server_error", "server error")
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", audioContentType(track.FileFormat))
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
http.ServeContent(w, r, filepath.Base(track.FilePath), info.ModTime(), f)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user