cmus-lyric
English | 中文
A terminal-based synced lyrics viewer for cmus, built with Bubble Tea.
Inspired by pekrockstar/cmus-lyric, rewritten from scratch with a modern Go stack.
Overview
cmus-lyric connects to your running cmus instance via Unix socket (with cmus-remote fallback), reads the current track, and displays time-synced lyrics in a beautiful TUI. It resolves lyrics from multiple sources — embedded audio tags, local .lrc files, a disk cache, and online APIs — all fetched asynchronously without blocking the UI.
Features:
- Real-time synced lyric scrolling with highlight
- Auto-fetch from LRCLIB and Netease Music (non-blocking)
- Translation lyrics support (
.t.lrc / .t.lyric side-by-side)
- Embedded lyrics extraction from audio files (ID3/Vorbis Comment)
- Album cover display (
lyrics cover)
- Lyrics caching (location determined by
os.UserCacheDir(), e.g. ~/Library/Caches/cmus-lyric/ on macOS, ~/.cache/cmus-lyric/ on Linux) for offline and read-only directories
- Duration tolerance (±2s) for better lyric matching
- Unix socket IPC for low-overhead cmus communication
- GBK/UTF-8 auto-detection
- Progress bar and playback status
- Debug mode (
d key) to inspect track metadata and lyric sources
- Minimal, distraction-free UI
Install
Homebrew (macOS / Linux)
brew install index-null/tap/lyrics
Shell script
curl -fsSL https://raw.githubusercontent.com/index-null/cmus-lyric/master/install.sh | bash
Or install to a custom directory:
INSTALL_DIR=~/.local/bin curl -fsSL https://raw.githubusercontent.com/index-null/cmus-lyric/master/install.sh | bash
Go
go install github.com/index-null/cmus-lyric/cmd/lyrics@latest
Manual download
Download the binary for your platform from the Releases page, extract and move to your PATH:
tar xzf cmus-lyric_*_darwin_arm64.tar.gz
sudo install -m 755 lyrics /usr/local/bin/lyrics
From source
git clone https://github.com/index-null/cmus-lyric.git
cd cmus-lyric
task install # or: go build -o lyrics ./cmd/lyrics && sudo mv lyrics /usr/local/bin/
Prerequisites
- cmus music player (must be running)
Usage
Start cmus and play a song, then in another terminal:
lyrics
| Key |
Action |
q Ctrl+C |
Quit |
? |
Toggle help |
d |
Toggle debug |
r |
Refetch lyrics |
How lyrics are resolved
- Extract embedded lyrics from the audio file (ID3 USLT / Vorbis Comment)
- Look for
<filename>.lrc or <filename>.lyric next to the audio file
- If a
.t.lrc / .t.lyric file exists alongside, translation lines are shown below each lyric line
- Check the local cache (location determined by
os.UserCacheDir(), e.g. ~/Library/Caches/cmus-lyric/ on macOS, ~/.cache/cmus-lyric/ on Linux)
- If nothing is found, fetch from LRCLIB (preferred) then Netease Music, save as
.lrc and cache
- Duration tolerance: ±2 seconds when matching tracks by duration
Album cover
Display the album cover of the current track:
lyrics cover
Cover is fetched from:
- Embedded album art in audio file
- Local cache (location determined by
os.UserCacheDir(), e.g. ~/Library/Caches/cmus-lyric/ on macOS, ~/.cache/cmus-lyric/ on Linux)
- Netease Music API (auto-saved to cache)
Project Structure
cmus-lyric/
├── cmd/lyrics/ # Application entry point
├── internal/
│ ├── cmus/ # cmus IPC (Unix socket + exec fallback)
│ ├── cover/ # Album cover display
│ ├── lyric/ # Lyric loading, parsing, fetching, caching
│ └── player/ # Bubble Tea model, view, styles
├── .github/workflows/ # CI/CD (auto-release on tag)
├── Taskfile.yml # Build tasks
├── .golangci.yml # Linter config (v2)
├── lefthook.yml # Git hooks (fmt + lint + build + test)
├── .goreleaser.yaml # Release config
├── install.sh # One-line install script
└── go.mod
Development
task build # Build binary to bin/
task run # Build and run
task lint # Run golangci-lint
task test # Run tests
task check # Full quality check (tidy + lint + test)
[!NOTE]
Linting requires golangci-lint. Install with brew install golangci-lint or see the docs.
Release
Releases are fully automated via GitHub Actions. To create a new release:
git tag v0.1.0
git push origin v0.1.0
This triggers the workflow which:
- Builds binaries for linux/darwin x amd64/arm64
- Creates a GitHub Release with checksums
- Updates the Homebrew tap formula
[!TIP]
To preview a release locally: goreleaser release --snapshot --clean