@oxiaom/adoremix 1.0.14 → 1.0.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxiaom/adoremix",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "AdoreMix broadcast server - cross-platform installer, runner and service manager",
5
5
  "bin": {
6
6
  "adoremix": "./bin/adoremix.js"
@@ -38,7 +38,8 @@
38
38
  "bin",
39
39
  "src",
40
40
  "templates",
41
- "tts"
41
+ "tts",
42
+ "webui"
42
43
  ],
43
44
  "keywords": [
44
45
  "adoremix",
package/src/cli.js CHANGED
@@ -229,6 +229,21 @@ function buildProgram() {
229
229
  process.exitCode = code || 0;
230
230
  });
231
231
 
232
+ config
233
+ .command('webui')
234
+ .description('切换 WebUI 版本(low=16k 互联网 / high=44.1k 局域网)')
235
+ .option('--workdir <path>')
236
+ .option('--variant <v>', '直接指定: low | high')
237
+ .option('--no-interactive', '用当前配置部署')
238
+ .action(async (opts) => {
239
+ const webui = require('./config/webui');
240
+ const code = await webui.setupWebui(resolveWorkdir(opts.workdir), {
241
+ variant: opts.variant,
242
+ interactive: opts.interactive !== false
243
+ });
244
+ process.exitCode = code || 0;
245
+ });
246
+
232
247
  const runner = require('./runner');
233
248
  const nativeRef = () => {
234
249
  try { return paths.loadNative(); }
@@ -54,7 +54,8 @@ module.exports = {
54
54
  ttsxfAPISecret: '',
55
55
  ttsxfAPIKey: '',
56
56
  cutepath: 'etc/docroot',
57
- cuteport: 12083
57
+ cuteport: 12083,
58
+ webui: 'low'
58
59
  },
59
60
  listener: {
60
61
  port: 12080,
@@ -0,0 +1,118 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const fse = require('fs-extra');
6
+ const prompts = require('prompts');
7
+ const logger = require('../logger');
8
+ const cfg = require('./index');
9
+
10
+ const WEBUI_KEY = 'Settings.webui';
11
+
12
+ const WEBUI_VARIANTS = {
13
+ low: {
14
+ name: '低码率',
15
+ desc: '16k stereo / 32kbps(WiFi 音响、互联网环境)',
16
+ dir: 'low'
17
+ },
18
+ high: {
19
+ name: '高码率',
20
+ desc: '44.1k stereo / 64kbps(局域网、音质要求高)',
21
+ dir: 'high'
22
+ }
23
+ };
24
+
25
+ function getWebuiDir(variant) {
26
+ const v = WEBUI_VARIANTS[variant];
27
+ if (!v) return null;
28
+ // npm 包里 webui/ 在主包根
29
+ return path.join(__dirname, '..', '..', 'webui', v.dir);
30
+ }
31
+
32
+ function deployWebui(workdir, variant) {
33
+ const srcDir = getWebuiDir(variant);
34
+ if (!srcDir) {
35
+ logger.error(`未知 webui 变体: ${variant}(可选: low / high)`);
36
+ return false;
37
+ }
38
+ if (!fs.existsSync(srcDir)) {
39
+ logger.error(`webui 源目录不存在: ${srcDir}`);
40
+ logger.warn('主包可能没包含 webui/(旧版?)');
41
+ return false;
42
+ }
43
+ const docroot = path.join(workdir, 'etc', 'docroot');
44
+ // 备份原 docroot(如果存在且不是我们自己部署的)
45
+ // 简单做法:直接覆盖(用户业务资源应该在其他地方,docroot 是纯前端 UI)
46
+ if (fs.existsSync(docroot)) {
47
+ // 保留 docroot/mp3/ 目录(广播系统运行时存 mp3 的地方)
48
+ const mp3Backup = path.join(workdir, 'etc', 'docroot_mp3_backup');
49
+ const mp3Dir = path.join(docroot, 'mp3');
50
+ if (fs.existsSync(mp3Dir)) {
51
+ fse.removeSync(mp3Backup);
52
+ fse.moveSync(mp3Dir, mp3Backup);
53
+ }
54
+ fse.removeSync(docroot);
55
+ } else {
56
+ fse.ensureDirSync(path.join(workdir, 'etc'));
57
+ }
58
+ fse.copySync(srcDir, docroot);
59
+ // 恢复 mp3/
60
+ const mp3Backup = path.join(workdir, 'etc', 'docroot_mp3_backup');
61
+ if (fs.existsSync(mp3Backup)) {
62
+ fse.moveSync(mp3Backup, path.join(docroot, 'mp3'));
63
+ }
64
+ return true;
65
+ }
66
+
67
+ async function setupWebui(workdir, opts) {
68
+ opts = opts || {};
69
+ const current = cfg.getConfigValue(workdir, WEBUI_KEY) || 'low';
70
+
71
+ let variant;
72
+ if (opts.variant) {
73
+ if (!WEBUI_VARIANTS[opts.variant]) {
74
+ logger.error(`未知变体: ${opts.variant}(可选: ${Object.keys(WEBUI_VARIANTS).join(' / ')})`);
75
+ return 1;
76
+ }
77
+ variant = opts.variant;
78
+ } else if (opts.interactive === false) {
79
+ variant = current;
80
+ } else {
81
+ logger.log('');
82
+ logger.log('=== WebUI 版本选择 ===');
83
+ logger.log('说明:');
84
+ logger.log(' • 低码率 (16k/32kbps) - WiFi 音响、互联网环境,省流量');
85
+ logger.log(' • 高码率 (44.1k/64kbps) - 局域网、音质要求高');
86
+ logger.log(`当前:${current}(${WEBUI_VARIANTS[current].desc})`);
87
+ logger.log('');
88
+ const resp = await prompts({
89
+ type: 'select',
90
+ name: 'variant',
91
+ message: '选择 WebUI 版本',
92
+ choices: Object.keys(WEBUI_VARIANTS).map(k => ({
93
+ title: `${WEBUI_VARIANTS[k].name.padEnd(6)} ${WEBUI_VARIANTS[k].desc}`,
94
+ value: k
95
+ })),
96
+ initial: Object.keys(WEBUI_VARIANTS).indexOf(current)
97
+ });
98
+ if (!resp.variant) return 1;
99
+ variant = resp.variant;
100
+ }
101
+
102
+ logger.info(`部署 WebUI: ${variant} (${WEBUI_VARIANTS[variant].desc})`);
103
+ const ok = deployWebui(workdir, variant);
104
+ if (!ok) return 1;
105
+
106
+ cfg.setConfigValue(workdir, WEBUI_KEY, variant);
107
+ logger.ok(`Settings.webui = ${variant}`);
108
+ logger.ok(`已部署到 ${path.join(workdir, 'etc', 'docroot')}`);
109
+ logger.log('改完后记得:adoremix restart');
110
+ return 0;
111
+ }
112
+
113
+ module.exports = {
114
+ setupWebui,
115
+ deployWebui,
116
+ WEBUI_VARIANTS,
117
+ WEBUI_KEY
118
+ };
package/src/install.js CHANGED
@@ -140,6 +140,22 @@ function deployTtsDispatcher(workdir) {
140
140
  logger.log(' 测试:adoremix tts test "你好"');
141
141
  }
142
142
 
143
+ // 部署 WebUI 到 etc/docroot/(按 Settings.webui 配置选 low/high)
144
+ function deployWebuiIfPresent(workdir) {
145
+ try {
146
+ const webui = require('./config/webui');
147
+ const cfg = require('./config');
148
+ const variant = cfg.getConfigValue(workdir, 'Settings.webui') || 'low';
149
+ if (webui.deployWebui(workdir, variant)) {
150
+ logger.ok(`部署 WebUI: ${variant} → etc/docroot/`);
151
+ logger.log(' 切换:adoremix config webui');
152
+ }
153
+ } catch (e) {
154
+ // 静默失败(webui 目录不存在时不算错误)
155
+ logger.warn(`WebUI 部署跳过:${e.message}`);
156
+ }
157
+ }
158
+
143
159
  async function runInstall(opts) {
144
160
  opts = opts || {};
145
161
  const workdir = opts.workdir || paths.defaultWorkdir();
@@ -177,6 +193,7 @@ async function runInstall(opts) {
177
193
  return 1;
178
194
  }
179
195
  deployTtsDispatcher(workdir);
196
+ deployWebuiIfPresent(workdir);
180
197
 
181
198
  const config = require('./config');
182
199
  const cfgOk = await config.ensureConfig(workdir, { interactive: opts.interactive !== false, force: opts.force });
package/src/tts-cli.js CHANGED
@@ -192,12 +192,10 @@ async function cmdTest(workdir, text, opts) {
192
192
  return 1;
193
193
  }
194
194
 
195
- // 准备文本 + 输出
195
+ // 准备文本 + 输出(都用相对路径,dispatcher 在 cwd=workdir 下跑)
196
196
  const ttyDir = path.join(workdir, 'tty');
197
197
  if (!fs.existsSync(ttyDir)) fs.mkdirSync(ttyDir, { recursive: true });
198
- const txtFile = path.join(ttyDir, '_cli_test.txt');
199
- const outFile = path.join(ttyDir, '_cli_test.mp3');
200
- fs.writeFileSync(txtFile, text);
198
+ fs.writeFileSync(path.join(ttyDir, '_cli_test.txt'), text);
201
199
 
202
200
  // 调用 dispatcher
203
201
  const ttsJs = path.join(workdir, 'tts.js');
@@ -207,10 +205,12 @@ async function cmdTest(workdir, text, opts) {
207
205
  }
208
206
  logger.info(`provider=${c.provider} voice=${voice} text="${text.slice(0, 40)}${text.length > 40 ? '...' : ''}"`);
209
207
  try {
210
- execSync(`node "${ttsJs}" ${volume} ${speed} ${voice} _cli_test.mp3 _cli_test.txt`, {
208
+ // dispatcher 接收:mp3 名(写到 ./tty/)+ txt 路径(cwd 相对)
209
+ execSync(`node "${ttsJs}" ${volume} ${speed} ${voice} _cli_test.mp3 tty/_cli_test.txt`, {
211
210
  cwd: workdir,
212
211
  stdio: 'inherit'
213
212
  });
213
+ const outFile = path.join(ttyDir, '_cli_test.mp3');
214
214
  if (fs.existsSync(outFile)) {
215
215
  const size = fs.statSync(outFile).size;
216
216
  logger.ok(`✓ 生成成功: ${outFile} (${(size / 1024).toFixed(1)} KB)`);