Strafe is a command-line interface (CLI) tool and accompanying HTTP server designed for processing, managing, and serving a music library.
It provides a robust pipeline for handling audio files, including vocal/instrumental separation, metadata extraction, waveform generation, database storage (PostgreSQL), and object storage (S3-compatible) integration for audio segments and cover art. Initially built to power https://dj.cansu.dev, it aims to be a flexible tool for music library management.
- Audio Processing Pipeline:
- Uploads audio files via the CLI.
- Uses
audio-separator(via Python/uv) for optional vocal/instrumental splitting. - Leverages a dedicated Docker container with tools like
ffmpeg,audiowaveform,exiftool,aubio,keyfinder-clito:- Extract metadata (ID3 tags, duration).
- Determine tempo and musical key.
- Generate compressed waveform data (JSON compressed with zlib).
- Segment audio into HLS streams (
.m3u8,.ts).
- Storage:
- Stores track/album metadata and listening history in a PostgreSQL database.
- Uploads HLS segments (vocals, instrumentals) and cover art to an S3-compatible object storage bucket.
- Database Management:
- Uses
sqlcfor type-safe SQL query generation. - Uses
goosefor database schema migrations (embedded in the binary).
- Uses
- CLI (
strafe):- Commands for uploading audio (
audio upload). - Commands for managing the processing Docker image (
docker image ...). - Commands for querying the database (
db search ...). - Configuration display (
cfg).
- Commands for uploading audio (
- HTTP Server (
strafe server):- Serves track data via a RESTful API (using
chi). - Endpoints for retrieving specific tracks or random tracks (with basic listening history tracking).
- Serves track data via a RESTful API (using
- CLI (
strafe audio upload): User provides an audio file and optionally cover art. - (Optional) Pre-processing:
audio-separator(viauv) splits the input audio into vocal and instrumental stems on the host machine. - Docker: The CLI mounts the original audio (or stems), temporary output directories, and a generated script into the
strafeDocker container. - Container Processing: The container runs the script which executes
ffmpeg,audiowaveform,exiftool,aubio,keyfinder-clito process the audio, generate HLS segments, waveforms, and extract metadata into temporary files. - CLI (Post-processing): Reads the generated metadata and waveform files.
- Database: Inserts/updates album and track metadata (including compressed waveforms) into the PostgreSQL database. Checks if the album exists and requires cover art if it's new.
- S3 Storage: Uploads the generated HLS segments (
.m3u8,.tsfiles for vocals/instrumentals) and cover art (if applicable) to the configured S3 bucket. - Server (
strafe server): Listens for HTTP requests, queries the database, and serves track metadata (including S3 paths and decompressed waveforms) as JSON.
- Go: Version 1.23 or higher (see
go.mod). - Docker: Docker Engine and CLI installed and running. The user running
strafeneeds permission to interact with the Docker socket. - Just: A command runner used for building and managing the project (
https://github.com/casey/just). Recommended for development. - uv: A Python package installer/resolver (
https://github.com/astral-sh/uv), required by theaudio uploadcommand foraudio-separator. Follow installation instructions in the uv documentation. - PostgreSQL: A running PostgreSQL database accessible from where
strafeis run. - S3-Compatible Storage: An S3 bucket (e.g., Cloudflare R2, AWS S3, MinIO) and corresponding credentials.
- Clone the Repository:
git clone https://github.com/caner-cetin/strafe.git cd strafe - Build using
just: (Requiresjustto be installed)- Build for your current OS/Architecture:
just build-current # Output: dist/strafe - Build for multiple platforms:
just build # Output: dist/strafe-<os>-<arch>[.exe] - Build and create compressed packages for distribution:
just package # Output: dist/strafe-<os>-<arch>.(tar.gz|zip)
- Build for your current OS/Architecture:
- (Alternative) Go Install:
# Ensure GOPATH/bin is in your PATH go install github.com/caner-cetin/strafe@latest # Or if proxies cause issues: # GOPROXY=direct go install github.com/caner-cetin/strafe@latest
- (Optional) Pre-built Binaries: Check the Releases page for pre-built binaries corresponding to the
just packagecommand output.
Strafe uses a YAML configuration file named .strafe.yaml.
-
Create the File: Copy the provided
.strafe.dummy.yamlfile. -
Rename: Rename it to
.strafe.yaml. -
Location: Place the file in your user home directory (
$HOME/.strafe.yaml). Alternatively, specify a path using the--configflag or theSTRAFE_CFGenvironment variable. -
Edit: Crucially, edit the file and fill in the required values:
# .strafe.yaml docker: # Image for audio processing. # Option A: Use the pre-built image from Docker Hub (recommended unless modifying the Dockerfile). image: name: cansucetin/strafe # Default: Pre-built image tag: latest # Default: latest tag # Option B: Build your own using `strafe docker image build`. # image: # name: strafe # Or your custom name # tag: local # Path to the Docker socket. Adjust if needed (e.g., for Orbstack, Colima, Podman). socket: unix:///var/run/docker.sock # Example for Linux/macOS default db: # REQUIRED: Connection URL for your PostgreSQL database. url: postgresql://user:password@host:port/database?sslmode=disable # Replace with your actual URL # REQUIRED: Configuration for your S3-compatible storage (e.g., Cloudflare R2) s3: # REQUIRED: Name of the bucket to store audio segments and covers. bucket: your-strafe-bucket-name # REQUIRED: Account ID (Specific to Cloudflare R2). Omit or adjust endpoint for other providers. account_id: your_r2_account_id # REQUIRED: Access Key ID for your S3 credentials. access_key_id: YOUR_ACCESS_KEY_ID # REQUIRED: Secret Access Key for your S3 credentials. access_key_secret: YOUR_SECRET_ACCESS_KEY # Optional: Display random ASCII art on --help messages. display_ascii_art_on_help: true
strafe [command] [subcommand] [flags]-
Upload the first track of an album (requires cover art):
strafe audio upload -i "/path/to/your/Music/Artist/Album/01 Track Name.flac" \ -c "/path/to/your/Music/Artist/Album/cover.jpg" \ [--model <model_name>] # Optional: Specify audio separator model
-i, --input: Path to the audio file.-c, --cover_art: Path to the album cover image. Required if the album doesn't exist in the database yet.--model: Name of theaudio-separatormodel checkpoint file (seestrafe audio models). Defaults tomel_band_roformer_karaoke_aufr33_viperx_sdr_10.1956.ckpt.--instrumental: Flag if the source audio is purely instrumental (skips vocal/instrumental separation if needed, assumes input is instrumental).-P, --pps: Waveform pixels per second (default: 100).-d, --dry_run: Process audio but don't insert into DB or upload to S3.
-
Upload subsequent tracks from the same album: (Cover art is no longer needed as the album exists)
strafe audio upload -i "/path/to/your/Music/Artist/Album/02 Another Track.flac" -
Check available audio separator models:
strafe audio models
- Search for an album by name and artist:
strafe db search album -a "Artist Name" -n "Album Name"
- This will query the database and display album details along with track information, potentially rendering the cover art as ASCII in the terminal.
- Build the processing image locally: (Needed if you don't use the
cansucetin/strafeimage or modify theDockerfile)# Run from the project root directory containing the Dockerfile strafe docker image build [-f --force] [-q --quiet] # Use -f to rebuild even if an image with the configured tag exists. # Use -q to suppress build logs.
- Check if the configured image exists:
strafe docker image exists
- Remove the configured image:
strafe docker image remove # Will ask for confirmation - Check if tools inside the image are runnable:
strafe docker image health
- Display configuration:
strafe cfg [-s --sensitive] # Use -s to show sensitive values like DB URL - Show version:
strafe version
- Get help:
strafe --help strafe [command] --help
The server provides API endpoints, suitable for powering a music streaming frontend.
- Run the server:
strafe server [-p <port>] [--host <ip_address>] # Example: Run on port 8080 on all interfaces # strafe server -p 8080 --host 0.0.0.0 # If -p is omitted, it finds a random available port.
The Dockerfile builds an image containing various command-line tools necessary for audio processing:
ffmpeg: Audio/video conversion, used here for HLS segmentation.audiowaveform: Generates waveform data from audio files.exiftool: Reads/writes metadata (used for ID3 tags).aubio: Provides tools for audio analysis, used here for tempo (BPM) detection.libkeyfinder/keyfinder-cli: Detects the musical key of audio tracks.
Building this image can take time due to dependencies. Using the pre-built cansucetin/strafe:latest image is recommended unless customization is needed.
Database schema migrations are managed using goose and are embedded within the strafe binary. They are automatically applied when the strafe server command starts or when any command requiring database access (audio upload, db search) runs its initialization. The migration files are located in pkg/db/migrations/.
- Install Tools: Use
just install sqlcandjust install gooseif you need to manage the database schema or regenerate SQL code. - Generate SQL Code: After modifying
query.sqlor the schema, runjust generate. - Tidy Go Modules:
just tidy. - Linting: Uses
golangci-lint. Rungolangci-lint run(configuration is in.golangci.yml).
This project uses the highly unconventional Push-Up License (PUL). Please see the LICENSE file for details. (TL;DR: If you copy the software, you owe one (1) push-up).
Contributions are welcome! If you find a bug, have a feature request, or want to improve the code, please feel free to open an issue or submit a pull request.