feat: Sample Tag Viewer — read-only tag browser for AKAI disk images
Backend: - extract.go: listTags() navigates to volume, runs akaiutil lstags - extract.go: parseTags() parses tag name/index from lstags output - serve.go: GET /api/disk/partitions — list partitions on an ISO - serve.go: GET /api/disk/volumes — list volumes on a partition - serve.go: GET /api/volume/tags — list tags on a volume Web UI: - Tag Viewer section with ISO path input and Browse button - Partition selector buttons - Volume grid with click-to-select - Tag chips with color-coded dots (20-color palette) Tests: - 6 parseTags tests (basic, spaces, defaults, no tags, empty, no-type) - 1 listTags integration test - 4 API endpoint tests (partitions, missing-ISO, missing-params, tags) Karpathy: read-only view first — no write operations yet (settagi, clrtagi)
This commit is contained in:
@@ -55,6 +55,9 @@ func cmdServe(args []string) {
|
||||
mux.HandleFunc("/api/search", handleSearch)
|
||||
mux.HandleFunc("/api/list", handleList)
|
||||
mux.HandleFunc("/api/list-wavs", handleListWavs)
|
||||
mux.HandleFunc("/api/disk/partitions", handleDiskPartitions)
|
||||
mux.HandleFunc("/api/disk/volumes", handleDiskVolumes)
|
||||
mux.HandleFunc("/api/volume/tags", handleVolumeTags)
|
||||
mux.HandleFunc("/api/download", handleAPIDownload)
|
||||
mux.HandleFunc("/api/extract", handleAPIExtract)
|
||||
mux.HandleFunc("/api/progress", handleProgress)
|
||||
@@ -300,6 +303,63 @@ func handleListWavs(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, files)
|
||||
}
|
||||
|
||||
func handleDiskPartitions(w http.ResponseWriter, r *http.Request) {
|
||||
iso := r.URL.Query().Get("iso")
|
||||
if iso == "" {
|
||||
writeJSON(w, map[string]any{"error": "missing iso parameter"})
|
||||
return
|
||||
}
|
||||
parts, err := listPartitions(iso)
|
||||
if err != nil {
|
||||
writeJSON(w, map[string]any{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
writeJSON(w, parts)
|
||||
}
|
||||
|
||||
func handleDiskVolumes(w http.ResponseWriter, r *http.Request) {
|
||||
iso := r.URL.Query().Get("iso")
|
||||
part := r.URL.Query().Get("part")
|
||||
if iso == "" || part == "" {
|
||||
writeJSON(w, map[string]any{"error": "missing iso or part parameter"})
|
||||
return
|
||||
}
|
||||
parts, err := listPartitions(iso)
|
||||
if err != nil {
|
||||
writeJSON(w, map[string]any{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
vols, err := listVolumes(iso, parts)
|
||||
if err != nil {
|
||||
writeJSON(w, map[string]any{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
var filtered []volInfo
|
||||
for _, v := range vols {
|
||||
if v.Part == part {
|
||||
filtered = append(filtered, v)
|
||||
}
|
||||
}
|
||||
writeJSON(w, filtered)
|
||||
}
|
||||
|
||||
func handleVolumeTags(w http.ResponseWriter, r *http.Request) {
|
||||
iso := r.URL.Query().Get("iso")
|
||||
part := r.URL.Query().Get("part")
|
||||
vol := r.URL.Query().Get("vol")
|
||||
if iso == "" || part == "" || vol == "" {
|
||||
writeJSON(w, map[string]any{"error": "missing iso, part, or vol parameter"})
|
||||
return
|
||||
}
|
||||
|
||||
tags, err := listTags(iso, part, vol)
|
||||
if err != nil {
|
||||
writeJSON(w, map[string]any{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
writeJSON(w, tags)
|
||||
}
|
||||
|
||||
func handleProgress(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
|
||||
Reference in New Issue
Block a user