Commit Graph
68 Commits
Author SHA1 Message Date
HoneyandClaude Sonnet 4.6 d8908c69e9 feat: add session-level API cache — skip spinners on home/albums/artists/playlists revisit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 11:45:22 +02:00
HoneyandClaude Sonnet 4.6 45cb62198e fix: album cards use romaji index for album name display via _albumRomajiMap
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 01:10:38 +02:00
Honey 52f5385988 fix: import dispAlbum in views.js 2026-06-06 01:03:56 +02:00
HoneyandClaude Sonnet 4.6 eb47a42f15 fix: album detail header re-renders with sort tags after songs load; search artist uses dispArtistById
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 00:56:33 +02:00
HoneyandClaude Sonnet 4.6 961511b3d0 fix: apply romaji disp functions in _restoreLastPlayed and album detail header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 00:44:28 +02:00
HoneyandClaude Sonnet 4.6 8704a17b4f fix: romaji display race on reload; iTunes search uses original Japanese name
- Await romaji overrides before restoring player bar so disp* functions
  have the cache ready on first render after reload
- dispArtistParts now carries originalName so artist clicks pass the
  Japanese name to Navidrome/iTunes search while displaying romaji

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 00:09:13 +02:00
Honey 4e6f8782ca fix: artist page song clicks bypass shuffle — play exact song in order 2026-06-04 23:06:01 +02:00
HoneyandClaude Sonnet 4.6 c21f3be696 fix: fetch real playlist song counts from getPlaylist in background
getPlaylists returns stale/wrong songCount from Navidrome's index.
After rendering the grid, fire one getPlaylist request per playlist
in parallel and update each card's subtitle as responses arrive.
Counts are visually corrected within a second of the page loading.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 11:06:34 +02:00
HoneyandClaude Sonnet 4.6 1d5f4a620d fix: NP flicker, fully-random shuffle, playlist count backpatch
NP overlay flicker (stronger fix):
- Remove contain:layout style paint (causes layer issues on some Android WebView)
- Add ::before pseudo-element with solid background so no frame can be transparent
- Add -webkit-transform prefixes for both open and closed states

Shuffle fully random:
- playQueue no longer pins startIdx when shuffle is on
- All songs shuffled into a completely random order, S.qIdx=0 always
- toggleShuffle mid-queue still pins current song first (Spotify toggle behavior)

Playlist count wrong in overview:
- Navidrome's getPlaylists returns stale/wrong songCount in its index
- Add data-pl-id to each playlist card in loadPlaylists
- After loadPlaylistDetail gets the accurate entry count, backpatch the
  matching overview card's subtitle so the grid shows the real song count

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 11:03:54 +02:00
HoneyandClaude Sonnet 4.6 1f1a5cd3a6 fix: startup speed, image retry, shuffle random start, genres, search badge, playlist refresh
- Remove await on fetchRomajiIndex() at startup so navigation is not blocked
  by the romaji index network call (was the main cause of 30s Android startup)
- Add window._imgRetry() with 3 retries (1.5s/3s/4.5s backoff) for all card/
  song/cover images that fail to load; falls back to emoji only after exhausting retries
- playQueue with HAS_BRIDGE + shuffle: pick a random startIdx so album/playlist
  playback starts at a random track, not always index 0
- Reduce mobile genre grid limit from 12 to 6
- Fix "Global Suche" badge text: was "iTunes Store + Local", now "iTunes Store"
- deleteSong: always refresh loadPlaylists() unconditionally (not just when
  page is active) with a 3s delay so song counts are current when navigating back

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 10:38:15 +02:00
Honey 3837783225 fix: iTunes JP-first with US fallback; romaji filter in playlist/starred search 2026-05-27 17:16:57 +02:00
Honey b5ffb1e73d fix: non-blocking romaji fetch in artist detail — prevent blank page on slow index load 2026-05-27 15:08:11 +02:00
Honey 27acede41d fix: fetch romaji index in loadArtistDetail before dispArtistById 2026-05-27 14:02:42 +02:00
HoneyandClaude Sonnet 4.6 c8ccb80f2f fix: header search overlay clipping and mobile fit
- Change overlay from position:absolute to position:fixed so it isn't
  clipped by main-content's overflow-y:auto
- Set overlay top dynamically from header.offsetHeight so it always
  anchors exactly below the sticky header
- Responsive max-height: accounts for player bar + bottom nav on mobile
- Hide logo text on ≤359px screens to keep search pill wide enough

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 13:04:34 +02:00
HoneyandClaude Sonnet 4.6 36f968881b feat: persistent inline header search with overlay results
Replaces the hidden toggle-based mobile search bar with a permanently
visible pill-shaped search input in the header row, next to the logo.

- Search is always visible — no button click required
- Typing shows a floating overlay with library results (artists, albums,
  songs) without navigating away from the current page
- Clearing the input or navigating to any page closes the overlay silently
- The ✕ clear button appears only while text is present
- navigate() now calls closeHeaderSearch() so results disappear cleanly
  when tapping any result or bottom nav tab
- Old toggleMobileSearch / closeMobileSearch kept as no-op stubs for safety

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 12:55:26 +02:00
HoneyandClaude Sonnet 4.6 b7afa19f70 feat: romaji artist names, Apple Music autofill, romaji index invalidation
- Artist grid and detail header now show romaji names when toggle is on.
  Builds a Map<artistId, artistRomaji> from the existing song romaji index
  so no extra API call is needed.

- Apple Music autofill button added to edit modal next to MusicBrainz.
  Reuses the existing lookupItunesTrackMeta backend function via a new
  GET /api/itunes/lookup endpoint — fills album, year, genre, track#,
  and cover art.

- Romaji index is invalidated after every successful download so newly
  added songs appear with correct sort tags without requiring a page reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 12:26:51 +02:00
HoneyandClaude Sonnet 4.6 5dda1a7101 fix: iTunes Japanese artist lookup + sort tag editing in info modal
- views.js: skip ASCII word-match when artist name is non-ASCII so Japanese
  artists (e.g. ヨルシカ) resolve correctly to an iTunes artist ID
- index.html + styles.css: collapsible Sort-Tags section in edit modal
- ui.js: pre-fill sort fields from romaji index; include in save body
- novasonic-server.js: accept manual titleSort/artistSort/albumArtistSort/albumSort
  overrides; fall back to auto-computed romaji when not provided

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 19:49:47 +02:00
HoneyandClaude Sonnet 4.6 88533b8835 fix: verify iTunes artist name matches query before using result
iTunes ranks by popularity, so searching "WRLD Tunes" returned Juice WRLD
first. Now fetches 5 results and picks the first where all query words
appear in the iTunes artist name, preventing false-positive matches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 23:36:46 +02:00
HoneyandClaude Sonnet 4.6 c6990cfd7b feat: remove album from song subtitle; add Go to Album in context menu
Album name no longer shown inline next to the artist — navigate via
right-click > Zum Album instead, available everywhere.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 22:47:43 +02:00
HoneyandClaude Sonnet 4.6 ee65183555 feat: SoundCloud downloader + rename page to Song Importer
- New src/soundcloud.js: resolves SoundCloud URLs via yt-dlp --dump-single-json,
  renders track/playlist preview with per-track download buttons
- Backend POST /api/soundcloud/resolve: extracts metadata (title, artist, genre,
  artwork, duration) directly from SoundCloud — no iTunes lookup needed
- ytdlp.js: sourceUrl param — if set, downloads directly from URL instead of
  ytsearch cascade (used for SoundCloud tracks)
- Spotify importer page renamed to Song Importer, now contains both
  Spotify and SoundCloud sections in one view

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 20:35:48 +02:00
HoneyandClaude Sonnet 4.6 1a44f8bd73 feat: show newest albums first on home screen, recently played below
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 18:56:21 +02:00
HoneyandClaude Sonnet 4.6 a6e6af0333 fix: use parseArtists() on album detail page — stops Au/Ra splitting on /
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 14:13:02 +02:00
HoneyandClaude Sonnet 4.6 4f83eebe79 feat: sort genre pills by total play count via backend
Page loads instantly with song-count order, then silently re-sorts
once the backend aggregates play counts across all songs. Result cached
20 min server-side to avoid repeated full-library fetches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 12:02:25 +02:00
HoneyandClaude Sonnet 4.6 790f02e5b4 feat: show 24 genre pills on desktop, 12 on mobile
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 11:54:31 +02:00
HoneyandClaude Sonnet 4.6 a8f56a9bc6 fix: genre shuffle/play no longer navigates away from genre page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 21:48:14 +02:00
HoneyandClaude Sonnet 4.6 b9a5c6468f refactor: dedup buildTrackList, extract topsong row helper, split romaji to lib
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 11:36:06 +02:00
HoneyandClaude Sonnet 4.6 da185e1d96 fix: hero label shows source (Meistgespielt/Zuletzt gehört); play count column always visible when enabled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:53:43 +02:00
HoneyandClaude Sonnet 4.6 3128b06b24 fix: 15s scrobble, play count clarity, star always visible, all-songs actions
- Scrobble timer: 12s → 15s
- Play count moved after action buttons, shown as "23×" (distinct from duration)
- Song star/menu buttons always visible (removed opacity:0 hover-only rule)
- Artist all-songs page: added star + 3-dots to every row (same as top songs)
- Hero card: picks from full recent+frequent pool (was capped at first 5 = all frequent)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:47:06 +02:00
HoneyandClaude Sonnet 4.6 7e07fef7ba feat: timer scrobble (12s), artist topsong star+menu, play count toggle
Scrobbling:
- Replace end-of-track scrobble with 12s timer approach
- Android: schedule on onTrackChanged, cancel on pause
- Web: schedule in playCurrent, cancel in togglePlay pause + onEnded
- Skip/new track resets the timer automatically (new song ID)

Artist top songs:
- Add star button and 3-dots context menu to every top song row
- Topsong grid expanded to 5 columns to fit action buttons

Settings — play count toggle:
- New "Bibliothek" section with toggle switch
- When on: shows play count in album/playlist song rows
- Artist page always shows play count regardless of toggle
- Persisted in ns_cfg localStorage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:35:26 +02:00
HoneyandClaude Sonnet 4.6 f79817410b feat: scrobbling, genre grid redesign with detail view + play button
- Scrobble to Navidrome on auto-advance (Android) and track end (web)
  so type=recent and type=frequent are accurate for the hero card
- Genre section: pill chips → grid cards with colored left bars
- Top 15 genres shown by default (sorted by song count), expand toggle
- Genre card: click → genre detail page with full song list
- Genre card: hover play button → shuffle-play without navigating
- Genre detail page reuses album-detail layout (back btn, stats, song list)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:18:56 +02:00
HoneyandClaude Sonnet 4.6 d3a1bf6a82 feat: home hero+genres, fix Android queue desync via song ID verification
Home view:
- Add hero card (random pick from recent+frequent combined pool)
- Add genre browser chips (sorted by song count, tap = shuffle-play)

Android sync fix:
- Add currentId to getState() snapshot so JS can verify song identity
- onReady: reset stale localStorage queue when native song ID mismatches
- onTrackChanged: reject stale old-queue callbacks by ID verification
- onPlaybackStateChanged safety net: ID-guard prevents wrong-queue index corruption
- connectToService: call updateStateSnapshot() before onReady so getState() is never empty

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:06:47 +02:00
HoneyandClaude Sonnet 4.6 96e3cb0451 fix: prevent stacked reorder mode from multiple 'Neu anordnen' clicks
Added _reorderCtx.active flag — plReorderEnter bails early if already
active, preventing duplicate handles and event listeners from stacking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 19:54:36 +02:00
HoneyandClaude Sonnet 4.6 9d8a5a22bb fix: button focus ring, playlist reorder mode, edit modal mobile, backdrop-filter
- button:focus{outline:none} — removes the blue tap-highlight box in WebView
- Playlist reorder: replaced always-on drag handles with explicit 'Neu anordnen'
  mode. Handles only appear after tapping the button; a sticky Speichern/Abbrechen
  bar appears above the list. Touch drag is now fully supported. Context-menu
  (long-press) is blocked while reorder mode is active to prevent conflicts.
- styles.css: .pl-drag-handle always visible when pl-draggable (no hover needed)
- Edit modal footer: wrap buttons on small screens so Save doesn't overflow
- Edit modal overlay: remove backdrop-filter:blur — causes WebView compositor
  glitch where 3/4 of the modal disappears after returning from background

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:40:11 +02:00
HoneyandClaude Sonnet 4.6 e893b7cc12 fix: radio mode appends songs without restarting; favorites/song row mobile fixes
- fillRadioQueue: use addToQueue instead of setQueue so toggling radio mode
  no longer resets position to 0 on the current song
- loadStarred: pass noArtistLink/noAlbumLink to prevent accidental navigation
  taps on mobile (matches playlist behavior)
- styles.css: add pointer:coarse alongside hover:none so song-actions are
  visible on Android WebView which may report hover:hover
- components.js: remove inline download button from song row; keep only star
  and 3-dots (download stays accessible via context menu)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:25:26 +02:00
HoneyandClaude Sonnet 4.6 aa239f8e6a feat: romaji index for Japanese kanji song search
Backend:
- Add /api/romaji-index endpoint using kuromoji morphological analyzer
- Fetches all Navidrome songs, converts kanji → hiragana readings → romaji
- Only indexes songs with Japanese characters; caches for 20 min
- /api/romaji-index DELETE clears cache (force rebuild)

Frontend:
- fetchRomajiIndex() in api.js: lazy-fetches and caches the index
- doLocalSearch: when query is romaji (ASCII), queries romaji index in
  parallel with Navidrome search3 and merges+deduplicates results

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 21:15:07 +02:00
HoneyandClaude Sonnet 4.6 a47b2be177 feat: romaji search for Japanese songs via wanakana
When search input is pure ASCII (romaji), converts it to hiragana in
parallel using wanakana and merges both result sets. Deduplicates by ID
so no double entries. Helps find artists/songs tagged with hiragana in
sort fields (e.g. 'inabakumori' → 'いなばくもり').

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 21:03:42 +02:00
HoneyandClaude Sonnet 4.6 27eb209945 feat: three-dot context menu on song rows + search shows songs as rows
- Add ⋮ button to every song-item triggering the context menu (same as right-click)
- Show song-actions always visible on touch devices via @media (hover:none)
- Search results: songs now render as makeSongItem rows instead of cards
  (artists/albums remain as horizontal card rows)
- Fix Android app opening system settings on every launch after notification
  permission denial — now only redirects to settings once using notif_settings_shown flag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 20:58:59 +02:00
Honey e78df7bdb9 feat: add search filter bar to playlist detail and favorites views 2026-05-13 13:58:08 +02:00
Honey 47f1605965 feat: add sort filter chips to albums and favorites views 2026-05-13 12:53:34 +02:00
HoneyandClaude Sonnet 4.6 76ecfe2268 feat: wire NSBridge fully + HD artwork + disable watchdog in wrapper mode
player.js
- Replace `_native()` function with `const HAS_BRIDGE` (evaluated once at
  module load so bridge detection is rock-solid)
- Add `buildTrackList()` — maps S.queue to NSBridge Track array with 1024px
  artworkUrl so lock-screen cover is crisp on high-DPR displays
- Add `_pushQueueIfBridge()` — called by `fillRadioQueue()` so radio top-ups
  are pushed to ExoPlayer in real time (fixes autoplay gap after radio refill)
- `playQueue`: route through `NSBridge.setQueue` when bridge present; old
  `S.audio` path retained for browser/PWA fallback
- `playCurrent`: `NSBridge.seekToIndex + play` in bridge mode
- `nextSong / prevSong / togglePlay / onEnded`: delegate to bridge, skip local
  S.qIdx manipulation (native sends onTrackChanged callback instead)
- `seekTo / _initBarScrub`: use `_lastDurationMs` for ms-accurate seeks
- `onTrackChanged`: guard with `p.index !== S.qIdx` to avoid redundant redraws
- `updateMediaSession`: artwork sizes 96/300/512 → 256/512/1024
- Player-bar cover: 100 → 256px; NP cover/bg: 400 → 1024px;
  queue items: 60 → 128px; preload hint sizes: 96/300/512 → 256/512/1024

main.js
- Wrap watchdog setInterval in `typeof window.NSBridge === 'undefined'` guard;
  the foreground service keeps ExoPlayer alive — JS watchdog not needed there

views.js
- Album detail / playlist detail covers: 300 → 512px
- Playlist grid cards: 200 → 512px
- Search result song cards: 200 → 256px
- Artist top-songs / all-songs thumbnails: 60 → 128px
- Partial album art in _renderArtistAlbums: 300 → 512px

components.js
- makeAlbumCard: 200 → 512px
- makeSongItem: 60 → 128px

nowplaying.js
- NP queue items: 60 → 128px
- NP action sheet thumb: 80 → 256px

sw.js
- Bump CACHE to ns-v41 so stale small-cover entries are evicted on next load

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 10:33:43 +02:00
HoneyandClaude Sonnet 4.6 c17b7ea11a feat: Audiobookshelf integration — browse, stream, chapters, sleep timer
- src/abs.js: full ABS API client + player engine
  - Login/token auth, library browsing, search
  - Playback session API (multi-file book support via startOffset)
  - Progress sync to ABS every 30s and on pause
  - Chapter navigation (prev/next/seek-to), ±10s / ±30s skip
  - Speed control (0.75–2×), sleep timer with countdown
- index.html: sidebar nav, audiobooks/detail pages, full-screen player overlay,
  ABS settings section (URL + credentials + library picker)
- state.js: abs + absPlayer state objects
- views.js: navigate() handles 'audiobooks' and 'abs-book-detail'
- styles.css: book grid, detail page, player overlay, pickers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 14:35:00 +02:00
HoneyandClaude Sonnet 4.6 3988d18182 fix: drag-and-drop — use fromHandle bool instead of e.target check
e.target in dragstart is always the draggable item element, never the
handle child — so closest('.pl-drag-handle') always returned null and
every drag was cancelled. Now mousedown on handle sets fromHandle=true
and item.draggable=true; dragstart checks the bool instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 00:10:36 +02:00
HoneyandClaude Sonnet 4.6 ca6dd87531 fix: drag-and-drop — set draggable upfront, add Firefox setData, fix duplicate dragend
draggable=true must be set before any mouse event (not on mousedown).
Firefox requires setData() for drag to work. Removed duplicate dragend
listener that was resetting draggable=false and conflicting with the first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:21:13 +02:00
HoneyandClaude Sonnet 4.6 8deeaa6475 feat: drag-and-drop reordering for playlist tracks
Drag handle appears on hover, moves items in DOM, syncs order to
songs array, and saves to Navidrome via createPlaylist 800ms after
last drop (debounced to avoid rapid API calls).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:15:48 +02:00
HoneyandClaude Sonnet 4.6 8a256b9463 feat: artist cards navigate-only (no play); add Top Songs + Shuffle buttons to artist detail page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:14:07 +02:00
HoneyandClaude Sonnet 4.6 a907773afb fix: artist link quotes in album detail; card art=play / info=navigate; artist play button via quickPlayArtist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:03:53 +02:00
HoneyandClaude Sonnet 4.6 e75d90e165 fix: eliminate flash on skip, refresh home on nav
- renderQueue: in-place active-class update when queue unchanged — no DOM rebuild, no image reload
- updatePlayerUI: update img.src directly instead of replacing innerHTML
- _syncNpDirect: same img.src update for now-playing cover
- navigate('home'): always reloads home data so new albums appear without restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 09:21:12 +02:00
HoneyandClaude Sonnet 4.6 fef8578a27 feat: add greeting header and recently played row to home screen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 08:39:54 +02:00
HoneyandClaude Sonnet 4.6 a61436669e fix: per-span hover highlight, use • as artist separator everywhere
- CSS: target #player-artist-name span:hover and #np-artist-name span:hover so only the hovered artist name highlights, not all at once
- change artist separator from / to • in song items, player bar, now playing overlay, album header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 00:51:38 +02:00
HoneyandClaude Sonnet 4.6 60c9cb6cbb fix: no artist/album links in playlist, add comma to artist split
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 00:35:05 +02:00