HoneyandClaude Sonnet 4.6 20545f71be chore: add Android project files to version control
Adds build config, Gradle wrapper, resources, and gitignore.
Kotlin sources, manifests and app build.gradle were already tracked.
Excludes build output, .gradle cache, .idea, local.properties, and release APK.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 00:34:40 +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%