A personal iOS music player with a clean, native SwiftUI interface.
Personal use only — not for distribution.
PeacePlayer has two parts:
- iOS app — SwiftUI client running on your iPhone
- Python backend — runs on your Mac, handles music search, streaming, and audio extraction
The iPhone connects to your Mac over your local network (WiFi or Tailscale).
The backend refuses to start without a strong PEACEPLAYER_JWT_SECRET
(it signs the session JWTs the iOS app uses to authenticate to
user-data endpoints). Copy the example file and fill in a real value:
cp backend/.env.example backend/.env
# Generate a high-entropy secret:
python3 -c "import secrets; print(secrets.token_urlsafe(48))"
# Paste the result into backend/.env as PEACEPLAYER_JWT_SECRET=...backend/.env is gitignored. For the launchd-managed service, the
env var is set in the plist (~/Library/LaunchAgents/com.peaceplayer.backend.plist)
and the file is not consulted.
The backend runs automatically as a macOS background service (com.peaceplayer.backend) — it starts on login and restarts if it crashes. No manual start needed after initial setup.
For first-time setup:
make setup # Install Python dependenciesThen load the service (once):
launchctl load ~/Library/LaunchAgents/com.peaceplayer.backend.plistThe service plist is at ~/Library/LaunchAgents/com.peaceplayer.backend.plist.
make auth # Follow prompts to connect your Google accountThis unlocks your liked songs, playlists, and personalized recommendations. Without it, search and streaming still work.
Edit ios/Sources/APIService.swift and set your Mac's hostname or IP:
return "http://YOUR_MACHINE_HOSTNAME:8181"To find your IP:
make ipOr, after launching the app once, open Settings → Backend Host and type the new URL there — the change takes effect immediately (no app restart needed) and there's a "Test connection" button to confirm the backend is reachable.
Open the Xcode project:
make iosIn Xcode:
- Set your Development Team (Signing & Capabilities)
- Select your iPhone as the target device
- Build and run (Cmd+R)
| Feature | Guest | Authenticated |
|---|---|---|
| Search songs | ✅ | ✅ |
| Stream audio | ✅ | ✅ |
| Download tracks | ✅ | ✅ |
| Lyrics | ✅ | ✅ |
| Radio / autoplay | ✅ | ✅ |
| Liked songs | ❌ | ✅ |
| Your playlists | ❌ | ✅ |
| Personalized recommendations | ❌ | ✅ |
┌─────────────────────────────────────────────────────┐
│ iOS App (Swift) │
│ SwiftUI · AVPlayer · Core Data · Background Audio │
└────────────────────────┬────────────────────────────┘
│ HTTP (WiFi / Tailscale)
┌────────────────────────┴────────────────────────────┐
│ Python Backend (macOS) │
│ FastAPI · ytmusicapi · yt-dlp · FFmpeg │
└─────────────────────────────────────────────────────┘
The backend runs as a macOS LaunchAgent (com.peaceplayer.backend) that auto-starts on login.
# Check if running
launchctl list | grep peaceplayer
# Stop the service
launchctl unload ~/Library/LaunchAgents/com.peaceplayer.backend.plist
# Start the service
launchctl load ~/Library/LaunchAgents/com.peaceplayer.backend.plist
# View logs (live)
tail -f ~/iYMusic/YTAudioSystem/backend/server.log
# Verify backend is responding
curl http://localhost:8181/If the plist isn't installed yet:
cp ~/iYMusic/YTAudioSystem/backend/com.peaceplayer.backend.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.peaceplayer.backend.plistmake setup # Install Python dependencies
make dev # Start with auto-reload (development mode)
make auth # Authenticate with Google (optional)
make ios # Open Xcode project
make ip # Show your Mac's local IP address
make clean # Remove cached/temp files
make distclean # Full reset (removes venv + oauth)"Cannot connect to server"
- Confirm the backend is running:
curl http://localhost:8181/ - Check the IP/hostname in
APIService.swiftmatches your Mac - Make sure iPhone and Mac are on the same network, or both on Tailscale
No audio in background
- Info.plist must have
UIBackgroundModes→audio - Accept background audio permissions when prompted
Auth fails
- Re-run
make auth - Delete
backend/oauth.jsonto reset to guest mode