tt-help-cli-ycl 1.4.53 → 1.4.55
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 +1 -1
- package/src/lib/args.js +4 -3
- package/src/webserver/server.mjs +38 -10
package/package.json
CHANGED
package/src/lib/args.js
CHANGED
|
@@ -407,7 +407,8 @@ function parseWebserverArgs(args) {
|
|
|
407
407
|
let webserverPort = 3000;
|
|
408
408
|
let webserverPoolSize = 0;
|
|
409
409
|
let webserverProxy = null;
|
|
410
|
-
|
|
410
|
+
// 默认汇报到 ~/.tt-help.json 中配置的 server 地址
|
|
411
|
+
let webserverNotify = defaultServer;
|
|
411
412
|
|
|
412
413
|
for (let i = 0; i < args.length; i++) {
|
|
413
414
|
const arg = args[i];
|
|
@@ -419,9 +420,9 @@ function parseWebserverArgs(args) {
|
|
|
419
420
|
webserverProxy = args[++i] || null;
|
|
420
421
|
} else if (arg === "--notify") {
|
|
421
422
|
const next = args[i + 1];
|
|
422
|
-
// 没写地址或下一个是别的参数 →
|
|
423
|
+
// 没写地址或下一个是别的参数 → 使用配置中的 server 地址
|
|
423
424
|
if (!next || next.startsWith("--")) {
|
|
424
|
-
webserverNotify =
|
|
425
|
+
webserverNotify = defaultServer;
|
|
425
426
|
} else {
|
|
426
427
|
webserverNotify = args[++i];
|
|
427
428
|
}
|
package/src/webserver/server.mjs
CHANGED
|
@@ -222,14 +222,15 @@ async function handleTiktokProduct(req, res) {
|
|
|
222
222
|
);
|
|
223
223
|
return sendJSON(res, 200, result);
|
|
224
224
|
} catch (e) {
|
|
225
|
-
// 先返回错误,不阻塞请求
|
|
226
225
|
console.error(`[webserver] product FAIL | ${clientIP} | ${e.message}`);
|
|
227
|
-
sendJSON(res, 502, { error: e.message });
|
|
228
226
|
|
|
229
|
-
// 如果是 captcha
|
|
227
|
+
// 如果是 captcha,先触发上报+恢复(不阻塞其他请求)
|
|
228
|
+
// 必须在 sendJSON 之前调用,否则 sendJSON 抛异常会导致验证码通知丢失
|
|
230
229
|
if (e.message?.includes("Blocked by TikTok")) {
|
|
231
230
|
scheduleCaptchaRecovery(normalizedUrl, SCRAPER_CONFIG.proxyServer);
|
|
232
231
|
}
|
|
232
|
+
|
|
233
|
+
sendJSON(res, 502, { error: e.message });
|
|
233
234
|
return;
|
|
234
235
|
}
|
|
235
236
|
}
|
|
@@ -237,15 +238,17 @@ async function handleTiktokProduct(req, res) {
|
|
|
237
238
|
// 防止重复弹浏览器
|
|
238
239
|
let captchaRecoveryRunning = false;
|
|
239
240
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
// 通知 Watch Server:带重试,不受 captchaRecoveryRunning 锁限制
|
|
242
|
+
// captchaNotifyUrl 默认来自 ~/.tt-help.json 的 server 配置
|
|
243
|
+
async function notifyCaptchaToWatch(url, maxRetries = 3) {
|
|
244
|
+
if (!SCRAPER_CONFIG.captchaNotifyUrl) {
|
|
245
|
+
console.error(
|
|
246
|
+
"[webserver] Captcha detected but notify URL is empty, check --notify or ~/.tt-help.json server config",
|
|
247
|
+
);
|
|
243
248
|
return;
|
|
244
249
|
}
|
|
245
|
-
captchaRecoveryRunning = true;
|
|
246
250
|
|
|
247
|
-
|
|
248
|
-
if (SCRAPER_CONFIG.captchaNotifyUrl) {
|
|
251
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
249
252
|
try {
|
|
250
253
|
await fetch(`${SCRAPER_CONFIG.captchaNotifyUrl}/api/error-report`, {
|
|
251
254
|
method: "POST",
|
|
@@ -260,10 +263,35 @@ async function scheduleCaptchaRecovery(url, proxy) {
|
|
|
260
263
|
}),
|
|
261
264
|
});
|
|
262
265
|
console.error("[webserver] Captcha alert sent to watch server");
|
|
266
|
+
return;
|
|
263
267
|
} catch (e) {
|
|
264
|
-
|
|
268
|
+
if (attempt < maxRetries) {
|
|
269
|
+
const delay = attempt * 2000;
|
|
270
|
+
console.error(
|
|
271
|
+
`[webserver] Failed to notify watch server (attempt ${attempt}/${maxRetries}): ${e.message}, retrying in ${delay}ms...`,
|
|
272
|
+
);
|
|
273
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
274
|
+
} else {
|
|
275
|
+
console.error(
|
|
276
|
+
`[webserver] Failed to notify watch server after ${maxRetries} attempts: ${e.message}`,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
265
279
|
}
|
|
266
280
|
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function scheduleCaptchaRecovery(url, proxy) {
|
|
284
|
+
// 通知 Watch Server — 独立于浏览器恢复,每次验证码都尝试上报(带重试)
|
|
285
|
+
await notifyCaptchaToWatch(url);
|
|
286
|
+
|
|
287
|
+
// 防止重复弹浏览器
|
|
288
|
+
if (captchaRecoveryRunning) {
|
|
289
|
+
console.error(
|
|
290
|
+
"[webserver] Captcha recovery already in progress, skipping browser",
|
|
291
|
+
);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
captchaRecoveryRunning = true;
|
|
267
295
|
|
|
268
296
|
try {
|
|
269
297
|
const { getProductInfo } = await import("../lib/shop-scraper.mjs");
|