Files
Jocay 21945cc54f feat: 声匣 —— 网易云 / QQ 音乐自托管下载服务
由 163-music-dl CLI 重构为 Web 服务:
- 下载流水线、歌词与标签逻辑沿用旧版(node-id3 / ffmpeg)
- 网易云(chksz 接口 + music.163.com 元数据)与 QQ 音乐(VIP Cookie)provider
- QQ 扫码登录与 musickey 自动续期
- SQLite 持久化的下载队列,SSE 实时进度
- 曲库工具(M3U / ZIP / 回收站 / 补全标签)、历史统计与导出、访问密码
- Vite 8 + Vue 3 前端,浅色 / 深色
- Docker 部署配置(飞牛 NAS)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:05:30 +08:00

21 lines
785 B
JavaScript

// 同时启动后端(node --watch)与前端(vite),Ctrl+C 一起退出
import { spawn } from 'node:child_process';
const procs = [
['server', 'npm run dev:server', '\x1b[36m'],
['web', 'npm run dev:web', '\x1b[35m'],
].map(([name, cmd, color]) => {
const child = spawn(cmd, { shell: true, stdio: ['ignore', 'pipe', 'pipe'] });
const prefix = `${color}[${name}]\x1b[0m `;
const relay = (stream, out) => stream.on('data', (buf) => {
for (const line of buf.toString().split(/\r?\n/)) if (line) out.write(prefix + line + '\n');
});
relay(child.stdout, process.stdout);
relay(child.stderr, process.stderr);
return child;
});
const stop = () => { for (const p of procs) p.kill(); process.exit(0); };
process.on('SIGINT', stop);
process.on('SIGTERM', stop);