What's Changed
The work breaks into four logical themes, plus one unrelated stability fix.
1. Hosted XSPF robustness (3 commits)
68a2eee— Auto-recover from renderer crashes and disable background throttling. Unrelated to sync; keeps the renderer process alive through transient crashes.2e5d89a— Persist hosted playlists so they survive sync reloads and auto-sync to providers. FixedhandleImportPlaylistFromUrltowindow.electron.playlists.saveboth new and updated hosted playlists (previously they lived only in React state + a URL list, so sync reloads dropped them).30978b1— Mark hosted playlists aslocallyModifiedwhen XSPF content actually changes. Stops spurious push attempts on startup reload when content is identical.- Support for new radio station Rewind playlists (as found on https://jherskowitz.github.io/spinbin/)
2. Spotify duplicate-creation fix, layered (4 commits)
745e2db— In-session mutex (playlistSyncInProgressRef). Prevents the background-sync loop and the manual-sync post-IIFE from racing each other into concurrentcreatePlaylistcalls on the same playlist.acb2a76— PreservesyncedTo,sourceUrl,sourceon everysavePlaylistToStorecall. Title edits, track changes, etc. had been silently stripping the Spotify sync link, causing the next sync to treat the playlist as unlinked and create another duplicate.214333e— Defense-in-depth name match insync:create-playlist(main.js). Before creating on the remote, fetch the user's owned playlists and reuse any existing copy with the same name — last-ditch protection when the ID link is missing for any reason.40bb2cb—sync_playlist_links, a durable local→remote ID map stored in electron-store, independent of playlist-object saves. Primary dedup layer; name match demoted to last-resort fallback. Includes idempotent startup migration from existingsyncedTodata so existing users get the map populated on first launch with no migration work.
3. Cleanup + repair tooling (2 commits)
4b839f6— Link-aware keeper selection incleanupDuplicatePlaylists. Instead of "most tracks wins," prefer the Spotify copy a local playlist is actually linked to — so dedup no longer silently re-points a curated local to some other copy of the same name. Groups with ambiguous link patterns are skipped entirely and surfaced asambiguousin the result.8061b4c— Orphan relink as the first phase of cleanup. Before dedup runs, find local playlists with tracks but no link for the provider, match them by name to unambiguous user-owned remotes, writesyncedTo+sync_playlist_linksentries. This feeds into the link-aware keeper so existing-link info is current. Exposed as a standalonesync:relink-orphaned-playlistsIPC too, for future use.
4. Hosted-playlist UI honesty (1 commit)
e6386ad— Suppress pull/conflict UI on hosted XSPF playlists. If a hosted playlist hassourceUrl+syncedFrom.spotify, the "Pull" button was a trap — the 5-min XSPF poller would revert the pull within minutes and the next sync would overwrite Spotify with XSPF state anyway. Now: pull-only state hides the banner; conflict renders as push (XSPF wins).
5. Apple Music playlist sync (2 commits — community + follow-up)
8c409d5(PR #748, community contributor LeVINCEoN) —PUT→POSTon/me/library/playlists/{id}/tracks. Fixed a 401 when creating a new playlist with tracks on Apple Music. Apple's documented method is POST; PUT is rejected.b1e6104— Follow-up to PR #748 restoring replace-ish semantics. The raw POST from the PR was append-only, which would duplicate tracks on push-to-existing and link-to-existing paths. RewroteupdatePlaylistTracksto diff-based append: GET current remote, subtract existing catalog IDs, POST only the difference. Known limitation (documented): locally-removed tracks stay on Apple Music — Apple's public API has no per-track DELETE. Also fixeddeletePlaylist's clear-fallback that had been relying on the pre-PR PUT-to-empty-array "clear" trick.
6. Documentation (1 commit)
b16bc50— Expanded the Playlist Sync section of CLAUDE.md with the full data model, durable link map semantics, three-layer dedup order, cleanup phasing, hosted XSPF semantics, the full IPC surface, and an invariants/traps list. Intended as a reference for the Android implementation so the two platforms stay consistent. (The follow-upb1e6104above also appended a provider-specific push-semantics table calling out the Spotify-vs-Apple-Music asymmetry.)
Overall theme
The big story is playlist sync duplicate prevention on Spotify, approached in layers: first a simple mutex, then discovering syncedTo was being stripped on save (fix), then a defense-in-depth name match at the IPC gateway, then replacing name-match with a proper durable ID map, then making the cleanup tool link-aware so running it doesn't create the very bug we just fixed, then an orphan-repair step to backfill users who accumulated damage before the fixes. Plus the community Apple Music PR and its append-vs-replace follow-up. Hosted XSPF work and the renderer crash recovery are adjacent but smaller.
New Contributors
- @LeVINCEoN made their first contribution in #748
Full Changelog: v0.9.0-beta.9...v0.9.0-beta.10