Highlights ✨
🎼 Sidra v0.4.0 brings Apple Music Classical into the same desktop app as Apple Music. Switch at runtime from the tray's Player submenu, with separate start pages and last visited pages remembered for each service. Navigation controls and themes work on both. itms:// links still open regular Apple Music, and Classical has no Library route - we cannot wrap a page Apple does not provide.
📊 We've also added opt-in Last.fm scrobbling. Connect from the tray and approve Sidra in your browser, then Sidra sends Now Playing and scrobbles after half the track or four minutes, whichever comes first. Tracks of 30 seconds or less stay out. Temporary network or service failures queue up to 50 plays for a later successful playback request, though delivery is never guaranteed.
🎨 The Style menu now has six bundled themes: Catppuccin, Dracula, Gruvbox, Nord, Rosé Pine and Solarized, alongside the Apple Music default. A readable, non-blank custom.css adds a live-reloading Custom entry, though custom CSS remains an unsupported escape hatch rather than a stable API. Close to Tray is optional and off by default; enable it and closing Sidra hides the window while playback continues, with Show, Hide and Quit in the tray. You can also scroll over Apple's volume control in 5% steps.
What's Changed
- chore(nix): update hashes for v0.3.5 by @github-actions[bot] in #138
- build(deps): bump actions/cache from 5 to 6 in the github-actions group by @dependabot[bot] in #148
- build(deps): update Electron toolchain by @github-actions[bot] in #146
- add configurable close-to-tray behaviour by @MelonSmasher in #119
- fix(tray): only intercept tray clicks when close-to-tray is enabled by @flexiondotorg with @Copilot in #155
- build(deps): bump nixpkgs from
567a49dtod407951by @dependabot[bot] in #152 - fix(musicKitHook): prevent duplicate command listeners by @naxey in #154
- refactor(musicKitHook): rename injection guard to __sidraHookInjected by @flexiondotorg with @Copilot in #156
- fix(musicKitHook): report position state to navigator.mediaSession by @flexiondotorg with @Copilot in #157
- feat(theme): add bundled theme registry and custom.css escape hatch by @flexiondotorg with @Copilot in #158
- refactor: introduce music service registry by @flexiondotorg with @Copilot in #159
- feat: add Apple Music Classical support by @flexiondotorg with @Copilot in #160
- build(deps): bump nixpkgs from
d407951to753cc8aby @dependabot[bot] in #163 - feat: Last.fm scrobbling support by @rollecode in #145
- build(deps): bump nixpkgs from
753cc8atoe2587caby @dependabot[bot] in #167 - build(deps): bump fast-uri from 3.1.2 to 3.1.4 by @dependabot[bot] in #168
- build(deps-dev): bump postcss from 8.5.15 to 8.5.23 by @dependabot[bot] in #170
- fix(lastfm): resolve post-merge scrobbling defects by @flexiondotorg in #171
- fix(deps): bump js-yaml to 4.3.0 for CVE-2026-59869 by @flexiondotorg in #172
- docs(readme): update deprecated Nix install alias by @joermo in #169
- fix: remediate the six Copilot PRs merged 12 July (WW-91) by @flexiondotorg in #175
- refactor(tray): group Close to tray with the window settings by @flexiondotorg in #176
- fix(tray): give the Player, Hide, and Show menu items distinct icons by @flexiondotorg in #177
- fix(notifications): stop freeze when no D-Bus daemon is running by @flexiondotorg in #178
- fix(discord): show the track title in the Discord member list by @flexiondotorg in #179
- docs(readme): refresh Features and replace the security report by @flexiondotorg in #180
- feat(theme): apply bundled themes and custom.css on Classical by @flexiondotorg in #181
- refactor(theme): drop dead selectors and properties, correct docs by @flexiondotorg in #182
- fix(theme): match the player bar and LCD to the active theme by @flexiondotorg in #183
- refactor(theme): drop the dead dt-footer selector from styleFix.css by @flexiondotorg in #184
- build(deps): bump nixpkgs from
e2587cato624af66by @dependabot[bot] in #185 - fix(discord): rebuild the RPC client on every reconnect by @flexiondotorg in #186
- fix(hook): bind the volume listener to playbackVolumeDidChange by @flexiondotorg in #187
- feat(hook): scroll over the volume control to change volume by @flexiondotorg in #188
- build(deps-dev): bump the npm group with 2 updates by @dependabot[bot] in #190
- build(deps): bump the github-actions group with 4 updates by @dependabot[bot] in #191
- fix: close peer-review enforcement gaps and startup wedges by @flexiondotorg in #192
- fix(lastfm): report scrobbles Last.fm silently filtered by @flexiondotorg in #193
- feat(mpris): fall back to the share URL for xesam:url by @Thukumo in #189
- fix(player): build the share URL from the payload's own host by @flexiondotorg in #194
- docs: polish comments across the tree by @flexiondotorg in #195
- fix: clear behavioural residue from the comment quality pass by @flexiondotorg in #196
- docs: drop the false asarUnpack glob claim from AGENTS.md by @flexiondotorg in #197
- refactor: complete a code-smells review of the whole codebase by @flexiondotorg in #199
- fix(ci): open a pull request the toolchain workflow can land by @flexiondotorg in #200
- build(deps): update to CastLabs Electron 43.0.0+wvcus by @flexiondotorg in #201
- fix(lastfm): start playback accounting at opt-in by @flexiondotorg in #202
New Contributors
- @MelonSmasher made their first contribution in #119
- @flexiondotorg with @Copilot made their first contribution in #155
- @naxey made their first contribution in #154
- @rollecode made their first contribution in #145
- @joermo made their first contribution in #169
- @Thukumo made their first contribution in #189
Full Changelog: 0.3.5...0.4.0