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.
- π¨ 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
- Compact View: Limit visible lyrics with
- π§ Pipe Mode: Stream current lyrics to stdout for integration with status bars and scripts
- π€ Karaoke Mode: Per-word highlighting synchronized with playback (Musixmatch Richsync)
- π 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).
- π§ 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
- Rust toolchain (1.70+): Install from rustup.rs
- Linux with D-Bus support
- MPRIS-compatible media player
- playerctld
# 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# 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| 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 |
# 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 moduleexport LYRIC_PROVIDERS="lrclib,musixmatch"
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
| 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.
The database feature provides persistent SQLite-based lyrics caching for improved performance and offline access.
# Create cache directory
mkdir -p ~/.local/share/lyricsmpris
# Run with database enabled
lyricsmpris --database ~/.local/share/lyricsmpris/cache.db- 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
The database uses SQLite with indexed lookups for efficient storage and retrieval:
CREATE TABLE lyrics (
artist TEXT NOT NULL,
title TEXT NOT NULL,
album TEXT NOT NULL,
duration REAL,
format TEXT NOT NULL,
raw_lyrics BLOB NOT NULL
);
CREATE INDEX idx_lookup ON lyrics(artist, title, album);raw_lyrics is stored as a Zstd-compressed blob. It is transparently decompressed when reading from the cache.
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
| artist | title | album | duration | format | raw_lyrics |
|---|---|---|---|---|---|
| arctic monkeys | do i wanna know? | am | 272.0 | richsync | [{"ts":29.26,"te":31.597,...}] |
Note:
raw_lyricsis shown above decompressed for readability.
Note: Artist, title, and album are normalized (lowercase, trimmed) for case-insensitive matching.
- β‘ 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
Any MPRIS-compatible player works, including:
- Spotify (official client)
- Spotify (spotifyd, spotify-tui)
- VLC Media Player
- mpv
- Audacious
- Clementine
- Rhythmbox
- And many more...
Ignore specific players if needed:
# Block web browsers and unwanted players
lyricsmpris --block chromium,firefox# 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",
}- 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
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
- 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
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- Enable database: Use
--databaseto reduce API latency - Limit providers: Specify only needed providers with
--providers - Check player: Some MPRIS implementations send excessive updates
- 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
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
# 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 --checkSee the LICENSE file for details.
- 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
- 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
