tt-help-cli-ycl 1.3.34 → 1.3.35

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 (58) hide show
  1. package/README.md +17 -17
  2. package/cli.js +9 -9
  3. package/package.json +47 -47
  4. package/scripts/run-explore copy.bat +101 -101
  5. package/scripts/run-explore.bat +132 -132
  6. package/scripts/run-explore.ps1 +157 -157
  7. package/scripts/run-explore.sh +119 -119
  8. package/scripts/test-captcha-lib.mjs +68 -0
  9. package/scripts/test-captcha.mjs +81 -0
  10. package/scripts/test-incognito-lib.mjs +36 -0
  11. package/scripts/test-login-state.mjs +128 -0
  12. package/scripts/test-safe-click.mjs +45 -0
  13. package/src/cli/attach.js +180 -180
  14. package/src/cli/auto.js +240 -240
  15. package/src/cli/config.js +152 -152
  16. package/src/cli/explore.js +488 -488
  17. package/src/cli/info.js +88 -88
  18. package/src/cli/open.js +111 -111
  19. package/src/cli/progress.js +111 -111
  20. package/src/cli/refresh.js +216 -216
  21. package/src/cli/scrape.js +47 -47
  22. package/src/cli/utils.js +18 -18
  23. package/src/cli/videos.js +41 -41
  24. package/src/cli/watch.js +31 -31
  25. package/src/lib/args.js +722 -722
  26. package/src/lib/browser/anti-detect.js +23 -23
  27. package/src/lib/browser/cdp.js +261 -261
  28. package/src/lib/browser/health-checker.js +114 -114
  29. package/src/lib/browser/launch.js +43 -43
  30. package/src/lib/browser/page.js +183 -183
  31. package/src/lib/constants.js +216 -216
  32. package/src/lib/delay.js +54 -54
  33. package/src/lib/explore-fetch.js +118 -118
  34. package/src/lib/fetcher.js +45 -45
  35. package/src/lib/filter.js +66 -66
  36. package/src/lib/io.js +54 -54
  37. package/src/lib/output.js +80 -80
  38. package/src/lib/page-error-detector.js +105 -105
  39. package/src/lib/parse-ssr.mjs +69 -69
  40. package/src/lib/parser.js +47 -47
  41. package/src/lib/retry.js +45 -45
  42. package/src/lib/scrape.js +89 -89
  43. package/src/lib/tiktok-scraper.mjs +194 -194
  44. package/src/lib/url.js +52 -52
  45. package/src/main.js +48 -48
  46. package/src/results/user-videos-bar.lar.lar.moeta.json +37 -0
  47. package/src/scraper/auto-core.js +203 -203
  48. package/src/scraper/core.js +211 -211
  49. package/src/scraper/explore-core.js +177 -167
  50. package/src/scraper/modules/captcha-handler.js +114 -114
  51. package/src/scraper/modules/follow-extractor.js +194 -194
  52. package/src/scraper/modules/guess-extractor.js +51 -51
  53. package/src/scraper/modules/page-helpers.js +48 -48
  54. package/src/scraper/refresh-core.js +179 -179
  55. package/src/videos/core.js +125 -125
  56. package/src/watch/data-store.js +1040 -1030
  57. package/src/watch/public/index.html +1458 -753
  58. package/src/watch/server.js +939 -933
@@ -1,216 +1,216 @@
1
- import { join, dirname } from 'path';
2
- import { readFileSync, writeFileSync, existsSync } from 'fs';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = dirname(__filename);
7
- const homeDir = process.env.HOME || process.env.USERPROFILE || '';
8
- const configPath = join(homeDir, '.tt-help.json');
9
-
10
- const DEFAULT_PROXY = 'http://127.0.0.1:7897';
11
- const DEFAULT_OUTPUT = 'tiktok_data.json';
12
-
13
- let proxy = DEFAULT_PROXY;
14
- let server = 'http://127.0.0.1:3001';
15
- let configFile = null;
16
- let browser = null;
17
- let userId = null;
18
- let maxFollowing = 50;
19
- let maxFollowers = 50;
20
- let maxVideos = 16;
21
- let maxComments = 10;
22
-
23
- try {
24
- if (existsSync(configPath)) {
25
- const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
26
- if (cfg.proxy) {
27
- proxy = cfg.proxy;
28
- }
29
- if (cfg.server) {
30
- server = cfg.server;
31
- }
32
- if (cfg.browser) {
33
- browser = cfg.browser;
34
- }
35
- if (cfg.userId) {
36
- userId = cfg.userId;
37
- }
38
- if (cfg.maxFollowing !== undefined) {
39
- maxFollowing = cfg.maxFollowing;
40
- }
41
- if (cfg.maxFollowers !== undefined) {
42
- maxFollowers = cfg.maxFollowers;
43
- }
44
- if (cfg.maxVideos !== undefined) {
45
- maxVideos = cfg.maxVideos;
46
- }
47
- if (cfg.maxComments !== undefined) {
48
- maxComments = cfg.maxComments;
49
- }
50
- configFile = configPath;
51
- }
52
- } catch {
53
- // no config file
54
- }
55
-
56
- function saveBrowser(path) {
57
- const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
58
- cfg.browser = path;
59
- writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
60
- browser = path;
61
- configFile = configPath;
62
- }
63
-
64
- function saveUserId(id) {
65
- const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
66
- cfg.userId = id;
67
- writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
68
- userId = id;
69
- configFile = configPath;
70
- }
71
-
72
- function saveMaxFollowing(val) {
73
- const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
74
- cfg.maxFollowing = parseInt(val) || 5;
75
- writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
76
- maxFollowing = cfg.maxFollowing;
77
- configFile = configPath;
78
- }
79
-
80
- function saveMaxFollowers(val) {
81
- const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
82
- cfg.maxFollowers = parseInt(val) || 5;
83
- writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
84
- maxFollowers = cfg.maxFollowers;
85
- configFile = configPath;
86
- }
87
-
88
- function saveMaxVideos(val) {
89
- const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
90
- cfg.maxVideos = parseInt(val) || 16;
91
- writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
92
- maxVideos = cfg.maxVideos;
93
- configFile = configPath;
94
- }
95
-
96
- function saveMaxComments(val) {
97
- const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
98
- cfg.maxComments = parseInt(val) || 10;
99
- writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
100
- maxComments = cfg.maxComments;
101
- configFile = configPath;
102
- }
103
-
104
- const HELP_TEXT = [
105
- '用法:',
106
- '',
107
- ' tt-help explore <用户名> [preset] [选项]',
108
- ' 支持多个用户名: tt-help explore @user1 @user2 --server http://127.0.0.1:3001',
109
- ' 预设: fast, normal(默认), slow, stealth',
110
- ' 选项:',
111
- ' --server <URL> 服务端地址,默认 http://127.0.0.1:3001',
112
- ' --location <国家代码> 国家筛选,逗号分隔,默认 PL,NL,BE,DE,FR,IT,ES,IE,AT',
113
- ' --job-locations <国家> 任务国家筛选,逗号分隔(仅筛选服务端任务)',
114
- ' --max-comments <数量> 每视频最大评论数,默认 10',
115
- ' --max-guess <数量> 每视频最大猜你喜欢数,默认 0',
116
- ' --max-videos <数量> 每用户最大视频数,默认 16',
117
- ' --enable-follow 启用关注/粉丝提取(默认启用)',
118
- ' --disable-follow 禁用关注/粉丝提取',
119
- ' --max-following <数量> 最大获取关注数,默认 50(同时设置粉丝数)',
120
- ' --max-followers <数量> 最大获取粉丝数,默认 50',
121
- ' --max-users <数量> 最大处理用户数,默认无限制',
122
- ' --port <端口号> 固定 CDP 端口(调试用,关闭自动轮换)',
123
- ' --base-port <端口号> 起始端口,默认 9222',
124
- ' --port-count <数量> 端口数量(账户数),默认 10',
125
- ' --user-id <编号> 客户端编号(设备ID),默认自动生成',
126
- '',
127
- ' tt-help info <URL> [URL2 ...] [--onlyvideo]',
128
- ' 获取用户/视频信息,支持多个 URL',
129
- ' 主页 URL → 返回用户信息',
130
- ' 视频 URL → 返回用户信息 + 视频信息',
131
- ' 视频 URL + --onlyvideo → 只返回视频信息',
132
- ' 示例: tt-help info https://www.tiktok.com/@nike',
133
- ' tt-help info https://www.tiktok.com/@nike/video/7234567890 --onlyvideo',
134
- '',
135
- ' tt-help attach [-p 并行数] [-i 间隔秒数] [-s 服务端地址]',
136
- ' 后台轮询服务端任务接口,自动抓取 TikTok 用户信息',
137
- ' -p, --parallel <N> 并行抓取数(默认: 1)',
138
- ' -i, --interval <N> 无任务时轮询间隔,单位秒(默认: 10)',
139
- ' -s, --server <URL> 服务端地址(默认: http://127.0.0.1:3001)',
140
- ' 示例: tt-help attach -p 5 -i 10',
141
- '',
142
- ' tt-help open <端口号>',
143
- ' 打开指定端口的浏览器,用于配置 TikTok 登录账户',
144
- ' 端口范围: 9222 - 9231(对应 explore 的 10 个内置账户)',
145
- ' --list 列出所有端口和配置',
146
- ' 示例: tt-help open 9222',
147
- ' tt-help open --list',
148
- '',
149
- ' videostats <文件路径> -p <并发数>',
150
- ' 批量刷新视频统计数据(playCount, diggCount, commentCount, shareCount, collectCount)',
151
- ' 读取视频文件,通过 getVideoInfo 获取最新数据,更新后写回原文件',
152
- ' -p, --parallel <N> 并发数(默认: 3)',
153
- ' 示例: tt-help videostats data/result-videos.json -p 3',
154
- '',
155
- ' config [show|set|reset]',
156
- ' config 查看当前配置',
157
- ' config set <key> <value> 设置配置(key: proxy, server, browser, userId, maxFollowing, maxFollowers, maxVideos, maxComments)',
158
- ' config reset 重置所有配置为默认',
159
- '',
160
- ' 全局选项:',
161
- ' -h, --help 显示帮助',
162
- ' --version 显示版本号',
163
- '',
164
- ' 示例: tt-help info https://www.tiktok.com/@nike https://www.tiktok.com/@adidas',
165
- ' tt-help explore qiqi23280 fast --location ES --max-comments 50',
166
- ' tt-help config set server http://127.0.0.1:3001',
167
- ' tt-help attach -p 5 -i 10',
168
- ' tt-help videostats data/result-videos.json -p 3',
169
- ];
170
-
171
- function getConfigText() {
172
- let currentUserId = userId;
173
- if (!currentUserId && existsSync(configPath)) {
174
- try {
175
- const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
176
- if (cfg.userId) currentUserId = cfg.userId;
177
- } catch {}
178
- }
179
- return [
180
- 'tt-help v1.0.1',
181
- '',
182
- '配置:',
183
- ` 代理: ${proxy}`,
184
- ` 服务端: ${server}`,
185
- ` 浏览器: ${browser || '未配置(将自动探测或回退)'}`,
186
- ` 用户号: ${currentUserId || '未设置(首次运行 auto 自动创建)'}`,
187
- ` 商家关注采集数: ${maxFollowing}`,
188
- ` 粉丝采集数: ${maxFollowers}`,
189
- ` 视频采集数: ${maxVideos}`,
190
- ` 评论采集数: ${maxComments}`,
191
- ` 输出格式: json`,
192
- ` 默认输出: ${DEFAULT_OUTPUT}`,
193
- ` 配置文件: ${configFile || '无(使用默认值)'}`,
194
- ];
195
- }
196
-
197
- export {
198
- proxy,
199
- server,
200
- configPath,
201
- DEFAULT_PROXY,
202
- HELP_TEXT,
203
- browser,
204
- userId,
205
- maxFollowing,
206
- maxFollowers,
207
- maxVideos,
208
- maxComments,
209
- saveBrowser,
210
- saveUserId,
211
- saveMaxFollowing,
212
- saveMaxFollowers,
213
- saveMaxVideos,
214
- saveMaxComments,
215
- getConfigText,
216
- };
1
+ import { join, dirname } from 'path';
2
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ const homeDir = process.env.HOME || process.env.USERPROFILE || '';
8
+ const configPath = join(homeDir, '.tt-help.json');
9
+
10
+ const DEFAULT_PROXY = 'http://127.0.0.1:7897';
11
+ const DEFAULT_OUTPUT = 'tiktok_data.json';
12
+
13
+ let proxy = DEFAULT_PROXY;
14
+ let server = 'http://127.0.0.1:3001';
15
+ let configFile = null;
16
+ let browser = null;
17
+ let userId = null;
18
+ let maxFollowing = 50;
19
+ let maxFollowers = 50;
20
+ let maxVideos = 16;
21
+ let maxComments = 10;
22
+
23
+ try {
24
+ if (existsSync(configPath)) {
25
+ const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
26
+ if (cfg.proxy) {
27
+ proxy = cfg.proxy;
28
+ }
29
+ if (cfg.server) {
30
+ server = cfg.server;
31
+ }
32
+ if (cfg.browser) {
33
+ browser = cfg.browser;
34
+ }
35
+ if (cfg.userId) {
36
+ userId = cfg.userId;
37
+ }
38
+ if (cfg.maxFollowing !== undefined) {
39
+ maxFollowing = cfg.maxFollowing;
40
+ }
41
+ if (cfg.maxFollowers !== undefined) {
42
+ maxFollowers = cfg.maxFollowers;
43
+ }
44
+ if (cfg.maxVideos !== undefined) {
45
+ maxVideos = cfg.maxVideos;
46
+ }
47
+ if (cfg.maxComments !== undefined) {
48
+ maxComments = cfg.maxComments;
49
+ }
50
+ configFile = configPath;
51
+ }
52
+ } catch {
53
+ // no config file
54
+ }
55
+
56
+ function saveBrowser(path) {
57
+ const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
58
+ cfg.browser = path;
59
+ writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
60
+ browser = path;
61
+ configFile = configPath;
62
+ }
63
+
64
+ function saveUserId(id) {
65
+ const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
66
+ cfg.userId = id;
67
+ writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
68
+ userId = id;
69
+ configFile = configPath;
70
+ }
71
+
72
+ function saveMaxFollowing(val) {
73
+ const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
74
+ cfg.maxFollowing = parseInt(val) || 5;
75
+ writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
76
+ maxFollowing = cfg.maxFollowing;
77
+ configFile = configPath;
78
+ }
79
+
80
+ function saveMaxFollowers(val) {
81
+ const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
82
+ cfg.maxFollowers = parseInt(val) || 5;
83
+ writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
84
+ maxFollowers = cfg.maxFollowers;
85
+ configFile = configPath;
86
+ }
87
+
88
+ function saveMaxVideos(val) {
89
+ const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
90
+ cfg.maxVideos = parseInt(val) || 16;
91
+ writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
92
+ maxVideos = cfg.maxVideos;
93
+ configFile = configPath;
94
+ }
95
+
96
+ function saveMaxComments(val) {
97
+ const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};
98
+ cfg.maxComments = parseInt(val) || 10;
99
+ writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf-8');
100
+ maxComments = cfg.maxComments;
101
+ configFile = configPath;
102
+ }
103
+
104
+ const HELP_TEXT = [
105
+ '用法:',
106
+ '',
107
+ ' tt-help explore <用户名> [preset] [选项]',
108
+ ' 支持多个用户名: tt-help explore @user1 @user2 --server http://127.0.0.1:3001',
109
+ ' 预设: fast, normal(默认), slow, stealth',
110
+ ' 选项:',
111
+ ' --server <URL> 服务端地址,默认 http://127.0.0.1:3001',
112
+ ' --location <国家代码> 国家筛选,逗号分隔,默认 PL,NL,BE,DE,FR,IT,ES,IE,AT',
113
+ ' --job-locations <国家> 任务国家筛选,逗号分隔(仅筛选服务端任务)',
114
+ ' --max-comments <数量> 每视频最大评论数,默认 10',
115
+ ' --max-guess <数量> 每视频最大猜你喜欢数,默认 0',
116
+ ' --max-videos <数量> 每用户最大视频数,默认 16',
117
+ ' --enable-follow 启用关注/粉丝提取(默认启用)',
118
+ ' --disable-follow 禁用关注/粉丝提取',
119
+ ' --max-following <数量> 最大获取关注数,默认 50(同时设置粉丝数)',
120
+ ' --max-followers <数量> 最大获取粉丝数,默认 50',
121
+ ' --max-users <数量> 最大处理用户数,默认无限制',
122
+ ' --port <端口号> 固定 CDP 端口(调试用,关闭自动轮换)',
123
+ ' --base-port <端口号> 起始端口,默认 9222',
124
+ ' --port-count <数量> 端口数量(账户数),默认 10',
125
+ ' --user-id <编号> 客户端编号(设备ID),默认自动生成',
126
+ '',
127
+ ' tt-help info <URL> [URL2 ...] [--onlyvideo]',
128
+ ' 获取用户/视频信息,支持多个 URL',
129
+ ' 主页 URL → 返回用户信息',
130
+ ' 视频 URL → 返回用户信息 + 视频信息',
131
+ ' 视频 URL + --onlyvideo → 只返回视频信息',
132
+ ' 示例: tt-help info https://www.tiktok.com/@nike',
133
+ ' tt-help info https://www.tiktok.com/@nike/video/7234567890 --onlyvideo',
134
+ '',
135
+ ' tt-help attach [-p 并行数] [-i 间隔秒数] [-s 服务端地址]',
136
+ ' 后台轮询服务端任务接口,自动抓取 TikTok 用户信息',
137
+ ' -p, --parallel <N> 并行抓取数(默认: 1)',
138
+ ' -i, --interval <N> 无任务时轮询间隔,单位秒(默认: 10)',
139
+ ' -s, --server <URL> 服务端地址(默认: http://127.0.0.1:3001)',
140
+ ' 示例: tt-help attach -p 5 -i 10',
141
+ '',
142
+ ' tt-help open <端口号>',
143
+ ' 打开指定端口的浏览器,用于配置 TikTok 登录账户',
144
+ ' 端口范围: 9222 - 9231(对应 explore 的 10 个内置账户)',
145
+ ' --list 列出所有端口和配置',
146
+ ' 示例: tt-help open 9222',
147
+ ' tt-help open --list',
148
+ '',
149
+ ' videostats <文件路径> -p <并发数>',
150
+ ' 批量刷新视频统计数据(playCount, diggCount, commentCount, shareCount, collectCount)',
151
+ ' 读取视频文件,通过 getVideoInfo 获取最新数据,更新后写回原文件',
152
+ ' -p, --parallel <N> 并发数(默认: 3)',
153
+ ' 示例: tt-help videostats data/result-videos.json -p 3',
154
+ '',
155
+ ' config [show|set|reset]',
156
+ ' config 查看当前配置',
157
+ ' config set <key> <value> 设置配置(key: proxy, server, browser, userId, maxFollowing, maxFollowers, maxVideos, maxComments)',
158
+ ' config reset 重置所有配置为默认',
159
+ '',
160
+ ' 全局选项:',
161
+ ' -h, --help 显示帮助',
162
+ ' --version 显示版本号',
163
+ '',
164
+ ' 示例: tt-help info https://www.tiktok.com/@nike https://www.tiktok.com/@adidas',
165
+ ' tt-help explore qiqi23280 fast --location ES --max-comments 50',
166
+ ' tt-help config set server http://127.0.0.1:3001',
167
+ ' tt-help attach -p 5 -i 10',
168
+ ' tt-help videostats data/result-videos.json -p 3',
169
+ ];
170
+
171
+ function getConfigText() {
172
+ let currentUserId = userId;
173
+ if (!currentUserId && existsSync(configPath)) {
174
+ try {
175
+ const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
176
+ if (cfg.userId) currentUserId = cfg.userId;
177
+ } catch {}
178
+ }
179
+ return [
180
+ 'tt-help v1.0.1',
181
+ '',
182
+ '配置:',
183
+ ` 代理: ${proxy}`,
184
+ ` 服务端: ${server}`,
185
+ ` 浏览器: ${browser || '未配置(将自动探测或回退)'}`,
186
+ ` 用户号: ${currentUserId || '未设置(首次运行 auto 自动创建)'}`,
187
+ ` 商家关注采集数: ${maxFollowing}`,
188
+ ` 粉丝采集数: ${maxFollowers}`,
189
+ ` 视频采集数: ${maxVideos}`,
190
+ ` 评论采集数: ${maxComments}`,
191
+ ` 输出格式: json`,
192
+ ` 默认输出: ${DEFAULT_OUTPUT}`,
193
+ ` 配置文件: ${configFile || '无(使用默认值)'}`,
194
+ ];
195
+ }
196
+
197
+ export {
198
+ proxy,
199
+ server,
200
+ configPath,
201
+ DEFAULT_PROXY,
202
+ HELP_TEXT,
203
+ browser,
204
+ userId,
205
+ maxFollowing,
206
+ maxFollowers,
207
+ maxVideos,
208
+ maxComments,
209
+ saveBrowser,
210
+ saveUserId,
211
+ saveMaxFollowing,
212
+ saveMaxFollowers,
213
+ saveMaxVideos,
214
+ saveMaxComments,
215
+ getConfigText,
216
+ };
package/src/lib/delay.js CHANGED
@@ -1,54 +1,54 @@
1
- export const DELAY_PRESETS = {
2
- fast: { switchMax: 300, commentMax: 200, fast: true },
3
- normal: { switchMax: 1500, commentMax: 800 },
4
- slow: { switchMax: 3000, commentMax: 2000 },
5
- stealth: { switchMax: 5000, commentMax: 3500 },
6
- };
7
-
8
- const delayConfig = {
9
- switchMax: 2500,
10
- commentMax: 1500,
11
- fast: false,
12
- };
13
-
14
- export function setDelayConfig(config) {
15
- if (typeof config === 'string') {
16
- const preset = DELAY_PRESETS[config.toLowerCase()];
17
- if (!preset) {
18
- throw new Error(
19
- `未知的延迟预设: ${config}\n可用预设: ${Object.keys(DELAY_PRESETS).join(', ')}`
20
- );
21
- }
22
- delayConfig.switchMax = preset.switchMax;
23
- delayConfig.commentMax = preset.commentMax;
24
- delayConfig.fast = preset.fast || false;
25
- } else if (typeof config === 'object') {
26
- if (config.switchMax) delayConfig.switchMax = config.switchMax;
27
- if (config.commentMax) delayConfig.commentMax = config.commentMax;
28
- delayConfig.fast = config.fast || false;
29
- }
30
- }
31
-
32
- export function getDelayConfig() {
33
- return { ...delayConfig };
34
- }
35
-
36
- export function listDelayPresets() {
37
- return DELAY_PRESETS;
38
- }
39
-
40
- export function delay(min, max) {
41
- const lo = Math.min(min, max);
42
- const hi = Math.max(min, max);
43
- let ms;
44
- if (delayConfig.fast) {
45
- ms = 0;
46
- } else {
47
- ms = Math.floor(Math.random() * (hi - lo + 1)) + lo;
48
- }
49
- return new Promise(r => setTimeout(r, ms));
50
- }
51
-
52
- export function randomDelay(min = 200, max = 600) {
53
- return delay(min, max);
54
- }
1
+ export const DELAY_PRESETS = {
2
+ fast: { switchMax: 300, commentMax: 200, fast: true },
3
+ normal: { switchMax: 1500, commentMax: 800 },
4
+ slow: { switchMax: 3000, commentMax: 2000 },
5
+ stealth: { switchMax: 5000, commentMax: 3500 },
6
+ };
7
+
8
+ const delayConfig = {
9
+ switchMax: 2500,
10
+ commentMax: 1500,
11
+ fast: false,
12
+ };
13
+
14
+ export function setDelayConfig(config) {
15
+ if (typeof config === 'string') {
16
+ const preset = DELAY_PRESETS[config.toLowerCase()];
17
+ if (!preset) {
18
+ throw new Error(
19
+ `未知的延迟预设: ${config}\n可用预设: ${Object.keys(DELAY_PRESETS).join(', ')}`
20
+ );
21
+ }
22
+ delayConfig.switchMax = preset.switchMax;
23
+ delayConfig.commentMax = preset.commentMax;
24
+ delayConfig.fast = preset.fast || false;
25
+ } else if (typeof config === 'object') {
26
+ if (config.switchMax) delayConfig.switchMax = config.switchMax;
27
+ if (config.commentMax) delayConfig.commentMax = config.commentMax;
28
+ delayConfig.fast = config.fast || false;
29
+ }
30
+ }
31
+
32
+ export function getDelayConfig() {
33
+ return { ...delayConfig };
34
+ }
35
+
36
+ export function listDelayPresets() {
37
+ return DELAY_PRESETS;
38
+ }
39
+
40
+ export function delay(min, max) {
41
+ const lo = Math.min(min, max);
42
+ const hi = Math.max(min, max);
43
+ let ms;
44
+ if (delayConfig.fast) {
45
+ ms = 0;
46
+ } else {
47
+ ms = Math.floor(Math.random() * (hi - lo + 1)) + lo;
48
+ }
49
+ return new Promise(r => setTimeout(r, ms));
50
+ }
51
+
52
+ export function randomDelay(min = 200, max = 600) {
53
+ return delay(min, max);
54
+ }