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.
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.lyricside-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 (
dkey) to inspect track metadata and lyric sources - Minimal, distraction-free UI
brew install index-null/tap/lyricscurl -fsSL https://raw.githubusercontent.com/index-null/cmus-lyric/master/install.sh | bashOr install to a custom directory:
INSTALL_DIR=~/.local/bin curl -fsSL https://raw.githubusercontent.com/index-null/cmus-lyric/master/install.sh | bashgo install github.com/index-null/cmus-lyric/cmd/lyrics@latestDownload 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/lyricsgit 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/- cmus music player (must be running)
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 |
- Extract embedded lyrics from the audio file (ID3 USLT / Vorbis Comment)
- Look for
<filename>.lrcor<filename>.lyricnext to the audio file - If a
.t.lrc/.t.lyricfile 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
.lrcand cache- Duration tolerance: ±2 seconds when matching tracks by duration
Display the album cover of the current track:
lyrics coverCover 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)
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
# First time: install git hooks & verify toolchain (one-time)
task setup
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 v2.x. Install with brew install golangci-lint or other methods.
task setup installs lefthook git hooks (pre-commit: fmt+lint+build, pre-push: lint+test). Hooks prevent pushing code that would fail CI — they mirror the same checks that run on GitHub.
Releases are fully automated via GitHub Actions. To create a new release:
git tag v0.1.0
git push origin v0.1.0This 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

