Files
NovaSonic/CHANGELOG.md
T
HoneyandClaude Opus 4.8 73fcfae30f feat(android): offline downloads — albums, playlists, detail screen & playback
Download albums/playlists to private device storage (Room + WorkManager,
HttpURLConnection streaming). New Offline tab lists groups with progress;
tapping a group opens a detail screen (cover-art rows, play/shuffle, per-song
delete from device). Downloaded tracks play from disk on every screen.
Album/playlist cards show a downloaded badge; download button resumes missing
songs. Song storage is dedup'd by ID and reference-counted on delete.

Fixes: Android 15 download crash (dropped banned DATA_SYNC foreground service);
offline detail flash-back (initial empty state no longer mistaken for deleted).

Docs: CHANGELOG 0.10 + parity matrix; condensed README Features.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 10:06:43 +02:00

25 KiB
Raw Blame History

Changelog

All notable changes to NovaSonic are documented here. Format follows Keep a Changelog. Versioning: two-part MAJOR.MINOR — each release bumps the minor (features and fixes together).


Platform Parity Matrix

Feature Web (PWA) Android
Music playback (Navidrome) ✅ ✅
Seek bar / scrubbing ✅ ✅
Queue management ✅ ✅
Shuffle / Repeat ✅ ✅
Radio mode (similar songs) ✅ ✅
Now Playing overlay ✅ ✅
Dominant color background ✅ ✅
Cover art scale animation ❌ ✅
Synced lyrics (LRCLIB) ✅ ✅
Lyrics autoscroll ✅ ✅
Star / favorite song ✅ ✅
Multi-artist navigation ✅ ✅
Album detail page ✅ ✅
Artist page (Navidrome) ✅ ✅
Artist page (iTunes fallback) ✅ ❌
Concert events (Ticketmaster) ✅ ✅
Genre browsing ✅ ✅
Global search ✅ ✅
Playlist browsing ✅ ✅
Playlist create/edit ✅ ✅
Playlist cover upload ✅ ✅
Spotify / YouTube importer ✅ ✅
Metadata editor (tags + cover) ✅ ❌
Song delete (from disk) ✅ ❌
Import notification ✅ ✅
Import notification → nav ✅ ✅
ABS (Audiobookshelf) playback ✅ ✅
ABS chapter navigation ✅ ✅
ABS sleep timer ✅ ✅
ABS playback speed ✅ ✅
ABS library search ✅ ✅
ABS book descriptions (HTML) ✅ ✅
Media notification ✅ ✅
ABS notification (modern style) ❌ ✅
Android Auto — ✅
Offline download (albums/playlists) ❌ ✅
Offline playback ❌ ✅
Offline detail / manage downloads ❌ ✅
Romaji / Japanese sort ✅ ❌
Settings (Navidrome, ABS, etc.) ✅ ✅

[0.10] — 2026-06-25

Added

  • Android — Offline downloads: download albums and playlists to device storage with a single tap; album download button is in the album hero row (▶ / shuffle / ↓), playlist button next to the edit toggle. Tapping again resumes / re-downloads any missing songs (already-downloaded tracks are skipped)
  • Android — Offline tab in Library (position 2, next to Playlists): lists downloaded groups with cover art, track count, and an in-progress bar; shows total MB used
  • Android — Offline detail screen: tap a group to view its songs (with cover art, like the online playlist), play / shuffle, and remove individual songs from the device via the edit toggle. Works fully offline (reads from Room, no network)
  • Android — Offline playback: tap ▶ on a fully-downloaded group to play locally; downloaded songs are also served from disk automatically when opened from any album or playlist view
  • Android — Downloaded badge: albums and playlists in the Library tabs show a ↓-in-circle badge on the cover when fully downloaded
  • Android — Duplicate-safe storage: a song shared by an album and a playlist is stored once (keyed by song ID) and reference-counted on delete — removing one group keeps the file if another still needs it

Fixed

  • Android — Download crash on Android 15 (targetSdk 35): FOREGROUND_SERVICE_TYPE_DATA_SYNC is banned for apps targeting API 35; WorkManager's expedited path used it and the resulting exception killed the app ~1.5 s after tapping download. Fixed by dropping setExpedited() and all foreground-service use from DownloadWorker — downloads run as silent background work with progress shown in the Offline tab
  • Android — Offline detail screen flashed open then immediately returned: its initial empty state (before Room emitted) was mistaken for "deleted". Now shows a brief spinner until loaded, and only leaves when the last song is actually removed

Internal

  • Android — Offline system: Room DB (novasonic_offline.db) with downloaded_tracks, download_groups, group_track_cross_refs; OfflineRepository holds hot StateFlow maps for O(1) local-path lookups; DownloadWorker streams audio + cover art via HttpURLConnection to context.filesDir/offline/{audio|covers}/. MusicRepository.streamUrl() checks local files first, so playback uses the file:// URI on every entry point

[0.9] — 2026-06-22

Added

  • UI — New NovaSonic app icon: 5-bar equalizer waveform with blue→purple gradient (#7eb8ff → #8b3cf7) on dark background — replaces the generic music-note placeholder
  • UI — Favicon link added to <head> with SVG + PNG fallback (icon-192.png) so browser tabs show the icon
  • UI — Android launcher icon (ic_launcher.xml) updated to match the new equalizer design using the same blue→purple gradient via aapt:attr
  • UI (web) — Sidebar logo updated from ♫ emoji to the new equalizer SVG (icon.svg)
  • nginx — /app/ alias added so reverse-proxy deployments can resolve static assets (icon, manifest) under the /app prefix without Vite base changes

Fixed

  • UI — Player bar star/favorite button now vertically centred with the full track info block (title + album + artist), not pinned to the top of the title line
  • UI — Shuffle status badge no longer shifts when the player bar is active (removed overflow:hidden from .player-info-wrap that was clipping the status row)
  • UI (mobile) — Duplicate NovaSonic logo + name removed from mobile header next to the search bar
  • Backend (download) — Duplicate detection now matches case-insensitively (DJ OKAWARI vs DJ Okawari) and across all album folders under the artist folder, comparing normalized title without track prefix or release/variant suffix — prevents re-downloading songs whose filename drifted between runs
  • Backend (download) — iTunes collectionArtistName (album artist) is now captured and passed through the download pipeline as the album_artist tag; fixes compilation albums showing "Various Artists" for some tracks and the individual track artist for others
  • Metadata editor (autofill) — iTunes button now fills all available fields: title (trackName), artist (artistName), album-artist (collectionArtistName), album, genre, year, track #, disc #, total tracks, cover
  • Metadata editor (autofill) — MusicBrainz button now fills album-artist (from release artist-credit) and disc # in addition to the existing fields

Changed

  • Backend — Japanese tracks now stored with original Japanese names in folders, filenames, and all main tags (title/artist/album/album_artist); Romaji goes only into sort tags (TITLESORT / ARTISTSORT / ALBUMARTISTSORT / ALBUMSORT) for sorting and search in Navidrome. Previously, romaji was applied to filenames and tags too, causing name drift, duplicate misses, and wrong iTunes resolutions (e.g. "Hisaishi Yuzuru" instead of "Joe Hisaishi")
  • Backend — Metadata editor: files and album/artist folders are renamed using the original name typed in the form (may be Japanese), not romaji; sort tags still receive the romaji conversion
  • Backend — fix-artist-sort script now uses the original (kanji) artist name for folder and filename; artistSort (romaji) is only written to ARTISTSORT / ALBUMARTISTSORT sort tags
  • Backend — album_artist tag in downloaded tracks now consistently uses mainArtist (the iTunes-resolved album artist) rather than the raw per-track artist. This prevents Navidrome from splitting one album into multiple when track artists vary (e.g. compilations)
  • Backend (download) — No-duration cascade now ends after step 4 (same Mittelweg philosophy as the with-duration branch): no title-only or filter-free fallback grabs that pull wrong covers (observed: Yorushika 車窓 → Piano Echoes Shasou)
  • Backend (download) — --max-filesize 30M added to all yt-dlp calls; Mittelweg/no-duration steps also cap at 2× expected duration — a 28-min video can no longer be saved as a ~52 MB mp3

Investigated (album splitting root causes)

  1. Missing album_artist tag / inconsistent value across tracks — fixed above (mainArtist + collectionArtistName)
  2. tagAlbumArtist was using rawArtist (per-track Spotify name) instead of mainArtist — fixed
  3. Album name comes from iTunes collectionName — consistent within a collection, no fix needed
  4. Year from iTunes releaseDate — album-level date, consistent within a collection
  5. MBIDs not set — still missing; not the primary splitting cause

  • Backend — Japanese tracks now stored with original Japanese names in folders, filenames, and all main tags (title/artist/album/album_artist); Romaji goes only into sort tags (TITLESORT / ARTISTSORT / ALBUMARTISTSORT / ALBUMSORT) for sorting and search in Navidrome. Previously, romaji was applied to filenames and tags too, causing name drift, duplicate misses, and wrong iTunes resolutions (e.g. "Hisaishi Yuzuru" instead of "Joe Hisaishi")
  • Backend — Metadata editor: files and album/artist folders are renamed using the original name typed in the form (may be Japanese), not romaji; sort tags still receive the romaji conversion
  • Backend — album_artist tag in downloaded tracks now consistently uses mainArtist (the iTunes-resolved album artist) rather than the raw per-track artist. This prevents Navidrome from splitting one album into multiple when track artists vary (e.g. compilations)
  • Backend (download) — No-duration cascade now ends after step 4 (same Mittelweg philosophy as the with-duration branch): no title-only or filter-free fallback grabs that pull wrong covers (observed: Yorushika 車窓 → Piano Echoes Shasou)
  • Backend (download) — --max-filesize 30M added to all yt-dlp calls; Mittelweg/no-duration steps also cap at 2× expected duration — a 28-min video can no longer be saved as a ~52 MB mp3

Fixed

  • Backend (download) — Duplicate detection now matches case-insensitively (DJ OKAWARI vs DJ Okawari) and across all album folders under the artist folder, comparing normalized title without track prefix or release/variant suffix — prevents re-downloading songs whose filename drifted between runs
  • Backend (download) — iTunes collectionArtistName (album artist) is now captured and passed through the download pipeline as the album_artist tag; fixes compilation albums showing "Various Artists" for some tracks and the individual track artist for others
  • Metadata editor (autofill) — iTunes button now fills all available fields: title (trackName), artist (artistName), album-artist (collectionArtistName), album, genre, year, track #, disc #, total tracks, cover
  • Metadata editor (autofill) — MusicBrainz button now fills album-artist (from release artist-credit) and disc # in addition to the existing fields

Investigated (Point 4 — album splitting)

Primary causes identified:

  1. Missing album_artist tag / inconsistent value across tracks — fixed above (mainArtist + collectionArtistName)
  2. tagAlbumArtist was using rawArtist (per-track Spotify name) instead of mainArtist — fixed
  3. Album name comes from iTunes collectionName — consistent within a collection, no fix needed
  4. Year from iTunes releaseDate — album-level date, consistent within a collection
  5. MBIDs not set — still missing; not the primary splitting cause

[0.8] — 2026-06-19

Removed

  • Backend — squid.wtf (Qobuz) download backend removed; downloads now exclusively use yt-dlp. DOWNLOAD_BACKEND and SQUID_QUALITY env vars are no longer read.

Changed

  • Backend — Download cascade "Mittelweg": when a track's duration is known but no result matches the duration window, the cascade no longer falls back to blind title-only/no-filter grabs (which pulled same-titled videos by other uploaders). It now relaxes only the duration constraint while still requiring the artist channel — and if nothing matches, the job fails cleanly with "Nicht eindeutig gefunden — bitte Direktlink im Importer nutzen" instead of silently saving the wrong song
  • Backend — Duration match margin tightened from ±15% to ±10% (min 10s) to reject near-miss false positives
  • Backend — YTM search uses the web_music player client so YouTube Music "Art Track" / topic uploads are reachable (the previous android_vr client reported many as "video not available")
  • Backend — Search query uses a space between artist and title ("MINA recognize") instead of a dash, matching how the YTM search box ranks the exact track

Fixed

  • Backend — YTM search query: album name was appended for short-title tracks, causing duplicated words (e.g. "MINA - recognize recognize Single"); album is now only appended for Japanese titles, matching spotdl behaviour
  • Backend — Downloaded filename now strips the release suffix → 01 - Artist - Title.mp3 (no - Single/- EP in the filename); the album folder keeps the full album name. The embedded title tag is cleaned the same way
  • Backend — Duration metadata from the iTunes resolver now reaches the yt-dlp duration filter for all importer paths (single, album, playlist, global search), so the right-length track is preferred
  • Backend — Metadata editor / song delete: file resolution now tolerates a release-suffix mismatch between Navidrome's stored stem and the on-disk filename; the delete "file not found" error now reports the actual resolved path for diagnosis
  • Backend — Download no longer aborts the search cascade when a single result is geo-blocked or unavailable (e.g. "This video is not available") — it continues to the next candidate

[0.7] — 2026-06-18

Added

  • Android — Playlist create: "+" FAB on the Playlists tab opens a dialog to create a new playlist
  • Android — Playlist edit dialog (pencil icon): edit name, description, and upload cover — all in one place; matches web edit modal
  • Android — Playlist delete: trash icon in the playlist hero with confirmation dialog; navigates back to library on success
  • Android — Playlist song removal: edit-mode toggle in the playlist action row reveals a "−" button per song; removes via updatePlaylist.view?songIndexToRemove
  • Android — Playlist cover upload: image picker in the edit dialog uploads via Navidrome REST API (POST /api/playlist/{id}/image)
  • Android — ABS notification: current chapter name shown as the main title; book title moves to the artist line; updates automatically on chapter change without interrupting playback
  • Android — Home "Zuletzt gehört" section: recently played albums row matching the web's type=recent row
  • Android — Library Albums: sort chips (Neueste / Älteste / A-Z); Neueste uses type=newest from Navidrome (add-date order); scrolls to top on sort change
  • Android — Artist fast-scroll index bar: draggable letter strip on the right side of the Artists list with letter bubble while dragging
  • Web — Playlist edit modal: "Cover entfernen" button removed

Fixed

  • Android — In-app notification bell: notifications were never delivered after navigating away from the Importer screen (poll ran in viewModelScope, cancelled on navigation); polling now uses NotificationStore.startPoll() with an app-lifetime scope
  • Android — Home hero card: pool now matches web — union of frequent(5) ∪ recentlyPlayed(5) deduped, random pick; label is "MEISTGESPIELT" or "ZULETZT GEHÖRT" (was hardcoded "AKTUELL")
  • Android — Library Albums "Neueste": was incorrectly sorting by release year client-side; now uses type=newest from Navidrome (recently added to library)
  • Android — Artist screen crash: duplicate key in LazyColumn when Navidrome returns the same song ID twice in topSongs
  • Android — "Alle Alben anzeigen" crash: duplicate key when two albums share name + year
  • Android — "Alle Alben anzeigen": albums were left-aligned inside grid cells; now centered
  • Android — "Alle Alben anzeigen" search bar styling matches app design
  • Android — ABS notification button order: Samsung One UI mapping corrected; now shows Kapitel zurück | 30s zurück | Play/Pause | 30s vor | Kapitel vor

[0.6] — 2026-06-17

Added

  • Android — Lyrics preload on NowPlaying open; lyrics load in background while on Player tab, so switching to Lyrics tab is instant

Fixed

  • Android — Home hero card: play button now sits to the right of title/artist, not below
  • Android — ABS media notification now uses Media3's modern media card style (blurred cover art background) instead of a plain notification; identical look to the music notification
  • Android — ABS notification buttons corrected: now shows exactly Kapitel zurück | 30s zurück | Play/Pause | 30s vor | Kapitel vor in both compact and expanded view; previously showed double back-button and 30s-forward was cut off
  • Android — Lyrics autoscroll switches from fixed tween to spring animation (DampingRatioNoBouncy, StiffnessLow); rapid line changes no longer produce choppy stop-and-restart scrolling

Internal

  • Android — ABS notification rebuilt using a custom DefaultMediaNotificationProvider subclass (AbsAwareNotificationProvider) registered via setMediaNotificationProvider(); overrides getMediaButtons() to return exactly 5 session-command buttons when ABS is active, bypassing setCustomLayout() which only appends to (not replaces) the standard skip-prev/play-pause/skip-next buttons
  • Android — Removed abandoned AbsPlayerService.kt (unreferenced, unregistered, referenced missing drawable)

[0.5] — 2026-06

Added

  • Android — ABS full playback: chapter list, playback speed control, sleep timer, progress sync to ABS server
  • Android — ABS 30s skip-back / skip-forward buttons in media notification (compact + expanded view)
  • Android — ABS library search bar in Books tab (server-side search via /api/libraries/{id}/search, 400ms debounce)
  • Android — Notification sheet: shows import/download history with status icons; "Zum Album →" / "Öffnen →" button navigates to album or playlist on tap
  • Web — Notification sheet: "Zum Album →" link button after download completes
  • Android — NowPlaying lyrics: 200ms lookahead for better sync feel (matches web)

Fixed

  • Web + Android — ABS book descriptions: HTML tags (<p>, </p>) now stripped before display
  • Android — NowPlaying background: switched from darkMutedSwatch to vibrantSwatch (55% darken) for more visible color tinting
  • Android — NowPlaying top bar: fixed layout overflow with navigation labels
  • Android — Lyrics scroll: removed Phase 2 "drift" animation; now simply centers active line (matches web scrollTo({ behavior: 'smooth' }))
  • Android — ABS skip: library list skip fixed on first load

[0.4] — 2026-05

Added

  • Android — Full native app rewrite in Kotlin / Jetpack Compose (replaces React Native / Expo attempt)
  • Android — Media3 / ExoPlayer music playback with MusicService (MediaLibraryService)
  • Android — NowPlaying screen: cover art with scale animation (Apple Music style), seek bar with drag scrubbing, queue tab, lyrics tab
  • Android — Dominant color background in NowPlaying (Palette API, animated on song change)
  • Android — Multi-artist display with per-artist tap-to-navigate in NowPlaying
  • Android — Synced lyrics via LRCLIB (parallel requests, in-memory cache)
  • Android — ABS (Audiobookshelf) integration: login, library browse, book detail, chapter playback
  • Android — Android Auto support: browsable tree (Recent, Favorites, Playlists), play-all / shuffle pseudo-items
  • Android — Radio mode: auto-queues similar songs via Navidrome getSimilarSongs
  • Android — Global search (Navidrome)
  • Android — Genre browsing with play button per genre
  • Android — Concert events via Ticketmaster on artist page
  • Android — Spotify / YouTube importer (connects to backend)
  • Android — Notification sheet in-app (import/download job progress)
  • Android — Settings: Navidrome URL/credentials, ABS URL/token, theme, display name

Fixed

  • Android — Login flash on startup (credentials loaded before nav resolves)
  • Android — Album name casing normalization

[0.3] — 2025-Q4

Added

  • Web — Artist page: hero banner, iTunes + Navidrome album categorization, all-songs view
  • Web — Concert events via Ticketmaster (replaces Bandsintown); 30min server-side cache
  • Web — Playlist editing: name, description, public toggle, cover image upload
  • Web — Global search: artist cards with images, explicit badge (E)
  • Web — Romaji display for Japanese artists/albums (Navidrome sortName tag)
  • Web — iTunes album detail page (for tracks not in Navidrome)
  • Web — Mobile search bar in header (tap icon)
  • Web — Smooth progress bar scrubbing with touch drag

Fixed

  • Web — Multi-artist splitting: handles ·, /, ; separators; each name navigates to own artist profile
  • Web — Lyrics: LRCLIB fuzzy fallback, title-only search fallback, parallel requests, in-memory cache
  • Web — Lyrics scrollbar hidden, fade edges on active line
  • Web — Artwork: hi-res cover embedded; consistent album_artist tag for Navidrome grouping
  • Web — feat./ft./featuring converted to / in artist tag for correct Navidrome multi-artist split

[0.2] — 2025-Q3

Added

  • Web — Spotify / YouTube / SoundCloud importer: resolve link → yt-dlp download → optional Navidrome playlist creation
  • Web — iTunes per-track artwork lookup for playlist downloads
  • Web — Synced lyrics via LRCLIB in Now Playing overlay (200ms lookahead)
  • Web — Lyrics embedding in downloaded track metadata
  • Web — Explicit metadata tag + E badge in search
  • Web — Disc number and compilation metadata tags
  • Web — Genre metadata from iTunes primaryGenreName
  • Web — SW update banner (notify user, no force-reload)
  • Web — Duplicate detection before download (shows toast on skip)
  • Web — Player drag feedback; swipe-up player bar opens Now Playing

Fixed

  • Web — Spotify importer: multi-artist parsing, GraphQL embed format, locale URL support, public web-player token
  • Web — Playlist cover auto-refresh after upload
  • Web — Service worker: network-first strategy, does not intercept cross-origin requests, auto-reloads all PWA windows on SW update
  • Web — Bottom navigation: full-width edge-to-edge layout

[0.1] — 2025-Q2

Added

  • Web — Initial PWA music player (Vite + ES modules)
  • Web — Navidrome Subsonic API integration (albums, songs, playlists, search, cover art)
  • Web — Album and playlist browsing
  • Web — Basic player (play/pause, skip, shuffle, repeat)
  • Web — Media Session API (lock screen / notification controls)
  • Web — Service worker with offline support
  • Web — Docker setup: nginx frontend + Node.js backend + Navidrome
  • Web — Home screen: hero card (last played album), genre grid, recently added, most played, discover

Planned / Backlog

Features

  • Android — Playlist drag-and-drop / sort order
  • Android — Artist page iTunes fallback (for artists not in Navidrome)
  • Android — Romaji / Japanese sort support
  • Web + Android — Backend settings UI rework (move, reorganize)
  • Web + Android — yt-dlp backend update / maintenance

Known Bugs

  • Backend (download) — The duplicate check requires at least a firstArtist folder match. If the same song was previously stored under a very different artist name (e.g. before an iTunes-name fix), it will not be detected as a duplicate and will be re-downloaded.
  • Backend (metadata/sorting) — MusicBrainz release['artist-credit'] is often absent in the standard recording search response (requires inc=artist-credits which can slow the endpoint). The albumArtist field from MusicBrainz autofill may fall back to the recording artist rather than the release artist.
  • Backend (metadata/sorting) — MBIDs are not embedded in downloaded tracks; Navidrome cannot use them for authoritative album grouping (low priority — album splitting is mostly solved via consistent album_artist).