feat: reimplement WAV extraction in Go (replaces extract_wavs.sh)

extract.go replaces the bash script with idiomatic Go:
- akaiutil process communication via stdin/stdout pipes
- partition enumeration (df output parsing)
- volume enumeration (dir output parsing per partition)
- sample2wavall per volume with WAV count aggregation

runAkaiutil is a package-level var — tests stub it with canned
output to verify parsing without a real akaiutil binary or ISO.

Removed: findScript(), -tool flag on extract, os/exec from main.go
Kept: extract_wavs.sh as a standalone utility (no longer called)
This commit is contained in:
2026-06-21 22:17:24 -07:00
parent bc12130dd6
commit ea2bcde74b
4 changed files with 323 additions and 75 deletions
+3 -72
View File
@@ -8,7 +8,6 @@ import (
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"sort"
"strconv"
@@ -100,10 +99,9 @@ Download flags:
-dir "./isos" output directory (default: current dir)
-jobs 2 concurrent downloads (default: 2)
Extract flags:
Extract flags:
-dir "./isos" directory containing ISO files
-out "./wavs" output directory for WAV files
-tool "./extract_wavs.sh" path to extraction script
-jobs 2 concurrent extractions (default: 2)
Pipeline flags:
@@ -382,15 +380,9 @@ func cmdExtract(args []string) {
fs := flag.NewFlagSet("extract", flag.ExitOnError)
isoDir := fs.String("dir", ".", "directory with ISO files")
outDir := fs.String("out", "./wavs", "output directory for WAVs")
toolFlag := fs.String("tool", "", "path to extraction script (default: auto-detect)")
jobs := fs.Int("jobs", 2, "concurrent extractions")
_ = fs.Parse(args)
toolPath := *toolFlag
if toolPath == "" {
toolPath = findScript("extract_wavs.sh")
}
os.MkdirAll(*outDir, 0755)
entries, err := os.ReadDir(*isoDir)
@@ -414,8 +406,6 @@ func cmdExtract(args []string) {
sem := make(chan struct{}, *jobs)
var wg sync.WaitGroup
var mu sync.Mutex
results := map[string]string{}
for _, iso := range isos {
wg.Add(1)
@@ -425,10 +415,7 @@ func cmdExtract(args []string) {
defer func() { <-sem }()
out := *outDir
result, err := extractISO(toolPath, isoPath, out)
mu.Lock()
results[filepath.Base(isoPath)] = result
mu.Unlock()
result, err := extractISO(isoPath, out)
if err != nil {
fmt.Printf(" FAIL %-40s %v\n", filepath.Base(isoPath), err)
} else {
@@ -439,46 +426,6 @@ func cmdExtract(args []string) {
wg.Wait()
}
func extractISO(toolPath, isoPath, outDir string) (string, error) {
absTool, err := filepath.Abs(toolPath)
if err != nil {
return "", err
}
if _, err := os.Stat(absTool); os.IsNotExist(err) {
return "", fmt.Errorf("script not found: %s", absTool)
}
isoOutDir := filepath.Join(outDir, sanitiseISOName(filepath.Base(isoPath)))
if _, err := os.Stat(isoOutDir); err == nil {
var wavCount int
filepath.WalkDir(isoOutDir, func(p string, d os.DirEntry, err error) error {
if err == nil && !d.IsDir() && strings.HasSuffix(strings.ToLower(d.Name()), ".wav") {
wavCount++
}
return nil
})
if wavCount > 0 {
return fmt.Sprintf("skipped (%d WAVs exist)", wavCount), nil
}
}
cmd := exec.Command("bash", absTool, isoPath, outDir)
cmd.Stderr = nil
output, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("extract: %w", err)
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(line, "Total WAV files:") {
return strings.TrimSpace(line), nil
}
}
return "extracted (check output)", nil
}
func sanitiseISOName(path string) string {
name := path
if ext := filepath.Ext(name); ext != "" {
@@ -520,7 +467,6 @@ func cmdPipeline(args []string) {
isoDir := filepath.Join(*baseDir, "isos")
wavDir := filepath.Join(*baseDir, "wavs")
toolPath := findScript("extract_wavs.sh")
// Remaining args after flags are treated as explicit identifiers
identifiers := fs.Args()
@@ -566,28 +512,13 @@ func cmdPipeline(args []string) {
cmdDownload([]string{"-f", idFile, "-dir", isoDir, "-jobs", fmt.Sprintf("%d", *dlJobs)})
fmt.Println("\n=== Phase 3: Extract ===")
cmdExtract([]string{"-dir", isoDir, "-out", wavDir, "-tool", toolPath, "-jobs", fmt.Sprintf("%d", *extJobs)})
cmdExtract([]string{"-dir", isoDir, "-out", wavDir, "-jobs", fmt.Sprintf("%d", *extJobs)})
fmt.Printf("\n=== Pipeline Complete ===\n")
fmt.Printf(" ISOs: %s\n", isoDir)
fmt.Printf(" WAVs: %s\n", wavDir)
}
func findScript(name string) string {
candidates := []string{
filepath.Join(filepath.Dir(os.Args[0]), name),
filepath.Join(filepath.Dir(os.Args[0]), "scripts", name),
name,
filepath.Join("scripts", name),
}
for _, p := range candidates {
if _, err := os.Stat(p); err == nil {
return p
}
}
return name
}
// ─── Helpers ───────────────────────────────────────────────────────────
func fatal(format string, args ...any) {