# NovaSonic A self-hosted music streaming PWA for Navidrome / Subsonic-compatible servers. Built with Vite + vanilla ES modules, served via nginx in Docker. --- ## Features ### Home - Hero card — large banner featuring a random pick from your most-played and recently played albums, labelled "Meistgespielt" or "Zuletzt gehört" accordingly - Genre browser — top 15 genres (by song count) as a colored card grid; click to browse songs, hover-play to instantly shuffle the genre ### Music Library - Stream music from your Navidrome / Subsonic library - Browse artists, albums, playlists, starred tracks, and random picks - Sort and filter views (albums, favorites) with chip filters - Search/filter bar inside playlist detail and favorites (instant, client-side) - Synced and plain lyrics via LRCLIB (auto-fetched per track) - Play count display — optional toggle in Settings; always shown on artist pages - Star and context-menu on every song row (artist top songs, all-songs view, playlists, albums) ### Playback - Queue management with shuffle, repeat (all / once), and radio mode (endless random) - Now Playing overlay with swipe-to-dismiss; queue tab stays active when selecting a song from the queue - Lock screen media controls (Android / iOS via Media Session API) - Gapless-style queue with prev/next, skip forward/back - Scrobbling — plays are reported to Navidrome after 15 seconds of continuous playback ### Discovery - iTunes / Last.fm integration — charts, global search, 30-second previews, similar artists, recommendations - Spotify playlist importer — paste a Spotify playlist URL to preview and download all tracks, enriched with iTunes metadata and cover art ### Downloads (yt-dlp backend) - Download individual tracks, full albums, or entire artists from YouTube / SoundCloud - Spotify playlist importer downloads with iTunes-enriched metadata (album, year, track number, genre, cover art) - Duplicate detection — skips tracks already present on the server - Lyrics embedded into downloaded files (LRCLIB) ### Playlists - Create, edit, and delete playlists - Edit playlist name, description, cover art, and public/private toggle - Add / remove tracks; reorder via drag and drop ### Audiobookshelf Integration - Connect to your Audiobookshelf server (URL + API key) - Browse and stream audiobooks from your ABS library - Full player: chapters list, playback speed, sleep timer (preset or custom minutes), progress sync ### App - PWA — installable on Android / iOS / desktop, offline-capable via service worker - Android APK (WebView wrapper with native Media3/ExoPlayer backend) - Robust Android queue sync — song identity verified via media ID on every resume to prevent stale-state mismatches - Multiple color themes - Dark theme, mobile-first responsive layout - German UI --- ## Project Structure ``` Music_App/ ├── src/ # ES modules (Vite entry) │ ├── state.js # Shared mutable state (S object) │ ├── utils.js # md5, esc, formatDur, toast │ ├── api.js # Subsonic API, Navidrome REST, iTunes API │ ├── player.js # Playback, transport, queue, media session, preview │ ├── views.js # Navigation, page loaders, card makers, search │ ├── ui.js # Modals, overlays, sidebar, settings, context menu │ ├── nowplaying.js # Now Playing overlay │ ├── abs.js # Audiobookshelf integration │ ├── spotify.js # Spotify playlist importer │ ├── components.js # Shared UI components │ ├── themes.js # Theme switching │ ├── pwa.js # Service worker registration + update banner │ └── main.js # App init, audio wiring, window globals ├── backend/ │ ├── novasonic-server.js # Node.js download backend (yt-dlp + ffmpeg) │ └── lib/ │ └── metadata.js # iTunes lookup, lyrics fetch, artwork download ├── public/ # Static assets (copied as-is to dist/) │ ├── sw.js # Service worker │ ├── manifest.json # PWA manifest │ ├── icon.svg # App icon │ └── config.js # Runtime config placeholder (generated by Docker) ├── android/ # Android WebView APK wrapper ├── index.html # App shell + Vite entry point ├── styles.css # All styles ├── vite.config.js ├── Dockerfile # Multi-stage: Node build → nginx serve ├── docker-compose.yml ├── nginx.conf └── docker-entrypoint.sh # Injects NS_SERVER_URL / NS_BACKEND_URL at startup ``` --- ## Docker Setup ### Frontend only ```bash docker compose up -d ``` Environment variables (set in `docker-compose.yml` or via `-e`): | Variable | Description | |---|---| | `NS_SERVER_URL` | Pre-fills the Navidrome server URL on the login screen | | `NS_BACKEND_URL` | Pre-fills the download backend URL | ### With download backend The backend requires `yt-dlp` and `ffmpeg`. A separate `docker-compose.yml` lives in `backend/`. ```bash cd backend docker compose up -d ``` Environment variables for the backend: | Variable | Default | Description | |---|---|---| | `PORT` | `3700` | Port the backend listens on | | `MUSIC_PATH` | `/music` | Path to your Navidrome music folder (mount as volume) | | `AUDIO_FMT` | `mp3` | Output format (`mp3`, `flac`, `opus`, …) | | `AUDIO_QUALITY` | `0` | yt-dlp audio quality (0 = best) | | `MAX_PARALLEL` | `2` | Maximum concurrent downloads | --- ## 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 ``` --- ## First Launch 1. Open the app in a browser 2. Enter your Navidrome server URL, username and password 3. Optionally add a Last.fm API key (Settings) for recommendations and similar artists 4. Optionally add the backend URL (Settings) to enable yt-dlp downloads 5. Optionally connect Audiobookshelf (Settings) to stream audiobooks