Skip to content

Releases: sydlexius/canticle

v1.26.0

Choose a tag to compare

@github-actions github-actions released this 23 Jul 06:04
Immutable release. Only release title and notes can be modified.
v1.26.0
b2a2e70

canticle v1.26.0

Highlights

A repair tool for sidecars an older version got wrong, plus better ranking when a provider offers word-level timing.

Scope a re-fetch to an older batch of sidecars. scan --upgrade --unsynced-before <date> re-fetches only .txt sidecars last modified before a cutoff. When an earlier version wrote a batch of unsynced files badly, a plain --upgrade would re-fetch the entire unsynced population, spending provider requests on files that are already correct and rewriting their timestamps in the process. The cutoff narrows one run to the affected batch. It is refused with --update, which re-fetches every settled .lrc regardless of the cutoff. (#621)

Word-synced results now outrank line-synced ones. When a provider returns word-level timing for a track, it is preferred over a line-level result. The line cues are unchanged and the word detail is additive, so the richer result can never be worse than what it replaces. (#603)

What's changed

New

  • scan --unsynced-before scopes an --upgrade re-fetch to sidecars written before a cutoff (#621)
  • Word-synced provider results rank above line-synced ones (#603)

Bug fixes

  • petitlyrics now uses the structured API instead of a web scrape that had stopped working (#495)
  • Dropped the petitlyrics unsynced fallback retry, which could not return anything the first request would not (#608)
  • The detector circuit breaker keeps its state across an orchestrator rebuild, instead of resetting mid-run (#531)

Maintenance

  • Boundary guard and CLI reference docs for --unsynced-before (#622)
  • Collapsed the two CodeRabbit configs into one (#551)
  • Recorded that the Musixmatch richsync namespace returns nothing on the subtitles endpoint (#611)

Docker: docker pull ghcr.io/sydlexius/canticle:1.26.0

Full changelog: v1.25.0...v1.26.0

v1.25.0

Choose a tag to compare

@github-actions github-actions released this 21 Jul 05:47
Immutable release. Only release title and notes can be modified.
v1.25.0
bc58588

canticle v1.25.0

Highlights

Two serve-mode reliability changes, both aimed at the deferred backlog.

The Musixmatch token now bootstraps and renews itself. Serve mode mints a token when no tier supplies one, persists it to the encrypted secret store, and reuses it across restarts, so a fresh deployment no longer needs a hand-provisioned token. Renewal happens only on the provider's explicit renew signal, never on a bare 401 - a bare 401 is throttling, and renewing on it would burn rate-limited mints during exactly the window they are most likely to be refused. A restart never re-mints. (#554)

Serve mode now sends the same match signals the CLI does. The work queue persists neither duration nor ISRC, so serve-mode fetches were issuing a broader query than fetch for the same track. The worker now re-reads both from the file's tags at fetch time, reaching parity by construction rather than by agreement. Duration is present on effectively every track and ISRC on roughly two in five, so most fetches gain at least one disambiguator. (#584)

What's changed

New

  • Automatic Musixmatch API token bootstrap, persistence and renewal (#554)

Bug fixes

  • Worker re-reads ISRC and duration from tags at fetch time, so serve mode matches the CLI's query (#584)

Maintenance

  • Shared open + tag-read helper behind the three scanner single-file readers (#590)
  • Release-notes section grouping declared in the release config (#596)
  • Removed the manual Musixmatch token-extraction instructions, now that serve mode provisions a token automatically (#597)
  • Documented that the memory MCP must be queried, since spawned subagents never receive its index (#594)

Docker: docker pull ghcr.io/sydlexius/canticle:1.25.0

Full changelog: v1.24.1...v1.25.0

v1.24.1

Choose a tag to compare

@github-actions github-actions released this 21 Jul 01:55
Immutable release. Only release title and notes can be modified.
39fe612

canticle v1.24.1

Two serve-mode fixes.

Bug Fixes

  • The dashboard "Up next" panel no longer goes blank between the worker's processing cycles. The lookahead buffer is now topped up on every dequeue instead of draining to empty and only redrawing on the next claim, so it stays populated whenever work is eligible. (#587)
  • Backfilled album and album_artist onto the older queue rows that predated those columns. The value was already read from the tags into scan_results but never propagated to the work queue, so it was missing from the dashboard and, more importantly, from the q_album Musixmatch match signal for most of the deferred backlog. Runs automatically as a migration on the next start. (#583)

Docker: docker pull ghcr.io/sydlexius/canticle:1.24.1

Full changelog: v1.24.0...v1.24.1

v1.24.0

Choose a tag to compare

@github-actions github-actions released this 21 Jul 00:02
Immutable release. Only release title and notes can be modified.
a1b7d1c

canticle v1.24.0

Highlights

You can now see what the queue will do next, because the dequeue order is finally knowable.

Up next on the dashboard. A new panel lists buffered work in the order the worker will claim it: position, artist, title, album, tier, and time waited. The header pairs the buffered count with the eligible backlog, so a short buffer behind a large pool reads as starvation at a glance; an empty buffer shows counts only. (#572)

A knowable dequeue order. The worker now shuffles a batch of eligible rows once per cycle and serves it in a fixed order, instead of reshuffling on every claim, so the up-next list is truthful. Request composition stays random (anti-scraping intact). Configurable via queue.batch_size (default 10; 0 disables), and DB-backed so a restart keeps the order. (#571)

What's changed

New

  • "Up next" dashboard panel showing buffered work in claim order (#572)
  • Shuffled lookahead buffer for a knowable dequeue order, via queue.batch_size (#571)

Security & dependencies

  • Pinned mbedtls3 to >=3.6.7-r0 to clear Grype-flagged CVEs (#579)

Maintenance

  • Added pull-request templates (#578)

Docker: docker pull ghcr.io/sydlexius/canticle:1.24.0

Full changelog: v1.23.2...v1.24.0

v1.23.2

Choose a tag to compare

@github-actions github-actions released this 20 Jul 20:57
Immutable release. Only release title and notes can be modified.
v1.23.2
7dd797b

canticle v1.23.2

Three fixes. Two close a pair of gaps in how extracted lyrics get reconsidered on a later scan; the third repairs a queue state that a restart could strand.

When canticle writes a lyric sidecar from a track's embedded tags, that sidecar was treated as settled and skipped on every subsequent scan, even when you explicitly asked for a re-fetch. --upgrade would pass over a track whose extracted lyrics were unsynced, so it never got the chance to promote them to synced. And --update, whose whole purpose is refreshing already-settled synced lyrics, would skip a synced .lrc that came from extraction, pinning the track to whatever earlier tooling happened to embed with no supported way to refresh it short of deleting the file by hand. Both are the same defect: a skip that lost track of what the scan flags were asking for. Extracted embedded lyrics are now reconsidered under the flag that should reach them.

The queue fix addresses a state a release could leave behind. When a throttled row was released back to the queue, it returned to pending unconditionally, discarding the status it was claimed from. A deferred row released this way kept its deprioritization but landed in pending, a combination no other path produces. Release now preserves the pre-claim status, so a deferred row stays deferred.

What's changed

Fixed

  • --upgrade now reaches a track whose extracted lyrics are unsynced, instead of skipping it and leaving it unable to be promoted to synced (#574)
  • --update now re-fetches a synced .lrc that was written from embedded tags, rather than pinning the track to the extracted version with no way to refresh it (#575)
  • Releasing a throttled queue row preserves the status it was claimed from, so a deferred row is no longer stranded in pending with its deprioritization still applied (#569)

Docker: docker pull ghcr.io/sydlexius/canticle:1.23.2

Full changelog: v1.23.1...v1.23.2

v1.23.1

Choose a tag to compare

@github-actions github-actions released this 20 Jul 06:52
Immutable release. Only release title and notes can be modified.
490c368

canticle v1.23.1

v1.23.0 said the audio detector's result count would climb several-fold the moment you upgraded. On the dashboard, where you would actually look for it, nothing moved. This release makes that true.

The count lives in two places. The Prometheus metrics read one of them and the dashboard reads the other, and v1.23.0 only corrected the first. So the detector's tile carried on reporting a few hundred results against several thousand real ones, exactly as before the upgrade. The correction now covers both, and arrives with the upgrade rather than waiting on a command nobody knew to run.

On a decent-sized library the detector's tile climbs sharply the first time you start this version, then settles. That is the correction landing, and it does not repeat.

What's changed

Fixed

  • The dashboard's provider-effectiveness tile now credits the audio detector for tracks it settled before it became a tracked source. v1.23.0 corrected only the Prometheus counters, leaving the dashboard unchanged and its promise of a jump unfulfilled (#537)

Upgrading

Nothing to do. The correction runs during the database upgrade on first start, applies once, and records that it has run.

If you already ran canticle scan reconcile-detector-stats by hand, nothing here disturbs it. Attempts recorded live always take precedence over reconstructed ones, so the upgrade fills only what is genuinely missing.

Detector failures remain a known gap and are still not reconstructed: canticle knows how many times a track was passed over but not when, and the detector has not always existed, so some of those attempts predate it. Filling that in would mean crediting work to something that was not running yet. The Prometheus metrics and the dashboard tile will therefore still disagree about the detector's failures, on purpose.


Docker: docker pull ghcr.io/sydlexius/canticle:1.23.1

Full changelog: v1.23.0...v1.23.1

v1.23.0

Choose a tag to compare

@github-actions github-actions released this 20 Jul 06:27
Immutable release. Only release title and notes can be modified.
5774730

canticle v1.23.0

Highlights

When no lyrics service can find a track, canticle listens to the audio and decides whether it is an instrumental. That is a real result, and the statistics page was barely counting it. It credited the audio detector with a few hundred settled tracks when the true figure was several thousand: everything it resolved before it became a tracked source was never recorded against it. The one part of canticle that needs no lyrics service at all looked like the least productive thing it does. This release corrects the record in a single pass the first time the new version starts.

Correction, added after release: install v1.23.1 instead. This release corrected only the Prometheus counters. The dashboard's detector tile reads a different table that this release did not touch, so on the dashboard nothing changed and the promise below went unfulfilled. v1.23.1 fixes that and covers both.

Expect the number to jump, and expect it only once. On a decent-sized library the detector's result count climbs several-fold the moment you upgrade. That is the correction arriving, not a fault, and it does not repeat on later restarts.

One half of the history could not be recovered, and has been left alone rather than guessed at. Successful detections could be reconstructed exactly, because each one settles a track permanently and leaves an unambiguous record. Failed attempts could not: canticle knows how many times a track was passed over but not when, and the detector has not always existed, so some of those attempts happened before it was there to fail. Filling that in would have meant crediting work to something that was not running yet, with a precise-looking number to make it look certain. The gap is documented instead. The practical effect is that the Prometheus metrics and the dashboard's own tile still disagree about the detector's failures, on purpose.

What's changed

Fixed

  • The statistics behind /metrics now credit the audio detector for the tracks it settled before it became a tracked source, correcting a long-standing undercount in a one-time pass at startup (#548)

Changed

  • Reports and the dashboard now call it the "Instrumental Detector" rather than the bare "detector", matching the name the configuration has always used (#539)

Maintenance

  • CI action bumps: actions/setup-python to 7.0.0, anthropics/claude-code-action to 1.0.178 (#562, #563)

Upgrading

Nothing to do. The correction runs by itself during the database upgrade on first start, takes effect once, and records that it has run so a later restart does not apply it twice. No command, no flag, and nothing is rewritten in your library.

The only thing worth knowing is the one above: your detector figures will step up sharply and stay there.


Docker: docker pull ghcr.io/sydlexius/canticle:1.23.0

Full changelog: v1.22.0...v1.23.0

v1.22.0

Choose a tag to compare

@github-actions github-actions released this 19 Jul 08:05
Immutable release. Only release title and notes can be modified.
v1.22.0
3474be6

canticle v1.22.0

Highlights

When no lyrics service can find a track, canticle listens to the audio and decides whether it is an instrumental. That decision is permanent, so it never looks again. The setting behind it was an early placeholder that had never actually been tested. Measured at last against a few hundred known tracks, it was calling about one song in twenty an instrumental despite it having real lyrics. In a decent-sized library that is hundreds of songs quietly written off. The new default makes it rare.

The trade is that canticle is now slower to call anything an instrumental, which costs a little wasted searching and never costs you lyrics. The surprise was the direction: everyone assumed it was too strict, and it turned out too generous. Fixing the number does nothing for decisions already made, because canticle never revisited a track it considered settled. So this release also adds a cleanup command that re-examines past instrumental verdicts and undoes the wrong ones. It shows you the list before changing anything, and never touches a marker that came from a lyrics service rather than canticle's own listening.

What's changed

Fixed

  • The audio detector no longer marks roughly one in twenty genuinely sung tracks as an instrumental. The setting behind that call is now based on measurement against known tracks rather than an untested placeholder (#555)

Added

  • A new cleanup command re-examines tracks previously marked as instrumentals, undoes the ones the corrected setting no longer agrees with, and sends them back for a normal lyrics search. Shows you what it would do first, changes nothing without --yes, and keeps a record of everything it touches (#556)

Upgrading

If you set instrumental_detector.vocal_max_confidence yourself, nothing changes for you. Everything below applies to the default.

Your existing library still carries the old decisions, and they will not fix themselves. Upgrading changes what happens next, not what already happened. Start with the version that changes nothing:

canticle scan reconcile-instrumental-recalibrate --reverse

That prints one line per track it thinks it got wrong and touches nothing. When you are happy with the list, add --yes to apply it. Corrected tracks go back into the queue ahead of the ordinary backlog so they are looked up promptly, and on a large library the whole pass takes a minute or two.

Two things it cannot do. Tracks analyzed before v1.11.0 predate canticle recording the scores behind each decision, so there is nothing to re-examine and the cleanup passes over them; correcting those needs a full re-scan. And the measurement behind the new default came from one real music collection, so a library weighted very differently, heavily choral or spoken-word, may still want a different number. That is what the config key is for.

v1.21.0

Choose a tag to compare

@github-actions github-actions released this 19 Jul 04:01
Immutable release. Only release title and notes can be modified.
v1.21.0
bdd8faf

canticle v1.21.0

Highlights

A throughput collapse that got worse the longer the service ran. The Musixmatch client backs off when the provider signals throttling, but that back-off ratcheted up with no path down a real deployment could reach. A short burst of genuine 401s degraded throughput until restart. Where this was found, three throttle events had taken the effective interval from 15 seconds to 120 seconds and held it. Real work per item is about 0.2 seconds, so the cycle was almost entirely the service waiting on itself.

The recovery path existed but could not fire. Stepping down required five consecutive catalog hits. In the measured window, 52 items settled and 2 qualified; most were benign misses, which never reach the pacer. The audio detector made it worse: since v1.19.0 it settles instrumentals without going through Musixmatch, but its lane had no pacer, so that work stopped crediting recovery and nothing noticed.

Back-off now decays on time rather than on luck. One level per throttle-free interval, evaluated when the next request is paced. Twenty minutes per level, so a full unwind takes an hour: long enough that a brief lull does not erase the back-off and re-provoke the provider, short enough to recover within a day. Decay never goes below the configured minimum, and a fresh throttle signal re-applies immediately.

Throttle detection is unchanged, deliberately. Those signals were real provider push-back, so the fix is entirely on the recovery side.

The detector's statistics stop under-reporting. Instrumentals settled before the detector became a lane were never attributed to it, so the dashboard showed a fraction of its work. scan reconcile-detector-stats backfills them from recorded data, hits and misses together.

What's changed

Fixed

  • The adaptive request pacer steps back down after a throttle-free interval, instead of holding an elevated interval until restart (#492)
  • Tracks settled locally by the audio detector credit pacer recovery, without paying the provider pacing cost they never incurred (#550)
  • A configuration read in the pacing path happened outside its lock (#494)

Added

  • scan reconcile-detector-stats corrects the detector lane's undercounted statistics. Dry-run by default, --yes to apply, with a JSONL backup (#537)

Upgrading

No configuration changes are required.

Restarting alone gives immediate relief, because the back-off level lives in memory and a fresh process starts at the base interval. Throughput will jump on upgrade regardless of what this release contains. The signal that matters is whether it is still healthy hours later, after some genuine throttle signals have come and gone.

The backfill is optional and writes nothing until you pass --yes:

canticle scan reconcile-detector-stats          # preview
canticle scan reconcile-detector-stats --yes    # apply

Re-running it is a no-op. Rows with no recorded verdict are reported as an uncovered remainder rather than estimated.

v1.20.1

Choose a tag to compare

@github-actions github-actions released this 19 Jul 00:20
Immutable release. Only release title and notes can be modified.
v1.20.1
55a2283

canticle v1.20.1

Highlights

This fixes a command that v1.20.0 shipped in an unusable state. canticle admin set-password, the password-rotation command introduced in v1.20.0, could not be invoked. Running it produced the legacy CLI's usage text and unknown argument --user. If you upgraded to v1.20.0 to rotate a web-UI admin password, that path did not work; it does now.

Why it broke, since the shape is worth knowing. Adding a subcommand required touching four places: the command struct, the dispatch switch, the shell-completion tables, and a hand-maintained list deciding whether input is parsed as a modern subcommand or the legacy flag-only CLI. The first three were done and the fourth was missed, so the command fell through to a parser that knows nothing about its flags. That list is now derived from the command definitions themselves rather than maintained by hand, so a newly added command is recognized the moment it is declared. A test drives every declared subcommand through the real entry point and fails if any is unreachable.

Documentation for resetting a lost admin password. The user guide previously said to rotate the password "from inside the UI". That was never possible, and following it leads to editing MXLRC_WEBAUTH_ADMIN_PASSWORD, which silently does nothing once an admin exists: the service starts healthy, logs a skip, and keeps the old password. That is how an operator ends up locked out believing a credential was rotated. There is now a Changing or resetting the admin password section covering the command, the Docker form, the locked-out case, and why the password is read from standard input rather than passed as a flag.

A third silent no-op, found while verifying the above. The environment bootstrap that creates the first admin only runs when the web UI is enabled. Setting MXLRC_WEBAUTH_ADMIN_USER and MXLRC_WEBAUTH_ADMIN_PASSWORD with web_ui_enabled left at its default produced no admin account, no error, and no explanation. It is now reported at warning level, naming both variables and the setting to change.

What's changed

Fixed

  • canticle admin set-password is reachable. In v1.20.0 it fell through to the legacy argument parser and could not be run at all (#547)
  • The subcommand-recognition set is derived from the command definitions instead of a hand-maintained list, so a declared command cannot be silently unreachable. A test drives every subcommand through the real entry point (#547)
  • Setting the web-admin bootstrap variables while the web UI is disabled now logs a warning naming the setting to change, instead of silently creating no account (#547)

Documentation

  • New "Changing or resetting the admin password" section in the user guide, including the locked-out case and the Docker form (#547)
  • Removed the instruction to rotate the password from the web UI, which was never possible and sends operators to a setting that does nothing after first run (#547)
  • Password examples never place the credential on a command line, where it is visible in the host process list and recorded in shell history. This matches canticle secrets set, which already rejects a value passed as an argument (#547)
  • The CLI reference usage synopsis lists every top-level command; admin and realign were both missing (#547)

Upgrading

No configuration changes are required. If you are on v1.20.0 and need to rotate or recover a web-UI admin password, upgrade first, then:

canticle admin set-password --user admin < newpass.txt

This works even when you are locked out, because it acts on the database rather than requiring a login. Existing sessions are revoked as part of the change.