Let Music Assistant resolve Tidal tracks by name when no URI works - #2364
Merged
Conversation
… last resort Odesli retired its public API on 2026-07-31 (401 PUBLIC_API_ACCESS_DEPRECATED). It was the only source Beatify ever had for Tidal ids, so a missing `uri_tidal` can no longer be filled by the backfill — 1063 catalogue gaps are now permanently unreachable that way. Music Assistant can resolve a track from name + artist, and already does so for `ma_library`. This extends that path to `tidal`. It is a net *behind* the stored URIs, never a replacement: the candidate loop runs first, so a song with a working `uri_tidal` never reaches the fallback. Only `ma_library` and `tidal` opt in; every other provider keeps today's hard failure. Two supporting changes: * The early return for an empty candidate list now yields to the fallback. Without this the new path could never fire, because a Tidal song without a URI has no candidates at all and returned before reaching it. * A name search can land on a remix, a live take or a karaoke version, and `_titles_plausibly_match` does not catch that — it accepts a normalized prefix, and a title is always a prefix of its own remix. That leniency is load-bearing for #1381 ("Das Modell" vs "The Model"), so it stays; a stricter edition check is applied on the fallback path only. The risk is measured, not assumed. Against ~2000 catalogue tracks with a known Deezer id, a plain "artist title" search returned a different recording for 2% of mainstream tracks but 19% of EDM ones. Every rejection case in the new tests is verbatim from that measurement. This matters more here than it would in a music player: the game asks players to guess the release year, so a 2014 remix standing in for a 1998 original does not merely sound different — it makes the round's correct answer wrong. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012W9Pj7vqs7Yv31j19B4vRt
`test_stale_uris_fall_back_to_a_name_lookup` matched the literal string "MA library fallback" in the source. That log line now reads "MA name fallback (<provider>)" because Tidal shares the path, so the assertion broke on a rename while the behaviour it guards was untouched. It now checks `_NAME_FALLBACK_PROVIDERS` and the `ma_library` membership — the guard that actually decides whether the fallback runs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012W9Pj7vqs7Yv31j19B4vRt
mholzi
marked this pull request as ready for review
August 23, 2026 19:31
mholzi
added a commit
that referenced
this pull request
Aug 23, 2026
Bumps the manifest to 4.3.1-rc2, adds the changelog entry for what landed since the previous build, and adds the pre-release notes. Two changes since the last tag: the Tidal name fallback (#2364) and the start-failure banner layout fix (#2365 / #2366). The dead YouTube links repaired in #2362 are catalogue maintenance and stay out of the user-facing notes, as pre-release notes always do. The notes file is force-added — `docs/` is gitignored and every previous release-notes file was added the same way. Claude-Session: https://claude.ai/code/session_012W9Pj7vqs7Yv31j19B4vRt Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Odesli retired its public API on 2026-07-31 —
api.song.linknow answers401 PUBLIC_API_ACCESS_DEPRECATED, and the docs confirm keys are no longer handed out. It was the only source Beatify ever had for Tidal ids, so a missinguri_tidalcan no longer be filled by the backfill. 1063 catalogue gaps are permanently unreachable that way.Music Assistant can resolve a track from name + artist, and already does for
ma_library. This extends that path totidal.What this is, and what it is not
It is a net behind the stored URIs. The candidate loop runs first, so a song with a working
uri_tidalnever reaches the fallback — the existing 5942 Tidal URIs keep their precedence, because they are more precise than any search. Onlyma_libraryandtidalopt in; every other provider keeps today's hard failure.The non-obvious part
The early return for an empty candidate list had to yield to the fallback. Without that change the new path could never fire: a Tidal song without a URI has no candidates at all and returned before reaching it.
The risk, measured rather than assumed
A name search can land on a remix, a live take or a karaoke version.
_titles_plausibly_matchdoes not catch that — it accepts a normalized prefix, and a title is always a prefix of its own remix. That leniency is load-bearing for #1381 (Das ModellvsThe Model), so it stays; a stricter, one-directional edition check runs on the fallback path only.How big the risk actually is was measured against ~2000 catalogue tracks with a known Deezer id — same question, and Deezer can be searched without a key:
community/edm-anthemsThe risk is a function of genre, not a single number — roughly 2 % for pop and rock, 19 % for EDM. Every rejection case in the new tests is verbatim from that measurement:
Satisfaction→Satisfaction (Uk Radio Edit),Scary Monsters and Nice Sprites→… (Zedd Remix),Without You (feat. Usher)→… (Extended).This matters more here than it would in a music player. The game asks players to guess the release year, so a 2014 remix standing in for a 1998 original does not merely sound different — it makes the round's correct answer wrong, and nothing on screen reveals that.
Tests
21 new tests in
tests/unit/test_tidal_name_fallback.py. Per the house rule they were run against the unpatched code first: the three behaviour tests fail onorigin/mainand pass here; the three guard tests pass on both, which is what they are for. The 134 existing media-player tests stay green.Known gap, deliberately left
ma_libraryhas the same wrong-edition exposure and does not get the new check — changing its behaviour is out of scope for this PR. Worth a follow-up.Why draft
The measurement above says the fallback will occasionally hand a player the wrong edition of the right song. That trade — a round that plays something instead of failing outright — is a product decision, not a technical one.
🤖 Generated with Claude Code
https://claude.ai/code/session_012W9Pj7vqs7Yv31j19B4vRt