@mingxy/ocosay 1.1.7 → 1.1.9

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": "@mingxy/ocosay",
3
- "version": "1.1.7",
3
+ "version": "1.1.9",
4
4
  "description": "OpenCode TTS 播放插件 - 支持豆包模式边接收边朗读",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",
@@ -1,117 +1,172 @@
1
1
  const { execSync, spawn } = require('child_process');
2
2
  const fs = require('fs');
3
- const os = require('os');
3
+ const readline = require('readline');
4
4
 
5
+ const platform = process.platform;
5
6
  const isWSL = fs.existsSync('/proc/version') &&
6
7
  fs.readFileSync('/proc/version', 'utf8').includes('Microsoft');
7
- const platform = process.platform;
8
8
 
9
9
  const log = {
10
- info: (msg) => console.log(`📦 ${msg}`),
11
- success: (msg) => console.log(`✅ ${msg}`),
12
- warn: (msg) => console.log(`⚠️ ${msg}`),
13
- error: (msg) => console.error(`❌ ${msg}`)
10
+ info: (msg) => console.log(`[INFO] ${msg}`),
11
+ success: (msg) => console.log(`[OK] ${msg}`),
12
+ warn: (msg) => console.log(`[WARN] ${msg}`),
13
+ error: (msg) => console.error(`[ERROR] ${msg}`)
14
14
  };
15
15
 
16
- function checkCmd(cmd) {
16
+ function exec(cmd, ignoreError = false) {
17
+ try {
18
+ const output = execSync(cmd, { stdio: 'pipe', encoding: 'utf8' });
19
+ return { success: true, output };
20
+ } catch (err) {
21
+ if (ignoreError) return { success: false, output: '' };
22
+ return { success: false, output: err.message };
23
+ }
24
+ }
25
+
26
+ function askPassword() {
27
+ return new Promise((resolve) => {
28
+ const rl = readline.createInterface({
29
+ input: process.stdin,
30
+ output: process.stdout
31
+ });
32
+ rl.question('需要 sudo 权限,请输入密码: ', (password) => {
33
+ rl.close();
34
+ resolve(password);
35
+ });
36
+ });
37
+ }
38
+
39
+ async function runWithSudo(cmd) {
40
+ // 先尝试直接运行(可能已缓存密码)
17
41
  try {
18
42
  execSync(cmd, { stdio: 'ignore' });
19
43
  return true;
20
- } catch {
44
+ } catch { /* 继续尝试密码 */ }
45
+
46
+ // 需要密码
47
+ const password = await askPassword();
48
+ if (!password) {
49
+ log.error('未输入密码,安装取消');
21
50
  return false;
22
51
  }
52
+
53
+ return new Promise((resolve) => {
54
+ const proc = spawn('bash', ['-c', `echo "${password}" | sudo -S ${cmd}`], {
55
+ stdio: 'inherit'
56
+ });
57
+ proc.on('close', (code) => resolve(code === 0));
58
+ proc.on('error', () => resolve(false));
59
+ });
23
60
  }
24
61
 
25
- async function runCmd(cmd) {
26
- return new Promise((resolve, reject) => {
62
+ async function execCmd(cmd) {
63
+ return new Promise((resolve) => {
27
64
  const shell = platform === 'win32' ? 'powershell' : 'bash';
28
65
  const args = platform === 'win32' ? ['-Command', cmd] : ['-c', cmd];
29
66
  const proc = spawn(shell, args, { stdio: 'inherit' });
30
- proc.on('close', (code) => (code === 0 ? resolve() : reject()));
31
- proc.on('error', reject);
67
+ proc.on('close', (code) => resolve(code === 0));
68
+ proc.on('error', () => resolve(false));
32
69
  });
33
70
  }
34
71
 
35
- async function installMacOS() {
36
- if (checkCmd('brew list portaudio')) {
37
- log.success('PortAudio 已安装 (macOS)');
38
- return true;
39
- }
40
- log.info('安装 PortAudio (macOS)...');
41
- try {
42
- await runCmd('brew install portaudio');
43
- return true;
44
- } catch {
45
- return false;
72
+ function checkAlsa() {
73
+ const result = exec('which aplay');
74
+ if (result.success) {
75
+ const aplayOutput = exec('aplay -l');
76
+ if (aplayOutput.success && !aplayOutput.output.includes('no soundcards')) {
77
+ return { available: true, type: 'alsa', command: result.output.trim() };
78
+ }
46
79
  }
80
+ return { available: false, type: null, command: result.success ? result.output.trim() : null };
47
81
  }
48
82
 
49
- async function installWSL() {
50
- if (checkCmd('dpkg -s libportaudio-dev')) {
51
- log.success('PortAudio 已安装 (WSL)');
52
- return true;
53
- }
54
- log.info('安装 PortAudio (WSL)...');
55
- try {
56
- await runCmd('sudo apt-get update && sudo apt-get install -y libportaudio-dev portaudio');
57
- return true;
58
- } catch {
59
- return false;
60
- }
83
+ async function installAlsaUtils() {
84
+ log.info('安装 alsa-utils...');
85
+ return runWithSudo('apt-get update && apt-get install -y alsa-utils');
61
86
  }
62
87
 
63
- async function installWindowsNative() {
64
- if (checkCmd('choco list --local-only portaudio')) {
65
- log.success('PortAudio 已安装 (Windows)');
66
- return true;
67
- }
68
- if (!checkCmd('where choco')) {
69
- log.warn('未检测到 choco,尝试直接安装...');
70
- return false;
71
- }
72
- log.info('安装 PortAudio (Windows)...');
73
- try {
74
- await runCmd('choco install portaudio -y');
75
- return true;
76
- } catch {
77
- return false;
88
+ async function installPortAudioDev() {
89
+ log.info('安装 libportaudio-dev...');
90
+ return runWithSudo('apt-get update && apt-get install -y libportaudio-dev');
91
+ }
92
+
93
+ function testAlsaPlayback() {
94
+ const result = exec('aplay -l');
95
+ if (!result.success) return { success: false, reason: 'aplay 命令不可用' };
96
+ if (result.output.includes('no soundcards') || result.output.includes('no devices')) {
97
+ return { success: false, reason: '没有音频设备' };
78
98
  }
99
+ return { success: true, devices: result.output };
79
100
  }
80
101
 
81
102
  async function main() {
82
- console.log('🔊 PortAudio 安装脚本');
83
- console.log('====================');
103
+ console.log('=== 音频环境检测与安装脚本 ===');
84
104
  console.log(`平台: ${platform}${isWSL ? ' (WSL)' : ''}`);
85
105
  console.log('');
86
- let success = false;
87
-
88
- if (isWSL) {
89
- success = await installWSL();
90
- } else if (platform === 'darwin') {
91
- success = await installMacOS();
92
- } else if (platform === 'win32') {
93
- success = await installWindowsNative();
106
+
107
+ // 步骤1: 检测 alsa
108
+ log.info('检测 alsa...');
109
+ const alsa = checkAlsa();
110
+ if (alsa.available) {
111
+ log.success(`alsa 可用: ${alsa.command}`);
112
+ const test = testAlsaPlayback();
113
+ if (test.success) {
114
+ log.success('alsa 播放设备检测通过:');
115
+ console.log(test.devices);
116
+ log.success('=== 音频环境就绪 ===');
117
+ process.exit(0);
118
+ } else {
119
+ log.warn(`alsa 测试失败: ${test.reason}`);
120
+ }
94
121
  } else {
95
- log.error('不支持的平台');
122
+ log.warn('alsa 未安装');
96
123
  }
97
124
 
98
- if (success) {
99
- log.success('PortAudio 安装完成!');
100
- process.exit(0);
101
- } else {
102
- log.error('========================================');
103
- log.error('PortAudio 安装失败,请手动安装:');
104
- log.error('========================================');
105
- if (platform === 'darwin') {
106
- log.error(' brew install portaudio');
107
- } else if (isWSL) {
108
- log.error(' sudo apt-get install -y libportaudio-dev portaudio');
109
- } else if (platform === 'win32') {
110
- log.error(' choco install portaudio');
111
- log.error(' 或下载: https://www.portaudio.com/download.html');
112
- }
125
+ // 步骤2: 安装 alsa-utils
126
+ log.info('安装 alsa-utils...');
127
+ const installed = await installAlsaUtils();
128
+ if (!installed) {
129
+ log.error('alsa-utils 安装失败');
113
130
  process.exit(1);
114
131
  }
132
+ log.success('alsa-utils 安装成功');
133
+
134
+ // 步骤3: 重新检测
135
+ const alsa2 = checkAlsa();
136
+ if (alsa2.available) {
137
+ const test = testAlsaPlayback();
138
+ if (test.success) {
139
+ log.success('alsa 播放设备检测通过:');
140
+ console.log(test.devices);
141
+ log.success('=== 音频环境就绪 ===');
142
+ process.exit(0);
143
+ } else {
144
+ log.warn(`检测到 alsa 但无播放设备: ${test.reason}`);
145
+ }
146
+ }
147
+
148
+ // 步骤4: WSL 安装 PortAudio
149
+ if (isWSL) {
150
+ log.info('安装 libportaudio-dev...');
151
+ await installPortAudioDev();
152
+ }
153
+
154
+ // 最终检测
155
+ const alsa3 = checkAlsa();
156
+ if (alsa3.available) {
157
+ const test = testAlsaPlayback();
158
+ if (test.success) {
159
+ log.success('=== 音频环境就绪 ===');
160
+ process.exit(0);
161
+ }
162
+ }
163
+
164
+ log.error('=== 无法配置音频环境 ===');
165
+ if (isWSL) {
166
+ log.error('WSL 没有音频设备');
167
+ log.error('方案: 配置 Windows 音频转发或手动安装音频驱动');
168
+ }
169
+ process.exit(1);
115
170
  }
116
171
 
117
172
  main();