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:
The token can come from several places. Precedence, highest first:
--tokenCLI flagMUSIXMATCH_TOKENenvironment variableMXLRC_API_TOKENenvironment variable (lower-precedence alias)[api] tokenin 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:
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:
Notes:
- The lyric file is written next to each audio file, so
-o/--outdiris ignored in directory mode. -d/--depthlimits recursion depth (default100);-d 0scans only the given directory.--upgradere-fetches tracks that previously produced a.txt(unsynced) file, to promote them to.lrconce synced lyrics become available. Instrumental.txtfiles are excluded from upgrade; use--updateto 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:
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:
Create a webhook-scoped key for it:
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:
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.
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; returns200whenever the server is accepting requests (unauthenticated).GET /readyz- readiness; returns200when the database is reachable,503when it is not (unauthenticated).GET /api/v1/status- a queue summary grouped by status; requires anadmin-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¶
401is usually throttling, not a dead token. A bare401most often means the request was throttled, not that the credential expired. This is measured, not assumed: a token that was working began returning401after a few closely spaced requests, then worked normally again later. So the first thing to try is slowing down (raiseMXLRC_API_COOLDOWN), not re-provisioning. A genuinely finished credential is reported differently, and canticle handles that case itself by obtaining a replacement and retrying. If401s persist across a long quiet period, then re-check the precedence: a--tokenflag 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 inqueue deferred, notqueue failed. This is not a failure; the row waits out a cooldown and re-checks itself later. - Unraid
/mnt/userwatcher 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 to0. Note the watcher switch isMXLRCGO_WATCH_ENABLED(theMXLRCGO_prefix, notMXLRC_).
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.