This release adds 3 notable features for engineering teams evaluating rollout.
✓ No known CVEs patched in this version
Summary
AI summaryBroad release touches UX overhauls, Test plan, Unified Playlist Sources layer, and mbid.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Feature | Low |
Dashboard enrichment panel redesigned as a vibey VU‑meter equalizer row with brand logos. Dashboard enrichment panel redesigned as a vibey VU‑meter equalizer row with brand logos. Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Feature | Low |
Auto‑Sync manager receives a full visual overhaul matching the dashboard's glassy / accent‑radial aesthetic. Auto‑Sync manager receives a full visual overhaul matching the dashboard's glassy / accent‑radial aesthetic. Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Feature | Low |
Weekly board cards now match hourly board cards with identical affordances (Run‑now button, unschedule X, next‑run countdown, health badge). Weekly board cards now match hourly board cards with identical affordances (Run‑now button, unschedule X, next‑run countdown, health badge). Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Feature | Low |
Sync page tabs collapsed from 14 pills into circular brand‑logo chips; active tab expands to a label pill. Sync page tabs collapsed from 14 pills into circular brand‑logo chips; active tab expands to a label pill. Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Feature | Low |
Auto‑Sync sidebar now shows a brand logo on each source‑group header (Spotify, Tidal, Qobuz, Deezer, YouTube, Last.fm, ListenBrainz, SoulSync Discovery, etc.). Auto‑Sync sidebar now shows a brand logo on each source‑group header (Spotify, Tidal, Qobuz, Deezer, YouTube, Last.fm, ListenBrainz, SoulSync Discovery, etc.). Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Feature | Low |
Unified Playlist Sources layer introduced via `PlaylistSource` ABC and registry, consolidating refresh handling across sources. Unified Playlist Sources layer introduced via `PlaylistSource` ABC and registry, consolidating refresh handling across sources. Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Bugfix | Medium |
Auto-Sync ListenBrainz pipelines no longer get stuck on `Refreshing:` for 5+ minutes. Auto-Sync ListenBrainz pipelines no longer get stuck on `Refreshing:` for 5+ minutes. Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Bugfix | Medium |
Album‑bundle staging now cleans Soulseek copies and sweeps orphan directories at server startup. Album‑bundle staging now cleans Soulseek copies and sweeps orphan directories at server startup. Source: llm_adapter@2026-05-28 Confidence: high |
— |
| Bugfix | Medium |
Soulseek album-bundle downloads no longer hang on "failed" after slskd completes the release (#715). Soulseek album-bundle downloads no longer hang on "failed" after slskd completes the release (#715). Source: llm_adapter@2026-05-28 Confidence: low |
— |
| Bugfix | Medium |
Wishlist backfill now correctly hydrates album metadata even when `tn=1` is present (previously produced folders without a year subfolder). Wishlist backfill now correctly hydrates album metadata even when `tn=1` is present (previously produced folders without a year subfolder). Source: llm_adapter@2026-05-28 Confidence: low |
— |
Full changelog
SoulSync 2.6.3 — Merge dev → main
Bug-fix + UX-polish release. Headline items:
- Soulseek album-bundle downloads no longer hang on
failedafter slskd completes the release (#715). - Auto-Sync ListenBrainz pipelines no longer sit on
Refreshing:for 5+ minutes silently. - Dashboard enrichment panel redesigned from 11 cramped speedometers into a vibey VU-meter equalizer row with brand logos.
- Auto-Sync manager got a full visual overhaul to match the dashboard's glassy / accent-radial aesthetic, plus the Weekly Board cards now mirror the hourly board cards.
- Sync page tabs collapsed from 14 wrapping pills into circular brand-logo chips with an active label pill.
- Album-bundle staging auto-cleans Soulseek copies + sweeps orphan dirs at startup.
488 downloads tests pass. ~80 new unit tests across the cycle.
Fixes
#715 — Soulseek album downloads stuck on "failed" after slskd finished the release
core/soulseek_client._resolve_downloaded_album_fileprobed 3 hard-coded candidate paths to locate each completed file in the slskd download dir. On the common slskd configdirectories.downloads.username = true, files land at<download_dir>/<username>/<filename>— none of the 3 candidates carried a username segment, so every file looked locally missing and the bundle poll silently spun for ~30 minutes before marking the batch failed.- Fix: lifted the per-track flow's recursive walk-by-basename helper into
core/downloads/file_finder.py(find_completed_audio_file). Bundle resolver now delegates to it. Default-slskd users see zero behavior change (3-candidate fast path preserved); username-subdir / preserved-tree users get the recursive walk fallback. - Belt-and-suspenders: bundle poll now detects "slskd reports Completed but local file can't be resolved past a 45s grace window" and exits early with an explicit log line pointing at the likely
soulseek.download_pathmismatch — no more silent 30-min spins. - Also fixed: misleading
"(0 tracks, quality=)"log on the preflight-reuse path (was reading attrs off a Nonepickedobject). - 17 new tests pin every slskd layout (flat, username-prefixed, full-tree-preserved, deep nested, dedup-suffix, quarantine-skip, YouTube/Tidal encoded, transfer-dir fallback, fuzzy variants).
Auto-Sync ListenBrainz pipelines stuck on Refreshing: for 5+ minutes
- Refresh path ran
_maybe_discover(matching engine, per-track Spotify/iTunes/Deezer matches) inline for any source returningneeds_discovery=Truetracks. Phase 2 of the pipeline then ran the SAME matching engine viarun_playlist_discovery_workeron the same tracks. LB tracks discovered twice; the refresh-side run blocked with zero progress emission. - ListenBrainz manager only exposed
update_all_playlists— refreshing one playlist re-pulled all 12+ cached LB playlists' details from the API. - LB adapter had a silent
except Exception: passmasking real API failures as stale-cache hits. - Fix:
- Pipeline sets
skip_discovery=Trueon its refresh config; Phase 2 handles discovery with proper progress emits. - New
LBManager.refresh_playlist(mbid)targeted refresh — pulls just the requested playlist's details. - LB adapter logs exceptions with traceback at warning level + returns
Noneso the outer handler counts the error.
- Pipeline sets
- 12 new tests pin the skip-discovery flag, targeted refresh, error propagation, and synthetic series id resolution.
Wishlist: harden Spotify backfill — poisoned tn=1 can't mask a lean album
- Residual per-track wishlist downloads produced folders without a year subfolder whenever the wishlist row carried a stale
track_number=1from an older payload default. - The Spotify-API backfill that hydrates
release_date/total_trackswas coupled to the "track_number missing" branch, so poisoned tn=1 short-circuited it. - Fix: lifted to
core/downloads/track_metadata_backfill.py(hydrate_download_metadata). Track-number resolution keeps its precedence chain; album hydration now runs wheneverrelease_date/total_tracksare missing, independent of where (or whether)track_numberwas resolved. Single API call still serves both. - Also:
core/wishlist/routes.py:_build_track_datano longer defaultstrack_number=1/disc_number=1/total_tracks=1/release_date=''when the library-modal payload omits them. - 24 new tests cover the precedence chain, the poisoned-tn=1 regression case, defensive non-dict inputs, cost guard, disc_number resolution.
Wishlist: fix three regressions causing all imports to land as track 01
- Three stacked regressions: Track→dict conversion in payload helpers dropped everything except
album.name; Deezer-sourced discovery matches saved withouttrack_number/disc_number; import pipeline only consultedalbum_info.track_numberbefore falling to the filename (which fails for VA-collection filenames). - All three patched; track_number resolution chain lifted into
core/imports/track_number.py:resolve_track_numberas a pure function with 18 unit tests pinning every branch.
Wishlist: only engage album-bundle when several tracks from the same album are missing
- Auto-wishlist runs promoted every single-track wishlist item to a per-album bundle search — so a wishlist of "26 single tracks from 26 different albums" downloaded full albums (5-42 files each, ~85% wasted bandwidth) and hammered slskd with concurrent searches.
- New
core/wishlist/album_grouping.pygroups tracks by album. Bundle path only engages when an album has ≥2 missing tracks; single-track items take the cheaper per-track path. - Configurable via
wishlist.album_bundle_min_tracks.
Wishlist: distinguish Queued from Analyzing batches in the UI
- Wishlist runs with more than 3 sub-batches rendered every batch as "Analyzing..." simultaneously, even though the download worker pool only ran 3 at a time. Now batches show
Queued ⏳while parked in the executor; flip toAnalyzing...when a worker picks them up.
Album-bundle staging: clean Soulseek copies + sweep orphans at startup
_cleanup_private_album_bundle_stagingwas gated to torrent / usenet only. Soulseek's bundle path ALSO copies files into staging — those copies leaked forever. Extended the allow-list to includesoulseek.- New
sweep_orphan_album_bundle_stagingruns once at server startup, removes orphan<batch_id>subdirs left behind by previous-session crashes / errored batches / pre-fix Soulseek bundles. Safe by construction (name-shape guard, rmtree errors swallowed). - 12 new tests cover orphan removal, active preservation, defensive guards.
Usenet album poll: tolerate SAB queue→history handoff (#706)
- SAB jobs in the queue→history transition window briefly appear in neither, and the poll treated one missing read as terminal failure. Now tolerates ~10s of transient misses, treats unmapped queue states as transient, fires terminal failed event on every failure path, queries by
nzo_iddirectly. Same tolerance applied to torrent polls.
Discogs: strip artist disambiguation suffixes everywhere (#634)
- Discogs marks duplicate-named artists with
(N)or trailing*. Centralized cleanup into one helper applied at every Discogs name surface (artist search, album search, track lookups, get_artist_albums).
Library: Enhanced / Standard view toggle persists per browser
- Artist detail page reverted to Standard view on every navigation. Now persisted in localStorage and reapplied automatically.
Fix popup: manual matches survive Playlist Pipeline runs
- Manually-mapped tracks reverted on the next pipeline run because (a) manual fix saves always stamped
provider: 'spotify'even when the match came from MB / iTunes / Deezer, (b) the discovery worker re-queued any matched_data lackingtrack_number/album.id/release_date(Fix-popup saves don't carry those by design), (c) prepare-discovery didn't honor themanual_matchflag. All three patched.
Fix popup: artist + track fields no longer surface unrelated covers
- Fields-mode now uses a field-scoped Lucene query that anchors the artist, with the old bare query kept as a fallback for diacritic mismatches. Results stable-prefer entries with known track length.
UX overhauls
Dashboard enrichment panel: equalizer-bar redesign
- 11 speedometer tiles → 11 vertical VU-meter equalizer bars in one symmetric flex row.
- 4% sliver floor on idle bars; continuous shimmer scan when running; slow breathing pulse when idle; red pulsing variant when rate-limited; white-hot peak tip in the service's accent.
- Next-level polish: brand-logo avatar disc above each bar (Spotify/Apple Music/Deezer/Last.fm/Genius/MusicBrainz/AudioDB/Tidal/Qobuz/Discogs/Amazon, with initial-letter fallback on CDN failure); peak-flash detector when
cpmsteps upward; rolling number counter with easeOutCubic; glass-surface reflection puddle that intensifies with bar height. - Last.fm avatar clipped to a circle; Tidal/Qobuz/Discogs/Amazon inverted to white silhouettes for legibility against the dark glass disc.
Auto-Sync manager: full visual overhaul
- Selector-based override layer (zero JS/HTML changes, functionality untouched). Touched every surface in the modal:
- Modal shell: glass + accent radial wash + thin accent border, dashboard
.dash-cardarchitecture - Header: gradient-clipped title, accent eyebrow, hairline accent separator, rotating-X close
- KPI summary tiles: dashboard gradient tiles with accent top-edge glow on hover + gradient stat numbers
- Live monitor strip: accent glass card, status-colored borders
- Buttons: accent pill primary
- Tabs: underline + accent fill + radial glow on active
- Sidebar: glass groups, accent border on scheduled tiles, accent ring on filter focus
- Board/columns: accent radial spotlight, gradient column headers, accent drag-over glow
- Drop zones: animated dashed pull with accent radial wash
- Scheduled cards: accent left-edge stripe, gradient pill timing badges, pill Run-now, rotating ghost X
- History rows: dashboard recent-activity aesthetic, pill status badges with colored borders
- Bulk popover + Weekly editor: glass overlays matching the version-modal vibe
- Accent-tinted scrollbars throughout
- Modal shell: glass + accent radial wash + thin accent border, dashboard
Auto-Sync: weekly board cards now match the hourly board
- Weekly cards had diverged from the hourly card visual (no Run-now button, no unschedule X, no next-run countdown, no health badge). Standardised on the hourly shape so dropping onto a day column produces a card with the exact same affordances. Click anywhere outside the buttons still opens the weekly editor. Weekly cards now draggable between day columns.
Auto-Sync sidebar: brand logo on each source-group header
- 18px circular brand-logo chip to the left of each source-group title (Spotify / Tidal / Qobuz / Deezer / YouTube / Last.fm / ListenBrainz / iTunes Link / SoulSync Discovery / Spotify Link). Same logo vocabulary as the dashboard equalizer + header orbs. Last.fm circle-clipped; Tidal/Qobuz/iTunes-Link inverted to white silhouette.
Sync page tabs: brand-logo chips with active label pill
- 14 tabs no longer fit in one labeled-pill row. Collapsed to circular brand-logo chips; active tab swells into a pill with its label inline. Per-source brand color drives hover ring + active fill.
Linkvariants (Spotify Link / Deezer Link / iTunes Link) carry a small chain-link badge bottom-right to disambiguate from their native-source siblings.
Architectural lifts (Phase 1 of the Playlist Source unification, shipped)
Unified Playlist Sources layer
PlaylistSourceABC + registry incore/playlists/sources/. Refresh handler dropped from ~190 lines of if/elif to ~80 lines. ListenBrainz / Last.fm / SoulSync Discovery are now Sync-page tabs alongside Spotify / Tidal / Qobuz / YouTube. LB rolling-series mirrors.
Auto-Sync schedule types: weekday + time
- New Weekly Board tab on the Auto-Sync manager. Drag a playlist onto a day column (Mon-Sun) to schedule it for that weekday at a default time, then click for an editor for multi-day picks, custom time, and IANA timezone.
iTunes / Apple Music link import
- New iTunes Link tab on the Sync page. Paste an Apple Music album, track, or playlist URL and SoulSync pulls the tracklist through the same discovery → sync → download flow as the other link tabs.
Test plan
- [x] 488 downloads tests pass after the cycle
- [x] 80+ new unit tests across the new modules:
tests/downloads/test_file_finder.py— 17 tests (slskd layout coverage for #715)tests/downloads/test_track_metadata_backfill.py— 24 tests (wishlist tn=1 regression)tests/downloads/test_album_bundle_staging_sweep.py— 11 tests (orphan cleanup)tests/imports/test_track_number_resolver.py— 18 tests (per-track wishlist track number)tests/test_listenbrainz_manager.py— 8 tests (targeted LB refresh)tests/test_playlist_sources_adapters.py— 3 new tests (LB adapter refresh routing)tests/automation/test_handlers_playlist.py— 1 new test (skip_discovery flag)
- [x] Smoke: dashboard enrichment row renders with brand logos, equalizer bars animate, peak-flash fires on cpm increase
- [x] Smoke: Auto-Sync manager opens with new glass styling, hourly + weekly cards both render the full action row
- [x] Smoke: Sync page tab strip renders as logo chips; active expands to label pill; Link variants show chain-link badge
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]