Commit Graph
671 Commits
Author SHA1 Message Date
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 377a6954e3 fix: radio mode uses getSimilarSongs2 for artist/genre-aware playback
- Dedup now checks only the last 50 queued songs instead of the entire
  queue, so the radio doesn't stall on small libraries once every similar
  song has been seen
- If every candidate is a recent duplicate (tiny library), allow up to 5
  repeats rather than returning empty and letting the queue run dry
- Add second _queueGen guard after the getRandomSongs fallback await

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 08:45:16 +02:00
HoneyandClaude Sonnet 4.6 9fe8656a21 fix: resolve queue desync causing player bar / NP to show wrong song
Root cause: addToQueue was sent to native twice for every radio top-up.
fillRadioQueue() already sends addToQueue internally, but onTrackChanged
and onQueueEnded also re-sent the same songs in their .then() callbacks,
causing native to accumulate duplicates. With native having double the
songs JS has, native indices no longer map to the correct JS queue entries.

Also fixed: playQueue called fillRadioQueue before setQueue was dispatched,
so addToQueue could land in the old native queue before setQueue wiped it.

Changes:
- fillRadioQueue: add _queueGen guard — bail if playQueue() replaced the
  queue while the network request was in flight
- playQueue: increment _queueGen; move fillRadioQueue() inside the rAF
  after setQueue so addToQueue always lands in the correct native queue
- onTrackChanged: remove .then() that re-sent addToQueue (double-send fix)
- onQueueEnded: remove addToQueue re-send, keep only _nsBridge('play')
- onPlaybackStateChanged: add safety-net sync when isPlaying transitions
  to true — catches any remaining edge cases where onTrackChanged missed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 00:02:42 +02:00
HoneyandClaude Sonnet 4.6 f97e31178c fix: revert MusicService debounce — it was causing the desync, not fixing it
The 120ms debounce on JS-initiated transitions (seek/setQueue) delayed
updateStateSnapshot(), leaving a stale window where getState() returned
the old index. If an AUTO callback fired during that window and the JS
onTrackChanged handler called getState(), it would read the stale index
and overwrite the correct player bar state with the wrong song.

Fix: always fire onTrackChanged immediately so updateStateSnapshot() runs
synchronously. The JS-side getState() reconciliation (from the previous
commit) then reliably gets the settled native index every time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 23:51:15 +02:00
HoneyandClaude Sonnet 4.6 52079536b6 fix: eliminate notification/playerbar song desync on Android
Two-pronged fix for the state drift between the system notification
(ground truth) and the WebView player bar:

JS (player.js): onTrackChanged now reconciles the incoming index with a
synchronous NSBridge.getState() call before applying it. Stale callbacks
from earlier rapid skips immediately correct themselves to the live
settled index instead of overwriting the correct state.

Kotlin (MusicService.kt): debounce JS-initiated transitions (seek /
setQueue) by 120 ms so rapid skip sequences produce one onTrackChanged
notification at the final index rather than one per skip step. Auto-advance
transitions are still fired immediately since JS doesn't initiate those.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 23:38:25 +02:00
HoneyandClaude Sonnet 4.6 0874fd4f9f feat: radio mode uses getSimilarSongs2 for artist/genre-aware playback
Replaces getRandomSongs with getSimilarSongs2 seeded from the current track.
Falls back to random if Navidrome returns nothing (no Last.fm config or unknown song).
Deduplicates against songs already in the queue.
Compatible with AudioMuse-AI plugin if added later — same endpoint, better results.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 23:06:17 +02:00
HoneyandClaude Sonnet 4.6 2d0ee021e6 fix: sync track state before opening NP on notification tap; remove clickable title from player bar
- MainActivity: emit onTrackChanged + openNowPlaying in one JS tick on notification tap
  to prevent race where stale song appeared in NP overlay and bottom bar
- index.html: remove onclick/cursor from player-title so only album/artist are clickable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 22:58:49 +02:00
HoneyandClaude Sonnet 4.6 084c1728cd fix: prevent lyrics line reflow on active — remove font-weight change
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 19:18:54 +02:00
HoneyandClaude Sonnet 4.6 7894790436 tweak: lyrics no wrap + reduce active line glow/scale
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 19:16:34 +02:00
HoneyandClaude Sonnet 4.6 e4cc93d362 fix: restore LRCLIB fallback for synced lyrics; fix np-drag-handle null crash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 19:03:42 +02:00
HoneyandClaude Sonnet 4.6 654cde6796 refactor: remove LRCLIB fallback — handled by navidrome-lyrics-plugin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 18:54:45 +02:00
HoneyandClaude Sonnet 4.6 4b2f277ff7 feat: persist volume level in localStorage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 21:39:56 +02:00
HoneyandClaude Sonnet 4.6 4f152028f4 feat: auto-close preview when main playback starts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 21:10:08 +02:00
HoneyandClaude Sonnet 4.6 9f134883d9 tweak: widen PC progress bar controls from 420px to 520px
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 21:06:15 +02:00
HoneyandClaude Sonnet 4.6 d99145cce6 tweak: increase album/artist gap in player bar to 4px
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 21:05:44 +02:00
HoneyandClaude Sonnet 4.6 2553534cc8 tweak: keep player bar static during swipe-up; improve title/album/artist spacing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 21:03:54 +02:00
HoneyandClaude Sonnet 4.6 32036b7312 fix: collapse status-badge row when inactive so player-info centers correctly
.player-status-row had min-height:16px + margin-top:3px = 19px of permanent
invisible space, making player-info ~63px tall on desktop. Centered in 112px
this pushed the title to ~25px from top instead of ~34px.

Switched badges from opacity:0 (still in layout) to display:none, removed
min-height — row collapses to 0 when no badge is active so player-info
is only as tall as the visible title+album+artist rows (~44px), and
align-items:center on player-track places them at the true bar midpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:59:56 +02:00
HoneyandClaude Sonnet 4.6 bc068551de fix: desktop player-track stretch + mobile padding breathing room
Desktop: player-track had align-self:center (from grid align-items:center),
collapsing it to 52px content height. align-items:center inside it then
centered against 52px, not the full 112px bar — text appeared at top.
align-self:stretch forces player-track to fill the bar height so internal
centering works correctly.

Mobile: padding:14px 12px was too symmetric — art filled the 46px content
area exactly and touched the progress strip. Changed to padding:6px 12px 14px
(6px top breathing room, 14px bottom for progress strip, ~54px content area).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:56:16 +02:00
HoneyandClaude Sonnet 4.6 a5048abd2e fix: center player bar content vertically; use theme accent for artist
padding:0 12px 14px meant zero top padding, so align-items:center placed
content in the top 60px of the 74px bar — visually 7px above center.
Changed to padding:14px 12px (symmetric) so art+text center at exactly
37px, the visual midpoint of the bar. Progress strip stays absolute at bottom.

Artist color changed from hardcoded gold to var(--accent) in both the
bottom bar and Now Playing UI so it follows the active theme.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:50:24 +02:00
HoneyandClaude Sonnet 4.6 ea293a498f fix: tighten player bar line-height; accent color for artist in bar + NP
- line-height:1.2 on title and artist rows keeps the text block within
  the 46px art circle so it no longer overflows above/below
- Artist name uses accent color (gold) in both the bottom bar and the
  Now Playing UI, making it immediately distinguishable from the album

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:39:28 +02:00
HoneyandClaude Sonnet 4.6 494361191a fix(android): debounce onReady; pre-warm artwork before playback starts
Song restart: onPageFinished can fire multiple times mid-session (hash/state
changes in WebView). Added 3s debounce so onReady is not re-delivered
spuriously while a song is playing.

Notification artwork: warmArtworkCache was called from onTimelineChanged
where player.currentMediaItemIndex hadn't updated yet (lags until prepare()),
so it warmed the wrong tracks. WebBridge.setQueue now calls
MusicService.publicWarmArtwork(startIndex) immediately after setMediaItems
and before prepare()/play(), giving the bitmap loader a head start with
the correct index.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:27:39 +02:00
HoneyandClaude Sonnet 4.6 ac4f09c8b8 fix: never rebuild native queue in onReady while ExoPlayer is playing
When onReady fires during MediaController reconnect (fragment navigation,
activity resume), calling setQueue restarts the current song from pos 0.
Guard: if native isPlaying=true, only re-sync JS UI — never touch the queue.
Only push a new queue when native is idle/empty (cold start).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:22:27 +02:00
HoneyandClaude Sonnet 4.6 0e05740df7 feat: show title/album/artist order in bottom bar and now playing UI
- Bottom bar: player-info is now a centered flex column so text block
  aligns properly against the art circle
- Now playing: split artist·album line into album (above) + artist (below)
  matching the bottom bar layout; removed np-album-sep reference
- Removed stale np-album-sep style.display call from player.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:20:04 +02:00
HoneyandClaude Sonnet 4.6 4c4dee4e55 fix: remove player-album-sep references after HTML restructure
Removing the separator span from the HTML broke updatePlayerUI which still
called getElementById('player-album-sep').style — null crash on every
song play. Removed both occurrences since album now has its own line.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:03:11 +02:00
HoneyandClaude Sonnet 4.6 aa8d58d01f fix: null guard in hideCtxMenu and scroll/touchmove listeners
hideCtxMenu now guards against null #ctx-menu element. scroll/touchmove
listeners only fire when menu is actually visible, preventing spurious
calls on every scroll event.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:00:23 +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 92edaa9da4 feat: show album above artist in bottom bar; close ctx menu on scroll
- Player bar sub-line now shows album (clickable) on first row, artist below
- Context menu now closes on scroll and touchmove (was staying open on mobile)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 00:03:20 +02:00
HoneyandClaude Sonnet 4.6 47cf3d13e5 fix: use pointerdown+pointerType to block touch seeks on bottom bar
mousedown does not expose the input source — replaced with pointerdown
which carries pointerType='touch', allowing noTouch=true to reliably
skip touch input without affecting mouse/stylus on PC.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:39:02 +02:00
HoneyandClaude Sonnet 4.6 162bf530a2 fix: block synthetic mousedown on bottom progress bar from touch taps
noTouch=true now also adds a touchstart preventDefault listener so the
browser does not fire synthetic mousedown/click after a tap, which was
still triggering seeks in the PWA despite touch events being disabled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:35:43 +02:00
HoneyandClaude Sonnet 4.6 e47450b20d tweak: reduce swipe-up overlay speed from 2.5x to 1.5x for smoother feel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:32:00 +02:00
HoneyandClaude Sonnet 4.6 eeb822bbb2 fix: suppress login screen flash on load when already authenticated
Adds a synchronous inline script that checks localStorage before first
paint and sets html.ns-authed, hiding #setup-screen via CSS immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:28:32 +02:00
HoneyandClaude Sonnet 4.6 43312be65d fix: remove overlay cap during swipe-up so NP slides smoothly without stopping
The Math.min(160) cap on 'lift' meant the overlay froze after 160px of drag
(at ~70% down the screen) while the finger kept moving — the felt 'stop'.

Now: player bar caps at its own height (once it slides off, no more movement
needed), overlay tracks the finger with no cap at 2.5× speed so ~360px of
upward drag fully reveals the now-playing screen. Release animation (from
the previous fix) then carries it smoothly to position 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:16:32 +02:00
HoneyandClaude Sonnet 4.6 b0fb1b200d fix: smooth NP swipe-open animation; live playing highlight in song lists
Swipe animation:
- _resetDrag(true) now reads the overlay's current drag position and starts
  the CSS transition from there instead of resetting to translateY(100%) first.
  That reset was causing the visible stutter (overlay jumped off-screen then
  slid back up). Now the overlay continues seamlessly from wherever the finger
  released to translateY(0).

Playing highlight:
- makeSongItem: adds data-song-id attribute to every .song-item element.
- updatePlayerUI: calls _updatePlayingHighlights() after every track change.
  This toggles .playing on all visible song items in any open list/playlist/
  favorites view so the highlighted row always matches what's actually playing,
  without requiring the user to navigate away and back.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:10:03 +02:00
HoneyandClaude Sonnet 4.6 0fbb1385f1 fix: remove blue tap highlight and focus ring globally in WebView
-webkit-tap-highlight-color was only on 2 specific elements; every
div/song-item/card still showed a blue flash on tap in Android WebView.
*:focus{outline:none} replaces the button-only rule and covers clickable
divs as well.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:44:40 +02:00
HoneyandClaude Sonnet 4.6 4856f0ca57 fix: bottom bar no touch seek; lyrics seek on Android; smoother NP animation
- initProgressScrub: pass noTouch=true for the bottom mini-bar so touch
  events are never registered on it; only mouse events remain (desktop-only).
  The now-playing scrubber is unchanged and keeps full touch support.
- Export seekToMs(ms) from player.js; use it in the lyrics click handler
  instead of S.audio.currentTime which has no effect when HAS_BRIDGE
  (native ExoPlayer handles playback, not the HTML audio element).
- styles.css: add will-change:transform to .player and .np-overlay to keep
  them on GPU compositor layers during the swipe gesture; tweak NP open
  transition to cubic-bezier(.4,0,.2,1) for a snappier feel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:42:58 +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 68bec67880 fix: sync queue insert/append to native Android player
Both 'Als Nächstes einfügen' and 'Am Ende der Queue' updated S.queue in JS
but never called NSBridge, so the native ExoPlayer ignored the change and
kept playing the original next item.

- Export nativeInsertAt(song, position) from player.js
- Call it in showCtxMenu with the exact splice index for insert-next
  and -1 (append) for add-to-end

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:27:25 +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 1b7c05f66d feat: notification 'Öffnen' routes to album for track/album downloads
- Single track and album downloads now navigate to the album page
- Artist downloads continue to navigate to the artist page
- Button label changes to 'Zum Album →' or 'Zum Künstler →' accordingly
- album name stored in job metadata so it survives until poll completes
- Search uses exact album+artist match, falls back to album-name-only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:16:15 +02:00
HoneyandClaude Sonnet 4.6 ba382aa6d9 fix: cover art caching, skip desync, notification tap opens now playing
- api.js: cache coverUrl() per id+size so WebView HTTP cache can work;
  previously each call generated a new random salt/token → unique URL →
  no cache hits → images re-fetched on every render

- player.js: replace _nsBridge('next')/'prev' with explicit seekToIndex
  in nextSong/prevSong so native always jumps to the exact same index JS
  computed; 'next'/'prev' relied on native's internal pointer being in sync
  which caused 'UI shows new song but audio plays old one' when they drifted

- MusicService: set setSessionActivity PendingIntent on MediaSession so
  tapping the playback notification opens the app

- MainActivity: handle open_now_playing extra in onCreate (cold start)
  and onNewIntent (app already running) to show the Now Playing screen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:12:29 +02:00
HoneyandClaude Sonnet 4.6 66099c12f0 fix: add kuromoji to backend container npm install
The backend uses NODE_PATH=/deps/node_modules with its own npm install
step — not the root package.json. Added kuromoji there and reverted
the incorrect root package.json change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 21:48:13 +02:00
HoneyandClaude Sonnet 4.6 5bcb8b09a8 fix: romaji index routes moved after app init + kuromoji in root package.json
- app.get/delete for /api/romaji-index were placed before const app = express()
  causing ReferenceError on startup — moved into the ROUTES section
- kuromoji moved from backend/package.json to root package.json so Docker
  picks it up during the existing npm install step
- Fixed dicPath resolution to use path.dirname(require.resolve(...))

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 21:26:46 +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 369a5e82b3 fix: remove duplicate search bar from PC sidebar
The magnifier icon in the top-right already opens search.
Having a second search box in the sidebar was redundant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 21:08:37 +02:00
HoneyandClaude Sonnet 4.6 bd8919fb39 fix: prevent accidental seek on tap in mobile progress bar
Touch scrubbing now requires ≥8px horizontal drag before committing.
A plain tap on the progress bar is ignored — no unintentional position jump.
Also removed redundant onclick="seekTo()" since _initBarScrub already
handles mouse seeking via mousedown/mousemove/mouseup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 21:05:55 +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