- itunesProxy: drop 3-arg form (url, options, cb) — use 2-arg (url, cb) like lookupItunesTrackMeta
- _iGet: if proxy returns {results:[]} trust it (iTunes said no results); only fall back to direct Apple if proxy gave no response at all
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_iGet now tries backend proxy first (if backendUrl set), falls back to direct
Apple API URL so iTunes search/lookup/charts work regardless of backend config.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Apple now blocks direct browser requests from custom origins. Added backend proxy routes:
GET /api/itunes/search — iTunes search
GET /api/itunes/lookup — iTunes lookup by ID
GET /api/itunes/charts — Apple RSS most-played charts (albums/songs)
All itunesSearch/Lookup/TopCharts/TopSongs functions in api.js now route through backend.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- itunesSearch: use r.text() + JSON.parse so empty body (rate-limit) returns [] instead of throwing
- reduce Spotify artwork batch size 8→4 to avoid hammering iTunes and affecting global search
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- _loadSpotifyTrackArtwork: rewritten to call itunesSearch() directly from browser (same as global search) instead of backend endpoint — same quality, works for all regions
- enriches track objects with collectionName, releaseDate, trackNumber, trackExplicitness so downloads get full metadata too
- 8-concurrent batch to avoid hammering iTunes
- adds onerror fallback to makeGlobalTrackItem img so broken URLs show 🎵 placeholder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- player bar: fix onclick broken by JSON.stringify producing double-quoted strings inside double-quoted HTML attribute; use single-quoted JS args instead
- now playing overlay: np-artist-name now splits artists and each is individually clickable (closes NP then navigates to artist)
- remove wrapper onclick from both np-artist-name and player-artist-name in HTML
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- track-artwork endpoint: split artist on ,/•/ before iTunes search (same as download flow)
- track-artwork endpoint: fall back to existingArt when iTunes returns nothing
- frontend: render any artwork already in Spotify data immediately, don't wait for iTunes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- components.js: expand artist split regex to handle both ' / ' and '•' separators
- views.js: enable artist+album links in playlist song items (were noArtistLink:true)
- views.js: enable artist links in album detail song items
- views.js: album header artist is now split and renders as clickable links
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- sw.js: ns-v38 → ns-v39 forces PWA cache clear so previous fixes take effect
- components: split s.artist by ' / ' in makeSongItem — each part becomes its
own clickable link; noArtistLink turns all parts into plain text
- views: s_goArtist searches Navidrome by name when no artistId is available
(needed for secondary artists that only have the primary artistId in the song)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- nowplaying: add cancellation token to _loadNpLyrics to prevent stale async
calls overwriting newer results (synced→plain race condition)
- nowplaying: replace scrollIntoView with explicit container.scrollTo to prevent
page-level scroll on desktop (topbar shifting / gap at edge)
- backend: remove results[0] fallback in lookupItunesTrackMeta — only use
exact title+artist match to avoid embedding wrong artwork
- components/views: makeSongItem accepts noArtistLink/noAlbumLink opts;
album-detail disables both, playlist-detail disables artist link
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Retry LRCLIB without album_name when exact match fails (404) —
album name mismatch was the most common cause of falling back to plain
- Capture plainLyrics from LRCLIB and prefer it over Navidrome plain
(LRCLIB plain text is usually higher quality)
- Use only first artist for LRCLIB lookup (multi-artist strings like
'Artist A / Artist B' cause 404)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- _restoreLastPlayed: set audio.src + call updateMediaSession so play
button works immediately and notification shows artwork on app open
- visibilitychange: re-register all MediaSession handlers after screen
unlock, fold/flip, or background return (fixes vanishing notification)
- Stall watchdog (3s interval): detects frozen audio in background and
calls play() to recover; also catches missed 'ended' events so
auto-advance works reliably when screen is off
- stalled/error listeners: attempt audio reload on network hiccup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds POST /api/spotify/track-artwork endpoint that takes an array of
{idx, trackName, artistName} and returns iTunes artwork URLs in batches
of 8 concurrent requests.
Frontend calls this after rendering the track list, then patches each
.gtrack-art element with the correct album cover as results arrive.
Also updates _spotifyResolved.tracks so downloads use the right artwork.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- _spTrackItem now unwraps GraphQL-style {data:{__typename,...}} wrappers
- _spAllArtists joins all featured artists (e.g. "Kløn, Renzyx")
- _spArtwork adds albumOfTrack path used by newer Spotify embed
- fetchSpotifyEmbed: added entity.content.items / entity.data fallback paths
- Track download now uses Spotify metadata directly (album, art, year,
trackNum) when provided — avoids iTunes returning wrong album for
multi-artist tracks
- Playlist trackList also tries entity.content.items and entity.tracks.items
- Frontend: redesigned preview card with green top accent, bigger art,
playlist checkbox styled as pill with Spotify color on check, album
button shows actual album name
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace Client Credentials flow with Spotify's public web-player token endpoint
(open.spotify.com/get_access_token) which works without any account or Premium.
Remove Spotify credential fields from UI entirely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New 'Spotify Importer' page under Entdecken (sidebar + mobile nav)
- Backend: POST /api/spotify/resolve — resolves track/album/playlist URLs via Spotify API
- Backend: new 'playlist' download type accepting pre-resolved track list (no iTunes re-fetch)
- Frontend: paste Spotify link → preview with cover, type badge, track list
- Track: single download or full album via iTunes fallback
- Album: download all tracks with Spotify metadata
- Playlist: download all tracks + optional 'Als Navidrome-Playlist speichern' checkbox
- Navidrome playlist creation: searches library by title/artist after download, creates playlist
- Spotify Client ID + Secret stored in app settings (setup screen + settings modal)
- iTunes metadata tags kept for all downloaded files (existing pipeline unchanged)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Parse [offset:N] metadata from LRC files (was silently ignored, caused ~1s drift)
- Apply 200ms lookahead so active line highlights slightly before it's sung
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hero height 220px mobile → 320px desktop (min-width: 769px)
- Larger artist name (46px) and more padding on desktop
- Overlay gradient now also darkens the right edge instead of fading to transparent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 'Alle X Songs' button now navigates to a dedicated page instead of expanding inline
- Partial/not-downloaded albums now open an iTunes album detail page with track list,
preview buttons and download option
- Added page-artist-all-songs and page-itunes-album-detail to index.html
- Replaced _expandArtistAllSongs with loadArtistAllSongs + loadItunesAlbumDetail
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- loadArtistDetail now works for both Navidrome artists and iTunes-only
artists (id=null + itunesArtistId). loadItunesArtistResults from global
search now navigates to the same artist-detail page.
- Album sections: "In Library" (fully downloaded), "Unvollständig" (partial
— e.g. 2/12 tracks), "Noch nicht heruntergeladen" (iTunes-only). Partial
albums show X/Y badge and a direct download button on hover.
- iTunes albums now fetched via lookup endpoint (up to 200 albums) instead
of search (max 20), fixing the missing-albums problem.
- "Alle X Songs in Library" expand button fetches all songs across albums
and renders them grouped by album with play/context-menu support.
- Back button uses _navGoBack() for context-aware navigation.
- CSS: .section-count, .album-partial-badge, .card-dl-btn (hover reveal)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename "Warteschlange" -> "Queue", tighten tab padding/letter-spacing
so all 3 tabs fit on narrow screens
- _loadNpLyrics now tries Navidrome getLyricsBySongId first (works once
.lrc sidecar is rescanned), then falls back to fetching synced LRC
directly from LRCLIB and parsing [mm:ss.xx] timestamps in the frontend
- Plain text shown as last resort if no synced lyrics found
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a Lyrics tab to the NP overlay using Navidrome's getLyricsBySongId
endpoint. Synced lyrics auto-scroll and highlight the current line as
the track plays; tapping a line seeks to that position. Falls back to
plain text for unsynced lyrics.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- fetchLyrics() queries LRCLIB for plain + synced lyrics
- Synced lyrics saved as .lrc file (Navidrome reads these)
- Plain lyrics embedded via ffmpeg -metadata lyrics=
- ITUNESADVISORY=1 written for explicit tracks
- explicit flag passed through album/track download chain
- fetchItunesTracks + searchItunesAlbumTracks use country=us&explicit=Yes
Frontend:
- explicit:true sent in download payload from iTunes track data
- "E" badge shown on explicit tracks in global search track list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
iTunes search endpoint always returns cleaned versions.
Added itunesLookupArtistSongs() using /lookup?explicit=Yes which returns
the actual explicit tracks. Used in artist profile (global search) and
artist detail page (library). Album track lookup also gets explicit=Yes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
country=de silently filtered explicit content from iTunes results.
Switched to country=us&explicit=Yes so all songs appear regardless of explicit flag.
Removed wrong explicit-filtering code from views.js.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Global search now shows only iTunes results (no Navidrome library section)
- All iTunes results (tracks, albums, artist pages, album detail, recommendations)
filtered to exclude explicit content (trackExplicitness/collectionExplicitness === 'explicit')
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Player bar: drag handle pill + live lift/peek animation when swiping up to NP
- Global search: now includes Navidrome library results alongside iTunes; fix songs not showing (filter wrapperType=track)
- iTunes artist page: hero banner with album art, top songs section
- Artist detail: iTunes global top tracks + extra albums not on server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend: set skipped:true on job when track already exists on disk.
Album downloads report "X geladen, Y bereits vorhanden" in the message.
Frontend: pollJob shows "⏭ bereits auf dem Server" instead of "✅ gespeichert"
when the job has skipped:true.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
switchNavMode, stopPreview, npToggleStar, loadRandom were imported
but not exposed to window — causing onclick ReferenceErrors in HTML.
Added npSeek stub (was empty function in original app.js).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>