Minimal menu bar controller for a Music Assistant server.
- Menu bar-only app (no dock icon via accessory activation policy)
- WebSocket API client (
ws://<host>:<port>/ws) - Configurable API host + port
- Token input with permanent Keychain storage
- Bonjour auto-discovery (
_music-assistant._tcpthen_home-assistant._tcp) - Auto target selection:
- Prefer currently playing group player
- Else currently playing non-synced coordinator
- Else last successful target
- Previous/Play-Pause/Next transport controls
- Play/Pause button label reflects current state (
Playwhen paused/idle,Pausewhen playing) - Volume slider (0-100)
- Group target:
players/cmd/group_volume - Normal player:
players/cmd/volume_set
- Group target:
- Now Playing line with marquee scrolling for long track text
- Global hardware Play/Pause media-key listener (native, no dependencies)
- Exclusive Play/Pause key capture via
CGEventTapwhen permissions allow - Automatic reconnect with backoff
swift run MusicAssistantMenuBarswift buildswift testUse build.sh for a signed distributable .app and .zip (outside Mac App Store):
./build.shOptional environment variables:
SIGN_APP(default:1; set0to skip code signing for CI/dev artifacts)SIGNING_IDENTITY(optional; auto-detected when possible)APP_NAME(default:MusicAssistantMenuBar)PRODUCT_NAME(default:MusicAssistantMenuBar)APP_ICON_PATH(default:Assets/AppIcon.icns)BUNDLE_ID(default:io.example.musicassistant.menubar)VERSION(default:1.0.0)BUILD_NUMBER(default:1)OUTPUT_DIR(default:dist)SIGNING_KEYCHAIN(path to a specific keychain)SIGNING_CERT_P12_BASE64(optional; base64-encoded.p12for CI import)SIGNING_CERT_PASSWORD(required whenSIGNING_CERT_P12_BASE64is set)CI_KEYCHAIN_PASSWORD(optional; temp keychain password)NOTARIZE=1to notarize- Use
NOTARY_PROFILE(recommended), or APPLE_ID,APPLE_APP_SPECIFIC_PASSWORD,APPLE_TEAM_ID
- Use
Artifacts are written to dist/.
Publishing Instructions (Click to Expand)
GitHub Actions workflow: .github/workflows/build.yml
- Every push/PR runs
swift test, then builds on macOS and uploads an unsigned.app+.zipas workflow artifacts - Tag pushes with prefix
v(for examplev1.2.3) runswift test, then build a signed app and publish${APP_NAME}-${tag}.app.zipto GitHub Releases
To use signing in CI, export your certificate:
- Open
Keychain Access->login->My Certificates. - Find
Developer ID Application: .... - Right click ->
Export ...-> save as.p12with a password. - Convert to base64:
base64 -i /path/to/DeveloperID.p12 | pbcopySet repository secrets:
SIGNING_CERT_P12_BASE64SIGNING_CERT_PASSWORDSIGNING_IDENTITY(optional, recommended)CI_KEYCHAIN_PASSWORD(optional)
Optional notarization secrets:
NOTARIZE=1NOTARY_PROFILE(recommended), orAPPLE_ID+APPLE_APP_SPECIFIC_PASSWORD+APPLE_TEAM_ID
Optional repository variable:
BUNDLE_ID(defaults toio.example.musicassistant.menubar)
Create a release:
git tag v1.0.0
git push origin v1.0.0- Host/port are saved in
UserDefaultsand token is saved in Keychain. - Use the gear button in the menu panel to configure host/port/token and connect.
- To fully block Apple Music from launching on Play/Pause, grant Accessibility/Input Monitoring permissions to the app process. Without permissions, the app falls back to passive key monitoring.
- The permission warning includes quick actions:
Allow Access,Open Settings, andRetry.
