@oxiaom/adoremix 1.0.18 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/adoremix.js CHANGED
@@ -2,9 +2,12 @@
2
2
  'use strict';
3
3
 
4
4
  const cli = require('../src/cli');
5
- cli.run(process.argv.slice(2)).then((code) => {
6
- process.exit(code || 0);
7
- }).catch((err) => {
5
+ // 注意:不能在 run() resolve 后强制 process.exit —— 前台模式 `adoremix start`
6
+ // spawn 出的二进制是 active handle,node 会自然挂起等待它运行(Ctrl+C 退出)。
7
+ // 无脑 process.exit 会把 node 杀掉,二进制成孤儿后收 SIGHUP 被终止,表现为"启动即退"。
8
+ // 普通命令(version/install/config 等)action 完成后事件循环空了会自然退出,
9
+ // 退出码由各命令自己设 process.exitCode(doctor/doctor --fix 等已设)。
10
+ cli.run(process.argv.slice(2)).catch((err) => {
8
11
  const logger = require('../src/logger');
9
12
  logger.error('未捕获的错误:', err);
10
13
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxiaom/adoremix",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "AdoreMix broadcast server - cross-platform installer, runner and service manager",
5
5
  "bin": {
6
6
  "adoremix": "./bin/adoremix.js"
@@ -14,7 +14,9 @@
14
14
  "@oxiaom/adoremix-win32-x64": "^1.0.0",
15
15
  "@oxiaom/adoremix-linux-x64": "^1.0.0",
16
16
  "@oxiaom/adoremix-linux-arm64": "^1.0.0",
17
- "@oxiaom/adoremix-linux-arm": "^1.0.0"
17
+ "@oxiaom/adoremix-linux-arm": "^1.0.0",
18
+ "@oxiaom/adoremix-darwin-x64": "^1.0.0",
19
+ "@oxiaom/adoremix-darwin-arm64": "^1.0.0"
18
20
  },
19
21
  "dependencies": {
20
22
  "commander": "^12.1.0",
package/src/doctor.js CHANGED
@@ -26,6 +26,57 @@ const LIB_TO_PKG = {
26
26
  'libkrb5.so.3': 'libkrb5-3'
27
27
  };
28
28
 
29
+ // ICU 70 兜底:
30
+ // AdoreMix 二进制在 Ubuntu 22.04(ICU 70)编译,链接 libicui18n.so.70 / libicuuc.so.70 / libicudata.so.70。
31
+ // Debian 12 / 树莓派 OS / Armbian 等 apt 源里只有 libicu72,没有 libicu70,跨发行版运行会缺库。
32
+ // 这三个 .so 都由同一个包 libicu70 提供,从 Ubuntu 官方源下载对应架构 .deb 装上即可(与系统 libicu72 共存,不冲突)。
33
+ const ICU70_LIBS = ['libicui18n.so.70', 'libicuuc.so.70', 'libicudata.so.70'];
34
+ const ICU70_DEB_SOURCES = {
35
+ // node arch → [deb arch, Ubuntu 源根]
36
+ arm64: ['arm64', 'http://ports.ubuntu.com/ubuntu-ports'], // 非 amd64 架构走 ports
37
+ arm: ['armhf', 'http://ports.ubuntu.com/ubuntu-ports'], // armv7 / armhf(树莓派 32 位、老款盒子)
38
+ x64: ['amd64', 'http://archive.ubuntu.com/ubuntu']
39
+ };
40
+
41
+ function getIcu70DebInfo() {
42
+ const src = ICU70_DEB_SOURCES[process.arch];
43
+ if (!src) return null;
44
+ const [debArch, base] = src;
45
+ return {
46
+ debArch,
47
+ url: `${base}/pool/main/i/icu/libicu70_70.1-2_${debArch}.deb`,
48
+ tmpPath: '/tmp/adoremix-libicu70.deb'
49
+ };
50
+ }
51
+
52
+ function tryFixIcu70() {
53
+ const info = getIcu70DebInfo();
54
+ if (!info) {
55
+ logger.warn(` ICU 70 兜底暂不支持架构 ${process.arch},请手动安装 libicu70`);
56
+ return false;
57
+ }
58
+ logger.info(`==> ICU 70 兜底:从 Ubuntu 官方源下载 libicu70 (${info.debArch})`);
59
+ logger.log(` ${info.url}`);
60
+ try {
61
+ execSync(`wget -q -O ${info.tmpPath} '${info.url}'`, { stdio: 'inherit' });
62
+ const size = fs.statSync(info.tmpPath).size;
63
+ if (size < 100000) {
64
+ logger.error(`下载失败(文件 ${size} 字节,可能 URL 失效或网络不通)`);
65
+ try { fs.unlinkSync(info.tmpPath); } catch (e) {}
66
+ return false;
67
+ }
68
+ logger.info(`==> dpkg -i libicu70_70.1-2_${info.debArch}.deb (${(size / 1024 / 1024).toFixed(1)} MB)`);
69
+ execSync(`dpkg -i ${info.tmpPath}`, { stdio: 'inherit' });
70
+ try { fs.unlinkSync(info.tmpPath); } catch (e) {}
71
+ return true;
72
+ } catch (e) {
73
+ logger.error(`ICU 70 安装失败:${(e.message || '').split('\n')[0]}`);
74
+ logger.warn(` 可能需要 root,手动执行:`);
75
+ logger.warn(` wget -O /tmp/libicu70.deb '${info.url}' && sudo dpkg -i /tmp/libicu70.deb`);
76
+ return false;
77
+ }
78
+ }
79
+
29
80
  function runDoctor(workdir, opts) {
30
81
  opts = opts || {};
31
82
  logger.log('=== AdoreMix 健康检查 ===');
@@ -93,38 +144,69 @@ function runDoctor(workdir, opts) {
93
144
  logger.ok(`✓ 动态库依赖完整`);
94
145
  } else {
95
146
  logger.error(`❌ 缺动态库:${missing.join(', ')}`);
147
+ // 分类:apt 可装 / ICU 70 跨发行版兜底 / 完全未知
96
148
  const pkgs = [];
149
+ const icu70 = [];
97
150
  const unknown = [];
98
151
  for (const lib of missing) {
99
- const pkg = LIB_TO_PKG[lib];
100
- if (pkg) pkgs.push(pkg);
152
+ if (ICU70_LIBS.includes(lib)) icu70.push(lib);
153
+ else if (LIB_TO_PKG[lib]) pkgs.push(LIB_TO_PKG[lib]);
101
154
  else unknown.push(lib);
102
155
  }
103
156
  const allPkgs = [...new Set(pkgs)];
157
+
158
+ // 1) apt 可装的库
159
+ let aptSolved = allPkgs.length === 0;
104
160
  if (allPkgs.length > 0) {
105
161
  const cmd = `apt-get install -y ${allPkgs.join(' ')}`;
106
162
  logger.log(` 建议命令(root 用户):${cmd}`);
107
- if (unknown.length > 0) {
108
- logger.warn(` 未知库(无 apt 映射):${unknown.join(', ')}`);
109
- }
110
- issues.push({
111
- type: 'libs',
112
- severity: 'error',
113
- msg: missing.join(', '),
114
- fixCmd: cmd,
115
- pkgs: allPkgs
116
- });
117
163
  if (opts.fix) {
118
164
  logger.info(`==> 自动修复:执行 ${cmd}`);
119
165
  try {
120
166
  execSync(cmd, { stdio: 'inherit', cwd: workdir });
121
167
  logger.ok('✓ 缺库已安装');
168
+ aptSolved = true;
122
169
  } catch (e) {
123
170
  logger.error(`修复失败:${e.message}`);
124
171
  logger.warn('可能需要 sudo:手动执行 sudo ' + cmd);
125
172
  }
126
173
  }
127
174
  }
175
+
176
+ // 2) ICU 70 跨发行版兜底(Debian 12 / 树莓派 OS / Armbian 等无 libicu70)
177
+ let icuSolved = icu70.length === 0;
178
+ if (icu70.length > 0) {
179
+ const icuMsg = `ICU 70 缺失(${icu70.join(', ')})— 二进制在 Ubuntu 22.04 编译,Debian 12 等需补 libicu70`;
180
+ if (opts.fix) {
181
+ if (tryFixIcu70()) {
182
+ logger.ok('✓ libicu70 已安装(ICU 70 兜底)');
183
+ icuSolved = true;
184
+ } else {
185
+ issues.push({ type: 'icu70', severity: 'error', msg: icuMsg });
186
+ }
187
+ } else {
188
+ logger.warn(` ${icuMsg}`);
189
+ logger.log(` 自动修复:adoremix doctor --fix(从 Ubuntu 官方源下载 libicu70 .deb)`);
190
+ issues.push({ type: 'icu70', severity: 'error', msg: icuMsg });
191
+ }
192
+ }
193
+
194
+ // 3) 未解决的记 issue
195
+ if (!aptSolved) {
196
+ issues.push({
197
+ type: 'libs',
198
+ severity: 'error',
199
+ msg: missing.join(', '),
200
+ fixCmd: `apt-get install -y ${allPkgs.join(' ')}`,
201
+ pkgs: allPkgs
202
+ });
203
+ }
204
+
205
+ // 4) 完全未知的库
206
+ if (unknown.length > 0) {
207
+ logger.warn(` 未知库(无 apt 映射,需手动排查):${unknown.join(', ')}`);
208
+ issues.push({ type: 'libs-unknown', severity: 'error', msg: unknown.join(', ') });
209
+ }
128
210
  }
129
211
  } catch (e) {
130
212
  logger.warn(`⚠ ldd 检查失败(非 Linux 或权限问题):${e.message.split('\n')[0]}`);
package/src/paths.js CHANGED
@@ -9,7 +9,9 @@ const PLATFORM_PKG = {
9
9
  'win32_x64': '@oxiaom/adoremix-win32-x64',
10
10
  'linux_x64': '@oxiaom/adoremix-linux-x64',
11
11
  'linux_arm64': '@oxiaom/adoremix-linux-arm64',
12
- 'linux_arm': '@oxiaom/adoremix-linux-arm'
12
+ 'linux_arm': '@oxiaom/adoremix-linux-arm',
13
+ 'darwin_x64': '@oxiaom/adoremix-darwin-x64',
14
+ 'darwin_arm64': '@oxiaom/adoremix-darwin-arm64'
13
15
  }[PLATFORM_KEY];
14
16
 
15
17
  let _native = null;
@@ -19,7 +21,7 @@ function loadNative() {
19
21
  if (_native) return _native;
20
22
  if (_loadError) throw _loadError;
21
23
  if (!PLATFORM_PKG) {
22
- _loadError = new Error(`不支持的平台:${PLATFORM_KEY}。当前支持 win32-x64 / linux-x64 / linux-arm64 / linux-arm。`);
24
+ _loadError = new Error(`不支持的平台:${PLATFORM_KEY}。当前支持 win32-x64 / linux-x64 / linux-arm64 / linux-arm / darwin-x64 / darwin-arm64。`);
23
25
  throw _loadError;
24
26
  }
25
27
  try {
package/src/tts-deps.js CHANGED
@@ -76,6 +76,27 @@ function pythonHasModule(pyCmd, modName) {
76
76
  } catch (e) { return false; }
77
77
  }
78
78
 
79
+ // python3 自带 pip 吗(Debian/Armbian 精简系统默认不带,要 apt install python3-pip)
80
+ function pythonHasPip(pyCmd) {
81
+ if (!pyCmd) return false;
82
+ try {
83
+ execFileSync(pyCmd, ['-m', 'pip', '--version'], { stdio: 'pipe' });
84
+ return true;
85
+ } catch (e) { return false; }
86
+ }
87
+
88
+ // 是否 PEP 668 externally-managed(Debian 12 / Ubuntu 23.04+ 默认禁止往系统 Python 装 pip 包)
89
+ // 这种环境 pip install 会报 externally-managed-environment,需加 --break-system-packages
90
+ function isExternallyManaged(pyCmd) {
91
+ if (!pyCmd) return false;
92
+ try {
93
+ const out = execFileSync(pyCmd, ['-c',
94
+ 'import sysconfig,os;print(os.path.exists(os.path.join(sysconfig.get_path("stdlib"),"EXTERNALLY-MANAGED")))'
95
+ ], { stdio: 'pipe', encoding: 'utf8' });
96
+ return String(out).trim() === 'True';
97
+ } catch (e) { return false; }
98
+ }
99
+
79
100
  function nodeModuleInstalled(workdir, modName) {
80
101
  try {
81
102
  require.resolve(modName, { paths: [workdir] });
@@ -220,7 +241,27 @@ function fixDeps(workdir, issues, opts) {
220
241
  });
221
242
  } else if (issue.fixType === 'pip') {
222
243
  const py = issue.fixArgs.pyCmd || findPythonCmd() || 'python3';
223
- execSync(`${sudo}${py} -m pip install ${issue.fixArgs.pkg}`, { stdio: 'inherit' });
244
+ // 1. 确保 pip 可用(Debian/Armbian 精简系统 python3 自带但 pip 缺失)
245
+ if (!pythonHasPip(py)) {
246
+ const pkgMgr = detectAptLike();
247
+ console.log(` pip 未安装,先补 python3-pip ...`);
248
+ if (pkgMgr) {
249
+ execSync(`${sudo}${pkgMgr} install -y python3-pip`, { stdio: 'inherit' });
250
+ } else {
251
+ // 退路:用 Python 自带的 ensurepip 引导
252
+ execSync(`${sudo}${py} -m ensurepip --upgrade`, { stdio: 'inherit' });
253
+ }
254
+ }
255
+ // 2. PEP 668:Debian 12 / Ubuntu 23.04+ 禁止往系统 Python 装包,需 --break-system-packages
256
+ const breakFlag = isExternallyManaged(py) ? ' --break-system-packages' : '';
257
+ if (breakFlag) console.log(' 检测到 externally-managed-environment,加 --break-system-packages');
258
+ // 3. PyPI 镜像:默认用清华(国内默认 PyPI 慢,常因下载损坏导致 hash 校验失败)。
259
+ // 国外用户可设环境变量 ADOREMIX_PIP_INDEX 覆盖,留空则用官方源。
260
+ const indexUrl = process.env.ADOREMIX_PIP_INDEX !== undefined
261
+ ? process.env.ADOREMIX_PIP_INDEX
262
+ : 'https://pypi.tuna.tsinghua.edu.cn/simple';
263
+ const indexFlag = indexUrl ? ` -i ${indexUrl}` : '';
264
+ execSync(`${sudo}${py} -m pip install${breakFlag}${indexFlag} ${issue.fixArgs.pkg}`, { stdio: 'inherit' });
224
265
  } else if (issue.fixType === 'system') {
225
266
  if (!issue.fixArgs.pkgMgr) throw new Error('包管理器未识别');
226
267
  execSync(`${sudo}${issue.fixArgs.pkgMgr} install -y ${issue.fixArgs.aptPkg}`, { stdio: 'inherit' });
@@ -1,6 +1,6 @@
1
1
  [Unit]
2
2
  Description=AdoreMix Broadcast Server
3
- Documentation=https://github.com/your-org/adoremix
3
+ Documentation=https://github.com/oxiaom/adoremix-npm
4
4
  After=network.target mysqld.service redis.service
5
5
 
6
6
  [Service]
@@ -8,7 +8,11 @@ Type=simple
8
8
  User=__USER__
9
9
  Group=__GROUP__
10
10
  WorkingDirectory=__WORKDIR__
11
- ExecStart=__NODE__ __CLI__ start --daemon --workdir __WORKDIR__
11
+ # 用前台模式(不加 --daemon):node 持续运行作为 systemd 主进程,
12
+ # systemd 才能正确跟踪/重启/停止服务。
13
+ # daemon 模式 node 会 unref 后退出,systemd 默认 KillMode=control-group
14
+ # 会把整个 cgroup(含刚 spawn 的二进制)一起杀掉,服务起不来。
15
+ ExecStart=__NODE__ __CLI__ start --workdir __WORKDIR__
12
16
  Restart=on-failure
13
17
  RestartSec=5
14
18
  StandardOutput=append:__WORKDIR__/logs/svc.log