Commit Graph
77 Commits
Author SHA1 Message Date
saopig1andClaude Opus 4.6 d0d2f57066 fix: 自动连接改为非阻塞并行 — 一个bot连接失败不影响其他bot
之前 loadSavedBots 用 await 顺序连接所有bot,一个超时会阻塞
后续所有bot和web server启动。改为 .then()/.catch() 并行连接,
每个bot独立成败互不影响。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:33:32 +08:00
saopig1andClaude Opus 4.6 eb92b04e11 fix: 机器人状态显示 — 区分在线/播放中/已暂停/离线四种状态
之前只有在线/离线两种,播放中也显示为在线。
现在:绿色=播放中,蓝色=在线,橙色=已暂停,灰色=离线

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:27:01 +08:00
saopig1andClaude Opus 4.6 01d16281d5 fix: Settings页面mount时刷新bot状态,防止显示过期数据
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:16:06 +08:00
saopig1andClaude Opus 4.6 e466f5cd61 fix: NetEase API端口冲突检查,Settings页面create-bot样式修复
- NetEase API启动前检查端口是否被占用(与QQ API相同逻辑)
- 添加.create-bot CSS(分隔线+间距)
- 防止EADDRINUSE崩溃

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:13:11 +08:00
saopig1andClaude Opus 4.6 ef9d41fd44 docs: 更新多机器人独立播放功能描述
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:58:36 +08:00
saopig1andClaude Opus 4.6 4dbbaaf8f5 fix: 删除bot后重置activeBotId,编辑立即更新名称,config fetch await防空值
1. 删除活跃bot后将activeBotId置null,由fetchBots自动选新的
2. updateBot同时更新内存中的name(无需重启即可看到名称变化)
3. openEditBot改为async await config请求,失败时用bot名称做fallback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:54:33 +08:00
saopig1andClaude Opus 4.6 067a30233f feat: 机器人管理 — 删除、编辑配置、完整创建表单
- PUT /api/bot/:id 更新机器人配置(保存到数据库,重启生效)
- GET /api/bot/:id/config 获取保存的配置
- BotManager.updateBot/getBotConfig 方法
- Settings 页面:删除按钮(带确认)、编辑弹窗(修改所有字段)
- 创建表单:完整字段(名称、地址、端口、昵称、默认频道)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:50:49 +08:00
saopig1andClaude Opus 4.6 bc9b2366d0 feat: make frontend fully support multiple independent bots
Store queue and timing state per-bot instead of globally, move bot
selector from Home page into Navbar dropdown, show bot name badge
in the player bar, and route WebSocket stateChange queues per-bot.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:45:24 +08:00
saopig1andClaude Opus 4.6 75d359f65f docs: 标注兼容 TS3/TS5/TS6 服务器(协议层向后兼容,无需额外适配)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:36:13 +08:00
saopig1andClaude Opus 4.6 223ba45e65 feat: 启动时自动连接所有已保存的机器人实例
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:28:43 +08:00
saopig1andClaude Opus 4.6 942a715542 docs: README 更新 — 三平台支持(网易云+QQ+B站),B站徽章/命令/架构/FAQ
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:26:01 +08:00
saopig1andClaude Opus 4.6 fbf8cc82de fix: cidCache 大小限制为500条,防止内存泄漏
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:20:42 +08:00
saopig1andClaude Opus 4.6 5e4d318a2a feat: 我的歌单超过20个时折叠,点击展开/收起
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:16:31 +08:00
saopig1andClaude Opus 4.6 cf293299c8 feat: B站首页推荐 — 个性化推荐/音乐区排行/热门视频
- BiliBiliProvider.getDailyRecommendSongs: 个性化推荐(登录后更准确),
  fallback 到音乐区排行榜
- BiliBiliProvider.getPopularVideos: 热门视频列表
- 新增 GET /api/music/bilibili/popular 端点
- 首页新增"B站热门"板块,带B站蓝色徽标
- Store 缓存 bilibiliPopular 数据

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:12:06 +08:00
saopig1andClaude Opus 4.6 05d7f7d5f7 fix: 封面加载失败 — 添加referrerpolicy=no-referrer,移除crossorigin,添加placeholder
B站CDN可能基于Referer拒绝图片请求。添加referrerpolicy="no-referrer"
让浏览器不发送Referer头。同时:
- 移除crossorigin="anonymous"避免CORS问题
- alt=""替代alt="Cover",不再显示文字
- 图片加载失败时显示音符图标placeholder
- watch url变化重置错误状态

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:04:11 +08:00
saopig1andClaude Opus 4.6 960ca756a6 fix: 使用SPI API获取buvid3替代访问主页 — 可靠解决412问题
之前通过axios访问bilibili.com主页获取cookie失败(axios不解析set-cookie)。
改用专用API: /x/frontend/finger/spi 直接获取buvid3和buvid4值,
构造cookie字符串传入搜索请求。已验证搜索正常返回结果和封面URL。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:54:21 +08:00
saopig1andClaude Opus 4.6 dcec26feb1 fix: B站搜索412错误 — 自动获取buvid3匿名Cookie绕过反爬
B站搜索API强制要求buvid3 cookie,否则返回412。
Provider启动时自动从bilibili.com获取buvid3/b_nut cookie,
与用户登录cookie合并发送。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:46:51 +08:00
saopig1andClaude Opus 4.6 341faffdbb fix: B站封面 — http转https防止mixed content,CDN参数@300w_300h_1c正方形裁切
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:40:07 +08:00
saopig1andClaude Opus 4.6 a6881403ef feat: add BiliBili audio source integration
Implement BiliBiliProvider for video-as-audio playback using direct
BiliBili API calls (search, video info, DASH audio URL extraction).
Add QR code login support and cookie persistence. Update FFmpeg to
send Referer header for BiliBili CDN URLs. Extend platform union type
to "netease" | "qq" | "bilibili" across all interfaces. Add -b flag
for chat commands and B站 badge in web UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:14:27 +08:00
saopig1andClaude Opus 4.6 7d329a0db1 fix: safe router.back() — fallback to home if no history (prevents navigating to external site)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:57:32 +08:00
saopig1andClaude Opus 4.6 eb0088d110 fix: edge case bugs + toggle lyrics from player bar and lyrics button
Bugs fixed:
- play-at: stop current playback before jumping to queue index
- playNext retry: use break instead of return to ensure stateChange emits
- sendVoiceData: skip if disconnecting to avoid errors during teardown

UI: player-left and lyrics button now toggle lyrics page (open/close)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:50:14 +08:00
saopig1andClaude Opus 4.6 90019e7424 feat: 点击播放条左侧歌曲封面/信息打开歌词页面
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:43:54 +08:00
saopig1andClaude Opus 4.6 d8c0911593 feat: 双击播放队列中的歌曲(不清空队列)
- 新增 POST /api/player/:botId/play-at 端点,跳转到队列指定索引
- 使用 queue.playAt(index) + resolveAndPlay,保留队列完整
- Queue.vue 添加 @dblclick 处理,双击即播放对应歌曲
- 添加 store.playAtIndex() action

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:37:53 +08:00
saopig1andClaude Opus 4.6 17991b936a fix: resolve critical race conditions and high-severity bugs
- Add isAdvancing guard to playNext() to prevent concurrent calls from
  skipping songs (trackEnd + user !next race condition)
- Replace removeAllListeners in WebSocket setup with tracked named
  listeners, attach only once per bot instead of every 5 seconds
- Add .catch() to unhandled playNext() in cmdVote
- Add sessionId counter to AudioPlayer to discard stale setTimeout
  callbacks after stop()+play() transitions
- Defer nulling TS3 client until disconnect() promise resolves
- Add null checks for providers in play-by-id and add-by-id endpoints
- Add PCM buffer backpressure (pause FFmpeg at 960KB, resume at 480KB)
- Change volume slider from @input to @change to avoid flooding server
- Wrap error-reporting sendTextMessage in try/catch to prevent
  unhandled rejection in error handler
- Clamp elapsed getter to song duration
- Log FFmpeg stderr at debug level instead of swallowing
- Return null from prev() in Sequential mode instead of wrapping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:31:03 +08:00
saopig1andClaude Opus 4.6 4c71a0a37f fix: auto-play next song — set ffmpeg=null on close, handle async playNext
Two bugs prevented auto-advance:
1. FFmpeg close handler was empty — ChildProcess object persisted after
   close, so frame loop check `!this.ffmpeg` never triggered trackEnd
2. playNext() is async (resolves URL) but trackEnd handler didn't catch
   rejected promises, causing silent failures

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:14:56 +08:00
TIANYAO ZHANG 5c4c7051d7 Update README.md 2026-03-30 14:08:48 +08:00
TIANYAO ZHANG 7789ac18af Update README.md 2026-03-30 14:06:57 +08:00
TIANYAO ZHANG 1a041d11f6 Update README.md 2026-03-30 14:06:21 +08:00
saopig1andClaude Opus 4.6 97fccc44eb docs: 扩展致谢列表 — 添加所有参考项目和开发者
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:52:38 +08:00
saopig1andClaude Opus 4.6 833c6b7b05 docs: 全中文 README — 徽章、快速开始、使用说明、FAQ、贡献指南
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:38:27 +08:00
saopig1andClaude Opus 4.6 c4b16c8205 docs: professional GitHub README with badges, FAQ, contributing guide, LICENSE
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:28:28 +08:00
saopig1andClaude Opus 4.6 ee5b0d36c6 docs: expand Docker deployment section with commands and network notes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:23:26 +08:00
saopig1andClaude Opus 4.6 74193ffbf0 fix: Docker one-click deployment — all deps bundled, native modules, health check
- Multi-stage build: builder installs backend + frontend deps, compiles
- Production stage: npm ci --production rebuilds native modules (opus, sqlite3)
- FFmpeg bundled via ffmpeg-static (no apt install ffmpeg)
- .dockerignore prevents node_modules/dist from being copied
- docker-compose uses host network for TS3 UDP connectivity
- Named volume for persistent data
- Health check endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:20:00 +08:00
saopig1andClaude Opus 4.6 ea38636e9b docs: update README — one-click deploy, quality levels, full architecture, credits
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:59:35 +08:00
saopig1andClaude Opus 4.6 61d9bbe0b7 feat: bundle FFmpeg via ffmpeg-static for one-click deployment
Users no longer need to install FFmpeg separately — it is now bundled as
an npm dependency (ffmpeg-static). player.ts resolves the bundled binary
automatically and falls back to system PATH. start.bat and a new
setup.bat script handle dependency installation and project building.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 03:43:10 +08:00
saopig1andClaude Opus 4.6 00231db0cb docs: add comprehensive README with features, architecture, and usage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 03:38:12 +08:00
saopig1andClaude Opus 4.6 b74c8e8add feat: add audio quality selector (standard to jymaster/Hi-Res)
- MusicProvider interface: setQuality/getQuality methods
- NeteaseProvider: passes quality level to /song/url/v1
- Default: exhigh (320kbps MP3)
- Settings page: 6-option grid selector
- GET/POST /api/music/quality endpoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 03:37:26 +08:00
saopig1andClaude Opus 4.6 0439bd047f fix: server-side elapsed tracking via frame count, periodic sync, playlist respects play mode
Progress/lyrics sync:
- AudioPlayer tracks framesPlayed (ground truth: frames * 20ms + seekOffset)
- BotStatus.elapsed is the real elapsed from server
- Frontend polls GET /elapsed every 3s for ground truth
- Client interpolates between syncs (serverElapsed + timeSinceSync)
- Pause freezes at interpolated value, resume resyncs from server
- No more client-side timestamp drift

Playlist play all:
- Stops current playback before loading
- Respects play mode: random/rloop picks random first song, seq plays first

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 03:27:16 +08:00
saopig1andClaude Opus 4.6 1cdface33c feat: implement seeking (FFmpeg -ss restart), fix lyrics sync with seekOffset
- AudioPlayer.seek() restarts FFmpeg with -ss parameter for actual seeking
- New POST /api/player/:botId/seek endpoint
- BotStatus includes seekOffset and playStartTime from server
- Frontend elapsed = seekOffset + (now - playStartedAt)
- Progress bar click now seeks to clicked position
- All timing actions use _resetTiming() helper with seekOffset
- Lyrics sync uses store.elapsed which includes seekOffset

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 03:16:37 +08:00
saopig1andClaude Opus 4.6 080c2836c9 refactor: lazy URL resolution — store only metadata, fetch URL at play time
Follows TS3AudioBot-NetEaseCloudmusic-plugin pattern:
- QueuedSong.url is now optional (metadata-only queue entries)
- resolveAndPlay() fetches URL on-demand right before playback
- Playlist/album/FM load instantly (only metadata stored)
- playNext() resolves URL lazily, skips up to 3 songs on failure
- Avoids expired URLs for songs deep in the queue

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 03:05:40 +08:00
saopig1andClaude Opus 4.6 2e4d6d8d40 feat: play-by-id and play-playlist endpoints, fix lyrics sync timing
- 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>
2026-03-30 02:55:15 +08:00
saopig1andClaude Opus 4.6 2c87f1cff9 fix: progress bar smooth via rAF with direct Date.now(), queue panel moved outside player div
- 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>
2026-03-30 02:47:25 +08:00
saopig1andClaude Opus 4.6 dc9d181783 fix: check port availability before starting QQ Music API, update default port to 3200
Prevents EADDRINUSE crash that killed the entire app when port 3200
was still occupied from a previous run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 02:40:02 +08:00
saopig1andClaude Opus 4.6 d84f23c2b2 fix: resolve multiple UI issues in player, playlist, lyrics, and queue
- 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>
2026-03-30 02:34:48 +08:00
saopig1andClaude Opus 4.6 94a0df8391 feat: add QQ Music API integration, Pinia home cache, and unified search
- Start @sansenjian/qq-music-api server via dynamic import in api-server.ts
- Rewrite QQ Music provider to use real API endpoints (getSearchByKey,
  getMusicPlay, getSongListDetail, getAlbumInfo, getLyric, etc.)
- Cache home page data (recommend playlists, daily songs, user playlists)
  in Pinia store with 5-minute TTL to avoid refetching on every mount
- Add unified /api/music/search/all endpoint that queries both Netease
  and QQ providers in parallel and returns merged results
- Remove platform toggle from Search.vue; search both platforms at once
- Add platform badge (网易云 / QQ) to SongCard component

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 02:31:15 +08:00
saopig1andClaude Opus 4.6 ce6fc92780 fix: playlist cards use RouterLink for reliable navigation, lyrics use scrollTo for smooth sync
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 02:22:50 +08:00
saopig1andClaude Opus 4.6 ee5a75ab5e fix: add play mode toggle, wire play history API, add back navigation buttons
- 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>
2026-03-30 02:16:18 +08:00
saopig1andClaude Opus 4.6 9dce883384 fix: queue panel fetches data on open, lyrics auto-sync with playback time
- Player store tracks playStartedAt/pausedElapsed for elapsed time
- Queue component fetches from server when opened
- Lyrics page syncs every 200ms using elapsed time
- Lyrics auto-scroll to active line with smooth animation
- Translation lines shown below main lyrics
- Fade mask on lyrics scroll area

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 02:12:12 +08:00
saopig1andClaude Opus 4.6 67584d2622 feat: add YesPlayMusic-style home page with daily recs, FM, and user playlists
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>
2026-03-30 02:07:11 +08:00
saopig1andClaude Opus 4.6 6b725f43f9 fix: replace setInterval with drift-correcting setTimeout for audio timing
- High-precision frame loop using performance.now() tracking
- PCM-level volume control (live adjustable, no FFmpeg restart)
- Proper buffer drain on track end
- Fixes audio quality and playback speed issues

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 02:01:16 +08:00