- New guest flag playCollection (default OFF), gates play-playlist/play-album
- Keeps playNow's non-destructive semantics intact (Play All clears the queue)
- Admin-toggleable in Settings → 游客模式; default-off, backward-compatible
- Frontend: gate the 播放全部 button on the flag + surface 403 as a toast
instead of failing silently (the silent-failure half of the issue)
The album detail endpoint intentionally 404s (no /api/music/album/:id/detail
route), so we fall through to the stub built from songs. The album name is
already on every song (Song.album), so use it instead of the literal "专辑".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Library / Search / History / Playlist now route the third action to
store.playNextSong. Home is unchanged (it doesn't use SongCard).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three small reliability fixes from re-auditing:
1. Playlist.vue used Promise.all, so a flaky /detail endpoint would
blank out the whole page even though /songs returned just fine.
Switch to allSettled and synthesize a stub playlist header from
the song list when only detail fails. User can still play the
playlist; just loses the description/cover.
2. sourceTabs.readAll: typeof null === 'object' AND typeof [] ===
'object', so a corrupted localStorage value (e.g. an array) would
be treated as a record and its missing keys would silently fall
back. Reject explicitly so the failure mode is "clean defaults"
instead of "wrong shape that almost works".
3. Settings.vue loadProfileConfig: a 200 response with empty/wrong
body would set profileConfigs[botId] to a falsy/wrong-shape value,
leaving the row stuck on "加载中..." (because the v-if uses
!profileConfigs[id]). Validate the shape; surface "响应格式异常"
so the retry link is reachable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New endpoints: play-by-id, add-by-id, play-playlist (load all songs at once)
- Playlist 'Play All' now uses server-side bulk load (no N sequential searches)
- Search/Home/Playlist views use playById instead of search-by-name
- Fixed updateBotStatus timing: capture prev state before mutation
- Early return on song change prevents stale pause/resume logic
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Progress bar reads playStartedAt directly in requestAnimationFrame loop
bypassing Vue reactivity caching for smooth 60fps updates
- Queue panel moved to sibling of player-bar (was trapped inside causing z-index issues)
- Added progress thumb dot on hover
- Click on progress shows 'seek not available' tooltip
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Playlist: add console.error in catch block so load failures are visible
- Player: add progress bar with requestAnimationFrame and time display
- Player: extract toggleQueue function with debug logging for queue panel
- WebSocket: fetch queue on stateChange when not included in event payload
- Lyrics: use CSS transform scrolling and reduce sync to 500ms to fix flicker
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add play mode cycle button (seq/loop/random/rloop) to Player bar
- Wire GET /api/player/:botId/history to query database instead of returning empty array
- Pass database instance from server.ts to createPlayerRouter
- Add back navigation button to Playlist, Lyrics, History, Search, and Settings views
- SongCard already had dblclick-to-play (no change needed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add backend endpoints for daily recommended songs, personal FM, user
playlists, and playlist detail. Extend NeteaseProvider and MusicProvider
interface with getDailyRecommendSongs and getUserPlaylists. Rewrite Home
page with FM card, daily recommendations grid, and user playlists section.
Fix Playlist view to fetch detail and songs from separate endpoints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>