b07212fdcee882cbc6e38aef2327c31d5ddacd93
Shows the live NavController back stack at the top of the screen so we can see whether detail screens are being pushed correctly or the back button isn't being handled. To be reverted once the back-navigation issue is diagnosed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
NovaSonic
A self-hosted music streaming PWA and Android app for Navidrome / Subsonic-compatible servers.
Built with Vite + vanilla ES modules (web) and Jetpack Compose + Media3/ExoPlayer (Android).
Features
- Library — Stream from Navidrome / Subsonic; browse artists, albums, playlists, genres, starred, and random; search; star + context menu on every row.
- Playback — Queue with shuffle, repeat, and radio mode (endless similar songs); gapless-style preload; lock-screen / notification controls; Navidrome scrobbling.
- Lyrics — Synced and plain lyrics via lrclib.net, auto-fetched and cached per session.
- Artist pages — Hero card, Last.fm bio / similar / top songs, Ticketmaster events, and iTunes cross-reference showing owned vs. missing tracks.
- Playlists — Create, rename, delete, add/remove tracks, and upload a cover (Web + Android).
- Importer & downloads — Paste a Spotify / YouTube / YouTube Music / SoundCloud link to download via yt-dlp, with iTunes metadata enrichment and duplicate detection.
- Metadata editor (web) — Edit tags + cover art; files are renamed/moved and Navidrome is rescanned on save.
- Offline (Android) — Download albums/playlists to private storage; an Offline tab to play and manage them; downloaded tracks play from disk on every screen.
- Audiobookshelf — Browse and stream audiobooks with chapter navigation, speed control, sleep timer, and progress sync.
Web is an installable PWA (themes, German UI); Android is native Jetpack Compose + Media3/ExoPlayer with a mini player, media/ABS notifications, and Android Auto. See CHANGELOG.md for the full web/Android parity matrix.
Project Structure
NovaSonic/
├── src/
│ ├── player/
│ │ ├── player.js # Playback, queue, transport, media session, preload
│ │ └── nowplaying.js # Now Playing overlay + synced lyrics
│ ├── views/
│ │ ├── detail.js # Artist / album detail pages
│ │ ├── views.js # Navigation, page loaders, search
│ │ ├── events.js # Ticketmaster concert events
│ │ ├── home.js # Home page
│ │ ├── search.js # Search, artist/album navigation
│ │ ├── playlists.js # Playlist management
│ │ ├── spotify.js # Spotify importer
│ │ ├── youtube.js # YouTube importer
│ │ ├── soundcloud.js # SoundCloud importer
│ │ ├── navigation.js # Client-side router
│ │ └── abs.js # Audiobookshelf integration
│ ├── ui/
│ │ ├── ui.js # Modals, sidebar, context menu
│ │ ├── components.js # Song rows, cards, shared UI
│ │ ├── downloads.js # Download modal + job tracker
│ │ ├── metadata.js # Metadata editor
│ │ ├── modals.js # Song info, events modals
│ │ ├── notify.js # Toast notifications
│ │ └── settings.js # Settings page
│ ├── state.js # Shared mutable state (S object)
│ ├── utils.js # Helpers (md5, esc, formatDur, toast)
│ ├── api.js # Subsonic API, iTunes API, cover art
│ └── main.js # App init, audio wiring, window globals
├── backend/
│ ├── novasonic-server.js # Express API: downloads, metadata, events proxy, ABS proxy
│ └── lib/
│ ├── config.js # Env var → config object
│ ├── jobs.js # In-memory download job store
│ ├── metadata.js # iTunes lookup, artwork, filename helpers
│ ├── ytdlp.js # yt-dlp download + ffmpeg metadata embedding
│ ├── downloader.js # Unified downloadTrack / downloadAlbumTracks
│ └── romaji.js # Japanese → romaji search index
├── android/ # Native Android app (Jetpack Compose + Media3)
│ └── app/src/main/kotlin/com/novasonic/app/
│ ├── api/ # SubsonicClient, AbsClient, LrcLibClient, ItunesClient
│ ├── data/ # PrefsStore (DataStore), MusicRepository
│ ├── offline/ # Room DB, DAO, OfflineRepository, DownloadWorker (offline downloads)
│ ├── player/ # PlayerController, MusicService (Media3)
│ ├── ui/
│ │ ├── screen/ # HomeScreen, NowPlayingScreen, AbsScreen, SettingsScreen, …
│ │ ├── component/ # MiniPlayer, SongRow, SongContextSheet, …
│ │ └── theme/ # Color, Type, Theme
│ └── viewmodel/ # ViewModel per screen
├── public/
│ ├── sw.js # Service worker
│ ├── manifest.json # PWA manifest
│ └── config.js # Runtime config (generated by Docker entrypoint)
├── index.html
├── styles.css
├── vite.config.js
├── Dockerfile
├── docker-compose.yml
├── nginx.conf
└── docker-entrypoint.sh # Injects NAVIDROME_URL / BACKEND_URL at runtime
Setup
1. Clone and configure
git clone <repo>
cd NovaSonic
cp .env.example .env
Edit .env:
NAVIDROME_URL=https://music.yourdomain.com
BACKEND_URL=https://novasonic-api.yourdomain.com
MUSIC_PATH=/srv/navidrome/music
AUDIO_FMT=mp3 # mp3 | flac | opus | best
AUDIO_QUALITY=0 # 0 = best (yt-dlp)
MAX_PARALLEL=2
TICKETMASTER_API_KEY= # optional — free key from developer.ticketmaster.com
2. Start
docker compose up -d
Frontend on port 8080, backend on port 3700. Route both through your reverse proxy.
3. First launch
- Enter your Navidrome server URL, username, and password
- Optionally add a Last.fm API key in Settings for bios and recommendations
- Optionally connect Audiobookshelf in Settings
- Optionally add the NovaSonic backend URL in Settings to enable downloads
Environment Variables
Frontend container
| Variable | Description |
|---|---|
NAVIDROME_URL |
Pre-fills the Navidrome server URL on the login screen |
BACKEND_URL |
Pre-fills the download backend URL on the login screen |
Backend container
| Variable | Default | Description |
|---|---|---|
PORT |
3700 |
Port the backend listens on |
MUSIC_PATH |
/music |
Absolute path to your Navidrome music folder |
AUDIO_FMT |
mp3 |
Download format (mp3, flac, opus, best) |
AUDIO_QUALITY |
0 |
yt-dlp audio quality (0 = best) |
MAX_PARALLEL |
2 |
Max concurrent download jobs |
TICKETMASTER_API_KEY |
— | Free key from developer.ticketmaster.com |
Development
npm install
npm run dev # Vite dev server with HMR
npm run build # Production build → dist/
npm run preview # Preview the production build locally
Releases
1
NovaSonic 1.26
Latest
Languages
Kotlin
47.4%
JavaScript
40.1%
CSS
5.5%
HTML
5.4%
Python
0.8%
Other
0.8%