feat: Audio Preview Player — browse and play WAV samples via Web Audio API

Issue: #9

Backend:
- GET /api/list-wavs?dir=<path> — lists .wav files in a directory
- GET /wavs/<file> — static file serving from ./output/wavs

Web UI:
- WAV Browser section with path input + Browse button
- AudioContext-based playback (zero deps) — progress bar, time display
- WAV file grid with Play buttons, active item highlighting

Tests:
- 3 new tests for handleListWavs (wav files, empty dir, nonexistent dir)
- Fix TestFindAkaiutil: add t.Chdir(tmp) so relative path lookups don't
  accidentally find the repo's third_party/akaiutil/akaiutil binary
This commit is contained in:
2026-06-22 00:01:15 -07:00
parent 120993fb02
commit cf53912a33
6 changed files with 349 additions and 0 deletions
+34
View File
@@ -54,10 +54,20 @@ func cmdServe(args []string) {
mux.HandleFunc("/api/search", handleSearch)
mux.HandleFunc("/api/list", handleList)
mux.HandleFunc("/api/list-wavs", handleListWavs)
mux.HandleFunc("/api/download", handleAPIDownload)
mux.HandleFunc("/api/extract", handleAPIExtract)
mux.HandleFunc("/api/progress", handleProgress)
wavsBase := "./output/wavs"
if abs, err := filepath.Abs(wavsBase); err == nil {
wavsBase = abs
}
if err := os.MkdirAll(wavsBase, 0755); err != nil {
fatal("create wavs dir: %v", err)
}
mux.Handle("/wavs/", http.StripPrefix("/wavs/", http.FileServer(http.Dir(wavsBase))))
addr := fmt.Sprintf("%s:%d", host, port)
listener, err := net.Listen("tcp", addr)
if err != nil {
@@ -254,6 +264,30 @@ func handleAPIDownload(w http.ResponseWriter, r *http.Request) {
writeJSON(w, map[string]any{"jobs": jobIDs})
}
func handleListWavs(w http.ResponseWriter, r *http.Request) {
dir := r.URL.Query().Get("dir")
if dir == "" {
dir = "./output/wavs"
}
if abs, err := filepath.Abs(dir); err == nil {
dir = abs
}
entries, err := os.ReadDir(dir)
if err != nil {
writeJSON(w, map[string]any{"error": err.Error()})
return
}
var files []string
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(strings.ToLower(e.Name()), ".wav") {
files = append(files, e.Name())
}
}
writeJSON(w, files)
}
func handleProgress(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")