Skip to content

SoulSync

v2.6.3 Feature

This release adds 3 notable features for engineering teams evaluating rollout.

Published 7d Media Servers
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Summary

AI summary

Broad release touches UX overhauls, Test plan, Unified Playlist Sources layer, and mbid.

Changes in this release

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 devmain

Bug-fix + UX-polish release. Headline items:

  • Soulseek album-bundle downloads no longer hang on failed after 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_file probed 3 hard-coded candidate paths to locate each completed file in the slskd download dir. On the common slskd config directories.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_path mismatch — no more silent 30-min spins.
  • Also fixed: misleading "(0 tracks, quality=)" log on the preflight-reuse path (was reading attrs off a None picked object).
  • 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 returning needs_discovery=True tracks. Phase 2 of the pipeline then ran the SAME matching engine via run_playlist_discovery_worker on 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: pass masking real API failures as stale-cache hits.
  • Fix:
    • Pipeline sets skip_discovery=True on 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 None so the outer handler counts the error.
  • 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=1 from an older payload default.
  • The Spotify-API backfill that hydrates release_date / total_tracks was 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 whenever release_date / total_tracks are missing, independent of where (or whether) track_number was resolved. Single API call still serves both.
  • Also: core/wishlist/routes.py:_build_track_data no longer defaults track_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 without track_number/disc_number; import pipeline only consulted album_info.track_number before 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_number as 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.py groups 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 to Analyzing... when a worker picks them up.

Album-bundle staging: clean Soulseek copies + sweep orphans at startup

  • _cleanup_private_album_bundle_staging was gated to torrent / usenet only. Soulseek's bundle path ALSO copies files into staging — those copies leaked forever. Extended the allow-list to include soulseek.
  • New sweep_orphan_album_bundle_staging runs 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_id directly. 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 lacking track_number/album.id/release_date (Fix-popup saves don't carry those by design), (c) prepare-discovery didn't honor the manual_match flag. 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 cpm steps 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-card architecture
    • 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

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. Link variants (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

  • PlaylistSource ABC + registry in core/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

Track SoulSync

Get notified when new releases ship.

Sign up free

About SoulSync

Automated Music Discovery and Collection Manager

All releases →

Beta — feedback welcome: [email protected]