soulsync 3.2.0: dev → main
the react migration release. ~650 commits since 3.1.9. every main music page is now
react, the dashboard and discover got full redesigns, chat grew an arcade's worth of
new toys, and a long list of reported bugs got fixed.
the react migration
this is the bulk of the release. the music webui has been moving from the old vanilla
js pages to react one page at a time, and 3.2.0 is where the last of the big ones land.
sixteen pages are now react: dashboard, sync, search, discover, playlist explorer,
watchlist, wishlist, automations, active downloads, import, library, tools, artist
detail, label detail, stats and issues. settings, help, hydrabase and chat are still
vanilla and stay that way for now.
the two biggest ports in this release were sync and discover, about 80 commits each.
discover included the artist map and artist web visualisations, roughly 4,450 lines of
canvas and sigma code. sync included the whole per-source playlist pipeline, the
discovery pool, mirrored export (#903) and the auto-sync builder.
each page was ported the same way: read the vanilla region end to end first, port the
pure logic with differential tests against the original behaviour, then the ui, then
flip the route and delete the vanilla code. the download engine itself is untouched and
stays vanilla.
dashboard redesign
the dashboard is content-first now. music leads the page: a recently-added rail with
album art and a fresh-from-your-artists rail with owned badges, then the library strip,
with the ops stuff demoted below.
- the sync band: auto sync and recent syncs merged into one section, with sync-again on
manual rows, listen buttons on sync cards, and one honest completeness number per row - alerts band and listen band
- the automations card went live — history, progress, pause/resume — plus a
quick-settings strip with accent color swatches - clicking a card in recently played plays that song again — your library copy first,
the stream source if you don't have it — the way recently added already worked - the services card and the rate-equalizer grid retired; test buttons moved to the
sidebar rows and the worker graphs into manage workers
discover, search, wishlist facelifts
- discover got the streaming-service redesign: rails and a billboard hero, personal row
names in a personal order, ownership chips on new releases and an ownership meter on
the hero. the page also pre-computes itself now — shelf caches plus a background
warmer, so the hero answers in milliseconds instead of tens of seconds - search got the premier visual makeover plus the behavior layer: recents, a top
result, jump chips and loading skeletons - wishlist got a list view — a dense operational twin of the nebula, with an artist
index that expands on demand, real album art, and artist clicks that resolve to the
actual artist page - the sync page's fifteen tabs are readable chips instead of slivers
tools & automations
both pages got the same treatment the dashboard and discover got — a full read, then a
rebuild around what you actually go there to do.
tools. the maintenance section opens with a health score and what's dragging it
down, instead of a wall of thirty identical job cards. findings are an inbox grouped by
type with a plain-english line explaining each one, so 3,000 findings read as a dozen
decisions. recent runs became its own card that says what a run accomplished rather
than that it happened. the thirty jobs are tiles now, grouped into families the backend
serves, each with its schedule editable on the tile face — previously every job ran on a
fixed interval you could not see or change. the glow edge on a tile is its progress bar.
automations. the page opens with a verdict — how many are armed, failing, never run
— and each number is a filter. sections became families that summarise themselves. the
cards stopped lying: a paused side no longer shows countdowns for runs that will not
happen, and a failed run is visible from across the room instead of being a grey
fragment at the end of a meta line. last-run summaries are sentences now ("added 4
tracks to 2 playlists") rather than raw handler keys. the cards then got the same tile
chassis as the maintenance jobs, including editing when an automation runs without
opening the builder. the builder's block palette — 45 triggers, 52 actions — is
searchable and grouped by category, on both the music and video sides.
music finally re-reads the library on a clock. it only ever re-read after soulsync
itself downloaded something, so music you added any other way — dropped in by hand,
ripped, moved from another box — sat outside soulsync's own database for up to a week
until the deep scan. the video side has had an hourly safety net for a while; music has
one now. same cheap incremental read it always used, just on a timer.
chat & arcade
the chat page is still vanilla js, but it grew a lot this release:
- movie night: nominate movies or episodes from your own library, the room votes, and
anyone missing the pick can wishlist it with full metadata in one click - trivia — the room itself is the buzzer, first right answer takes the pot
- othello and gomoku join chess, connect 4 and battleship, plus a full arcade visual
redesign and wagers so the bank economy finally closes - moderator powers for the room owner: hide, pin, game-kill
- message editing (twice max, history retained), channel mute, and challenging a user
straight from their card - fixes: channels other than #general work again, cold arcade tables expire themselves
instead of squatting in the lobby, and battleship's send path was dead
enrichment & player
- the enrichment matcher stopped smearing one artist id across multiple artists,
locking rows that were being played, and black-holing errors - verify matches: a targeted repair pass for rows the pre-fix matcher corrupted
- library radio, plus five player defects found in the deep review
fixes
- #1139 album torrent grabs stalling for hours, then losing the file
(Zombiehamser). six things at once. the album flow preferred a magnet when the
indexer offered both, and a magnet gives the client an info-hash and nothing else, so
one that can't reach the swarm parks on "downloading metadata" forever — it now
prefers the .torrent, fetches it here and pushes the file, keeping the magnet as the
fallback. the stall timeout was wired into the per-track path and never consulted for
album bundles. nothing enforced a minimum seeder count, so a field of dead releases
still got one queued. a stalled grab was never cleaned out of the client. every one of
those failures killed the whole batch instead of falling back to per-track. and a
torrent that completed could still report "no audio files found", because staging
walked the save path plus the torrent's display name rather than the client's exact
content path — the error also now separates "soulsync can't read that path" from "that
folder holds no audio" - #1138 a manual library match to a deleted file swallowed the track
(carlosjfcasero). match a song to a library file, delete the file, reprocess the
playlist: the song was neither downloaded nor wishlisted, every run, with only a
warning in the log. the download analysis treated the existence of a match row as
proof, so it marked the track found, pulled it off the wishlist and skipped the
download. it checks the match still resolves now — against the library database, not
the filesystem, because the stored path is the media server's and may not exist here
at all. removing a match from tools → manual library match also reports honestly
instead of claiming success when it deleted nothing - #1137 settings lost after a crash. an unreadable config row could be mistaken for
an absent one, and defaults got written over your settings. the db row now has to be
positively observed missing, a corrupt blob is quarantined instead of replaced, and
saves coalesce into one write. the deezer test no longer hangs on a slow arl, and the
qobuz pill lights when it should - #1134 /api/wishlist/process crashed on its own runtime factory
- watchlist → view discography could hard-fail with "provider is unavailable"
(the discord report). the link pinned a provider you'd switched off even when the
artist had no other match; it now only pins a source that can actually serve. a
related fix: a blind provider no longer starves the wishlist during watchlist scans - #1109 upgraded tracks landing in the library root. two separate bugs under one
report — the destination resolver treated a configured library root as an album
folder, and the superseded file was never retired because the exists-check ran
against the unresolved path - #1129 album and track names starting with a dot became hidden folders
- #1127 tools ignored custom file organization templates
- #1130 flac downloaded despite an mp3-only quality profile. the fallback honoured
bitrate but not format - #1132 acoustid suggesting wrong track metadata. correct files were flagged when a
variant happened to be listed first, and ambiguous fingerprints were asserted as
identities. it now declines to guess - #1128 manual track matches not remembered across syncs
- #1124 jellyfin library sync hardcoded to localhost:8096, shipping
placeholder credentials real enough to pass a truthiness check - youtube music (#1136, nstrelow). music.youtube.com playlists read from the yt
music catalog via ytmusicapi, per-track channel as artist, "- Topic" stripped,
cookies.txt fed through, and the plural creators field read too - tidal followed playlists appear now, and refresh no longer blocks for minutes
- discovery matches on an "Unknown Artist" row now fix the row itself instead of
leaving it unknown forever - #1067 / #1071 artist detail discography gaps. gap-fill plus gap ownership
- #889 re-identify track moved into the react library page
- #251 your mixes registry hook, and the #1079 preview bar folded into discover
- #863 a review of the sync port found an artist fallback that could never fire
- repair page (#1081, Lenochxd): one bad finding no longer blanks the whole page,
and errors say why - #1121 (nick2000713): the pre-library-v2 bugfix batch merged in
spotify free
explicit spotify requests now engage the no-auth free source without needing the
persistent opt-in, so clicking a spotify result gives you spotify rather than silently
serving another provider under a spotify label.
and a fix from testing this release: get_primary_source() was gating spotify on
is_spotify_authenticated(). a spotify free user has no credentials by design, so their
configured source was being silently demoted to the default on every call. the ui still
said spotify while everything actually ran on deezer, and watchlist scans for artists
the fallback couldn't resolve found nothing. it now checks metadata availability, which
is what the other gates already used. album art also now comes back at the same
resolution premium gets.
performance
- idle enrichment workers stopped scanning the 10gb database every 2 seconds — status
is cached at 30s when idle, live at 2s when running - the watchlist badge is a sql count instead of loading every row
- video library queries got their missing indexes, and type-ahead sheds the 3-second
size aggregate - background pages stop polling in hidden tabs, wishlist orbs mount their album fans
lazily, and the mirrored sync list no longer refetched itself every 2 seconds - slskd calls that could hang the page now carry timeouts
other
- on-screen error console at
?debug=1for phones and tablets with no devtools - mobile sidebar fixes: the drawer closes on an outside tap, a scroll gesture is no
longer treated as a tap, and dragging the drawer no longer opens whatever it started
on - the floating global search bar retired; sidebar sections renamed to collect / manage
dev.py --lan=<ip>so the vite dev server is reachable from another device- two startup bugs fixed: a hydration guard and a root-path race that could leave a
react page blank
notes
the download engine is unchanged. the settings, help,
hydrabase and chat pages are still vanilla js (chat gained features but not a rewrite).
the video side is unchanged except three fixes: a string limit that killed every library
scan, a wishlist-drain crash in the blocklist path, and the same magnet-over-.torrent
preference behind #1139 — video grabs now prefer the .torrent and carry the magnet as a
fallback, exactly like the music side.
the automation builder is still vanilla and still shared with the video side; its block
palette gained search and categories in place rather than being rewritten. roughly 2,000
lines of the old vanilla tools page were deleted this release after the react flip, once
each function was proven to have no remaining caller.