tt-help-cli-ycl 1.3.48 → 1.3.50

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 (64) hide show
  1. package/README.md +33 -33
  2. package/cli.js +9 -9
  3. package/package.json +52 -52
  4. package/scripts/run-explore copy.bat +101 -101
  5. package/scripts/run-explore.bat +134 -134
  6. package/scripts/run-explore.ps1 +159 -159
  7. package/scripts/run-explore.sh +121 -121
  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/scripts/test-watch-db-smoke.mjs +246 -0
  14. package/src/cli/attach.js +331 -331
  15. package/src/cli/auto.js +265 -265
  16. package/src/cli/comments.js +620 -620
  17. package/src/cli/config.js +170 -170
  18. package/src/cli/db-import.js +51 -51
  19. package/src/cli/explore.js +555 -555
  20. package/src/cli/open.js +109 -111
  21. package/src/cli/progress.js +111 -111
  22. package/src/cli/refresh.js +288 -288
  23. package/src/cli/scrape.js +47 -47
  24. package/src/cli/utils.js +18 -18
  25. package/src/cli/videos.js +41 -41
  26. package/src/cli/videostats.js +196 -196
  27. package/src/cli/watch.js +30 -30
  28. package/src/lib/api-interceptor.js +161 -161
  29. package/src/lib/args.js +809 -809
  30. package/src/lib/browser/anti-detect.js +23 -23
  31. package/src/lib/browser/cdp.js +261 -261
  32. package/src/lib/browser/health-checker.js +114 -114
  33. package/src/lib/browser/launch.js +43 -43
  34. package/src/lib/browser/page.js +184 -184
  35. package/src/lib/constants.js +297 -297
  36. package/src/lib/delay.js +54 -54
  37. package/src/lib/explore-fetch.js +118 -118
  38. package/src/lib/fetcher.js +45 -45
  39. package/src/lib/filter.js +66 -66
  40. package/src/lib/io.js +54 -54
  41. package/src/lib/output.js +80 -80
  42. package/src/lib/page-error-detector.js +109 -109
  43. package/src/lib/parse-ssr.mjs +69 -69
  44. package/src/lib/parser.js +47 -47
  45. package/src/lib/retry.js +45 -45
  46. package/src/lib/scrape.js +90 -90
  47. package/src/lib/target-locations.js +61 -61
  48. package/src/lib/tiktok-scraper.mjs +98 -61
  49. package/src/lib/url.js +52 -52
  50. package/src/main.js +73 -73
  51. package/src/npm-main.js +70 -70
  52. package/src/results/user-videos-bar.lar.lar.moeta.json +37 -0
  53. package/src/scraper/auto-core.js +203 -203
  54. package/src/scraper/core.js +255 -255
  55. package/src/scraper/explore-core.js +208 -208
  56. package/src/scraper/modules/captcha-handler.js +114 -114
  57. package/src/scraper/modules/follow-extractor.js +250 -250
  58. package/src/scraper/modules/guess-extractor.js +51 -51
  59. package/src/scraper/modules/page-helpers.js +48 -48
  60. package/src/scraper/refresh-core.js +213 -213
  61. package/src/videos/core.js +143 -143
  62. package/src/watch/data-store.js +2980 -2980
  63. package/src/watch/public/index.html +2355 -2355
  64. package/src/watch/server.js +727 -727
package/src/lib/args.js CHANGED
@@ -1,809 +1,809 @@
1
- import { readFileSync } from "fs";
2
- import { server as defaultServer } from "./constants.js";
3
- import { DEFAULT_TARGET_LOCATIONS_CSV } from "./target-locations.js";
4
-
5
- const PRESETS = ["fast", "normal", "slow", "stealth"];
6
-
7
- function parseScrapeArgs(args) {
8
- let scrapeUrl = null;
9
- let scrapePreset = null;
10
- let scrapeMaxVideos = 20;
11
- let scrapeMaxComments = 999;
12
- let scrapeMaxGuess = 10;
13
- let scrapeSwitchDelay = null;
14
- let scrapeCommentDelay = null;
15
- let outputFile = null;
16
-
17
- const positional = [];
18
-
19
- for (let i = 0; i < args.length; i++) {
20
- const arg = args[i];
21
- if (arg === "-o" || arg === "--output") {
22
- outputFile = args[++i];
23
- } else if (arg === "--switch-delay") {
24
- scrapeSwitchDelay = parseInt(args[++i]) || null;
25
- } else if (arg === "--comment-delay") {
26
- scrapeCommentDelay = parseInt(args[++i]) || null;
27
- } else {
28
- positional.push(arg);
29
- }
30
- }
31
-
32
- scrapeUrl = positional[0] || null;
33
-
34
- if (positional[1]) {
35
- if (PRESETS.includes(positional[1].toLowerCase())) {
36
- scrapePreset = positional[1].toLowerCase();
37
- scrapeMaxVideos = parseInt(positional[2]) || 20;
38
- scrapeMaxComments = parseInt(positional[3]) || 999;
39
- scrapeMaxGuess = parseInt(positional[4]) || 10;
40
- } else {
41
- scrapeMaxVideos = parseInt(positional[1]) || 20;
42
- scrapeMaxComments = parseInt(positional[2]) || 999;
43
- scrapeMaxGuess = parseInt(positional[3]) || 10;
44
- }
45
- }
46
-
47
- return {
48
- subcommand: "scrape",
49
- scrapeUrl,
50
- scrapePreset,
51
- scrapeMaxVideos,
52
- scrapeMaxComments,
53
- scrapeMaxGuess,
54
- scrapeSwitchDelay,
55
- scrapeCommentDelay,
56
- outputFile,
57
- urls: [],
58
- outputFormat: "json",
59
- exploreCount: 0,
60
- showConfig: false,
61
- showHelp: false,
62
- customProxy: null,
63
- configAction: null,
64
- configValue: null,
65
- pipeMode: false,
66
- filterStr: null,
67
- };
68
- }
69
-
70
- function parseAutoArgs(args) {
71
- let autoCollectMax = 1;
72
- let autoScrapeDepth = 50;
73
- let autoMaxComments = 200;
74
- let autoMaxGuess = 10;
75
- let autoPreset = "fast";
76
- let autoSwitchDelay = null;
77
- let autoCommentDelay = null;
78
- let serverUrl = defaultServer;
79
- let autoEnableFollow = false;
80
- let autoMaxFollowing = 200;
81
- let autoMaxFollowers = 200;
82
-
83
- const positional = [];
84
- const PRESETS = ["fast", "normal", "slow", "stealth"];
85
-
86
- for (let i = 0; i < args.length; i++) {
87
- const arg = args[i];
88
- if (arg === "--server") {
89
- serverUrl = args[++i];
90
- } else if (arg === "--switch-delay") {
91
- autoSwitchDelay = parseInt(args[++i]) || null;
92
- } else if (arg === "--comment-delay") {
93
- autoCommentDelay = parseInt(args[++i]) || null;
94
- } else if (arg === "--enable-follow") {
95
- autoEnableFollow = true;
96
- } else if (arg === "--max-following") {
97
- autoMaxFollowing = parseInt(args[++i]) || 200;
98
- } else if (arg === "--max-followers") {
99
- autoMaxFollowers = parseInt(args[++i]) || 200;
100
- } else {
101
- positional.push(arg);
102
- }
103
- }
104
-
105
- // 收集用户名(非 preset、非数字的都是用户名)
106
- const usernames = [];
107
- let j = 0;
108
- while (
109
- j < positional.length &&
110
- !PRESETS.includes(positional[j]?.toLowerCase()) &&
111
- isNaN(positional[j])
112
- ) {
113
- usernames.push(positional[j].replace("@", ""));
114
- j++;
115
- }
116
-
117
- // preset
118
- if (j < positional.length && PRESETS.includes(positional[j].toLowerCase())) {
119
- autoPreset = positional[j].toLowerCase();
120
- j++;
121
- autoCollectMax = parseInt(positional[j]) || 1;
122
- j++;
123
- autoScrapeDepth = parseInt(positional[j]) || 50;
124
- j++;
125
- autoMaxComments = parseInt(positional[j]) || 200;
126
- j++;
127
- autoMaxGuess = parseInt(positional[j]) || 10;
128
- j++;
129
- } else if (usernames.length > 0) {
130
- autoCollectMax = parseInt(positional[j]) || 1;
131
- j++;
132
- autoScrapeDepth = parseInt(positional[j]) || 50;
133
- j++;
134
- autoMaxComments = parseInt(positional[j]) || 200;
135
- j++;
136
- autoMaxGuess = parseInt(positional[j]) || 10;
137
- }
138
-
139
- return {
140
- subcommand: "auto",
141
- autoUsernames: usernames,
142
- autoCollectMax,
143
- autoScrapeDepth,
144
- autoMaxComments,
145
- autoMaxGuess,
146
- autoPreset,
147
- autoSwitchDelay,
148
- autoCommentDelay,
149
- serverUrl,
150
- autoEnableFollow,
151
- autoMaxFollowing,
152
- autoMaxFollowers,
153
- urls: [],
154
- outputFormat: "json",
155
- exploreCount: 0,
156
- showConfig: false,
157
- showHelp: false,
158
- customProxy: null,
159
- configAction: null,
160
- configValue: null,
161
- pipeMode: false,
162
- filterStr: null,
163
- };
164
- }
165
-
166
- function parseExploreArgs(args) {
167
- let serverUrl = defaultServer;
168
- let explorePreset = "normal";
169
- let exploreInterval = 10;
170
- let exploreMaxComments = 10;
171
- let exploreMaxGuess = 0;
172
- let exploreEnableFollow = true;
173
- let exploreMaxFollowing = 50;
174
- let exploreMaxFollowers = 50;
175
- let exploreLocation = DEFAULT_TARGET_LOCATIONS_CSV;
176
- let exploreJobLocations = null;
177
- let exploreMaxUsers = 0;
178
- let explorePort = null;
179
- let exploreBasePort = null;
180
- let explorePortCount = null;
181
- let exploreUserId = null;
182
- let exploreMaxVideos = 16;
183
-
184
- const positional = [];
185
- const PRESETS = ["fast", "normal", "slow", "stealth"];
186
-
187
- for (let i = 0; i < args.length; i++) {
188
- const arg = args[i];
189
- if (arg === "--server") {
190
- serverUrl = args[++i];
191
- } else if (arg === "-i" || arg === "--interval") {
192
- exploreInterval = parseInt(args[++i], 10) || 10;
193
- } else if (arg === "--max-comments") {
194
- exploreMaxComments = parseInt(args[++i]) || 0;
195
- } else if (arg === "--max-guess") {
196
- exploreMaxGuess = parseInt(args[++i]) || 0;
197
- } else if (arg === "--location") {
198
- exploreLocation = args[++i];
199
- } else if (arg === "--job-locations") {
200
- exploreJobLocations = args[++i];
201
- } else if (arg === "--enable-follow") {
202
- exploreEnableFollow = true;
203
- } else if (arg === "--disable-follow") {
204
- exploreEnableFollow = false;
205
- } else if (arg === "--max-following") {
206
- exploreMaxFollowing = parseInt(args[++i]) || 50;
207
- } else if (arg === "--max-followers") {
208
- exploreMaxFollowers = parseInt(args[++i]) || 50;
209
- } else if (arg === "--max-users") {
210
- exploreMaxUsers = parseInt(args[++i]) || 0;
211
- } else if (arg === "--port") {
212
- explorePort = parseInt(args[++i]) || 9222;
213
- } else if (arg === "--base-port") {
214
- exploreBasePort = parseInt(args[++i]) || 9222;
215
- } else if (arg === "--port-count") {
216
- explorePortCount = parseInt(args[++i]) || 10;
217
- } else if (arg === "--user-id") {
218
- exploreUserId = args[++i];
219
- } else if (arg === "--max-videos") {
220
- exploreMaxVideos = parseInt(args[++i]) || 16;
221
- } else {
222
- positional.push(arg);
223
- }
224
- }
225
-
226
- const usernames = [];
227
- let j = 0;
228
- while (
229
- j < positional.length &&
230
- !PRESETS.includes(positional[j]?.toLowerCase()) &&
231
- isNaN(positional[j])
232
- ) {
233
- usernames.push(positional[j].replace("@", ""));
234
- j++;
235
- }
236
-
237
- if (j < positional.length && PRESETS.includes(positional[j].toLowerCase())) {
238
- explorePreset = positional[j].toLowerCase();
239
- j++;
240
- }
241
-
242
- return {
243
- subcommand: "explore",
244
- exploreUsernames: usernames,
245
- explorePreset,
246
- exploreInterval,
247
- exploreMaxComments,
248
- exploreMaxGuess,
249
- exploreEnableFollow,
250
- exploreMaxFollowing,
251
- exploreMaxFollowers,
252
- exploreLocation,
253
- exploreJobLocations,
254
- serverUrl,
255
- exploreMaxUsers,
256
- explorePort,
257
- exploreBasePort,
258
- explorePortCount,
259
- exploreUserId,
260
- exploreMaxVideos,
261
- urls: [],
262
- outputFormat: "json",
263
- exploreCount: 0,
264
- showConfig: false,
265
- showHelp: false,
266
- customProxy: null,
267
- configAction: null,
268
- configValue: null,
269
- pipeMode: false,
270
- filterStr: null,
271
- };
272
- }
273
-
274
- function parseVideosArgs(args) {
275
- let videosUsername = null;
276
- let videosMax = 5;
277
- let outputFile = null;
278
-
279
- const positional = [];
280
-
281
- for (let i = 0; i < args.length; i++) {
282
- const arg = args[i];
283
- if (arg === "-o" || arg === "--output") {
284
- outputFile = args[++i];
285
- } else {
286
- positional.push(arg);
287
- }
288
- }
289
-
290
- videosUsername = positional[0] ? positional[0].replace("@", "") : null;
291
- videosMax = parseInt(positional[1]) || 5;
292
-
293
- return {
294
- subcommand: "videos",
295
- videosUsername,
296
- videosMax,
297
- outputFile,
298
- urls: [],
299
- outputFormat: "json",
300
- exploreCount: 0,
301
- showConfig: false,
302
- showHelp: false,
303
- customProxy: null,
304
- configAction: null,
305
- configValue: null,
306
- pipeMode: false,
307
- filterStr: null,
308
- };
309
- }
310
-
311
- function parseInfoArgs(args) {
312
- let onlyVideo = false;
313
- const urls = [];
314
-
315
- for (let i = 0; i < args.length; i++) {
316
- const arg = args[i];
317
- if (arg === "--onlyvideo") {
318
- onlyVideo = true;
319
- } else if (!arg.startsWith("--")) {
320
- urls.push(arg);
321
- }
322
- }
323
-
324
- return {
325
- subcommand: "info",
326
- infoUrls: urls,
327
- infoOnlyVideo: onlyVideo,
328
- outputFile: null,
329
- outputFormat: "json",
330
- exploreCount: 0,
331
- showConfig: false,
332
- showHelp: false,
333
- showVersion: false,
334
- customProxy: null,
335
- configAction: null,
336
- configKey: null,
337
- configValue: null,
338
- pipeMode: false,
339
- filterStr: null,
340
- };
341
- }
342
-
343
- function parseWatchArgs(args) {
344
- let dataAnchor = "./result.db";
345
- let watchPort = 3001;
346
-
347
- for (let i = 0; i < args.length; i++) {
348
- const arg = args[i];
349
- if (arg === "-o" || arg === "--output") {
350
- dataAnchor = args[++i];
351
- } else if (arg === "-p") {
352
- watchPort = parseInt(args[++i]) || 3001;
353
- }
354
- }
355
-
356
- return {
357
- subcommand: "watch",
358
- outputFile: dataAnchor,
359
- dataAnchor,
360
- watchPort,
361
- urls: [],
362
- outputFormat: "json",
363
- exploreCount: 0,
364
- showConfig: false,
365
- showHelp: false,
366
- customProxy: null,
367
- configAction: null,
368
- configValue: null,
369
- pipeMode: false,
370
- filterStr: null,
371
- };
372
- }
373
-
374
- function parseWebserverArgs(args) {
375
- let webserverPort = 3000;
376
-
377
- for (let i = 0; i < args.length; i++) {
378
- const arg = args[i];
379
- if (arg === "-p" || arg === "--port") {
380
- webserverPort = parseInt(args[++i]) || 3000;
381
- }
382
- }
383
-
384
- return {
385
- subcommand: "webserver",
386
- webserverPort,
387
- urls: [],
388
- outputFile: null,
389
- outputFormat: "json",
390
- exploreCount: 0,
391
- showConfig: false,
392
- showHelp: false,
393
- customProxy: null,
394
- configAction: null,
395
- configValue: null,
396
- pipeMode: false,
397
- filterStr: null,
398
- };
399
- }
400
-
401
- function parseDbImportArgs(args) {
402
- let dbPath = "./result.db";
403
- let usersFilePath = null;
404
- let doneFilePath = null;
405
- let videosFilePath = null;
406
-
407
- for (let i = 0; i < args.length; i++) {
408
- const arg = args[i];
409
- if (arg === "--db") {
410
- dbPath = args[++i] || dbPath;
411
- } else if (arg === "--users") {
412
- usersFilePath = args[++i] || null;
413
- } else if (arg === "--done") {
414
- doneFilePath = args[++i] || null;
415
- } else if (arg === "--videos") {
416
- videosFilePath = args[++i] || null;
417
- }
418
- }
419
-
420
- return {
421
- subcommand: "db-import",
422
- dbPath,
423
- usersFilePath,
424
- doneFilePath,
425
- videosFilePath,
426
- urls: [],
427
- outputFormat: "json",
428
- exploreCount: 0,
429
- showConfig: false,
430
- showHelp: false,
431
- customProxy: null,
432
- configAction: null,
433
- configValue: null,
434
- pipeMode: false,
435
- filterStr: null,
436
- };
437
- }
438
-
439
- function parseRefreshArgs(args) {
440
- let serverUrl = defaultServer;
441
- let explorePreset = "normal";
442
- let exploreMaxComments = 10;
443
- let exploreMaxGuess = 0;
444
- let explorePort = null;
445
- let exploreProfile = null;
446
- let exploreUserId = null;
447
-
448
- for (let i = 0; i < args.length; i++) {
449
- const arg = args[i];
450
- if (arg === "--server") {
451
- serverUrl = args[++i];
452
- } else if (arg === "--comments") {
453
- exploreMaxComments = parseInt(args[++i]) || 10;
454
- } else if (arg === "--guess") {
455
- exploreMaxGuess = parseInt(args[++i]) || 0;
456
- } else if (arg === "--preset") {
457
- explorePreset = args[++i];
458
- } else if (arg === "--port") {
459
- explorePort = parseInt(args[++i]) || 9222;
460
- } else if (arg === "--profile") {
461
- exploreProfile = args[++i];
462
- } else if (arg === "--user-id") {
463
- exploreUserId = args[++i];
464
- }
465
- }
466
-
467
- return {
468
- subcommand: "refresh",
469
- explorePreset,
470
- exploreMaxComments,
471
- exploreMaxGuess,
472
- explorePort,
473
- exploreProfile,
474
- exploreUserId,
475
- serverUrl,
476
- urls: [],
477
- outputFormat: "json",
478
- exploreCount: 0,
479
- showConfig: false,
480
- showHelp: false,
481
- customProxy: null,
482
- configAction: null,
483
- configValue: null,
484
- pipeMode: false,
485
- filterStr: null,
486
- };
487
- }
488
-
489
- function parseAttachArgs(args) {
490
- let parallel = 1;
491
- let interval = 10;
492
- let serverUrl = defaultServer;
493
- let countries = [];
494
-
495
- for (let i = 0; i < args.length; i++) {
496
- const arg = args[i];
497
- if (arg === "-p" || arg === "--parallel") {
498
- parallel = parseInt(args[++i], 10) || 1;
499
- } else if (arg === "-i" || arg === "--interval") {
500
- interval = parseInt(args[++i], 10) || 10;
501
- } else if (arg === "-s" || arg === "--server") {
502
- serverUrl = args[++i];
503
- } else if (arg === "-c" || arg === "--countries") {
504
- countries = args[++i]
505
- .split(",")
506
- .map((c) => c.trim().toUpperCase())
507
- .filter(Boolean);
508
- }
509
- }
510
-
511
- return {
512
- subcommand: "attach",
513
- attachParallel: parallel,
514
- attachInterval: interval,
515
- serverUrl,
516
- attachCountries: countries,
517
- urls: [],
518
- outputFormat: "json",
519
- exploreCount: 0,
520
- showConfig: false,
521
- showHelp: false,
522
- customProxy: null,
523
- configAction: null,
524
- configValue: null,
525
- pipeMode: false,
526
- filterStr: null,
527
- };
528
- }
529
-
530
- function parseOpenArgs(args) {
531
- let openPort = null;
532
- let openList = false;
533
-
534
- for (let i = 0; i < args.length; i++) {
535
- const arg = args[i];
536
- if (arg === "--list") {
537
- openList = true;
538
- } else if (!arg.startsWith("-")) {
539
- openPort = arg;
540
- }
541
- }
542
-
543
- return {
544
- subcommand: "open",
545
- openPort,
546
- openList,
547
- urls: [],
548
- outputFormat: "json",
549
- exploreCount: 0,
550
- showConfig: false,
551
- showHelp: false,
552
- customProxy: null,
553
- configAction: null,
554
- configValue: null,
555
- pipeMode: false,
556
- filterStr: null,
557
- };
558
- }
559
-
560
- function parseVideoStatsArgs(args) {
561
- let statsSource = null;
562
- let statsParallel = 3;
563
-
564
- for (let i = 0; i < args.length; i++) {
565
- const arg = args[i];
566
- if (arg === "-p" || arg === "--parallel") {
567
- statsParallel = parseInt(args[++i]) || 3;
568
- } else if (!arg.startsWith("-")) {
569
- statsSource = args[i] || null;
570
- }
571
- }
572
-
573
- return {
574
- subcommand: "videostats",
575
- statsFile: statsSource,
576
- statsSource,
577
- statsParallel,
578
- commentsUrl: null,
579
- commentsMax: 20,
580
- commentsSave: false,
581
- commentsParallel: 1,
582
- commentsInterval: 10,
583
- commentsServer: defaultServer,
584
- urls: [],
585
- outputFormat: "json",
586
- exploreCount: 0,
587
- showConfig: false,
588
- showHelp: false,
589
- customProxy: null,
590
- configAction: null,
591
- configValue: null,
592
- pipeMode: false,
593
- filterStr: null,
594
- };
595
- }
596
-
597
- function parseCommentsArgs(args) {
598
- let commentsUrl = null;
599
- let commentsMax = 20;
600
- let commentsSave = false;
601
- let commentsParallel = 1;
602
- let commentsInterval = 10;
603
- let commentsServer = defaultServer;
604
-
605
- const positional = [];
606
-
607
- for (let i = 0; i < args.length; i++) {
608
- const arg = args[i];
609
- if (arg === "--save") {
610
- commentsSave = true;
611
- } else if (arg === "-p" || arg === "--parallel") {
612
- commentsParallel = parseInt(args[++i]) || 1;
613
- } else if (arg === "-i" || arg === "--interval") {
614
- commentsInterval = parseInt(args[++i]) || 10;
615
- } else if (arg === "-s" || arg === "--server") {
616
- commentsServer = args[++i];
617
- } else if (arg === "-m" || arg === "--max-comments") {
618
- commentsMax = parseInt(args[++i]) || 20;
619
- } else {
620
- positional.push(arg);
621
- }
622
- }
623
-
624
- commentsUrl = positional[0] || null;
625
- if (positional[1]) {
626
- commentsMax = parseInt(positional[1]) || 20;
627
- }
628
-
629
- return {
630
- subcommand: "comments",
631
- commentsUrl,
632
- commentsMax,
633
- commentsSave,
634
- commentsParallel,
635
- commentsInterval,
636
- commentsServer,
637
- urls: [],
638
- outputFormat: "json",
639
- exploreCount: 0,
640
- showConfig: false,
641
- showHelp: false,
642
- customProxy: null,
643
- configAction: null,
644
- configValue: null,
645
- pipeMode: false,
646
- filterStr: null,
647
- };
648
- }
649
-
650
- export function parseArgs() {
651
- const args = process.argv.slice(2);
652
-
653
- if (args.includes("-h") || args.includes("--help")) {
654
- return {
655
- showHelp: true,
656
- showVersion: false,
657
- subcommand: null,
658
- urls: [],
659
- outputFile: null,
660
- outputFormat: "json",
661
- exploreCount: 0,
662
- showConfig: false,
663
- customProxy: null,
664
- configAction: null,
665
- configValue: null,
666
- pipeMode: false,
667
- filterStr: null,
668
- };
669
- }
670
- if (args.includes("--version")) {
671
- return {
672
- showHelp: false,
673
- showVersion: true,
674
- subcommand: null,
675
- urls: [],
676
- outputFile: null,
677
- outputFormat: "json",
678
- exploreCount: 0,
679
- showConfig: false,
680
- customProxy: null,
681
- configAction: null,
682
- configValue: null,
683
- pipeMode: false,
684
- filterStr: null,
685
- };
686
- }
687
-
688
- if (args.length > 0 && args[0] === "explore") {
689
- return parseExploreArgs(args.slice(1));
690
- }
691
-
692
- if (args.length > 0 && args[0] === "info") {
693
- return parseInfoArgs(args.slice(1));
694
- }
695
-
696
- if (args.length > 0 && args[0] === "watch") {
697
- return parseWatchArgs(args.slice(1));
698
- }
699
-
700
- if (args.length > 0 && args[0] === "webserver") {
701
- return parseWebserverArgs(args.slice(1));
702
- }
703
-
704
- if (args.length > 0 && args[0] === "attach") {
705
- return parseAttachArgs(args.slice(1));
706
- }
707
-
708
- if (args.length > 0 && args[0] === "open") {
709
- return parseOpenArgs(args.slice(1));
710
- }
711
-
712
- if (args.length > 0 && args[0] === "comments") {
713
- return parseCommentsArgs(args.slice(1));
714
- }
715
-
716
- if (args.length > 0 && args[0] === "videostats") {
717
- return parseVideoStatsArgs(args.slice(1));
718
- }
719
-
720
- if (args.length > 0 && args[0] === "db-import") {
721
- return parseDbImportArgs(args.slice(1));
722
- }
723
-
724
- const urls = [];
725
- let inputFile = null;
726
- let outputFile = null;
727
- let outputFormat = "json";
728
- let exploreCount = 0;
729
- let showConfig = false;
730
- let showHelp = false;
731
- let showVersion = false;
732
- let customProxy = null;
733
- let configAction = null;
734
- let configKey = null;
735
- let configValue = null;
736
- let pipeMode = false;
737
- let filterStr = null;
738
-
739
- for (let i = 0; i < args.length; i++) {
740
- const arg = args[i];
741
-
742
- if (arg === "--explore") {
743
- exploreCount =
744
- args[i + 1] && !args[i + 1].startsWith("http")
745
- ? parseInt(args[++i], 10)
746
- : 100;
747
- } else if (arg === "--proxy") {
748
- customProxy = args[++i];
749
- } else if (arg === "--filter") {
750
- filterStr = args[++i];
751
- } else if (arg === "config") {
752
- configAction = args[i + 1];
753
- if (!configAction) {
754
- configAction = "show";
755
- } else if (
756
- configAction === "set" ||
757
- configAction === "set-proxy" ||
758
- configAction === "set-browser"
759
- ) {
760
- configKey = args[i + 2];
761
- configValue = args[i + 3];
762
- i += 3;
763
- } else {
764
- i++;
765
- }
766
- } else if (arg === "--pipe") {
767
- pipeMode = true;
768
- } else if (arg === "-i" || arg === "--input") {
769
- inputFile = args[++i];
770
- } else if (arg === "-o" || arg === "--output") {
771
- outputFile = args[++i];
772
- } else if (arg === "-f" || arg === "--format") {
773
- outputFormat = args[++i];
774
- } else if (arg === "-c" || arg === "--config") {
775
- showConfig = true;
776
- } else if (arg === "-h" || arg === "--help") {
777
- showHelp = true;
778
- } else if (arg === "--version") {
779
- showVersion = true;
780
- } else if (arg.startsWith("http")) {
781
- urls.push(arg);
782
- }
783
- }
784
-
785
- if (inputFile) {
786
- const content = readFileSync(inputFile, "utf-8");
787
- const lines = content
788
- .split(/\r?\n/)
789
- .map((l) => l.trim())
790
- .filter((l) => l.startsWith("http"));
791
- urls.push(...lines);
792
- }
793
-
794
- return {
795
- urls,
796
- outputFile,
797
- outputFormat,
798
- exploreCount,
799
- showConfig,
800
- showHelp,
801
- showVersion,
802
- customProxy,
803
- configAction,
804
- configKey,
805
- configValue,
806
- pipeMode,
807
- filterStr,
808
- };
809
- }
1
+ import { readFileSync } from "fs";
2
+ import { server as defaultServer } from "./constants.js";
3
+ import { DEFAULT_TARGET_LOCATIONS_CSV } from "./target-locations.js";
4
+
5
+ const PRESETS = ["fast", "normal", "slow", "stealth"];
6
+
7
+ function parseScrapeArgs(args) {
8
+ let scrapeUrl = null;
9
+ let scrapePreset = null;
10
+ let scrapeMaxVideos = 20;
11
+ let scrapeMaxComments = 999;
12
+ let scrapeMaxGuess = 10;
13
+ let scrapeSwitchDelay = null;
14
+ let scrapeCommentDelay = null;
15
+ let outputFile = null;
16
+
17
+ const positional = [];
18
+
19
+ for (let i = 0; i < args.length; i++) {
20
+ const arg = args[i];
21
+ if (arg === "-o" || arg === "--output") {
22
+ outputFile = args[++i];
23
+ } else if (arg === "--switch-delay") {
24
+ scrapeSwitchDelay = parseInt(args[++i]) || null;
25
+ } else if (arg === "--comment-delay") {
26
+ scrapeCommentDelay = parseInt(args[++i]) || null;
27
+ } else {
28
+ positional.push(arg);
29
+ }
30
+ }
31
+
32
+ scrapeUrl = positional[0] || null;
33
+
34
+ if (positional[1]) {
35
+ if (PRESETS.includes(positional[1].toLowerCase())) {
36
+ scrapePreset = positional[1].toLowerCase();
37
+ scrapeMaxVideos = parseInt(positional[2]) || 20;
38
+ scrapeMaxComments = parseInt(positional[3]) || 999;
39
+ scrapeMaxGuess = parseInt(positional[4]) || 10;
40
+ } else {
41
+ scrapeMaxVideos = parseInt(positional[1]) || 20;
42
+ scrapeMaxComments = parseInt(positional[2]) || 999;
43
+ scrapeMaxGuess = parseInt(positional[3]) || 10;
44
+ }
45
+ }
46
+
47
+ return {
48
+ subcommand: "scrape",
49
+ scrapeUrl,
50
+ scrapePreset,
51
+ scrapeMaxVideos,
52
+ scrapeMaxComments,
53
+ scrapeMaxGuess,
54
+ scrapeSwitchDelay,
55
+ scrapeCommentDelay,
56
+ outputFile,
57
+ urls: [],
58
+ outputFormat: "json",
59
+ exploreCount: 0,
60
+ showConfig: false,
61
+ showHelp: false,
62
+ customProxy: null,
63
+ configAction: null,
64
+ configValue: null,
65
+ pipeMode: false,
66
+ filterStr: null,
67
+ };
68
+ }
69
+
70
+ function parseAutoArgs(args) {
71
+ let autoCollectMax = 1;
72
+ let autoScrapeDepth = 50;
73
+ let autoMaxComments = 200;
74
+ let autoMaxGuess = 10;
75
+ let autoPreset = "fast";
76
+ let autoSwitchDelay = null;
77
+ let autoCommentDelay = null;
78
+ let serverUrl = defaultServer;
79
+ let autoEnableFollow = false;
80
+ let autoMaxFollowing = 200;
81
+ let autoMaxFollowers = 200;
82
+
83
+ const positional = [];
84
+ const PRESETS = ["fast", "normal", "slow", "stealth"];
85
+
86
+ for (let i = 0; i < args.length; i++) {
87
+ const arg = args[i];
88
+ if (arg === "--server") {
89
+ serverUrl = args[++i];
90
+ } else if (arg === "--switch-delay") {
91
+ autoSwitchDelay = parseInt(args[++i]) || null;
92
+ } else if (arg === "--comment-delay") {
93
+ autoCommentDelay = parseInt(args[++i]) || null;
94
+ } else if (arg === "--enable-follow") {
95
+ autoEnableFollow = true;
96
+ } else if (arg === "--max-following") {
97
+ autoMaxFollowing = parseInt(args[++i]) || 200;
98
+ } else if (arg === "--max-followers") {
99
+ autoMaxFollowers = parseInt(args[++i]) || 200;
100
+ } else {
101
+ positional.push(arg);
102
+ }
103
+ }
104
+
105
+ // 收集用户名(非 preset、非数字的都是用户名)
106
+ const usernames = [];
107
+ let j = 0;
108
+ while (
109
+ j < positional.length &&
110
+ !PRESETS.includes(positional[j]?.toLowerCase()) &&
111
+ isNaN(positional[j])
112
+ ) {
113
+ usernames.push(positional[j].replace("@", ""));
114
+ j++;
115
+ }
116
+
117
+ // preset
118
+ if (j < positional.length && PRESETS.includes(positional[j].toLowerCase())) {
119
+ autoPreset = positional[j].toLowerCase();
120
+ j++;
121
+ autoCollectMax = parseInt(positional[j]) || 1;
122
+ j++;
123
+ autoScrapeDepth = parseInt(positional[j]) || 50;
124
+ j++;
125
+ autoMaxComments = parseInt(positional[j]) || 200;
126
+ j++;
127
+ autoMaxGuess = parseInt(positional[j]) || 10;
128
+ j++;
129
+ } else if (usernames.length > 0) {
130
+ autoCollectMax = parseInt(positional[j]) || 1;
131
+ j++;
132
+ autoScrapeDepth = parseInt(positional[j]) || 50;
133
+ j++;
134
+ autoMaxComments = parseInt(positional[j]) || 200;
135
+ j++;
136
+ autoMaxGuess = parseInt(positional[j]) || 10;
137
+ }
138
+
139
+ return {
140
+ subcommand: "auto",
141
+ autoUsernames: usernames,
142
+ autoCollectMax,
143
+ autoScrapeDepth,
144
+ autoMaxComments,
145
+ autoMaxGuess,
146
+ autoPreset,
147
+ autoSwitchDelay,
148
+ autoCommentDelay,
149
+ serverUrl,
150
+ autoEnableFollow,
151
+ autoMaxFollowing,
152
+ autoMaxFollowers,
153
+ urls: [],
154
+ outputFormat: "json",
155
+ exploreCount: 0,
156
+ showConfig: false,
157
+ showHelp: false,
158
+ customProxy: null,
159
+ configAction: null,
160
+ configValue: null,
161
+ pipeMode: false,
162
+ filterStr: null,
163
+ };
164
+ }
165
+
166
+ function parseExploreArgs(args) {
167
+ let serverUrl = defaultServer;
168
+ let explorePreset = "normal";
169
+ let exploreInterval = 10;
170
+ let exploreMaxComments = 10;
171
+ let exploreMaxGuess = 0;
172
+ let exploreEnableFollow = true;
173
+ let exploreMaxFollowing = 50;
174
+ let exploreMaxFollowers = 50;
175
+ let exploreLocation = DEFAULT_TARGET_LOCATIONS_CSV;
176
+ let exploreJobLocations = null;
177
+ let exploreMaxUsers = 0;
178
+ let explorePort = null;
179
+ let exploreBasePort = null;
180
+ let explorePortCount = null;
181
+ let exploreUserId = null;
182
+ let exploreMaxVideos = 16;
183
+
184
+ const positional = [];
185
+ const PRESETS = ["fast", "normal", "slow", "stealth"];
186
+
187
+ for (let i = 0; i < args.length; i++) {
188
+ const arg = args[i];
189
+ if (arg === "--server") {
190
+ serverUrl = args[++i];
191
+ } else if (arg === "-i" || arg === "--interval") {
192
+ exploreInterval = parseInt(args[++i], 10) || 10;
193
+ } else if (arg === "--max-comments") {
194
+ exploreMaxComments = parseInt(args[++i]) || 0;
195
+ } else if (arg === "--max-guess") {
196
+ exploreMaxGuess = parseInt(args[++i]) || 0;
197
+ } else if (arg === "--location") {
198
+ exploreLocation = args[++i];
199
+ } else if (arg === "--job-locations") {
200
+ exploreJobLocations = args[++i];
201
+ } else if (arg === "--enable-follow") {
202
+ exploreEnableFollow = true;
203
+ } else if (arg === "--disable-follow") {
204
+ exploreEnableFollow = false;
205
+ } else if (arg === "--max-following") {
206
+ exploreMaxFollowing = parseInt(args[++i]) || 50;
207
+ } else if (arg === "--max-followers") {
208
+ exploreMaxFollowers = parseInt(args[++i]) || 50;
209
+ } else if (arg === "--max-users") {
210
+ exploreMaxUsers = parseInt(args[++i]) || 0;
211
+ } else if (arg === "--port") {
212
+ explorePort = parseInt(args[++i]) || 9222;
213
+ } else if (arg === "--base-port") {
214
+ exploreBasePort = parseInt(args[++i]) || 9222;
215
+ } else if (arg === "--port-count") {
216
+ explorePortCount = parseInt(args[++i]) || 10;
217
+ } else if (arg === "--user-id") {
218
+ exploreUserId = args[++i];
219
+ } else if (arg === "--max-videos") {
220
+ exploreMaxVideos = parseInt(args[++i]) || 16;
221
+ } else {
222
+ positional.push(arg);
223
+ }
224
+ }
225
+
226
+ const usernames = [];
227
+ let j = 0;
228
+ while (
229
+ j < positional.length &&
230
+ !PRESETS.includes(positional[j]?.toLowerCase()) &&
231
+ isNaN(positional[j])
232
+ ) {
233
+ usernames.push(positional[j].replace("@", ""));
234
+ j++;
235
+ }
236
+
237
+ if (j < positional.length && PRESETS.includes(positional[j].toLowerCase())) {
238
+ explorePreset = positional[j].toLowerCase();
239
+ j++;
240
+ }
241
+
242
+ return {
243
+ subcommand: "explore",
244
+ exploreUsernames: usernames,
245
+ explorePreset,
246
+ exploreInterval,
247
+ exploreMaxComments,
248
+ exploreMaxGuess,
249
+ exploreEnableFollow,
250
+ exploreMaxFollowing,
251
+ exploreMaxFollowers,
252
+ exploreLocation,
253
+ exploreJobLocations,
254
+ serverUrl,
255
+ exploreMaxUsers,
256
+ explorePort,
257
+ exploreBasePort,
258
+ explorePortCount,
259
+ exploreUserId,
260
+ exploreMaxVideos,
261
+ urls: [],
262
+ outputFormat: "json",
263
+ exploreCount: 0,
264
+ showConfig: false,
265
+ showHelp: false,
266
+ customProxy: null,
267
+ configAction: null,
268
+ configValue: null,
269
+ pipeMode: false,
270
+ filterStr: null,
271
+ };
272
+ }
273
+
274
+ function parseVideosArgs(args) {
275
+ let videosUsername = null;
276
+ let videosMax = 5;
277
+ let outputFile = null;
278
+
279
+ const positional = [];
280
+
281
+ for (let i = 0; i < args.length; i++) {
282
+ const arg = args[i];
283
+ if (arg === "-o" || arg === "--output") {
284
+ outputFile = args[++i];
285
+ } else {
286
+ positional.push(arg);
287
+ }
288
+ }
289
+
290
+ videosUsername = positional[0] ? positional[0].replace("@", "") : null;
291
+ videosMax = parseInt(positional[1]) || 5;
292
+
293
+ return {
294
+ subcommand: "videos",
295
+ videosUsername,
296
+ videosMax,
297
+ outputFile,
298
+ urls: [],
299
+ outputFormat: "json",
300
+ exploreCount: 0,
301
+ showConfig: false,
302
+ showHelp: false,
303
+ customProxy: null,
304
+ configAction: null,
305
+ configValue: null,
306
+ pipeMode: false,
307
+ filterStr: null,
308
+ };
309
+ }
310
+
311
+ function parseInfoArgs(args) {
312
+ let onlyVideo = false;
313
+ const urls = [];
314
+
315
+ for (let i = 0; i < args.length; i++) {
316
+ const arg = args[i];
317
+ if (arg === "--onlyvideo") {
318
+ onlyVideo = true;
319
+ } else if (!arg.startsWith("--")) {
320
+ urls.push(arg);
321
+ }
322
+ }
323
+
324
+ return {
325
+ subcommand: "info",
326
+ infoUrls: urls,
327
+ infoOnlyVideo: onlyVideo,
328
+ outputFile: null,
329
+ outputFormat: "json",
330
+ exploreCount: 0,
331
+ showConfig: false,
332
+ showHelp: false,
333
+ showVersion: false,
334
+ customProxy: null,
335
+ configAction: null,
336
+ configKey: null,
337
+ configValue: null,
338
+ pipeMode: false,
339
+ filterStr: null,
340
+ };
341
+ }
342
+
343
+ function parseWatchArgs(args) {
344
+ let dataAnchor = "./result.db";
345
+ let watchPort = 3001;
346
+
347
+ for (let i = 0; i < args.length; i++) {
348
+ const arg = args[i];
349
+ if (arg === "-o" || arg === "--output") {
350
+ dataAnchor = args[++i];
351
+ } else if (arg === "-p") {
352
+ watchPort = parseInt(args[++i]) || 3001;
353
+ }
354
+ }
355
+
356
+ return {
357
+ subcommand: "watch",
358
+ outputFile: dataAnchor,
359
+ dataAnchor,
360
+ watchPort,
361
+ urls: [],
362
+ outputFormat: "json",
363
+ exploreCount: 0,
364
+ showConfig: false,
365
+ showHelp: false,
366
+ customProxy: null,
367
+ configAction: null,
368
+ configValue: null,
369
+ pipeMode: false,
370
+ filterStr: null,
371
+ };
372
+ }
373
+
374
+ function parseWebserverArgs(args) {
375
+ let webserverPort = 3000;
376
+
377
+ for (let i = 0; i < args.length; i++) {
378
+ const arg = args[i];
379
+ if (arg === "-p" || arg === "--port") {
380
+ webserverPort = parseInt(args[++i]) || 3000;
381
+ }
382
+ }
383
+
384
+ return {
385
+ subcommand: "webserver",
386
+ webserverPort,
387
+ urls: [],
388
+ outputFile: null,
389
+ outputFormat: "json",
390
+ exploreCount: 0,
391
+ showConfig: false,
392
+ showHelp: false,
393
+ customProxy: null,
394
+ configAction: null,
395
+ configValue: null,
396
+ pipeMode: false,
397
+ filterStr: null,
398
+ };
399
+ }
400
+
401
+ function parseDbImportArgs(args) {
402
+ let dbPath = "./result.db";
403
+ let usersFilePath = null;
404
+ let doneFilePath = null;
405
+ let videosFilePath = null;
406
+
407
+ for (let i = 0; i < args.length; i++) {
408
+ const arg = args[i];
409
+ if (arg === "--db") {
410
+ dbPath = args[++i] || dbPath;
411
+ } else if (arg === "--users") {
412
+ usersFilePath = args[++i] || null;
413
+ } else if (arg === "--done") {
414
+ doneFilePath = args[++i] || null;
415
+ } else if (arg === "--videos") {
416
+ videosFilePath = args[++i] || null;
417
+ }
418
+ }
419
+
420
+ return {
421
+ subcommand: "db-import",
422
+ dbPath,
423
+ usersFilePath,
424
+ doneFilePath,
425
+ videosFilePath,
426
+ urls: [],
427
+ outputFormat: "json",
428
+ exploreCount: 0,
429
+ showConfig: false,
430
+ showHelp: false,
431
+ customProxy: null,
432
+ configAction: null,
433
+ configValue: null,
434
+ pipeMode: false,
435
+ filterStr: null,
436
+ };
437
+ }
438
+
439
+ function parseRefreshArgs(args) {
440
+ let serverUrl = defaultServer;
441
+ let explorePreset = "normal";
442
+ let exploreMaxComments = 10;
443
+ let exploreMaxGuess = 0;
444
+ let explorePort = null;
445
+ let exploreProfile = null;
446
+ let exploreUserId = null;
447
+
448
+ for (let i = 0; i < args.length; i++) {
449
+ const arg = args[i];
450
+ if (arg === "--server") {
451
+ serverUrl = args[++i];
452
+ } else if (arg === "--comments") {
453
+ exploreMaxComments = parseInt(args[++i]) || 10;
454
+ } else if (arg === "--guess") {
455
+ exploreMaxGuess = parseInt(args[++i]) || 0;
456
+ } else if (arg === "--preset") {
457
+ explorePreset = args[++i];
458
+ } else if (arg === "--port") {
459
+ explorePort = parseInt(args[++i]) || 9222;
460
+ } else if (arg === "--profile") {
461
+ exploreProfile = args[++i];
462
+ } else if (arg === "--user-id") {
463
+ exploreUserId = args[++i];
464
+ }
465
+ }
466
+
467
+ return {
468
+ subcommand: "refresh",
469
+ explorePreset,
470
+ exploreMaxComments,
471
+ exploreMaxGuess,
472
+ explorePort,
473
+ exploreProfile,
474
+ exploreUserId,
475
+ serverUrl,
476
+ urls: [],
477
+ outputFormat: "json",
478
+ exploreCount: 0,
479
+ showConfig: false,
480
+ showHelp: false,
481
+ customProxy: null,
482
+ configAction: null,
483
+ configValue: null,
484
+ pipeMode: false,
485
+ filterStr: null,
486
+ };
487
+ }
488
+
489
+ function parseAttachArgs(args) {
490
+ let parallel = 1;
491
+ let interval = 10;
492
+ let serverUrl = defaultServer;
493
+ let countries = [];
494
+
495
+ for (let i = 0; i < args.length; i++) {
496
+ const arg = args[i];
497
+ if (arg === "-p" || arg === "--parallel") {
498
+ parallel = parseInt(args[++i], 10) || 1;
499
+ } else if (arg === "-i" || arg === "--interval") {
500
+ interval = parseInt(args[++i], 10) || 10;
501
+ } else if (arg === "-s" || arg === "--server") {
502
+ serverUrl = args[++i];
503
+ } else if (arg === "-c" || arg === "--countries") {
504
+ countries = args[++i]
505
+ .split(",")
506
+ .map((c) => c.trim().toUpperCase())
507
+ .filter(Boolean);
508
+ }
509
+ }
510
+
511
+ return {
512
+ subcommand: "attach",
513
+ attachParallel: parallel,
514
+ attachInterval: interval,
515
+ serverUrl,
516
+ attachCountries: countries,
517
+ urls: [],
518
+ outputFormat: "json",
519
+ exploreCount: 0,
520
+ showConfig: false,
521
+ showHelp: false,
522
+ customProxy: null,
523
+ configAction: null,
524
+ configValue: null,
525
+ pipeMode: false,
526
+ filterStr: null,
527
+ };
528
+ }
529
+
530
+ function parseOpenArgs(args) {
531
+ let openPort = null;
532
+ let openList = false;
533
+
534
+ for (let i = 0; i < args.length; i++) {
535
+ const arg = args[i];
536
+ if (arg === "--list") {
537
+ openList = true;
538
+ } else if (!arg.startsWith("-")) {
539
+ openPort = arg;
540
+ }
541
+ }
542
+
543
+ return {
544
+ subcommand: "open",
545
+ openPort,
546
+ openList,
547
+ urls: [],
548
+ outputFormat: "json",
549
+ exploreCount: 0,
550
+ showConfig: false,
551
+ showHelp: false,
552
+ customProxy: null,
553
+ configAction: null,
554
+ configValue: null,
555
+ pipeMode: false,
556
+ filterStr: null,
557
+ };
558
+ }
559
+
560
+ function parseVideoStatsArgs(args) {
561
+ let statsSource = null;
562
+ let statsParallel = 3;
563
+
564
+ for (let i = 0; i < args.length; i++) {
565
+ const arg = args[i];
566
+ if (arg === "-p" || arg === "--parallel") {
567
+ statsParallel = parseInt(args[++i]) || 3;
568
+ } else if (!arg.startsWith("-")) {
569
+ statsSource = args[i] || null;
570
+ }
571
+ }
572
+
573
+ return {
574
+ subcommand: "videostats",
575
+ statsFile: statsSource,
576
+ statsSource,
577
+ statsParallel,
578
+ commentsUrl: null,
579
+ commentsMax: 20,
580
+ commentsSave: false,
581
+ commentsParallel: 1,
582
+ commentsInterval: 10,
583
+ commentsServer: defaultServer,
584
+ urls: [],
585
+ outputFormat: "json",
586
+ exploreCount: 0,
587
+ showConfig: false,
588
+ showHelp: false,
589
+ customProxy: null,
590
+ configAction: null,
591
+ configValue: null,
592
+ pipeMode: false,
593
+ filterStr: null,
594
+ };
595
+ }
596
+
597
+ function parseCommentsArgs(args) {
598
+ let commentsUrl = null;
599
+ let commentsMax = 20;
600
+ let commentsSave = false;
601
+ let commentsParallel = 1;
602
+ let commentsInterval = 10;
603
+ let commentsServer = defaultServer;
604
+
605
+ const positional = [];
606
+
607
+ for (let i = 0; i < args.length; i++) {
608
+ const arg = args[i];
609
+ if (arg === "--save") {
610
+ commentsSave = true;
611
+ } else if (arg === "-p" || arg === "--parallel") {
612
+ commentsParallel = parseInt(args[++i]) || 1;
613
+ } else if (arg === "-i" || arg === "--interval") {
614
+ commentsInterval = parseInt(args[++i]) || 10;
615
+ } else if (arg === "-s" || arg === "--server") {
616
+ commentsServer = args[++i];
617
+ } else if (arg === "-m" || arg === "--max-comments") {
618
+ commentsMax = parseInt(args[++i]) || 20;
619
+ } else {
620
+ positional.push(arg);
621
+ }
622
+ }
623
+
624
+ commentsUrl = positional[0] || null;
625
+ if (positional[1]) {
626
+ commentsMax = parseInt(positional[1]) || 20;
627
+ }
628
+
629
+ return {
630
+ subcommand: "comments",
631
+ commentsUrl,
632
+ commentsMax,
633
+ commentsSave,
634
+ commentsParallel,
635
+ commentsInterval,
636
+ commentsServer,
637
+ urls: [],
638
+ outputFormat: "json",
639
+ exploreCount: 0,
640
+ showConfig: false,
641
+ showHelp: false,
642
+ customProxy: null,
643
+ configAction: null,
644
+ configValue: null,
645
+ pipeMode: false,
646
+ filterStr: null,
647
+ };
648
+ }
649
+
650
+ export function parseArgs() {
651
+ const args = process.argv.slice(2);
652
+
653
+ if (args.includes("-h") || args.includes("--help")) {
654
+ return {
655
+ showHelp: true,
656
+ showVersion: false,
657
+ subcommand: null,
658
+ urls: [],
659
+ outputFile: null,
660
+ outputFormat: "json",
661
+ exploreCount: 0,
662
+ showConfig: false,
663
+ customProxy: null,
664
+ configAction: null,
665
+ configValue: null,
666
+ pipeMode: false,
667
+ filterStr: null,
668
+ };
669
+ }
670
+ if (args.includes("--version")) {
671
+ return {
672
+ showHelp: false,
673
+ showVersion: true,
674
+ subcommand: null,
675
+ urls: [],
676
+ outputFile: null,
677
+ outputFormat: "json",
678
+ exploreCount: 0,
679
+ showConfig: false,
680
+ customProxy: null,
681
+ configAction: null,
682
+ configValue: null,
683
+ pipeMode: false,
684
+ filterStr: null,
685
+ };
686
+ }
687
+
688
+ if (args.length > 0 && args[0] === "explore") {
689
+ return parseExploreArgs(args.slice(1));
690
+ }
691
+
692
+ if (args.length > 0 && args[0] === "info") {
693
+ return parseInfoArgs(args.slice(1));
694
+ }
695
+
696
+ if (args.length > 0 && args[0] === "watch") {
697
+ return parseWatchArgs(args.slice(1));
698
+ }
699
+
700
+ if (args.length > 0 && args[0] === "webserver") {
701
+ return parseWebserverArgs(args.slice(1));
702
+ }
703
+
704
+ if (args.length > 0 && args[0] === "attach") {
705
+ return parseAttachArgs(args.slice(1));
706
+ }
707
+
708
+ if (args.length > 0 && args[0] === "open") {
709
+ return parseOpenArgs(args.slice(1));
710
+ }
711
+
712
+ if (args.length > 0 && args[0] === "comments") {
713
+ return parseCommentsArgs(args.slice(1));
714
+ }
715
+
716
+ if (args.length > 0 && args[0] === "videostats") {
717
+ return parseVideoStatsArgs(args.slice(1));
718
+ }
719
+
720
+ if (args.length > 0 && args[0] === "db-import") {
721
+ return parseDbImportArgs(args.slice(1));
722
+ }
723
+
724
+ const urls = [];
725
+ let inputFile = null;
726
+ let outputFile = null;
727
+ let outputFormat = "json";
728
+ let exploreCount = 0;
729
+ let showConfig = false;
730
+ let showHelp = false;
731
+ let showVersion = false;
732
+ let customProxy = null;
733
+ let configAction = null;
734
+ let configKey = null;
735
+ let configValue = null;
736
+ let pipeMode = false;
737
+ let filterStr = null;
738
+
739
+ for (let i = 0; i < args.length; i++) {
740
+ const arg = args[i];
741
+
742
+ if (arg === "--explore") {
743
+ exploreCount =
744
+ args[i + 1] && !args[i + 1].startsWith("http")
745
+ ? parseInt(args[++i], 10)
746
+ : 100;
747
+ } else if (arg === "--proxy") {
748
+ customProxy = args[++i];
749
+ } else if (arg === "--filter") {
750
+ filterStr = args[++i];
751
+ } else if (arg === "config") {
752
+ configAction = args[i + 1];
753
+ if (!configAction) {
754
+ configAction = "show";
755
+ } else if (
756
+ configAction === "set" ||
757
+ configAction === "set-proxy" ||
758
+ configAction === "set-browser"
759
+ ) {
760
+ configKey = args[i + 2];
761
+ configValue = args[i + 3];
762
+ i += 3;
763
+ } else {
764
+ i++;
765
+ }
766
+ } else if (arg === "--pipe") {
767
+ pipeMode = true;
768
+ } else if (arg === "-i" || arg === "--input") {
769
+ inputFile = args[++i];
770
+ } else if (arg === "-o" || arg === "--output") {
771
+ outputFile = args[++i];
772
+ } else if (arg === "-f" || arg === "--format") {
773
+ outputFormat = args[++i];
774
+ } else if (arg === "-c" || arg === "--config") {
775
+ showConfig = true;
776
+ } else if (arg === "-h" || arg === "--help") {
777
+ showHelp = true;
778
+ } else if (arg === "--version") {
779
+ showVersion = true;
780
+ } else if (arg.startsWith("http")) {
781
+ urls.push(arg);
782
+ }
783
+ }
784
+
785
+ if (inputFile) {
786
+ const content = readFileSync(inputFile, "utf-8");
787
+ const lines = content
788
+ .split(/\r?\n/)
789
+ .map((l) => l.trim())
790
+ .filter((l) => l.startsWith("http"));
791
+ urls.push(...lines);
792
+ }
793
+
794
+ return {
795
+ urls,
796
+ outputFile,
797
+ outputFormat,
798
+ exploreCount,
799
+ showConfig,
800
+ showHelp,
801
+ showVersion,
802
+ customProxy,
803
+ configAction,
804
+ configKey,
805
+ configValue,
806
+ pipeMode,
807
+ filterStr,
808
+ };
809
+ }