# Changelog All notable changes to NovaSonic are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 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 | — | ✅ | | Romaji / Japanese sort | ✅ | ❌ | | Settings (Navidrome, ABS, etc.) | ✅ | ✅ | --- ## [0.9] — 2026-06-21 ### 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** — `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 (`
`, `
`) 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`).