From cf88d87791f9a1673f1ddc00e99bb3e0f180ed5b Mon Sep 17 00:00:00 2001 From: Honey Date: Thu, 14 May 2026 19:04:12 +0200 Subject: [PATCH] fix: simplify audiobook sleep timer custom input; update README - Remove OK button and expand-on-click from sleep timer custom row - Always show label + plain number input (no spinners, Enter to confirm) - Update README with all current features (Spotify importer, ABS, lyrics, filters, etc.) Co-Authored-By: Claude Sonnet 4.6 --- README.md | 58 ++++++++++++++++++++++++++++++++++++++++++++---------- index.html | 7 +++---- styles.css | 15 ++++++-------- 3 files changed, 57 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1f36117..f186e4c 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,45 @@ Built with Vite + vanilla ES modules, served via nginx in Docker. ## Features +### Music Library - Stream music from your Navidrome / Subsonic library -- Browse artists, albums, playlists, starred tracks and random picks -- Queue management with shuffle, repeat (all / once) and radio mode (endless random) -- Now Playing overlay with swipe-to-dismiss and lock screen media controls (Android/iOS) -- iTunes / Last.fm integration — charts, global search, 30s previews, recommendations -- Download tracks from YouTube/SoundCloud via yt-dlp directly into your music library -- Duplicate detection — skips tracks that already exist on the server -- Edit playlists (name, description, cover art, public toggle) -- PWA — installable, offline-capable via service worker +- 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) + +### Playback +- Queue management with shuffle, repeat (all / once), and radio mode (endless random) +- Now Playing overlay with swipe-to-dismiss +- Lock screen media controls (Android / iOS via Media Session API) +- Gapless-style queue with prev/next, skip forward/back + +### Discovery +- iTunes / Last.fm integration — charts, global search, 30-second previews, similar artists, recommendations +- Spotify playlist importer — paste a Spotify playlist URL to preview and download all tracks, enriched with iTunes metadata and cover art + +### Downloads (yt-dlp backend) +- Download individual tracks, full albums, or entire artists from YouTube / SoundCloud +- Spotify playlist importer downloads with iTunes-enriched metadata (album, year, track number, genre, cover art) +- Duplicate detection — skips tracks already present on the server +- Lyrics embedded into downloaded files (LRCLIB) + +### 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 feel) +- Multiple color themes - Dark theme, mobile-first responsive layout +- German UI --- @@ -31,15 +60,23 @@ Music_App/ │ ├── player.js # Playback, transport, queue, media session, preview │ ├── views.js # Navigation, page loaders, card makers, search │ ├── ui.js # Modals, overlays, sidebar, settings, context menu +│ ├── nowplaying.js # Now Playing overlay +│ ├── abs.js # Audiobookshelf integration +│ ├── spotify.js # Spotify playlist importer +│ ├── components.js # Shared UI components +│ ├── themes.js # Theme switching │ ├── pwa.js # Service worker registration + update banner │ └── main.js # App init, audio wiring, window globals +├── backend/ +│ ├── novasonic-server.js # Node.js download backend (yt-dlp + ffmpeg) +│ └── lib/ +│ └── metadata.js # iTunes lookup, lyrics fetch, artwork download ├── 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) -├── backend/ -│ └── novasonic-server.js # Node.js download backend (yt-dlp + ffmpeg) +├── android/ # Android WebView APK wrapper ├── index.html # App shell + Vite entry point ├── styles.css # All styles ├── vite.config.js @@ -104,3 +141,4 @@ npm run preview # Preview the production build locally 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 diff --git a/index.html b/index.html index 974afc1..e161a25 100644 --- a/index.html +++ b/index.html @@ -719,10 +719,9 @@ -
- Eigene Zeit… - - +
+ Eigene Zeit +
diff --git a/styles.css b/styles.css index 4d6e0cb..1e31359 100644 --- a/styles.css +++ b/styles.css @@ -950,15 +950,12 @@ nav{flex:1;overflow-y:auto;padding:4px 10px} .abs-picker button{display:block;width:100%;padding:9px 16px;background:none;border:none;color:var(--text);font-family:var(--font);font-size:13px;cursor:pointer;text-align:left;transition:background .15s;white-space:nowrap} .abs-picker button:hover{background:var(--surface2)} .abs-picker button.active{color:var(--accent);font-weight:700} -.abs-sleep-custom-row{display:flex;align-items:center;gap:6px;width:100%;padding:9px 16px;background:none;border:none;border-top:1px solid var(--border2);color:var(--text);font-family:var(--font);font-size:13px;cursor:pointer;text-align:left;box-sizing:border-box;transition:background .15s} -.abs-sleep-custom-row:hover{background:var(--surface2)} -.abs-sleep-custom-row.active{background:var(--surface2);cursor:default;padding:8px 10px} -.abs-sleep-custom-label{flex:1;pointer-events:none} -.abs-sleep-custom-row.active .abs-sleep-custom-label{display:none} -.abs-sleep-custom-row input{display:none;flex:1;min-width:0;padding:5px 8px;background:var(--surface);border:1.5px solid var(--accent);border-radius:6px;color:var(--text);font-family:var(--font);font-size:13px;outline:none} -.abs-sleep-custom-row.active input{display:block} -.abs-sleep-custom-row button{display:none;padding:5px 12px;background:var(--accent);border:none;border-radius:6px;color:#fff;font-family:var(--font);font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0} -.abs-sleep-custom-row.active button{display:block} +.abs-sleep-custom-row{display:flex;align-items:center;gap:8px;width:100%;padding:7px 16px 9px;border-top:1px solid var(--border2);box-sizing:border-box} +.abs-sleep-custom-label{font-size:11px;color:var(--text3);white-space:nowrap;flex-shrink:0} +.abs-sleep-custom-row input{flex:1;min-width:0;padding:5px 8px;background:var(--surface);border:1.5px solid var(--border2);border-radius:6px;color:var(--text);font-family:var(--font);font-size:13px;outline:none;transition:border-color .15s} +.abs-sleep-custom-row input:focus{border-color:var(--accent)} +.abs-sleep-custom-row input[type=number]::-webkit-inner-spin-button,.abs-sleep-custom-row input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0} +.abs-sleep-custom-row input[type=number]{-moz-appearance:textfield} .abs-chapter-list{flex-shrink:0;overflow-y:auto;max-height:0;transition:max-height .3s ease;border-top:1px solid transparent} .abs-chapter-list.open{max-height:220px;border-color:var(--border)} .abs-ch-item{display:flex;align-items:center;gap:10px;padding:8px 20px;cursor:pointer;transition:background .15s}