HoneyandClaude Sonnet 4.6 e3c435420c fix: artist hero banner shows face/upper body on desktop
background-position: center crops to mid-body on wide desktop banners.
Shifting to center 20% anchors the crop in the upper-third of the image
where faces typically are, matching the phone experience.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 20:57:22 +02:00

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)
  • Spotify-style shuffle — pre-shuffles the full queue so every song plays exactly once
  • 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
  • Song Importer — paste a link from Spotify, YouTube, YouTube Music, or SoundCloud to preview and download tracks, enriched with iTunes metadata and cover art

Downloads (yt-dlp backend)

  • Download individual tracks, full albums, or entire artists
  • Sources: YouTube Music (primary), YouTube, SoundCloud, Spotify (via playlist importer)
  • iTunes enrichment — album, year, track number, genre, 1000×1000 cover art
  • Duplicate detection — skips tracks already present on the server
  • Standard filename convention: {01 - }Artist1, Artist2 - Title.ext
  • Files organised into MusicRoot/AlbumArtist/Album/ folders automatically

Metadata Editor

  • Edit title, artist, album artist, album, genre, year, track number, disc number from within the app
  • Update embedded cover art via URL or file upload
  • Artist separator normalization — accepts •, ·, ;, , as input; stores as ; for track artist and , for album artist (Navidrome/MusicBrainz style)
  • File renamed automatically on save to match the standard naming convention
  • File moved to the correct AlbumArtist/Album/ folder when those fields change
  • Empty folders cleaned up after a move
  • Navidrome rescan triggered automatically after every save

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, metadata editor
│   ├── nowplaying.js          # Now Playing overlay
│   ├── abs.js                 # Audiobookshelf integration
│   ├── spotify.js             # Spotify importer (resolve + download)
│   ├── youtube.js             # YouTube / YouTube Music importer
│   ├── soundcloud.js          # SoundCloud importer
│   ├── components.js          # Shared UI components (song rows, cards)
│   ├── themes.js              # Theme switching
│   ├── pwa.js                 # Service worker registration + update banner
│   └── main.js                # App init, audio wiring, window globals
├── backend/
│   ├── novasonic-server.js    # Express API: download jobs, metadata edit, resolvers
│   ├── spotify_resolve.py     # Spotify page scraper (track/album/playlist metadata)
│   └── lib/
│       ├── config.js          # Backend config (env vars, paths, format)
│       ├── jobs.js            # In-memory job store + log helper
│       ├── metadata.js        # iTunes lookup, artwork download, lyrics fetch, filename helpers
│       ├── ytdlp.js           # yt-dlp download cascade + ffmpeg metadata embedding
│       ├── squid.js           # Squid/Qobuz download backend
│       ├── downloader.js      # Unified downloadTrack / downloadAlbumTracks entry point
│       └── romaji.js          # Japanese → romaji index for search
├── 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

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/.

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

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
S
Description
No description provided
Readme
5 MiB
0 Stars 0 Watchers 0 Forks
2026-09-02 09:26:49 +02:00
Languages
Kotlin 47.4%
JavaScript 40.1%
CSS 5.5%
HTML 5.4%
Python 0.8%
Other 0.8%