Skip to main content

lyricsooo

Live, synced song lyrics — rendered as block letters right in your terminal.

CI License: MIT Python Platform

lyrics-tool is a small, cross-platform suite that fetches synced lyrics, prepares them into phrase- or word-level timing, and renders them live in the terminal as block letters, synchronized to whatever your media player is playing.

It follows your player natively on Linux (MPRIS / playerctl), Windows (System Media Transport Controls) and macOS (nowplaying-cli) — one code path, one snapshot, the right backend picked automatically for your OS. Works with Spotify and any local player (mpv, VLC, rhythmbox, Apple Music, …); auto-follows whatever is playing, or pin it with --player.


Contents


Quick start

Once installed (see Installation), there is nothing to configure — every command falls back to a shared default location under your data directory, so the whole flow works with zero flags:

lyricsooo-fetch --audio-dir ~/Music   # 1. download synced lyrics for your library
lyricsooo-cook                         # 2. prepare them (split long lines, etc.)
lyricsooo                              # 3. play — synced to your current track

Or skip steps 1–2 entirely: just run lyricsooo and start playing music. Missing lyrics are fetched and cached on the fly as each track plays.

lyricsooo            # just works — fetches lyrics live as songs play

The three commands

Command What it does
lyricsooo Live, terminal block-letter visualizer synced to the active player.
lyricsooo-fetch Batch-download synced lyrics from LRCLIB / syncedlyrics.
lyricsooo-cook Split long phrases; optionally convert to word-level (.wlrc).

Every command supports --help.

Previews

Rendered straight from the real engine — regenerate any time with python tools/generate_previews.py.

Feature & Description Visual Preview
Terminal Lyrics Visualizer

The core visualizer rendering block-letter lyrics in the terminal. Custom fonts, dynamic resizing, ambient floating notes, and real-time player synchronization.
Terminal lyric visualizer
Phrase-Level Playback

Tracks the playing song line by line, matching vocal delivery. A phase-locked clock cancels player lag so lines land with the vocal.
Phrase-level lyric rendering
Glitch Track Announce

Every track change opens with a short glitch burst — band tears, scrambling letters, chromatic flicker — that resolves into the album info card.
Glitch track switching
Dynamic Colour Tinting

Extracts the dominant colour from the album artwork and tints the now-playing card and lyrics to match the song — or follow your desktop theme instead.
Album-art colour tinting
Animated Ad-Break Screen

Detects when Spotify plays an advertisement and shows an animated idle card, resuming lyrics immediately on the next song.
Animated ad break screen

Features

  • Cross-platform live sync — follows your player on Linux, Windows and macOS through one pluggable backend layer; the right one is auto-selected. See Platform support.
  • Phrase and word-level sync — .lrc (per line) and .wlrc (per word).
  • On-the-beat timing — a phase-locked playback clock continuously eases onto the player's timeline and cancels reported-position lag, so lines land with the vocal, not behind it. Nudge live with -/+ (saved), or set --offset.
  • Four line-reveal effects — standard (instant), typewriter (char-by-char with a blinking cursor), fade (soft per-line fade-in) and glow (the active line gently breathes). Pick with --reveal, or open the themed --select picker to choose effect + style before you play.
  • Never blocks on the network — lyrics for the playing track are fetched in the background, so the display stays responsive and track switches register instantly. An animated finding lyrics screen shows while it searches; a calm no synced lyrics screen if a song genuinely has none.
  • Universal colour sources — by default the card is painted in the album cover's dominant colour and the lyrics tinted with a softer accent, but the source is pluggable (--color-source): follow pywal, caelestia, matugen, a fixed:#rrggbb accent, or file:PATH to track any JSON palette live.
  • Auto-follow any player — Spotify and local players out of the box; pin with --player spotify/mpv. Prefers whatever is actually playing, and skips web browsers and chat/telephony apps by default, so a YouTube lecture or a Telegram voice message can't hijack the lyrics (--ignore-player to customise).
  • Glitch track announce + ad-break screen + floating music notes — ambient polish that keeps the view alive; disable with --no-notes.
  • Responsive, diffed renderer — block letters wrap to fit and fall back to plain text when the window is tiny; repaints only when something changes, so a held line costs ~no CPU and never flickers.
  • Offline word mode and custom fonts (supply your own block font via JSON).

Platform support

Platform Live visualizer (lyricsooo) Offline tools (-fetch / -cook) Backend
Linux / BSD ✅ full (art + local files) ✅ playerctl (MPRIS)
Windows 10/11 ✅ ✅ smtc (System Media Transport Controls, [windows] extra)
macOS ✅¹ ✅ nowplaying-cli
WSL ✅ (as Linux) ✅ playerctl

The backend is auto-detected; override with --player-backend or $LYRICSOOO_PLAYER_BACKEND. A truecolor, UTF-8 terminal is recommended everywhere (Kitty, Alacritty, WezTerm, Windows Terminal, iTerm2, …); on Windows the console is switched into ANSI/VT mode automatically.

¹ macOS live sync depends on the nowplaying-cli helper; on macOS 15.4+ Apple restricted the underlying framework, so availability can vary by OS version and player. Album-art tinting works on Linux (MPRIS art URL) and macOS (nowplaying-cli artwork); on Windows it's best-effort from the SMTC thumbnail. If a track exposes no art, colour falls back to none — a theme source (--color-source pywal / caelestia / fixed:#…) always works.

Installation

Universal — works on every OS and distro

lyrics-tool is a pure-Python package, so pipx (or uv) is the simplest install anywhere:

# From PyPI
pipx install lyrics-tool          # …or:  uv tool install lyrics-tool

# Bleeding edge — straight from GitHub main
pipx install "git+https://github.com/hamza-abdelmoumene/lyrics-tool.git"

Then open a new terminal and run lyricsooo --help. The lyricsooo, lyricsooo-fetch, and lyricsooo-cook commands are now on your PATH.

Optional system dependencies

Only needed for the corresponding feature; the tool degrades gracefully without them.

Linux — live sync + audio durations
# Debian / Ubuntu
sudo apt install -y playerctl ffmpeg pipx && pipx ensurepath
# Arch
sudo pacman -S --needed playerctl ffmpeg python-pipx && pipx ensurepath
# Fedora
sudo dnf install -y playerctl ffmpeg pipx && pipx ensurepath

playerctl powers the live visualizer; ffmpeg (ffprobe) reads audio durations when processing.

Windows — native live sync

Install the System Media Transport Controls backend with the [windows] extra:

pipx install "lyrics-tool[windows]"
# or from a local clone:  pipx install ".[windows]"

That pulls in winsdk. No playerctl needed — it reads Windows' global media session directly. WSL users can instead follow the Linux steps for the full MPRIS experience.

macOS — live sync helper
brew install nowplaying-cli      # enables live sync
brew install ffmpeg              # optional, for audio durations
pipx install lyrics-tool

Distro packages

Method Command
Arch (AUR) — latest release yay -S lyrics-tool  (or paru, or makepkg -si on packaging/aur)
Arch (AUR) — build from main yay -S lyrics-tool-git

From source (development)

git clone https://github.com/hamza-abdelmoumene/lyrics-tool.git
cd lyrics-tool
pip install -e '.[dev]'

Optional — high-accuracy word timing. Per-word onset detection uses librosa (heavy, opt-in) — add the [onset] extra: pipx install "lyrics-tool[onset]".

Player backends

lyricsooo reads the active player through the backend that fits your OS. It's picked automatically, but you can force one:

lyricsooo --player-backend playerctl        # Linux / MPRIS
lyricsooo --player-backend smtc             # Windows media session
lyricsooo --player-backend nowplaying-cli   # macOS
export LYRICSOOO_PLAYER_BACKEND=smtc        # …or pin it in your shell rc

The active backend is shown in the startup banner. If your platform has no backend available, the offline lyricsooo-fetch / lyricsooo-cook tools still work and the visualizer shows its idle screen with a hint. Adding a new platform is a self-contained change — see CONTRIBUTING.

Colour sources

Where the lyric tint and now-playing card get their colour is fully pluggable. Pick a source with --color-source (or set $LYRICSOOO_COLOR_SOURCE):

Source Colours follow Needs
art (default) the current track's album art Pillow + a player/OS that exposes art (Linux, macOS; best-effort on Windows)
none terminal default foreground —
pywal ~/.cache/wal/colors.json you already run wal/pywal
caelestia the Caelestia desktop scheme Caelestia
matugen ~/.cache/matugen/colors.json matugen
fixed:#RRGGBB one static accent you choose —
file:PATH any JSON palette (configurable key map) —
lyricsooo --color-source pywal            # match your wal palette, live
lyricsooo --color-source fixed:#89b4fa    # one fixed accent (great on Win/macOS)
export LYRICSOOO_COLOR_SOURCE=caelestia   # …or make it the default everywhere

Theme-file sources update live — retheme your desktop and the lyrics recolour under your feet, no restart.

Usage

# 1. Fetch lyrics for your library
lyricsooo-fetch --audio-dir ~/Music

# 2. Prepare: split long phrases (add --wlrc for word-level)
lyricsooo-cook --no-require-audio

# 3. Visualize, synced to the current track
lyricsooo                       # phrase mode
lyricsooo --wlrc                # word mode
lyricsooo --reveal glow         # breathing active line
lyricsooo --player spotify      # pin to one player
lyricsooo --select              # pick effect + style interactively

Useful flags: --player <name> to pin a player, --player-backend <name> to force a backend, --reveal {standard,typewriter,fade,glow}, --select for the picker, --color-source <src>, --no-cover-color / --no-notes to strip effects, --offset <sec> to nudge sync (positive = earlier), --banner-hold <sec> for the title-card dwell. Press Ctrl+C to exit.

How your lyrics are stored

Unless you pass explicit --*-dir flags, everything lives under one root (honouring $XDG_DATA_HOME, or the platform equivalent):

~/.local/share/lyrics-tool/
└── lyrics/
    ├── raw/         # lyricsooo-fetch downloads here  →  lyricsooo-cook's input
    └── processed/   # lyricsooo-cook writes here      →  lyricsooo reads here

Live-nudged sync offsets are kept separately under ~/.local/state/lyrics-tool/. These directories are created automatically — you never have to mkdir anything.

Configuration

Processing, visualizer and colour defaults can be set in a YAML file (see src/lyrics_tool/config_example.yaml) and passed with --config path/to/config.yaml. CLI flags override the file.

Troubleshooting

Symptom Cause & fix
lyricsooo: command not found Your pipx/uv bin dir isn't on PATH. Run pipx ensurepath, then open a new terminal.
"no live-sync backend available" note Install the backend for your OS: playerctl (Linux), pipx install 'lyrics-tool[windows]' (Windows), brew install nowplaying-cli (macOS).
Lyrics don't move / no sync A player must be running. Check the startup banner's backend line; try pinning with --player spotify.
no synced lyrics for a track That song has no synced lyrics on LRCLIB — playback continues normally.
Block letters look like boxes / no colour Use a truecolor, UTF-8 terminal (Kitty, Alacritty, WezTerm, Windows Terminal, iTerm2, …).
Cover tint missing Some tracks/players expose no art (esp. streamed audio on Windows). Use --color-source fixed:#RRGGBB or a theme source (pywal/caelestia/matugen) instead.
ffprobe: not found when processing Install ffmpeg, or run lyricsooo-cook --no-require-audio to skip duration lookups.

Footprint

It's light — a sleep-driven loop, not a busy renderer. The diff renderer only repaints when the lyric line, the notes, or the terminal size actually change, and playback position is extrapolated from the monotonic clock instead of polling the player every frame.

Measured on Linux / CPython 3.14, one lyricsooo process during continuous playback:

Metric Idle / paused 80×24 terminal Large terminal (≈200×50)
Memory (RSS) ~30 MiB ~33 MiB ~33 MiB
CPU ~0% ~1% of one core ~3% of one core

CPU scales with terminal size and --refresh-rate; memory is flat. --no-notes trims steady-state CPU further. Numbers are approximate and hardware-dependent.

Development & contributing

pip install -e '.[dev]'
pytest                       # full suite — no playerctl, audio, or network needed
ruff check .                 # lint
mypy src                     # types (informational)

The test suite drives the visualizer loop with a stubbed player and unit-tests every OS backend through fakes, so it runs identically on Linux, Windows and macOS. See CONTRIBUTING.md for the full workflow and how to add a player backend, SECURITY.md for the security model and reporting, and CHANGELOG.md for release notes. By participating you agree to the Code of Conduct.

Uninstall

pipx uninstall lyrics-tool
rm -rf ~/.local/share/lyrics-tool ~/.local/state/lyrics-tool   # cached lyrics (optional)

Credits

Forked from tacos-terminal-lyrics; restructured into an installable, cross-platform package with a pluggable backend layer, a responsive/diffed renderer, offline word-mode, and a test suite.

License

MIT — see LICENSE.

Metadata

Release files for lyrics-tool 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lyrics-tool 0.2.3
File Size Uploaded
lyrics_tool-0.2.3.tar.gz 101.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lyrics-tool 0.2.3
File Interpreter ABI Platform
lyrics_tool-0.2.3-py3-none-any.whl Python 3 none any Details

Total release size: 189.9 kB

Release files / lyrics_tool-0.2.3.tar.gz

Download URL lyrics_tool-0.2.3.tar.gz
Size 101.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a81a0d130e7859edf0c102ea30bef91e3a452246fc50a640e3d5092b25ef9aef
BLAKE2b-256 checksum
How to use checksums
41953bb2a146e624a7cfb5702d44d4486741e88937c2289694d5abad1cea903a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release files / lyrics_tool-0.2.3-py3-none-any.whl

Download URL lyrics_tool-0.2.3-py3-none-any.whl
Size 88.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6162f524f7b5887f808a3d6bb8e22f7bff83106774b837b6a9436d007f86bf22
BLAKE2b-256 checksum
How to use checksums
550205010e8d5bd8bb60ac4fade082db6da61c3cc4bf9e48692e3ef86b3d2b31
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.4

2 release files

This release

0.2.3 This release

2 release files

0.2.2

2 release files

0.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page