tt-help-cli-ycl 1.3.82 → 1.3.84

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.3.82",
3
+ "version": "1.3.84",
4
4
  "description": "TikTok user & video data scraper - extract ttSeller, verified, locationCreated from HTML source",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli/attach.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { TikTokScraper } from "../lib/tiktok-scraper.mjs";
2
2
  import { CDNBlockedError } from "../lib/parse-ssr.mjs";
3
3
  import { proxy as configuredProxy } from "../lib/constants.js";
4
+ import { createApiClient } from "../lib/api-client.js";
4
5
  import v8 from "node:v8";
5
6
 
6
- const MAX_RETRY_WAIT = 5 * 60 * 1000;
7
7
  const HEAP_RESTART_RATIO = 0.72;
8
8
  const MAX_TASK_BATCHES_BEFORE_RESTART = 200;
9
9
 
@@ -17,39 +17,6 @@ function attachLog(message = "") {
17
17
  console.error(`[${formatNow()}] ${message}`);
18
18
  }
19
19
 
20
- async function withRetry(label, fn) {
21
- let backoff = 1000;
22
- while (true) {
23
- try {
24
- return await fn();
25
- } catch (err) {
26
- attachLog(
27
- `[连接] ${label} 失败: ${err.message},${backoff / 1000}秒后重试...`,
28
- );
29
- await new Promise((r) => setTimeout(r, backoff));
30
- if (backoff < MAX_RETRY_WAIT) backoff *= 2;
31
- }
32
- }
33
- }
34
-
35
- async function apiGet(url) {
36
- return withRetry(`GET ${url}`, async () => {
37
- const res = await fetch(url);
38
- return res.json();
39
- });
40
- }
41
-
42
- async function apiPost(url, body) {
43
- return withRetry(`POST ${url}`, async () => {
44
- const res = await fetch(url, {
45
- method: "POST",
46
- headers: { "Content-Type": "application/json" },
47
- body: JSON.stringify(body),
48
- });
49
- return res.json();
50
- });
51
- }
52
-
53
20
  function isBrowserClosedError(err) {
54
21
  if (!err) return false;
55
22
  const msg = err.message || err.toString() || "";
@@ -143,6 +110,8 @@ export async function handleAttach(options) {
143
110
  `[Attach] 并行数: ${attachParallel}, 空闲间隔: ${attachInterval}秒, 服务端: ${serverUrl}${countryStr}`,
144
111
  );
145
112
 
113
+ const { apiGet, apiPost } = createApiClient({ log: false });
114
+
146
115
  const scraper = new TikTokScraper({
147
116
  poolSize: attachPoolSize || 3,
148
117
  proxyServer: effectiveProxy || null,
package/src/cli/auto.js CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  import { userId as configuredUserId, saveUserId } from "../lib/constants.js";
7
7
  import { getMacOrUuid } from "../lib/mac-or-uuid.js";
8
8
  import { ensureBrowserReady as ensureBrowserReadyCDP } from "../lib/browser/cdp.js";
9
+ import { createApiClient } from "../lib/api-client.js";
9
10
 
10
11
  const MAX_RETRY_WAIT = 5 * 60 * 1000;
11
12
 
@@ -24,24 +25,6 @@ async function withRetry(label, fn) {
24
25
  }
25
26
  }
26
27
 
27
- async function apiPost(url, body) {
28
- return withRetry(`POST ${url}`, async () => {
29
- const res = await fetch(url, {
30
- method: "POST",
31
- headers: { "Content-Type": "application/json" },
32
- body: JSON.stringify(body),
33
- });
34
- return res.json();
35
- });
36
- }
37
-
38
- async function apiGet(url) {
39
- return withRetry(`GET ${url}`, async () => {
40
- const res = await fetch(url);
41
- return res.json();
42
- });
43
- }
44
-
45
28
  export async function handleAuto(options) {
46
29
  const {
47
30
  autoUsernames,
@@ -87,6 +70,8 @@ export async function handleAuto(options) {
87
70
  console.error(`[初始化] 未检测到本地用户编号,已生成并使用: ${userId}`);
88
71
  }
89
72
 
73
+ const { apiGet, apiPost } = createApiClient();
74
+
90
75
  const runOptions = {
91
76
  collectMax: autoCollectMax,
92
77
  scrapeDepth: autoScrapeDepth,
@@ -7,6 +7,7 @@ import {
7
7
  isLocationInList,
8
8
  normalizeLocation,
9
9
  } from "../lib/target-locations.js";
10
+ import { createApiClient } from "../lib/api-client.js";
10
11
 
11
12
  async function waitForPageReady(page, timeout = 30000) {
12
13
  const startTime = Date.now();
@@ -32,64 +33,7 @@ async function safeEvaluate(page, fn) {
32
33
  }
33
34
  }
34
35
 
35
- async function withRetry(label, fn, maxRetries = 3) {
36
- let backoff = 2000;
37
- for (let i = 0; i < maxRetries; i++) {
38
- try {
39
- return await fn();
40
- } catch (err) {
41
- if (i < maxRetries - 1) {
42
- console.error(
43
- ` [${label}] 失败: ${err.message},${backoff / 1000}s 后重试...`,
44
- );
45
- await new Promise((r) => setTimeout(r, backoff));
46
- backoff *= 2;
47
- } else {
48
- throw err;
49
- }
50
- }
51
- }
52
- }
53
-
54
- async function apiPost(url, body) {
55
- return withRetry(`POST ${url}`, async () => {
56
- const res = await fetch(url, {
57
- method: "POST",
58
- headers: { "Content-Type": "application/json" },
59
- body: JSON.stringify(body),
60
- });
61
- if (!res.ok) {
62
- const errText = await res.text();
63
- throw new Error(`HTTP ${res.status}: ${errText.substring(0, 200)}`);
64
- }
65
- return res.json();
66
- });
67
- }
68
36
 
69
- async function apiPut(url) {
70
- return withRetry(`PUT ${url}`, async () => {
71
- const res = await fetch(url, {
72
- method: "PUT",
73
- headers: { "Content-Type": "application/json" },
74
- });
75
- if (!res.ok) {
76
- const errText = await res.text();
77
- throw new Error(`HTTP ${res.status}: ${errText.substring(0, 200)}`);
78
- }
79
- return res.json();
80
- });
81
- }
82
-
83
- async function apiGet(url) {
84
- return withRetry(`GET ${url}`, async () => {
85
- const res = await fetch(url);
86
- if (!res.ok) {
87
- const errText = await res.text();
88
- throw new Error(`HTTP ${res.status}: ${errText.substring(0, 200)}`);
89
- }
90
- return res.json();
91
- });
92
- }
93
37
 
94
38
  function isBrowserClosedError(err) {
95
39
  if (!err) return false;
@@ -110,6 +54,12 @@ function isBrowserClosedError(err) {
110
54
  */
111
55
  async function runAutoMode(options) {
112
56
  const { serverUrl, parallel, interval, maxComments } = options;
57
+ const { apiGet, apiPost, apiPut } = createApiClient({
58
+ checkStatus: true,
59
+ maxRetries: 2,
60
+ backoff: 2000,
61
+ log: true,
62
+ });
113
63
  const actualParallel = Math.max(1, parallel || 1);
114
64
  const actualInterval = interval || 10;
115
65
  const actualMaxComments = maxComments || 200;
@@ -478,6 +428,12 @@ export async function handleComments(options) {
478
428
 
479
429
  const guessedLocation = normalizeLocation(videoInfo?.locationCreated);
480
430
  const serverUrl = commentsServer || defaultServer;
431
+ const { apiPost } = createApiClient({
432
+ checkStatus: true,
433
+ maxRetries: 2,
434
+ backoff: 2000,
435
+ log: true,
436
+ });
481
437
 
482
438
  if (
483
439
  guessedLocation &&