211 lines
8.0 KiB
Markdown
211 lines
8.0 KiB
Markdown
# 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
|
|
|
|
### Music Library
|
|
- Stream music from your Navidrome / Subsonic library
|
|
- Browse artists, albums, playlists, starred tracks, genres, and random picks
|
|
- Search across songs, albums, and artists
|
|
- Star and context menu on every song row
|
|
- Play count display (optional)
|
|
|
|
### Lyrics
|
|
- Synced and plain lyrics via lrclib.net, auto-fetched per track
|
|
- Fallback chain: exact match → no-duration match → fuzzy artist+title search → title-only search
|
|
- In-memory cache per session
|
|
|
|
### Artist Pages
|
|
- Hero card with artist photo and blurred background
|
|
- Bio, similar artists, top songs from Last.fm
|
|
- Concert events via Ticketmaster
|
|
- Albums cross-referenced against iTunes catalog — shows downloaded vs. missing tracks
|
|
- Artist cards with images in search results
|
|
|
|
### Playback
|
|
- Queue with shuffle, repeat (all / one), and radio mode (endless similar songs)
|
|
- Now Playing overlay with synced lyrics, queue view, star, and multi-artist links
|
|
- Gapless-style playback — next track pre-buffered before current track ends
|
|
- Lock screen / notification media controls
|
|
- Scrobbling to Navidrome (configurable delay)
|
|
|
|
### Discovery
|
|
- iTunes / Last.fm — charts, global search, 30-second previews, similar artists
|
|
- Song Importer — paste a Spotify, YouTube, YouTube Music, or SoundCloud link to download
|
|
|
|
### Downloads (yt-dlp backend)
|
|
- Download tracks, albums, or entire artists from YouTube Music / SoundCloud / Spotify
|
|
- iTunes metadata enrichment — album art, year, track number, genre
|
|
- Duplicate detection, standard folder/filename structure
|
|
|
|
### Metadata Editor
|
|
- Edit tags (title, artist, album, genre, year, track, disc, cover art)
|
|
- File renamed and moved automatically; Navidrome rescan triggered on save
|
|
|
|
### Playlists
|
|
- Create, edit, delete playlists; add / remove tracks
|
|
|
|
### Audiobookshelf Integration
|
|
- **Web:** browse libraries, stream audiobooks, chapter navigation, playback speed, sleep timer, progress sync
|
|
- **Android:** browse libraries and audiobook list (tab hidden until ABS is configured in Settings)
|
|
|
|
### App — Web PWA
|
|
- Installable on Android / iOS / desktop
|
|
- Multiple color themes, German UI
|
|
|
|
### App — Android (native Jetpack Compose)
|
|
- Media3 / ExoPlayer backend
|
|
- OS notification with playback controls
|
|
- Last played song shown in mini player bar on restart; tap to resume
|
|
|
|
---
|
|
|
|
## 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
|
|
│ ├── squid.js # Qobuz (squid.wtf) download backend
|
|
│ ├── 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
|
|
│ ├── 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
|
|
|
|
```bash
|
|
git clone <repo>
|
|
cd NovaSonic
|
|
cp .env.example .env
|
|
```
|
|
|
|
Edit `.env`:
|
|
|
|
```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
|
|
|
|
DOWNLOAD_BACKEND=auto # ytdlp | squid | auto
|
|
SQUID_QUALITY=mp3 # mp3 | flac | hi-res
|
|
|
|
TICKETMASTER_API_KEY= # optional — free key from developer.ticketmaster.com
|
|
```
|
|
|
|
### 2. Start
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
Frontend on port 8080, backend on port 3700. Route both through your reverse proxy.
|
|
|
|
### 3. First launch
|
|
|
|
1. Enter your Navidrome server URL, username, and password
|
|
2. Optionally add a Last.fm API key in Settings for bios and recommendations
|
|
3. Optionally connect Audiobookshelf in Settings
|
|
4. 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 |
|
|
| `DOWNLOAD_BACKEND` | `auto` | `ytdlp` / `squid` / `auto` |
|
|
| `SQUID_QUALITY` | `mp3` | Qobuz quality: `mp3`, `flac`, `hi-res` |
|
|
| `TICKETMASTER_API_KEY` | — | Free key from [developer.ticketmaster.com](https://developer.ticketmaster.com) |
|
|
|
|
---
|
|
|
|
## Development
|
|
|
|
```bash
|
|
npm install
|
|
npm run dev # Vite dev server with HMR
|
|
npm run build # Production build → dist/
|
|
npm run preview # Preview the production build locally
|
|
```
|