trackwatch
A beautiful terminal music visualizer with pixelated album art and synchronized lyrics

Features
- 🎵 Universal Player Support - Works with YouTube, Spotify, Tidal, VLC, and any MPRIS2-compatible player
- 🎨 Pixelated Album Art - 30x30 pixel art rendered with ANSI escape sequences (including YouTube video thumbnails!)
- 🌈 Dynamic Color Theming - Extracts colors from album art for UI elements
- 📝 Synchronized Lyrics - Auto-scrolling lyrics with LRC format support
- 💾 Smart Caching - Caches processed images and lyrics for performance
- ⚡ Real-time Updates - Live progress tracking and metadata updates
Requirements
- Rust 1.70+
playerctl (for media player detection)
- Terminal with 256 color support
- Tidal API credentials (optional, for enhanced metadata)
Installation
# Clone the repository
git clone https://github.com/estevaom/trackwatch
cd trackwatch
# Build and run
cargo build --release
./target/release/trackwatch
Optional: Enhanced Metadata with Tidal
For richer album metadata and high-quality cover art, you can optionally configure Tidal API credentials:
- Get Tidal API credentials from https://developer.tidal.com/dashboard/create
- Create a
.env file from the example:
bash
cp .env.example .env
- Edit the
.env file with your credentials:
TIDAL_CLIENT_ID=your_client_id
TIDAL_CLIENT_SECRET=your_client_secret
Note: Tidal integration is entirely optional. trackwatch works perfectly fine without it, using metadata and album art from your media player (playerctl).
Controls
q or Esc - Quit the application
How It Works
- Player Detection: Uses
playerctl to monitor any MPRIS2-compatible media player
- Metadata Enrichment: Fetches additional data from Tidal API when configured (optional)
- Album Art Processing: Downloads and converts images to 30x30 pixelated format
- Color Extraction: Uses k-means clustering in LAB color space for palette generation
- Lyrics Fetching: Downloads from LRCLIB API with intelligent caching
- UI Rendering: Updates every 500ms with smooth animations and color transitions
Architecture
- Two-thread model: Main thread for UI, background thread for data fetching
- Shared state: Thread-safe communication via
Arc<Mutex<App>>
- Hybrid async/sync: Synchronous playerctl polling with async API calls
- Graceful degradation: Falls back to basic metadata when services unavailable
Building from Source
# Development build
cargo build
# Run with debug output
RUST_LOG=debug cargo run
# Run tests
cargo test
# Generate documentation
cargo doc --open
CI/CD
This project uses GitHub Actions for continuous integration and deployment:
Automated Checks
- Code Formatting: Enforces consistent style with
cargo fmt
- Linting: Catches common mistakes with
cargo clippy
- Testing: Runs the full test suite (65+ tests)
- Code Coverage: Tracks test coverage with Codecov
- Cross-platform Builds: Builds for x86_64 and aarch64 Linux
Release Process
The CI pipeline automatically:
- Runs all quality checks on every push/PR
- Generates code coverage reports
- Creates release artifacts for multiple architectures
- Caches dependencies for faster builds
Running CI Locally
You can run the same checks locally before pushing:
# Format code
cargo fmt
# Run linter
cargo clippy -- -D warnings
# Run tests with coverage
cargo install cargo-tarpaulin
cargo tarpaulin --out Xml
# Build release binary
cargo build --release
Cache Location
- Images:
~/.cache/trackwatch/
- Lyrics:
~/.cache/trackwatch/lyrics/
License
MIT
Acknowledgments