metadata.go
package cmd
import (
"encoding/json"
"flag"
"fmt"
"os"
"skraak/wav"
)
// RunMetadata handles the "metadata" subcommand
//
// JSON output schema:
//
// {
// "file": string, // Path to the WAV file
// "duration_seconds": float, // Duration in seconds
// "sample_rate": int, // Sample rate in Hz
// "channels": int, // Number of audio channels
// "bits_per_sample": int, // Bits per sample
// "comment": string, // WAV comment (omitted if empty)
// "artist": string, // WAV artist (omitted if empty)
// "file_mod_time": string // File modification time RFC3339 (omitted if zero)
// }
func RunMetadata(args []string) error {
fs := flag.NewFlagSet("metadata", flag.ExitOnError)
filePath := fs.String("file", "", "Path to WAV file (required)")
fs.Usage = usagePrinter(fs,
"skraak metadata --file <path>",
"Extract metadata from a WAV file header.",
"skraak metadata --file recording.wav",
"skraak metadata --file /path/to/audio.wav | jq '.duration_seconds'",
)
if err := fs.Parse(args); err != nil {
return fmt.Errorf("parsing flags: %w", err)
}
if err := requireFlags(fs, map[string]any{"--file": *filePath}); err != nil {
return err
}
metadata, err := wav.ParseWAVHeader(*filePath)
if err != nil {
return fmt.Errorf("parsing WAV header: %w", err)
}
output := map[string]any{
"file": *filePath,
"duration_seconds": metadata.Duration,
"sample_rate": metadata.SampleRate,
"channels": metadata.Channels,
"bits_per_sample": metadata.BitsPerSample,
}
if metadata.Comment != "" {
output["comment"] = metadata.Comment
}
if metadata.Artist != "" {
output["artist"] = metadata.Artist
}
if !metadata.FileModTime.IsZero() {
output["file_mod_time"] = metadata.FileModTime.Format("2006-01-02T15:04:05Z07:00")
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(output); err != nil {
return fmt.Errorf("encoding output: %w", err)
}
return nil
}