tt-help-cli-ycl 1.4.61 → 1.4.63

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": "tt-help-cli-ycl",
3
- "version": "1.4.61",
3
+ "version": "1.4.63",
4
4
  "description": "TikTok user & video data scraper - extract ttSeller, verified, locationCreated from HTML source",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,8 +21,14 @@ export async function handleWatchdog(options) {
21
21
  const serverUrl =
22
22
  watchdogServer || clientConfig.server || "http://127.0.0.1:3001";
23
23
 
24
- // 客户端 ID
25
- const clientId = watchdogClientId || os.hostname() || `node-${process.pid}`;
24
+ // 客户端 ID:优先 --client-id,其次 userId@hostname,最后 hostname+pid
25
+ const userId = clientConfig.userId || "";
26
+ const hostname = os.hostname() || "";
27
+ const clientId =
28
+ watchdogClientId ||
29
+ (userId && hostname ? `${userId}@${hostname}` : null) ||
30
+ hostname ||
31
+ `node-${process.pid}`;
26
32
 
27
33
  // 心跳间隔
28
34
  const intervalSec = Math.max(5, parseInt(watchdogInterval) || 15);
@@ -3475,7 +3475,10 @@ function esc(s) {
3475
3475
 
3476
3476
  // ── 渲染主函数 ──
3477
3477
 
3478
+ var _wdLastRendered = "";
3479
+
3478
3480
  function renderWatchdogDashboard(clients, clientCommands) {
3481
+ // 顶栏统计始终更新(textContent 不闪烁)
3479
3482
  var onlineCount = clients.filter(function (c) {
3480
3483
  return c.online;
3481
3484
  }).length;
@@ -3484,27 +3487,48 @@ function renderWatchdogDashboard(clients, clientCommands) {
3484
3487
  }, 0);
3485
3488
  var cmdCount = 0;
3486
3489
  for (var k in clientCommands) cmdCount += clientCommands[k].length;
3487
-
3488
3490
  document.getElementById("wdOnlineCount").textContent = onlineCount;
3489
3491
  document.getElementById("wdProcessCount").textContent = procCount;
3490
3492
  document.getElementById("wdCmdCount").textContent = cmdCount;
3491
3493
 
3492
3494
  var el = document.getElementById("wdClientsList");
3493
3495
 
3494
- if (clients.length === 0) {
3495
- el.innerHTML = styled(
3496
+ // 空状态:无客户端且无配置的命令
3497
+ if (clients.length === 0 && cmdCount === 0) {
3498
+ var emptyHtml = styled(
3496
3499
  "div",
3497
3500
  "color:#666;padding:30px;text-align:center",
3498
3501
  "暂无客户端连接,等待看门狗上线...(每10秒自动刷新)",
3499
3502
  );
3503
+ if (_wdLastRendered !== emptyHtml) {
3504
+ _wdLastRendered = emptyHtml;
3505
+ el.innerHTML = emptyHtml;
3506
+ }
3500
3507
  return;
3501
3508
  }
3502
3509
 
3503
- var cards = clients
3504
- .map(function (c) {
3505
- return renderClientCard(c, clientCommands);
3506
- })
3507
- .join("");
3510
+ // 构建 userId → 在线客户端 映射
3511
+ var userClients = {};
3512
+ clients.forEach(function (c) {
3513
+ var uid = (c.config && c.config.userId) || "";
3514
+ if (uid) userClients[uid] = c;
3515
+ });
3516
+
3517
+ // 收集所有卡片:在线客户端 + 离线但有命令配置的 userId
3518
+ var allCards = [];
3519
+ clients.forEach(function (c) {
3520
+ allCards.push(renderClientCard(c, clientCommands));
3521
+ });
3522
+ for (var uid in clientCommands) {
3523
+ if (!userClients[uid]) {
3524
+ allCards.push(renderOfflineCard(uid, clientCommands[uid]));
3525
+ }
3526
+ }
3527
+
3528
+ // 数据指纹:只有变化时才重建卡片 HTML
3529
+ var fingerprint = JSON.stringify(allCards);
3530
+ if (fingerprint === _wdLastRendered) return;
3531
+ _wdLastRendered = fingerprint;
3508
3532
 
3509
3533
  el.innerHTML = styled(
3510
3534
  "div",
@@ -3512,7 +3536,41 @@ function renderWatchdogDashboard(clients, clientCommands) {
3512
3536
  style:
3513
3537
  "display:grid;grid-template-columns:repeat(auto-fill,minmax(440px,1fr));gap:16px",
3514
3538
  },
3515
- cards,
3539
+ allCards.join(""),
3540
+ );
3541
+ }
3542
+
3543
+ function renderOfflineCard(userId, cmds) {
3544
+ var cmdCount = cmds ? cmds.length : 0;
3545
+ return styled(
3546
+ "div",
3547
+ "background:#1e1e2e;border:1px solid #333;border-radius:12px;padding:16px;opacity:0.7",
3548
+ styled(
3549
+ "div",
3550
+ "display:flex;justify-content:space-between;align-items:center;margin-bottom:8px",
3551
+ styled(
3552
+ "div",
3553
+ "",
3554
+ styled("strong", "color:#666;font-size:14px", userId) +
3555
+ styled(
3556
+ "span",
3557
+ "color:#555;font-size:11px;margin-left:8px",
3558
+ "(未上线)",
3559
+ ),
3560
+ ) +
3561
+ styled(
3562
+ "div",
3563
+ "display:flex;gap:10px;align-items:center",
3564
+ styled("span", "color:#f87171", "● 离线") +
3565
+ styled("span", "color:#555;font-size:10px", "—"),
3566
+ ),
3567
+ ) +
3568
+ styled(
3569
+ "div",
3570
+ "color:#555;font-size:10px",
3571
+ "该机器尚未连接看门狗,配置了 " + cmdCount + " 条命令",
3572
+ ) +
3573
+ renderCmdList(cmds || [], userId),
3516
3574
  );
3517
3575
  }
3518
3576
 
@@ -506,6 +506,10 @@
506
506
  <div class="label">命令池</div>
507
507
  <div class="value slate" id="wdCmdCount">0</div>
508
508
  </div>
509
+ <div class="stat-card clickable" onclick="fetchWatchdogData()" style="background:rgba(96,165,250,0.05)">
510
+ <div class="label" style="font-size:18px">🔄</div>
511
+ <div class="value" style="font-size:11px;color:#60a5fa">刷新</div>
512
+ </div>
509
513
  </div>
510
514
  <div id="wdClientsList" style="color:#666;font-size:12px">加载中...</div>
511
515
  </div>
@@ -83,7 +83,12 @@ function getOnlineClients() {
83
83
 
84
84
  function normalizeCmd(c) {
85
85
  if (typeof c === "string")
86
- return { cmd: c.replace(/^[▶\n\r\s]+/, "").trim(), enabled: true, maxUptimeSeconds: 0, maxMemoryMB: 0 };
86
+ return {
87
+ cmd: c.replace(/^[▶\n\r\s]+/, "").trim(),
88
+ enabled: true,
89
+ maxUptimeSeconds: 0,
90
+ maxMemoryMB: 0,
91
+ };
87
92
  return {
88
93
  cmd: (c.cmd || "").replace(/^[▶\n\r\s]+/, "").trim(),
89
94
  enabled: c.enabled !== false,
@@ -13,14 +13,31 @@ import { spawn, execSync } from "child_process";
13
13
  import { EventEmitter } from "events";
14
14
 
15
15
  const MAX_RESTART = 3;
16
+ const IS_WIN = process.platform === "win32";
16
17
 
17
18
  function getProcessStats(pid) {
18
19
  try {
19
- const stdout = execSync(`ps -p ${pid} -o rss=,etime=`, {
20
+ const cmd = IS_WIN
21
+ ? `tasklist /FI "PID eq ${pid}" /FO CSV /NH`
22
+ : `ps -p ${pid} -o rss=,etime=`;
23
+ const stdout = execSync(cmd, {
20
24
  encoding: "utf-8",
21
25
  timeout: 3000,
26
+ stdio: ["ignore", "pipe", "ignore"],
22
27
  }).trim();
23
28
  if (!stdout) return null;
29
+
30
+ if (IS_WIN) {
31
+ // tasklist CSV: "name.exe","pid","session","session#","mem usage"
32
+ const cols = stdout.split(",");
33
+ const memStr = (cols[4] || "").replace(/[^0-9.]/g, "");
34
+ const memKB = parseInt(memStr, 10);
35
+ return {
36
+ memoryMB: isNaN(memKB) ? 0 : Math.round((memKB / 1024) * 10) / 10,
37
+ elapsed: "?",
38
+ };
39
+ }
40
+
24
41
  const parts = stdout.split(/\s+/);
25
42
  const rssKB = parseInt(parts[0], 10);
26
43
  const elapsed = parts.slice(1).join(" ") || "0";