This release includes 1 breaking change for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Summary
AI summaryUpdates New, Test plan, and Smaller fixes across a mixed release.
Full changelog
SoulSync 2.7.3 — Merge dev → main
patch release on top of 2.7.2. one new feature (Quality Upgrade Finder), a Tidal-discovery completeness fix, and a stack of import / wishlist / quarantine bug fixes.
Headline:
- Quality Upgrade Finder — new findings-based job that finds tracks you own in worse quality than is available and upgrades them (ISRC-first, tiered matching, dedup-skip, duration guard). replaces the old auto-acting Quality Scanner.
- #867 — Tidal playlist discovery capped at ~21 tracks → now walks the whole playlist, and the modal opens instantly instead of freezing ~10s. Reported against 2.7.2.
- #880 — Tidal "Favorite Tracks" mirror truncating to ~98 of 500+ on a transient 429. Reported by @Yug1900.
- #879 — opening Settings reset the whole config to defaults after a failed
GET /api/settings. Reported by @Lysticity (2.7.0–2.7.2). - #877 — Download Discography filters didn't match Artist Detail (dead EPs toggle; no Live/Compilations/Featured). Reported by @HolyFredy.
- #876 — Quarantine duplicates + stale count. Reported workflow pain: many failed attempts at one song, and a stale tab count on open.
- #874 — wishlist re-downloads a removed/cancelled track forever. New TTL'd ignore-list.
- "Track 01" bug — single tracks (esp. Deezer) imported as
01regardless of real album position.
New
Quality Upgrade Finder
Replaces the old auto-acting Quality Scanner with a findings-based repair job: it scans the library for tracks you own in worse quality than a source can provide, surfaces them as findings, and you choose what to upgrade — nothing acts on your library behind your back.
- Tiered structured matching: ISRC-first exact match (using the IDs enrichment already embedded) → album→track → artist+title.
- Best-in-class picker: a direct track-ID tier for exact source matches, a dedup-skip so the same upgrade isn't re-found, and a duration guard so a wrong-but-similarly-named track can never be swapped in.
- Old auto-acting Quality Scanner tool removed.
Fixes
#867 — Tidal playlist discovery only showed ~21 tracks
The discovery walk was capped; it now pages the full playlist. Plus a UX pass: the discovery modal renders before the blocking discovery-start POST and opens in its discovering state, so it no longer freezes the UI for ~10s on a track pre-fetch or leave an empty/loading modal interactable.
#880 — Tidal "Favorite Tracks" mirror captured ~98 of a 500+ collection
The cursor paginator (_iter_collection_resource_ids) bailed on any non-200 — including a transient 429 mid-walk — truncating a 524-track collection to 98. It now retries the same cursor page with backoff (5/10/15/20s, up to 4 attempts), mirroring the playlist paginator. 401/403 still bail + set the reconnect flag; other non-200s still break. 3 regression tests.
#879 — opening Settings reset the entire config to defaults
loadSettingsData() called response.json() without checking response.ok, so a failed GET /api/settings (its error body) was treated as settings → every field fell back to blank → autosave wrote the blanks over the real config. Fix (settings.js): bail before touching any field on a non-ok/error load, set window._settingsLoadFailed, and guard both save paths on it (cleared on next good load). Any load failure now leaves the saved config untouched. Regression test pins redacted_config stays a callable method.
#877 — Download Discography filters didn't match Artist Detail
The modal used the base get_artist_discography (which lumps EPs into singles) and only read {albums, singles} — so its EPs bucket was always empty (dead toggle), with no Live/Compilation/Featured classification. Now uses get_artist_detail_discography (same split Artist Detail uses) + a shared _classifyReleaseContent() adopted by both surfaces so they can't drift; adds Live/Compilations/Featured filters; the download payload is built from visible checked cards. Regression test pins EPs land in their own bucket.
#876 — Quarantine workflow: duplicates + stale count
- Group duplicates + auto-clear: failed attempts at the same song group by their intended target track-id (isrc → source id → uri, name fallback for legacy sidecars) and render as a collapsible group; approving one auto-deletes the sibling alternatives. Hooked so the success-cleanup path is never mistaken for a duplicate.
- Stale count: the quarantine tab badge now shows the real count the moment the modal opens, not a stale
0until you click the tab. - 13 tests incl. the capture-before-approve ordering regression.
#874 — wishlist re-downloads a removed/cancelled track forever
A removed or user-cancelled wishlist track used to be re-added on the next auto cycle (watchlist scan, failed-capture, cancel re-add), so the same release downloaded → failed → re-queued endlessly. New TTL'd ignore-list (core/wishlist/ignore.py + wishlist_ignore table) gates the single add_to_wishlist funnel: softer than the blocklist (expires after 30 days, never blocks a manual force-download), fail-open throughout, manual add bypasses + clears. New "Ignored" view to see/undo. 13 tests incl. the success-cleanup-does-not-ignore regression.
"Track 01" bug — single tracks imported as 01
A single Deezer track is matched via /search/track, which omits track_position, so the import context never carried the real number — then service.py/context.py fabricated a confident track_number=1 that beat the real source. Fix: stop fabricating 1 (default to the 0 "unknown" sentinel), and recover the position from the downloaded file's own embedded tag (mutagen, no network), consulted last — only when metadata + filename both come up empty, so it can never override a value the old resolver produced (strictly additive, no regression for albums). 13 resolver tests incl. the no-regression precedence guards.
Smaller fixes
- #870 — Deezer ARL "resets itself": the connection test ran against the redacted mask instead of the saved token, so a valid ARL read as broken. Tests the saved token now.
- #868 — same-name artist mis-enriched: an artist sharing a name with another got the wrong Standard discography. Disambiguated by owned-catalog overlap during enrichment; a re-match clears the stored id.
- Find & Add: a
Title - Remixsearch now matches the base-titled track in your library. - Normalization: a colon in a title (
T:T) now matches an underscore variant (T_T). - Sidebar UI: frosted-glass header blur, vertically-centered nav count badges, and the My-Accounts / Personal-Settings buttons hidden for admins (who use the global app account).
Earlier in 2.7.x (carried, already shipped)
- 2.7.2 — playlist-folder mirroring, server-playlist M3U export, follow-only watchlist, SoundCloud-link + better YouTube imports, ReplayGain Filler + Empty Folder Cleaner maintenance jobs, HiFi restore-defaults.
- 2.7.1 — download verification (AcoustID fingerprint-checks every download against what you asked for) + an unverified review queue; closed the websocket login-bypass (#852).
- 2.7.0 — multi-user for real: per-profile streaming accounts (My Accounts), opt-in username/password login with recovery, reverse-proxy support.
Test plan
- [x] full imports + wishlist suites green (no regressions from the Track-01 de-poison or the ignore-list)
- [x] 13 quarantine ignore-list tests (#874) incl. success-cleanup regression
- [x] 13 quarantine-grouping tests (#876) incl. capture-before-approve ordering
- [x] 13 track-number resolver tests incl. embedded-tag precedence / no-regression guards
- [x] 3 Tidal 429-retry regressions (#880); settings-redaction regressions (#879); EP-split regression (#877)
- [x]
ruff check .clean - [ ] Live: re-mirror Tidal Favorites grabs the full collection (#880)
- [ ] Live: Deezer single-track import lands at its real album position (Track-01)
- [ ] Live: Quality Upgrade Finder surfaces + upgrades a known lower-quality track
Post-merge checklist
- [ ] Tag
v2.7.3onmain - [ ] Trigger
docker-publish.ymlwithversion_tag: 2.7.3(default already bumped) →boulderbadgedad/soulsync:2.7.3+ghcr.io/nezreka/soulsync:2.7.3 - [ ] Discord release announcement (auto-fired by the workflow)
- [ ] Reply on #867 / #880 / #879 / #877 / #876 / #874 / #870 / #868 with the 2.7.3 release link
Breaking Changes
- Old auto‑acting Quality Scanner removed.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
Related context
Related tools
Beta — feedback welcome: [email protected]