This release includes breaking changes for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
ReleasePort's take
Light signalThe Auto‑Sync modal now opens in ~280 ms (down from ~1.5 s) and a bulk scheduling button is available, while several critical bugs affecting large libraries, UI displays, and download pipelines have been fixed.
Why it matters: Performance improvement of 81% on modal open time; bug fixes prevent hung schedules, display errors, and failed downloads for users with large libraries or timezone differences.
Summary
AI summaryUpdates Headline changes, Wishlist + album-bundle improvements, and Code health across a mixed release.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Feature | Low |
Bulk scheduling button added for source groups in Auto-Sync sidebar. Bulk scheduling button added for source groups in Auto-Sync sidebar. Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Feature | Low |
Wishlist albums‑cycle now uses per‑album release‑first searches. Wishlist albums‑cycle now uses per‑album release‑first searches. Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Feature | Low |
Redownload Album button restored on enhanced artist view (issue #699). Redownload Album button restored on enhanced artist view (issue #699). Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Feature | Low |
Thread ID support added for Telegram notifications (PR #594). Thread ID support added for Telegram notifications (PR #594). Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Feature | Low |
Sync page gains four new tabs: ListenBrainz, Last.fm Radio, SoulSync Discovery, iTunes/Apple Music Link. Sync page gains four new tabs: ListenBrainz, Last.fm Radio, SoulSync Discovery, iTunes/Apple Music Link. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Feature | Low |
Auto-Sync modal now shows custom interval columns for non‑standard schedules with dashed borders. Auto-Sync modal now shows custom interval columns for non‑standard schedules with dashed borders. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Feature | Low |
Sidebar search input and failure indicators (red !, yellow ⚠) added to Auto-Sync manager. Sidebar search input and failure indicators (red !, yellow ⚠) added to Auto-Sync manager. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Feature | Low |
Run history tab in Auto-Sync includes filter pills, pagination, and "Run pipeline again" button. Run history tab in Auto-Sync includes filter pills, pagination, and "Run pipeline again" button. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Feature | Low |
Cycle toggle in Wishlist now fires once per run instead of per sub‑batch, using a shared run ID. Cycle toggle in Wishlist now fires once per run instead of per sub‑batch, using a shared run ID. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Feature | Low |
Wishlist download modal aggregates tasks and analysis results across all album siblings. Wishlist download modal aggregates tasks and analysis results across all album siblings. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Feature | Low |
Enhanced view toggle state persists per browser via localStorage scoped per profile. Enhanced view toggle state persists per browser via localStorage scoped per profile. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Feature | Low |
Quick Actions UI redesigned as asymmetric bento with animations and softer flow lines. Quick Actions UI redesigned as asymmetric bento with animations and softer flow lines. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Performance | Medium |
Auto-Sync modal open time improved from ~1.5s to ~280ms. Auto-Sync modal open time improved from ~1.5s to ~280ms. Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Bugfix | Medium |
Hung‑forever loading‑schedule bug fixed for large libraries. Hung‑forever loading‑schedule bug fixed for large libraries. Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Bugfix | Medium |
"in library" always‑showing‑0 bug corrected. "in library" always‑showing‑0 bug corrected. Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Bugfix | Medium |
Timezone offset on countdowns corrected (~8h Pacific error). Timezone offset on countdowns corrected (~8h Pacific error). Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Bugfix | Medium |
Whole‑album downloads no longer fail with empty queues (issue #700). Whole‑album downloads no longer fail with empty queues (issue #700). Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Bugfix | Medium |
Album tracks no longer get requeued as singles (issue #698). Album tracks no longer get requeued as singles (issue #698). Source: llm_adapter@2026-05-27 Confidence: high |
— |
| Bugfix | Low |
Album‑bundle downloads now correctly assign track numbers, avoiding defaulting to track 1. Album‑bundle downloads now correctly assign track numbers, avoiding defaulting to track 1. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Bugfix | Low |
Songs stuck in quarantine loop when selecting a different candidate are now skipped for AcoustID processing. Songs stuck in quarantine loop when selecting a different candidate are now skipped for AcoustID processing. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Refactor | Low |
Unified `PlaylistSource` adapter layer replaces large if/elif chain in refresh handler. Unified `PlaylistSource` adapter layer replaces large if/elif chain in refresh handler. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Refactor | Low |
Auto-Sync JavaScript extracted into `webui/static/auto-sync.js` with node:test contract. Auto-Sync JavaScript extracted into `webui/static/auto-sync.js` with node:test contract. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
| Refactor | Low |
Mirrored playlist pipeline moved to `core/playlists/pipeline.py` from inline location. Mirrored playlist pipeline moved to `core/playlists/pipeline.py` from inline location. Source: granite4.1:30b@2026-05-27-audit Confidence: high |
— |
Full changelog
Release: dev → main, 2.6.1 → 2.6.2
Cycle release bundling 85 commits since the 2.6.1 cut on main. Version string bumped to 2.6.2 (commit 26eeb1e9). Bundles the unreleased 2.6.2 block and the in-flight 2.6.3 entries currently sitting on dev — both ship under the 2.6.2 tag.
Headline changes
New Sync-page tabs (4)
The Sync page absorbs four sources that previously lived only on the Discover page or had no first-class entry point at all. Each tab uses the same discovery → mirror → Auto-Sync flow as Spotify / Tidal / Qobuz / YouTube.
- ListenBrainz — lists For You / My Playlists / Collaborative LB playlists. Once mirrored, LB playlists participate in Auto-Sync schedules + pipeline automations like any other source.
- Last.fm Radio — sibling tab to ListenBrainz. Mirrors auto-trim when the Last.fm Radio cache rotates so old radios don't pile up.
- SoulSync Discovery — personalized SoulSync Discovery playlists (decade mixes, hidden gems, popular picks, daily mixes, discovery shuffle). Clicking a card regenerates + mirrors under a stable synthetic id so the same mirror updates in place every Auto-Sync refresh.
- iTunes / Apple Music Link — paste an Apple Music album / track / playlist URL. Handles the current SPA token shape; token gets scraped from the JS bundle on first use, cached for 6 hours, refetched on 401 if Apple rotates mid-session.
Backed by a new unified PlaylistSource adapter layer (core/playlists/sources/) — refresh handler shrunk from a ~190-line if/elif chain to ~80 lines that delegate to the source registry. Each source also implements a discover method on the same interface so LB / Last.fm tracks land already matched against Spotify / iTunes via the shared engine.
Auto-Sync manager overhaul
Top-to-bottom revamp of the Playlist Auto-Sync modal:
- Performance: modal open dropped from ~1.5s to ~280ms (batched
get_all_mirrored_playlist_status_countsinstead of N per-playlist queries). Playlist sync itself is way faster on partial-match playlists thanks to a lazy per-artist track pool (4+ min → seconds on a 30-track playlist with 9 matches). - Bulk scheduling: each source group in the sidebar gets a Bulk button — schedule every playlist at once (1h / 2h / 4h / 8h / 12h / 16h / 24h / 48h / 72h / weekly, or custom interval). "Unschedule all" clears a source's schedules.
- Custom interval columns: schedules with non-standard intervals (6h, 36h, etc.) now render as their own dashed-border column instead of disappearing because they didn't match a hardcoded bucket.
- Filters + failure indicators: sidebar gets a playlist search input. Scheduled cards show a red ! badge when the last three pipeline runs failed, yellow ⚠ for at least one. Run history tab gains All / Errors / Completed filter pills, "Load more" pagination, and a "Run pipeline again" button inside the expanded detail panel.
- Restyle: the whole modal now matches the rest of the app — standard SoulSync gradient + accent-tinted border, KPI summary as inset stat tiles, auto-fill pipeline monitor, underline-style tabs, dense dark-card schedule board sidebar. Picks up the user's chosen accent color instead of hardcoded sky-blue.
- Fixes: hung-forever-on-loading-schedule bug (300k-track libraries hit a
COLLATE NOCASEjoin that couldn't use indexes — ~3000x speedup by dropping NOCASE),in libraryalways-showing-0 bug (query referenced a removedtracks.artistcolumn), timezone offset on countdowns (~8h on Pacific time), run-history modal hardening.
Wishlist + album-bundle improvements
- Wishlist albums-cycle now uses per-album release-first searches: instead of dumping every missing track into one big batch and running ~50 per-track Soulseek / Prowlarr searches, the albums cycle splits into per-album sub-batches at submission time. Each engages the existing slskd / torrent / usenet album-bundle release-first flow with the album's context.
- Cycle toggle fires once per run, not per sub-batch: each wishlist invocation now stamps every sub-batch with a shared run id; cycle flip + completion event waits for the LAST sibling to finish.
- Wishlist download modal tracks across every album: backend merges every sibling sub-batch's tasks + analysis results into the original batch id (re-indexes track positions globally, aggregates phase across siblings).
- Album-bundle downloads all landing as track 1 — the staging-file reader was using the auto-import's filename extractor that defaults to 1 when no NN- prefix is present. Now uses a strict extractor that returns 0 when no explicit prefix exists, so the downstream resolver correctly falls through to Spotify metadata.
- Whole-album downloads ending up "failed" with empty queues (#700) — staging match now pulls the trailing-title segment when a bare track-number is present between " - " delimiters so slskd filename patterns match cleanly.
- Album tracks getting requeued as singles by the wishlist (#698) — album batches now carry
source_type='album', source-context preservesalbum_context/artist_context, fallbacks default toalbuminstead ofsingle.
Fix popup / mirrored playlist back-sync
- Manual matches survive Playlist Pipeline runs — three layered fixes: provider stamping no longer hardcodes
'spotify'(uses the actual source the popup matched against), prepare-discovery's drift check honoursmanual_match, and the discovery worker short-circuits onmanual_matchbefore the incomplete-data re-discovery branch. Pre-fix: manual fixes worked once, then flipped back to "Provider Changed" on the next Pipeline cycle. - MusicBrainz Fix popup: artist + track fields no longer surface unrelated covers — split-field input goes through a strict
recording:"X" AND artist:"Y"query that anchors the artist. Falls back to bare query for diacritic mismatches (BjorkvsBjörk). Results stable-prefer entries with known length so the canonical 3:04 sibling sits above the 0:00 duplicate.
Library + UX
- Enhanced view toggle persists per browser — artist detail no longer reverts to Standard every time. Saved in localStorage scoped per profile so multiple admin profiles keep different defaults.
- Quick Actions redesigned as asymmetric bento with signature animations and softer flow lines.
- Redownload Album button on enhanced artist view restored (#699) — silently broken when script.js got split into 17 domain modules.
Quarantine / candidates
- Songs stuck in quarantine loop when picking a different candidate (#701) — manual picks via the candidates modal now skip AcoustID for that one post-process pass (matching the Approve-on-restored-quarantine path). Integrity + bit-depth gates still run.
Telegram
- Thread id support on Telegram notifications (community PR #594).
Code health
- New
core/discovery/manual_match.pyextracts manual-fix provider derivation + provider-drift checks out ofweb_server.pyroute handlers — pinned by 12 unit tests. - New
core/playlists/sources/adapter layer (PlaylistSource ABC + registry). - Auto-Sync extracted into
webui/static/auto-sync.jswith node:test contract for its helpers. - Mirrored playlist pipeline lifted into
core/playlists/pipeline.py(was inline inweb_server.py). - Pre-existing ruff lint debt cleared (5 errors blocking CI) — duplicate
urlparseimport removed, fourtry/except/passblocks tagged with# noqa: S110 — reasonper existing convention, onezip()annotated withstrict=False.
Test plan
- [x] Full pytest: 4067 passed, 0 failed.
- [x]
python -m ruff check .clean. - [x] Live API smoke against local dev server for the MB Fix popup case (
Coffee Break+Zeds Dead) — canonical6e2d4a70recording with length 184000ms ranks first; Björk diacritic case (Bjork+Army of Me) returns 10/10 Björk recordings via strict-empty → bare fallback.
Closes
#594, #697, #698, #699, #700, #701, #708 (community feedback batch)
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]