README
ΒΆ
go-music
A serverless music browser and streaming API built with Go, Gin, and AWS Lambda. Browse, search, and stream music files stored in S3 with a beautiful web interface and powerful REST API.
Table of Contents
- Overview
- Features
- Quick Start
- Deployment
- Configuration
- API Endpoints
- Development
- Build Metadata
- Links
Overview
go-music provides a complete solution for browsing and streaming music files stored in AWS S3. It features:
- Interactive Web UI β Browse directories, search by title or folder, and stream audio directly from S3
- REST API β JSON endpoints for directory listing, search, and file operations
- Pre-signed URLs β Secure, time-limited audio streaming without exposing credentials
- Multi-format Support β Handles MP3, WAV, OGG, and MP4 audio files
- Flexible Deployment β Run on AWS Lambda, Docker, or standalone
The service automatically adapts to its environment, running as a Lambda function when AWS_LAMBDA_FUNCTION_NAME is detected or as a standard web server otherwise.
β¨ Features
- π΅ Music Streaming β Stream audio files from S3 using secure pre-signed URLs
- π Smart Search β Search by song title or directory name with real-time results
- π Directory Browsing β Navigate your S3 music collection like a file browser
- π¨ Modern UI β Responsive web interface with clean design
- βοΈ Lambda Ready β Auto-detects AWS Lambda environment with zero config changes
- π³ Docker Support β Containerized deployment with multi-arch builds (amd64/arm64)
- π Secure β Uses IAM roles and pre-signed URLs, never exposes credentials
- π Fast β Efficient S3 API usage with streaming support
- π Build Metadata β Version, commit hash, and build time baked into releases
π Quick Start
Run with Go
Requires Go 1.24+.
git clone https://github.com/johnwmail/go-music.git
cd go-music
# Set required environment variables
export BUCKET=your-s3-bucket-name
export AWS_REGION=us-east-1
export S3_PREFIX=music # optional
# Run the service
go run .
Visit http://localhost:8080 to browse your music collection.
Quick Docker Start
docker run -p 8080:8080 \
-e BUCKET=your-bucket \
-e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID=your-key \
-e AWS_SECRET_ACCESS_KEY=your-secret \
ghcr.io/johnwmail/go-music:latest
βοΈ Deployment
Docker
Build and run locally:
docker build -t go-music:local -f docker/Dockerfile .
docker run --rm -p 8080:8080 \
-e BUCKET=your-bucket \
-e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID=your-key \
-e AWS_SECRET_ACCESS_KEY=your-secret \
--name go-music go-music:local
Using Compose:
docker compose -f docker/docker-compose.yml up --build
Multi-arch support: Images are built for linux/amd64 and linux/arm64 automatically via GitHub Actions.
AWS Lambda
The app switches to Lambda mode when AWS_LAMBDA_FUNCTION_NAME is present. The deploy-lambda.yml workflow handles automated deployments.
Manual Deployment
-
Build the Lambda bootstrap binary:
go build \ -ldflags "-X main.Version=v1.0.0 -X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ) -X main.CommitHash=$(git rev-parse --short HEAD)" \ -tags netgo -trimpath \ -o bootstrap . -
Package with static and templates assets:
mkdir -p lambda-artifacts mv bootstrap lambda-artifacts/ cp -r static lambda-artifacts/ cp -r templates lambda-artifacts/ cd lambda-artifacts && zip -r ../deployment.zip . && cd .. -
Deploy via AWS CLI or Console with these environment variables:
BUCKETβ Your S3 bucket nameS3_PREFIXβ Optional prefix (e.g., "music")GIN_MODEβ Set to "release" for production
Automated Deployment
Push to the deploy/lambda branch or manually trigger the workflow:
gh workflow run deploy-lambda.yml \
-f function_name=your-lambda-function-name
Required GitHub secrets:
AWS_ACCESS_KEY_ID_DEPLOY_LAMBDAAWS_SECRET_ACCESS_KEY_DEPLOY_LAMBDAAWS_REGION
Required GitHub variables:
LAMBDA_FUNCTION_NAMEBUCKETS3_PREFIX(optional)LAMBDA_EXECUTION_ROLE
Container Registry
Pre-built images are available on GitHub Container Registry:
docker pull ghcr.io/johnwmail/go-music:latest
docker pull ghcr.io/johnwmail/go-music:v1.0.0 # specific version
βοΈ Configuration
The service uses environment variables for configuration:
| Variable | Required | Default | Description |
|---|---|---|---|
BUCKET |
Yes | β | S3 bucket containing your music files |
AWS_REGION |
Recommended | auto-detect | AWS region for S3 bucket |
S3_PREFIX |
No | "" |
Optional prefix path in S3 (e.g., "music") |
AWS_ACCESS_KEY_ID |
Docker only* | β | AWS access key (use IAM role in Lambda) |
AWS_SECRET_ACCESS_KEY |
Docker only* | β | AWS secret key (use IAM role in Lambda) |
PORT |
No | 8080 |
HTTP server port (ignored in Lambda) |
GIN_MODE |
No | debug |
Set to "release" for production |
* Lambda deployments should use IAM roles instead of static credentials.
S3 Bucket Setup
Your S3 bucket should contain audio files organized in directories:
my-music-bucket/
βββ music/ # S3_PREFIX="music"
β βββ Rock/
β β βββ song1.mp3
β β βββ song2.mp3
β βββ Jazz/
β βββ tune.mp3
Required IAM permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::your-bucket-name",
"arn:aws:s3:::your-bucket-name/*"
]
}
]
}
π API Endpoints
| Method | Path | Description |
|---|---|---|
| GET | / |
Serves the web UI |
| GET | /static/* |
Serves static assets (CSS, JS) |
| POST | /api |
Main API endpoint (see functions below) |
| GET | /audio/*path |
Returns pre-signed S3 URL for streaming |
API Functions (POST to /api)
Send JSON payloads with a function field and relevant parameters:
Directory Listing
curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"dir","path":"Rock/"}'
Search by Title
curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"searchTitle","searchStr":"love"}'
Search by Directory
curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"searchDir","searchStr":"jazz"}'
Get All MP3s
curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"getAllMp3"}'
Get All Directories
curl -X POST http://localhost:8080/api \
-H "Content-Type: application/json" \
-d '{"function":"getAllDirs"}'
Audio Streaming
# Get pre-signed URL (valid for 1 hour)
curl http://localhost:8080/audio/Rock/song.mp3
# Returns: {"url":"https://s3.amazonaws.com/..."}
Sample API response:
{
"files": [
{
"name": "song.mp3",
"path": "Rock/song.mp3",
"size": 5242880,
"modified": "2024-01-15T10:30:00Z"
}
],
"directories": ["Rock", "Jazz", "Classical"]
}
π§ Development
# Clone the repository
git clone https://github.com/johnwmail/go-music.git
cd go-music
# Install dependencies
go mod download
# Run tests (no AWS credentials required)
export MUSIC_DIR=/tmp/test-music
export GIN_MODE=release
go test -v ./...
# Run tests with coverage
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
go tool cover -html=coverage.out
# Format and lint
go fmt ./...
go vet ./...
golangci-lint run
# Run locally with live reload
go run .
Running Tests
The test suite is designed to run without AWS/S3 credentials. Tests use local filesystem operations and mocked dependencies:
# Run all tests
MUSIC_DIR=/tmp/test-music GIN_MODE=release go test -v ./...
# Run specific test
MUSIC_DIR=/tmp/test-music go test -v -run TestIsAudioFile
# Run with race detection
MUSIC_DIR=/tmp/test-music go test -race ./...
# Generate coverage report
MUSIC_DIR=/tmp/test-music go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out
The tests cover:
- β Audio file detection (mp3, wav, ogg, mp4)
- β JavaScript array encoding for web UI
- β Version endpoint handler
- β Local file system operations (listing, searching)
- β Directory browsing and filtering
- β Search functionality (case-insensitive)
The CI pipeline in .github/workflows/test.yml enforces code quality checks and runs the full test suite automatically.
Note: The unit tests are designed to run without AWS/S3 credentials. The test harness sets MUSIC_DIR automatically (see main_test.go) to a temporary directory to avoid S3 initialization β you can also set MUSIC_DIR yourself if you want tests to run against a specific local folder.
If you'd like to exercise S3 integration in tests, set BUCKET and AWS_REGION in your environment. The application will call initS3() in main() only when a local music directory is not provided.
Project Structure
go-music/
βββ .github/
β βββ instructions/ # Development guidelines
β βββ workflows/ # CI/CD pipelines
βββ docker/
β βββ Dockerfile # Multi-stage container build
β βββ docker-compose.yml # Local development setup
βββ static/ # Web UI assets (HTML, CSS, JS)
βββ main.go # Application entry point
βββ go.mod # Go module definition
βββ README.md
π·οΈ Build Metadata
main.go exposes three build-time variables for versioning:
| Variable | Default | Purpose |
|---|---|---|
Version |
dev |
Semantic version or git tag |
BuildTime |
unknown |
Build timestamp (ISO 8601) |
CommitHash |
none |
Git commit SHA (short) |
Inject values with Go build flags:
go build \
-ldflags "-X main.Version=v1.2.3 \
-X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-X main.CommitHash=$(git rev-parse --short HEAD)" \
-o go-music .
Values are logged on startup and accessible via the web UI.
π Links
- GitHub: https://github.com/johnwmail/go-music
- Container Images: https://github.com/johnwmail/go-music/pkgs/container/go-music
- Issues: https://github.com/johnwmail/go-music/issues
- Actions: https://github.com/johnwmail/go-music/actions
- Releases: https://github.com/johnwmail/go-music/releases
β Star the project if this music streamer helps you out!
Documentation
ΒΆ
There is no documentation for this package.