Skip to content

Getting Started

Canticle fetches synced lyrics from Musixmatch and saves them as .lrc files (falling back to .txt for unsynced lyrics or instrumental markers). This guide gets you from nothing to working lyrics, then points you at the reference pages for detail.

Which path is for you?

  • Just trying it out? Fetch one song from the command line. Start at First fetch.
  • Have a music library on disk? Point the tool at a folder and it writes a lyric file next to each track. See Directory mode.
  • Use Lidarr, or run containers? Run it as a long-lived service that accepts Lidarr webhooks and scans your libraries on a schedule. See Daemon / serve. If you do not know what Lidarr is, you probably do not need it.

Serve mode obtains a Musixmatch token on its own; the one-shot fetch CLI needs one supplied.

Get a Musixmatch token

In serve mode, a Musixmatch API token is optional. On first run canticle requests one automatically and stores it in its encrypted secret store, then reuses that stored token on every later start. For most installs there is nothing to do here.

The one-shot fetch CLI keeps no state and has no secret store, so it cannot save a token for reuse. It still needs one supplied explicitly, via --token, MUSIXMATCH_TOKEN, or a config file.

The token is a long opaque string (it is not your Musixmatch account password).

You may still want to supply your own, for example if you already have one or you are running somewhere the automatic request is refused. A token you supply always takes precedence and is never overwritten.

Supplying a token you already have

The quickest way to provision it for a shell session:

export MUSIXMATCH_TOKEN=YOUR_TOKEN

The token can come from several places. Precedence, highest first:

  1. --token CLI flag
  2. MUSIXMATCH_TOKEN environment variable
  3. MXLRC_API_TOKEN environment variable (lower-precedence alias)
  4. [api] token in the TOML config file

See Configuration for the full token and config-precedence detail.

First fetch (one-shot)

With the token exported, fetch a single song. The query is artist,title - a comma, no spaces:

canticle adele,hello

On success, a lyric file is written to the current directory (or to the directory you pass with -o/--outdir). What you get depends on what Musixmatch has:

  • .lrc - synced lyrics, with per-line [MM:SS.cc] timestamps. This is the goal.
  • .txt - unsynced (plain) lyrics, or an instrumental marker (♪ Instrumental ♪) when the track has no words.

A .txt result is not a failure. It means synced lyrics were not available, so the best available content was written instead. If synced lyrics appear later, you can promote the file (see --upgrade below). Note: if the file is an instrumental marker (♪ Instrumental ♪), it is excluded from --upgrade promotion - --update is the only flag that forces a re-fetch of instrumental markers.

For multiple songs, a text-file batch, and every flag, see the CLI Reference.

Directory mode

Point the tool at a folder and it walks the tree, writing a lyric file next to each audio file:

canticle /path/to/music

Notes:

  • The lyric file is written next to each audio file, so -o/--outdir is ignored in directory mode.
  • -d/--depth limits recursion depth (default 100); -d 0 scans only the given directory.
  • --upgrade re-fetches tracks that previously produced a .txt (unsynced) file, to promote them to .lrc once synced lyrics become available. Instrumental .txt files are excluded from upgrade; use --update to force a re-fetch of those.
  • When audio files contain ISRC, MusicBrainz recording ID, or duration tags, the scanner reads them automatically and passes them to Musixmatch to improve match precision - especially useful for albums with tracks that share the same title. See Recording enrichment for controls.

A bare argument that matches an existing directory triggers a recursive scan. That means canticle "Dream Theater" scans a folder named Dream Theater; it is not interpreted as a song query. Use the artist,title form for one-shot fetches.

Test on a single album first to confirm the result before scanning a whole library. See the CLI Reference for the full flag list.

Daemon / serve

For Lidarr or always-on container use, run the HTTP server. It accepts Lidarr webhooks, scans your registered libraries on a schedule, and processes work through a durable queue.

If you installed via a .deb, .rpm, or .apk package, the service is managed with systemctl (or rc-service on Alpine) and stores its data under /var/lib/mxlrcgo-svc. See Native packages in the User Guide before starting.

Register a library, then start the server:

canticle library add /path/to/music --name Music
canticle serve

serve listens on MXLRC_SERVER_ADDR (default 127.0.0.1:3876) unless you pass --listen. Registering and scanning your libraries first is what lets webhooks reuse the exact file paths a scan discovered, so they work even when Lidarr and canticle see the media through different mount paths.

Lidarr webhook

Lidarr posts to:

POST /api/v1/webhooks/lidarr

Create a webhook-scoped key for it:

canticle keys create --name lidarr --scope webhook

The endpoint authenticates the key in one of two ways (the server accepts either):

  • An Authorization: Bearer <key> header.
  • An apikey=<key> query parameter on the request URL (checked first).

Configure whichever your client supports. See the User Guide for path resolution and full webhook behavior.

Docker

The published image is ghcr.io/sydlexius/canticle. It runs the server on container port 50705, sets MXLRC_DOCKER=true automatically (so storage defaults resolve under /config), and honors PUID/PGID for file ownership. Mount your media data parent once (for example to /data):

docker run -d \
  --name canticle \
  -p 50705:50705 \
  -e MUSIXMATCH_TOKEN=YOUR_TOKEN \
  -e MXLRC_WEBHOOK_API_KEY=mxlrc_your_webhook_key \
  -v canticle-config:/config \
  -v /path/to/your/data:/data:rw \
  ghcr.io/sydlexius/canticle:latest

See the User Guide for the full Docker, Compose, and Unraid setup.

Windows

Download the .zip from the releases page, extract canticle.exe, and add it to your PATH. For a quick test:

set MUSIXMATCH_TOKEN=YOUR_TOKEN
canticle.exe serve --listen 127.0.0.1:3876

For an always-on background service, use NSSM to wrap the binary as a Windows service. See the User Guide for the full NSSM setup, environment variable configuration, and data paths.

Verify

Confirm the build and that work is flowing.

canticle --version

For one-shot and directory runs, check that the expected .lrc/.txt files were written.

For serve, the HTTP endpoints report health and status:

  • GET /healthz - liveness; returns 200 whenever the server is accepting requests (unauthenticated).
  • GET /readyz - readiness; returns 200 when the database is reachable, 503 when it is not (unauthenticated).
  • GET /api/v1/status - a queue summary grouped by status; requires an admin-scoped API key.

The inspection subcommands show queue and scan state:

canticle queue list
canticle queue list --status pending --limit 100
canticle scan results
canticle scan results --library Music --status pending

See the User Guide for the full inspection command set.

Troubleshooting

  • 401 is usually throttling, not a dead token. A bare 401 most often means the request was throttled, not that the credential expired. This is measured, not assumed: a token that was working began returning 401 after a few closely spaced requests, then worked normally again later. So the first thing to try is slowing down (raise MXLRC_API_COOLDOWN), not re-provisioning. A genuinely finished credential is reported differently, and canticle handles that case itself by obtaining a replacement and retrying. If 401s persist across a long quiet period, then re-check the precedence: a --token flag or a stale environment variable can silently override the token you think you are using.
  • Rate limiting / circuit breaker. When Musixmatch signals throttling, the worker opens a circuit breaker and pauses dequeuing globally to back off. If you hit this often, raise the request cooldown with MXLRC_API_COOLDOWN (seconds between requests). See Configuration for the cooldown and circuit-breaker variables.
  • Benign miss / deferred. A track Musixmatch has no lyrics for yet lands in queue deferred, not queue failed. This is not a failure; the row waits out a cooldown and re-checks itself later.
  • Unraid /mnt/user watcher caveat. The optional filesystem watcher relies on inotify events, which Unraid /mnt/user (FUSE/shfs) mounts often do not deliver into the container. Keep the periodic scan as the source of truth there; do not set the scan interval to 0. Note the watcher switch is MXLRCGO_WATCH_ENABLED (the MXLRCGO_ prefix, not MXLRC_).

Next steps

  • CLI Reference - every subcommand and flag.
  • User Guide - the webhook server, Docker/Unraid, the filesystem watcher, and inspection commands.
  • Configuration - the full environment-variable table, TOML keys, token precedence, and XDG paths.
  • Developer Guide - building from source, the make targets, and design decisions.

Advanced (all shipped in v1.4.0; see Configuration to enable): the language/script guard that rejects wrong-language matches, the petitlyrics provider as an alternative to Musixmatch, and bilingual_output for songs with a translation.