dsh-qq-stack 0.1.3 → 0.1.4

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/client.js CHANGED
@@ -48,7 +48,8 @@ window.__ModuleLoader__.load({
48
48
  .fs-login{display:flex;flex-direction:column;gap:10px}
49
49
  .fs-field{width:100%;box-sizing:border-box;border:0;border-bottom:1px solid rgba(127,127,127,.28);background:transparent;color:inherit;padding:10px 2px;font-size:15px;outline:none}
50
50
  .fs-wide{padding:11px}
51
- .fs-sep{text-align:center;font-size:12px;opacity:.5;margin-top:6px}`
51
+ .fs-sep{text-align:center;font-size:12px;opacity:.5;margin-top:6px}
52
+ .fs-install{font-size:14px;font-weight:600;margin-bottom:6px}`
52
53
 
53
54
  function Panel() {
54
55
  const [st, setSt] = react.useState(null)
@@ -78,11 +79,15 @@ window.__ModuleLoader__.load({
78
79
  row('OneBot 端口', !!st?.qq, st?.qq ? '已监听' : '未监听'),
79
80
  row('登录状态', logged, logged ? `已登录 ${st?.nickname || ''} ${st?.uin || ''}` : '未登录'),
80
81
  ),
81
- !logged ? h('div', { className: 'fs-card fs-center' },
82
+ (st?.installed !== false && !st?.installing && !logged) ? h('div', { className: 'fs-card fs-center' },
82
83
  st?.qrAt
83
84
  ? h('img', { className: 'fs-qr', src: qrUrl, alt: '登录二维码' })
84
85
  : h('div', { className: 'fs-hint' }, '正在生成二维码…'),
85
86
  ) : null,
87
+ (st && (!st.installed || st.installing)) ? h('div', { className: 'fs-card' },
88
+ h('div', { className: 'fs-install' }, st.installing ? '正在安装 QQ 运行环境…' : '运行环境未就绪'),
89
+ h('div', { className: 'fs-hint' }, st.installTail || '首次安装约 250MB,请稍候'),
90
+ ) : null,
86
91
  logged ? h('div', { className: 'fs-card fs-account' },
87
92
  h('img', {
88
93
  className: 'fs-avatar',
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { spawn } from 'node:child_process'
2
- import { existsSync, readFileSync, writeFileSync, statSync, readdirSync, unlinkSync, mkdirSync } from 'node:fs'
2
+ import { existsSync, readFileSync, writeFileSync, statSync, readdirSync, unlinkSync, mkdirSync, openSync } from 'node:fs'
3
3
  import { readFileSync as rf } from 'node:fs'
4
4
 
5
5
  export const name = 'dsh-qq-stack'
@@ -154,7 +154,10 @@ function applyInner(ctx, pluginConfig = {}) {
154
154
  if (!existsSync(installer)) { log('[qq-stack] 找不到 install.sh'); return }
155
155
  log('[qq-stack] 首次安装开始(LinuxQQ + NapCat,约 250MB)')
156
156
  try {
157
- const child = spawnSafe('bash', [installer], { cwd: cfg.root, detached: true, stdio: 'ignore', env })
157
+ mkdirSync(`${cfg.root}/logs`, { recursive: true })
158
+ const fd = openSync(`${cfg.root}/logs/install.log`, 'a')
159
+ const child = spawnSafe('bash', [installer], { cwd: cfg.root, detached: true, stdio: ['ignore', fd, fd], env })
160
+ if (child?.pid) { try { writeFileSync(`${cfg.root}/install.pid`, String(child.pid)) } catch {} }
158
161
  } catch (e) { log(`[qq-stack] 安装启动失败:${e?.message ?? e}`) }
159
162
  }
160
163
 
@@ -223,6 +226,15 @@ function applyInner(ctx, pluginConfig = {}) {
223
226
  const pidM = statSync(`${cfg.root}/qq.pid`).mtimeMs
224
227
  if (qrM >= pidM) qrAt = Math.floor(qrM)
225
228
  } catch {}
229
+ let installing = false
230
+ try { installing = alive(Number(readFileSync(`${cfg.root}/install.pid`, 'utf8').trim())) } catch {}
231
+ let installed = existsSync(`${cfg.root}/opt/opt/QQ/qq`)
232
+ let installTail = ''
233
+ try {
234
+ const raw = readFileSync(`${cfg.root}/logs/install.log`, 'utf8')
235
+ const lines = raw.split(/[\r\n]+/).map((x) => x.trim()).filter(Boolean)
236
+ installTail = lines.slice(-2).join(' ').slice(-160)
237
+ } catch {}
226
238
  const login = qq ? await probeLogin(Number(envFile.DSH_QQ_WS_PORT || cfg.wsPort || 3001), envFile.DSH_QQ_TOKEN || cfg.token) : { loggedIn: false, nickname: '' }
227
239
  if (login.loggedIn) {
228
240
  const qqUin = detectedUin || envFile.DSH_QQ_UIN || ''
@@ -245,7 +257,7 @@ function applyInner(ctx, pluginConfig = {}) {
245
257
  writeFileSync(`${cfg.root}/config.env`, Object.entries(e2).map(([k, x]) => `${k}=${x}`).join('\n') + '\n')
246
258
  } catch {}
247
259
  }
248
- return json({ ok: true, qq, loggedIn: !!login.loggedIn, nickname: login.nickname, uin: login.loggedIn ? login.uin : (envFile.DSH_QQ_UIN || detectedUin), port: envFile.DSH_QQ_WS_PORT || '3001', token: envFile.DSH_QQ_TOKEN || '', qrAt })
260
+ return json({ ok: true, qq, loggedIn: !!login.loggedIn, nickname: login.nickname, uin: login.loggedIn ? login.uin : (envFile.DSH_QQ_UIN || detectedUin), installed, installing, installTail, port: envFile.DSH_QQ_WS_PORT || '3001', token: envFile.DSH_QQ_TOKEN || '', qrAt })
249
261
  }
250
262
  if (req.method === 'GET' && p === '/qr.png') {
251
263
  let detectedUin = ''
package/install.sh CHANGED
@@ -32,9 +32,20 @@ QQ_DEB_URL="https://qqdl.gtimg.cn/qqfile/QQNT/9.9.36/beta/9ee04bef/linuxqq_${QQ_
32
32
  NAPCAT_ZIP="https://github.com/NapNeko/NapCatQQ/releases/latest/download/NapCat.Shell.zip"
33
33
 
34
34
  missing=""
35
- for p in xvfb libnss3 libgbm1 libasound2t64 libgtk-3-0 dbus-x11 unzip curl; do
36
- dpkg -s "$p" >/dev/null 2>&1 || missing="$missing $p"
35
+ for p in xvfb libnss3 libgbm1 libasound2t64 libasound2 libgtk-3-0 libgtk-3-0t64 dbus-x11 unzip curl; do
36
+ dpkg -s "$p" >/dev/null 2>&1 || continue
37
+ case "$p" in
38
+ libasound2) miss="$miss libasound2" ;;
39
+ libasound2t64) [ -n "${miss##*libasound2 }" ] && miss="$miss libasound2t64" ;;
40
+ libgtk-3-0) miss="$miss libgtk-3-0" ;;
41
+ libgtk-3-0t64) miss="$miss libgtk-3-0t64" ;;
42
+ *) miss="$miss $p" ;;
43
+ esac
37
44
  done
45
+ # 成对包只留一个(t64 与旧名并存,供不同发行版)
46
+ case " $miss " in *" libasound2 "*) miss=$(echo "$miss" | sed 's/ libasound2t64 / /g') ;; *) miss=$(echo "$miss" | sed 's/ libasound2 / /g') ;; esac
47
+ case " $miss " in *" libgtk-3-0t64 "*) miss=$(echo "$miss" | sed 's/ libgtk-3-0 / /g') ;; *) miss=$(echo "$miss" | sed 's/ libgtk-3-0t64 / /g') ;; esac
48
+ missing="$miss"
38
49
  if [ -n "$missing" ]; then
39
50
  say "安装依赖:$missing"
40
51
  export DEBIAN_FRONTEND=noninteractive
@@ -52,6 +63,29 @@ fi
52
63
 
53
64
  QQ_APP="$ROOT/opt/opt/QQ/resources/app"
54
65
 
66
+ ensure_deps() {
67
+ need=0
68
+ command -v xvfb-run >/dev/null 2>&1 || need=1
69
+ command -v dbus-run-session >/dev/null 2>&1 || need=1
70
+ if [ -x "$ROOT/opt/opt/QQ/qq" ] && ldd "$ROOT/opt/opt/QQ/qq" 2>/dev/null | grep -q "not found"; then
71
+ need=1
72
+ fi
73
+ [ "$need" = 0 ] && return 0
74
+ say "补齐运行依赖"
75
+ export DEBIAN_FRONTEND=noninteractive
76
+ apt-get update -qq || true
77
+ pkgs=""
78
+ for p in xvfb dbus-x11 libnss3 libgbm1 libasound2t64 libasound2 libgtk-3-0t64 libgtk-3-0 \
79
+ libxss1 libxtst6 libdrm2 libxkbcommon0 libcups2 libpango-1.0-0 libcairo2 \
80
+ libatk1.0-0 libatk-bridge2.0-0 libxdamage1 libxrandr2 libatspi2.0-0 libnspr4 \
81
+ libxcomposite1 libxfixes3 libxrender1; do
82
+ apt-cache show "$p" >/dev/null 2>&1 && pkgs="$pkgs $p"
83
+ done
84
+ apt-get install -y $pkgs || { say "依赖安装失败"; exit 1; }
85
+ }
86
+
87
+ ensure_deps
88
+
55
89
  if [ ! -f "$QQ_APP/app_launcher/napcat/napcat.mjs" ]; then
56
90
  say "下载 NapCat"
57
91
  if [ -f /tmp/NapCat.Shell.zip ] && unzip -t /tmp/NapCat.Shell.zip >/dev/null 2>&1; then
@@ -160,4 +194,3 @@ fi
160
194
  chmod +x "$ROOT"/*.sh
161
195
  say "安装完成,启动 QQ"
162
196
  bash "$ROOT/start-qq.sh"
163
- say "完成(首次需要扫码,之后启动会走 ${UIN:-未设置账号} 的快速登录)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-qq-stack",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "description": "DeepSeek Harness 的 QQ 协议端底座:LinuxQQ + NapCat 随引擎自启,扫码一次后自动快登。",