Professional tool in Go with Hexagonal Architecture to batch convert MKV files to MP4, with parallelism and subtitle support.
go build -o govc ./cmd/govc# Show help
./govc --help
./govc convert --help
# Convert with default settings (uses system CPU count, deletes logs)
./govc convert /path/to/videos
# Convert with 4 parallel workers (deletes logs by default)
./govc convert -p 4 /path/to/videos
# Keep logs (with alias -l, implicitly true)
./govc convert -p 4 -l /path/to/videos
# Keep logs (with alias -l=true, explicitly)
./govc convert -p 4 -l=true /path/to/videos
# Keep logs (with flag name --logs)
./govc convert -p 4 --logs /path/to/videos
# With go run
go run ./cmd/govc convert -p 4 /path/to/videos-p, --workers N (Integer)
- Controls how many
ffmpegprocesses run simultaneously - Default: number of CPUs on the machine
- Recommended:
-p 2on machines with few cores,-p 4on modern machines
-l, --logs BOOLEAN (Boolean)
- Default:
false- deletes successful logs after conversion (keeps error logs) - With
-l,--logsor--logs=true: keeps logs inmp4/<name>.logfor each converted video - Note: Error logs are always kept for diagnostics (regardless of flag)
- Logs contain ffmpeg stderr output for troubleshooting
Subtitle Support
Supports two types:
- Embedded: internal subtitles in MKV (mapped automatically)
- External:
.srtfile with same name as video- Example:
video.mkv→ looks forvideo.srt - Both are converted to
mov_text(MP4 compatible)
- Example:
This project follows Hexagonal Architecture (Ports & Adapters) for maximum testability and extensibility:
┌─────────────────────────────────────────┐
│ CLI Input Adapter │
└────────────────────┬────────────────────┘
│
↓
┌─────────────────────────┐
│ ConversionService │ ← Use Case (core)
│ (Orchestration) │
└────────┬──────┬─────────┘
│ │
┌───────┘ └────────┐
↓ ↓
Filesystem FFmpeg Adapter
(Video Discovery) (Converter)
Benefits:
- ✅ Testable: Mock adapters without running real ffmpeg
- ✅ Decoupled: Replace ffmpeg with another tool? New adapter, done
- ✅ Scalable: Add REST API? New input adapter
- ✅ Readable: Structure reflects business domain
GoVC/
├── cmd/govc/main.go ← Entry point (Bootstrap)
├── internal/core/
│ ├── domain/ ← Pure entities (Video, Conversion)
│ ├── ports/ ← Interfaces (contracts)
│ └── services/conversion_service.go ← Use case
└── internal/adapters/
├── cli/ ← Input: CLI adapter
├── commands/ ← urfave/cli command handlers
├── filesystem/ ← Output: File system
└── ffmpeg/ ← Output: Converter
For detailed documentation → see HEXAGONAL_ARCHITECTURE.md
- Go 1.20+
- ffmpeg and ffprobe installed and in PATH
# macOS
brew install ffmpeg
# Linux (Ubuntu/Debian)
sudo apt-get install ffmpeg
# Windows (with Chocolatey)
choco install ffmpeg./govc convert /videos- Uses all CPUs
- Saves logs in
/videos/mp4/
./govc convert -p 2 --logs=false /videos- 2 parallel workers
- Deletes successful logs after conversion
- Error logs are still kept
go build -o govc-v1.0 ./cmd/govc
./govc-v1.0 convert -p 4 /media/moviesTo test the domain in isolation (without ffmpeg):
package domain
import "testing"
func TestProgressTracker(t *testing.T) {
tracker := domain.NewProgressTracker(3)
tracker.Update("video1", 50)
if tracker.GetSnapshot()["video1"] != 50 {
t.Fatal("Progress not updated")
}
}All adapters can be mocked for pure unit tests.
Adding a new adapter is simple. Example: support for HTTP API to submit conversions:
- Create
internal/adapters/http/adapter.go - Implement
ConfigPortto read config via HTTP - Inject into
ConversionService(in bootstrap)
For complete guide → see EXTENSION_GUIDE.md
- v1.0 (current): Refactoring with Hexagonal Architecture
- ✅ Pure core domain
- ✅ Well-defined ports
- ✅ Decoupled adapters
- ✅ Testable and extensible
Developed with focus on Clean Code and Quality Architecture.