Deletes backend/lib/squid.js; strips all references from downloader.js, config.js, novasonic-server.js, docker-compose.yml, .env.example, README, and CHANGELOG. Default DOWNLOAD_BACKEND is now ytdlp. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.3 KiB
8.3 KiB
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
- Download tracks, albums, or entire artists from YouTube Music / SoundCloud / Spotify via yt-dlp
- 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, rename, and delete playlists
- Add tracks via "Add to Playlist" context menu
- Remove tracks from a playlist (edit mode on Android; inline on Web)
- Cover image upload (Web + Android)
Audiobookshelf Integration
- Browse libraries and audiobooks on both Web and Android
- Stream audiobooks with chapter-by-chapter navigation
- Playback speed control (0.5× – 2.0×)
- Sleep timer
- Progress sync — current position saved back to ABS server every 30 s
- Chapter track mode — progress bar shows current chapter length instead of full book (toggle in Settings)
- Tab/section 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
- ABS audiobook notification: chapter name shown as title, book title as artist; extra buttons — Kapitel zurück | 30s zurück | Play/Pause | 30s vor | Kapitel vor (compact + expanded)
- Last played song shown in mini player bar on restart; tap to resume
- Full playlist management: create, rename (with description), delete, remove tracks, cover upload
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
│ ├── 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