LyricsMPRIS-Rust
A lightweight, high-performance lyrics viewer for Linux that integrates seamlessly with MPRIS-compatible media players. Features real-time synchronized lyrics with optional karaoke-style word highlighting, local caching, and multiple provider support.
β¨ Features
Display Modes
-
π¨ Modern TUI: Beautiful terminal interface with centered lyrics and smooth scrolling
-
Compact View: Limit visible lyrics with
--visible-linesfor small terminals -
Manual Scrolling: Browse lyrics with arrow keys when paused
-
π§ Pipe Mode: Stream current lyrics to stdout for integration with status bars and scripts
-
π€ Karaoke Mode: Per-word highlighting synchronized with playback (Musixmatch Richsync)
Lyrics Sources
- π LRCLIB: Community-maintainedβ¦
LyricsMPRIS-Rust
A lightweight, high-performance lyrics viewer for Linux that integrates seamlessly with MPRIS-compatible media players. Features real-time synchronized lyrics with optional karaoke-style word highlighting, local caching, and multiple provider support.
β¨ Features
Display Modes
-
π¨ Modern TUI: Beautiful terminal interface with centered lyrics and smooth scrolling
-
Compact View: Limit visible lyrics with
--visible-linesfor small terminals -
Manual Scrolling: Browse lyrics with arrow keys when paused
-
π§ Pipe Mode: Stream current lyrics to stdout for integration with status bars and scripts
-
π€ Karaoke Mode: Per-word highlighting synchronized with playback (Musixmatch Richsync)
Lyrics Sources
- π LRCLIB: Community-maintained database (returns LRC timestamp format)
- π΅ Musixmatch: Professional lyrics with word-level/line-level timing (JSON formats)
- π Configurable Priority: Set your preferred provider order
- πΎ Local Cache: Optional database for offline access and reduced API calls
Note on Terminology: "LRCLIB" refers to the lrclib.net provider service, while "LRC format" refers to the timestamp standard (
[MM:SS.CC]lyrics) that LRCLIB returns. Musixmatch returns different JSON-based formats (Richsync/Subtitles).
Player Integration
- π§ MPRIS Support: Works with any MPRIS-compatible player (Spotify, VLC, mpv, etc.)
- π« Blocklist: Exclude specific players from monitoring
- β‘ Event-Driven: Efficient architecture with zero polling overhead
π Quick Start
Prerequisites
- Rust toolchain (1.70+): Install from rustup.rs
- Linux with D-Bus support
- MPRIS-compatible media player
- playerctld
Installation
# Clone the repository
git clone https://github.com/BEST8OY/LyricsMPRIS-Rust.git
cd LyricsMPRIS-Rust
# Build release version
cargo build --release
# Binary will be at: ./target/release/lyricsmpris
Basic Usage
# Launch with default settings
./target/release/lyricsmpris
# With local cache for faster loading
./target/release/lyricsmpris --database ~/.local/share/lyricsmpris/cache.db
# Disable karaoke highlighting
./target/release/lyricsmpris --no-karaoke
# Limit visible lyrics to 3 lines (compact mode)
./target/release/lyricsmpris --visible-lines 3
# Pipe mode for scripting
./target/release/lyricsmpris --pipe
βοΈ Configuration
Command Line Options
| Flag | Description | Example |
|---|---|---|
--database PATH | Enable SQLite lyrics cache | --database ~/.local/share/lyricsmpris/cache.db |
--providers LIST | Set provider priority | --providers musixmatch,lrclib |
--visible-lines COUNT | Limit visible lyric blocks (TUI only) | --visible-lines 3 |
--no-karaoke | Disable word-level highlighting | - |
--pipe | Output to stdout instead of TUI | - |
--block LIST | Ignore specific MPRIS services | --block vlc,chromium |
Environment Variables
# Musixmatch user token (required for Musixmatch provider)
export MUSIXMATCH_USERTOKEN="your-token-here"
# Logging configuration (uses tracing crate)
# Levels: error, warn, info, debug, trace
# Logs are OFF by default. Set RUST_LOG to enable:
export RUST_LOG=warn # Show warnings and errors
export RUST_LOG=info # Show info, warnings and errors
export RUST_LOG=debug # Show debug logs
export RUST_LOG=lyricsmpris::lyrics=trace # Trace specific module
Default provider list (if βproviders not specified)
export LYRIC_PROVIDERS="lrclib,musixmatch"
Getting a Musixmatch Token
Method 1: Curators Settings (Easiest)
- Go to the Musixmatch Curators Settings page
- Login if prompted
- Scroll down to the bottom of the page
- Click "Copy debug info"
- Paste the debug info into a text editor
- Find the
UserTokenin the copied text - Copy that token and set it as
MUSIXMATCH_USERTOKEN
TUI Keyboard Shortcuts
| Key | Action |
|---|---|
k | Toggle karaoke highlighting |
β (Up) | Scroll up one lyric (when paused) |
β (Down) | Scroll down one lyric (when paused) |
q or Esc | Quit application |
Note: Scrolling with arrow keys only works when playback is paused. When you resume playback, the view automatically resets to follow the current position.
πΎ Local Database
The database feature provides persistent SQLite-based lyrics caching for improved performance and offline access.
Setup
# Create cache directory
mkdir -p ~/.local/share/lyricsmpris
# Run with database enabled
lyricsmpris --database ~/.local/share/lyricsmpris/cache.db
How It Works
- First Play: Lyrics fetched from providers β stored in SQLite database
- Subsequent Plays: Lyrics loaded instantly from indexed database (no API calls)
- Auto-Persist: Database automatically commits to disk after each fetch
Storage Format
The database uses SQLite with indexed lookups for efficient storage and retrieval:
Schema
CREATE TABLE lyrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
artist TEXT NOT NULL,
title TEXT NOT NULL,
album TEXT NOT NULL,
duration REAL,
format TEXT NOT NULL,
raw_lyrics TEXT NOT NULL
);
CREATE INDEX idx_lookup ON lyrics(artist, title, album);
Format Types
Lyrics are stored in their original format by provider:
lrclib: LRC timestamp format ([MM:SS.CC]lyrics text)richsync: Musixmatch JSON with word-level timing datasubtitles: Musixmatch JSON with line-level timing data
Example Stored Entry
| artist | title | album | duration | format | raw_lyrics |
|---|---|---|---|---|---|
| arctic monkeys | do i wanna know? | am | 272.0 | richsync | [{"ts":29.26,"te":31.597,...}] |
Note: Artist, title, and album are normalized (lowercase, trimmed) for case-insensitive matching.
Benefits
- β‘ Instant Loading: Indexed lookups provide sub-millisecond retrieval
- π Offline Mode: No internet required for cached songs
- π Reduced API Calls: Be kind to provider rate limits
- πͺ Provider Independence: Lyrics persist even if APIs change
- π§ Minimal Memory: SQLite loads only requested rows, not entire database
- π Fast Queries: Indexed by artist/title/album for efficient lookups
- π WAL Mode: Write-Ahead Logging for better concurrency
π MPRIS Integration
Supported Players
Any MPRIS-compatible player works, including:
- Spotify (official client)
- Spotify (spotifyd, spotify-tui)
- VLC Media Player
- mpv
- Audacious
- Clementine
- Rhythmbox
- And many more...
Player Blocklist
Ignore specific players if needed:
# Block web browsers and unwanted players
lyricsmpris --block chromium,firefox
π§ Advanced Usage
Integration with Status Bars
# Polybar module example
[module/lyrics]
type = custom/script
exec = ~/bin/lyricsmpris --pipe
tail = true
# Waybar module example
"custom/lyrics": {
"exec": "lyricsmpris --pipe",
"return-type": "text",
}
ποΈ Architecture
Design Principles
- Event-Driven: No polling, minimal CPU usage
- Zero-Copy: Efficient Arc-based state sharing
- Async First: Tokio-powered concurrent operations
- Type Safety: Leverages Rustβs type system for correctness
Module Overview
src/
βββ lyrics/ # Lyrics providers and parsing
β βββ providers/ # LRCLIB, Musixmatch implementations
β βββ database.rs # Local cache management
β βββ parse.rs # LRCLIB, Richsync, Subtitle parsers
β βββ similarity.rs # Fuzzy matching for search results
βββ mpris/ # D-Bus/MPRIS integration
β βββ events.rs # Signal handler for player changes
β βββ metadata.rs # Track info extraction
β βββ playback.rs # Position tracking
βββ ui/ # Display backends
β βββ modern.rs # TUI implementation
β βββ pipe.rs # Stdout mode
βββ event.rs # Event processing and coordination
βββ pool.rs # Event loop management
βββ state.rs # Shared application state
π Troubleshooting
No Lyrics Found
- Check provider order: Try
--providers musixmatch,lrclib - Verify Musixmatch token: Ensure
MUSIXMATCH_USERTOKENis set - Enable debug logging: Use
RUST_LOG=debugto see detailed logs - Check metadata: Some players may not provide complete track info
Debugging
Use the RUST_LOG environment variable for diagnostics:
# Show all debug information
RUST_LOG=debug lyricsmpris
# Only show errors
RUST_LOG=error lyricsmpris
# Debug specific components
RUST_LOG=lyricsmpris::lyrics=debug lyricsmpris
RUST_LOG=lyricsmpris::mpris=trace lyricsmpris
# Multiple modules with different levels
RUST_LOG=lyricsmpris::lyrics=debug,lyricsmpris::database=trace lyricsmpris
# Save logs to file
RUST_LOG=debug lyricsmpris 2> debug.log
Performance Issues
- Enable database: Use
--databaseto reduce API latency - Limit providers: Specify only needed providers with
--providers - Check player: Some MPRIS implementations send excessive updates
Karaoke Not Working
- Provider limitation: Only Musixmatch Richsync supports word-level timing
- Track availability: Not all songs have Richsync data
- Fallback: App will show line-level sync if Richsync unavailable
π€ Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Test thoroughly (both TUI and pipe modes)
- Commit with clear messages (
git commit -m 'Add amazing feature') - Push to your fork (
git push origin feature/amazing-feature) - Open a Pull Request
Development Setup
# Run in debug mode
cargo run
# Run with debug logging
RUST_LOG=debug cargo run
# Run with trace logging for specific module
RUST_LOG=lyricsmpris::lyrics=trace cargo run
# Run tests
cargo test
# Check code quality
cargo clippy
cargo fmt --check
π License
See the LICENSE file for details.
π Acknowledgements
- Community: Thanks to all contributors and users
- Dependencies: Built with excellent Rust crates (see Cargo.toml)
- Providers: LRCLIB and Musixmatch for lyrics data
- Development: Created with VS Code and GitHub Copilot assistance
π Project Stats
- Language: Rust π¦
- Architecture: Event-driven, async/await
- Binary Size: ~15MB (release, stripped)
- Memory Usage: ~20MB typical
- CPU Usage: ~0% typical
- Dependencies: Minimal, security-conscious selection
Made with β€οΈ for the Linux audio community