tt-help-cli-ycl 1.4.10 → 1.4.11

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli/comments.js +112 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tt-help-cli-ycl",
3
- "version": "1.4.10",
3
+ "version": "1.4.11",
4
4
  "description": "TikTok user & video data scraper - extract ttSeller, verified, locationCreated from HTML source",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,7 +5,9 @@
5
5
  // 手动模式: tt-help comments <URL> [N] [--save] 单视频评论提取
6
6
  // ────────────────────────────────────────
7
7
 
8
+ import { writeFileSync, unlinkSync } from "fs";
8
9
  import os from "os";
10
+ import path from "path";
9
11
  import { execSync } from "child_process";
10
12
 
11
13
  import { fetchUserCommentsAPI } from "../lib/api-interceptor-comment.js";
@@ -65,6 +67,8 @@ const CFG = {
65
67
  periodicRecycleEvery: 0,
66
68
  /** 内存回收 — 回收时是否切换端口 */
67
69
  switchPortOnRecycle: true,
70
+ /** 连续任务处理错误阈值(达到后上报服务端) */
71
+ consecutiveTaskErrorsMax: 20,
68
72
  };
69
73
 
70
74
  /** 从环境变量覆写配置 */
@@ -97,6 +101,10 @@ function loadEnvConfig() {
97
101
  );
98
102
  CFG.switchPortOnRecycle =
99
103
  String(process.env.COMMENTS_SWITCH_PORT_ON_RECYCLE || "1") !== "0";
104
+ CFG.consecutiveTaskErrorsMax = Math.max(
105
+ 1,
106
+ int("COMMENTS_CONSECUTIVE_TASK_ERRORS_MAX", CFG.consecutiveTaskErrorsMax),
107
+ );
100
108
  }
101
109
 
102
110
  // ────────────────────────────────────────
@@ -108,32 +116,82 @@ function formatMemoryUsage(mem = process.memoryUsage()) {
108
116
  return `rss:${mb(mem.rss)}MB heap:${mb(mem.heapUsed)}MB ext:${mb(mem.external)}MB ab:${mb(mem.arrayBuffers)}MB`;
109
117
  }
110
118
 
111
- function getBrowserMemory(port) {
119
+ /**
120
+ * 获取 Edge 浏览器进程的内存占用(跨平台:macOS/Linux/Windows)
121
+ */
122
+ function getBrowserMemory(port = null) {
112
123
  try {
113
124
  const platform = os.platform();
114
- if (platform !== "darwin" && platform !== "linux") return null;
115
- const procName = platform === "darwin" ? "Microsoft Edge" : "msedge";
116
- const c = procName[0];
117
- const rest = procName.slice(1);
118
125
  let cmd;
119
- if (port) {
120
- cmd = `ps aux | grep "[${c}]${rest}" | grep "remote-debugging-port=${port}" | awk '{sum += $6} END {printf "%d", sum/1024}'`;
121
- } else {
122
- cmd = `ps aux | grep "[${c}]${rest}" | awk '{sum += $6} END {printf "%d", sum/1024}'`;
126
+ if (platform === "darwin") {
127
+ if (port) {
128
+ cmd = `ps aux | grep "[M]icrosoft Edge" | grep "remote-debugging-port=${port}" | awk '{sum += $6} END {printf "%d", sum/1024}'`;
129
+ } else {
130
+ cmd =
131
+ 'ps aux | grep "[M]icrosoft Edge" | awk \'{sum += $6} END {printf "%d", sum/1024}\'';
132
+ }
133
+ const result = execSync(cmd, { timeout: 5000 }).toString().trim();
134
+ const mb = parseInt(result, 10);
135
+ return mb > 0 ? mb : null;
136
+ } else if (platform === "linux") {
137
+ if (port) {
138
+ cmd = `ps aux | grep "[m]sedge" | grep "remote-debugging-port=${port}" | awk '{sum += $6} END {printf "%d", sum/1024}'`;
139
+ } else {
140
+ cmd =
141
+ 'ps aux | grep "[m]sedge" | awk \'{sum += $6} END {printf "%d", sum/1024}\'';
142
+ }
143
+ const result = execSync(cmd, { timeout: 5000 }).toString().trim();
144
+ const mb = parseInt(result, 10);
145
+ return mb > 0 ? mb : null;
146
+ } else if (platform === "win32") {
147
+ const ps1Path = path.join(os.tmpdir(), `edge-mem-${Date.now()}.ps1`);
148
+ try {
149
+ let ps1Content;
150
+ if (port) {
151
+ ps1Content =
152
+ `$procs = Get-CimInstance Win32_Process -Filter "Name LIKE 'msedge%'" -ErrorAction SilentlyContinue; ` +
153
+ `$sum = 0; ` +
154
+ `foreach ($p in $procs) { ` +
155
+ ` if ($p.CommandLine -and $p.CommandLine -like "*--remote-debugging-port=${port}*") { ` +
156
+ ` $sum += $p.WorkingSetSize ` +
157
+ ` } ` +
158
+ `}; ` +
159
+ `Write-Output $sum`;
160
+ } else {
161
+ ps1Content =
162
+ `$procs = Get-CimInstance Win32_Process -Filter "Name LIKE 'msedge%'" -ErrorAction SilentlyContinue; ` +
163
+ `$sum = 0; ` +
164
+ `foreach ($p in $procs) { $sum += $p.WorkingSetSize }; ` +
165
+ `Write-Output $sum`;
166
+ }
167
+ writeFileSync(ps1Path, ps1Content);
168
+ cmd = `powershell.exe -NoProfile -ExecutionPolicy Bypass -File "${ps1Path}"`;
169
+ const result = execSync(cmd, { timeout: 5000 }).toString().trim();
170
+ try {
171
+ unlinkSync(ps1Path);
172
+ } catch {}
173
+ const bytes = parseInt(result, 10);
174
+ const mb = bytes > 0 ? Math.round(bytes / 1048576) : 0;
175
+ return mb > 0 ? mb : null;
176
+ } catch {
177
+ try {
178
+ unlinkSync(ps1Path);
179
+ } catch {}
180
+ return null;
181
+ }
123
182
  }
124
- const mb = parseInt(execSync(cmd, { timeout: 5000 }).toString().trim(), 10);
125
- return mb > 0 ? mb : null;
183
+ return null;
126
184
  } catch {
127
185
  return null;
128
186
  }
129
187
  }
130
188
 
131
- function formatMemoryWithBrowser(port) {
189
+ function formatMemoryWithBrowser(port = null) {
132
190
  const nodeMem = formatMemoryUsage();
133
191
  const edgeMB = getBrowserMemory(port);
134
192
  if (!edgeMB) return nodeMem;
135
- const label = port ? ` edge:${port}:${edgeMB}MB` : ` edge:${edgeMB}MB`;
136
- return nodeMem + label;
193
+ const portLabel = port ? `:${port}` : "";
194
+ return `${nodeMem} edge${portLabel}:${edgeMB}MB`;
137
195
  }
138
196
 
139
197
  // ────────────────────────────────────────
@@ -481,7 +539,8 @@ async function runAutoMode(options) {
481
539
  browserRestartCount = 0;
482
540
  let consecutiveErrors = 0,
483
541
  consecutive403 = 0,
484
- consecutiveCaptchaCount = 0;
542
+ consecutiveCaptchaCount = 0,
543
+ consecutiveTaskErrors = 0;
485
544
 
486
545
  // ── CDP 会话 ──
487
546
  const session = new CdpSessionManager({
@@ -720,6 +779,7 @@ async function runAutoMode(options) {
720
779
  await apiPut(`${serverUrl}/api/comment-task/${id}`);
721
780
  processedCount++;
722
781
  consecutive403 = 0;
782
+ consecutiveTaskErrors = 0;
723
783
 
724
784
  // 每 10 个任务输出内存汇总
725
785
  if (totalTasks() % 10 === 0) {
@@ -729,6 +789,7 @@ async function runAutoMode(options) {
729
789
  }
730
790
  } catch (err) {
731
791
  errorCount++;
792
+ consecutiveTaskErrors++;
732
793
  const isBrowserClosed = isBrowserClosedError(err);
733
794
  const is403 =
734
795
  err.message &&
@@ -754,6 +815,22 @@ async function runAutoMode(options) {
754
815
  } else {
755
816
  console.error(` ${err.message}`);
756
817
  }
818
+
819
+ // 连续任务错误达到阈值,汇报服务端
820
+ if (consecutiveTaskErrors >= CFG.consecutiveTaskErrorsMax) {
821
+ console.error(
822
+ ` ⚠️ 连续任务错误 ${consecutiveTaskErrors}/${CFG.consecutiveTaskErrorsMax} → 汇报服务端`,
823
+ );
824
+ apiPost(`${serverUrl}/api/error-report`, {
825
+ userId,
826
+ username: "",
827
+ errorType: "consecutive_task_errors",
828
+ errorMessage: `连续 ${consecutiveTaskErrors} 个任务处理失败 (port=${session.port})`,
829
+ stage: "comments",
830
+ errorStack: "",
831
+ }).catch(() => {});
832
+ consecutiveTaskErrors = 0;
833
+ }
757
834
  }
758
835
 
759
836
  // 任务间内存检查
@@ -761,6 +838,7 @@ async function runAutoMode(options) {
761
838
  }
762
839
  } catch (err) {
763
840
  errorCount++;
841
+ consecutiveTaskErrors++;
764
842
  if (isBrowserClosedError(err)) {
765
843
  browserRestartCount++;
766
844
  console.error(` ⚠ 浏览器断开 (#${browserRestartCount}) → 重启`);
@@ -768,6 +846,22 @@ async function runAutoMode(options) {
768
846
  } else {
769
847
  console.error(` × ${err.message}`);
770
848
  }
849
+
850
+ // 连续轮间错误达到阈值,汇报服务端
851
+ if (consecutiveTaskErrors >= CFG.consecutiveTaskErrorsMax) {
852
+ console.error(
853
+ ` ⚠️ 连续轮间错误 ${consecutiveTaskErrors}/${CFG.consecutiveTaskErrorsMax} → 汇报服务端`,
854
+ );
855
+ apiPost(`${serverUrl}/api/error-report`, {
856
+ userId,
857
+ username: "",
858
+ errorType: "consecutive_task_errors",
859
+ errorMessage: `连续 ${consecutiveTaskErrors} 个轮次处理失败 (port=${session.port})`,
860
+ stage: "comments",
861
+ errorStack: "",
862
+ }).catch(() => {});
863
+ consecutiveTaskErrors = 0;
864
+ }
771
865
  }
772
866
 
773
867
  // 轮间内存检查 + 等待
@@ -794,7 +888,9 @@ async function runManualMode(url, options) {
794
888
  save: shouldSave,
795
889
  serverUrl = defaultServer,
796
890
  basePort = 9222,
891
+ proxy: proxyOption,
797
892
  } = options;
893
+ const effectiveProxy = proxyOption || configuredProxy;
798
894
 
799
895
  let browser;
800
896
  try {
@@ -930,5 +1026,6 @@ export async function handleComments(options) {
930
1026
  save: commentsSave,
931
1027
  serverUrl: commentsServer || defaultServer,
932
1028
  basePort: commentsBasePort,
1029
+ proxy: commentsProxy,
933
1030
  });
934
1031
  }