@web-auto/webauto 0.1.4 → 0.1.6
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/apps/desktop-console/default-settings.json +2 -2
- package/apps/desktop-console/dist/main/index.mjs +915 -85
- package/apps/desktop-console/dist/main/preload.mjs +7 -0
- package/apps/desktop-console/dist/renderer/index.html +622 -50
- package/apps/desktop-console/dist/renderer/index.js +2415 -470
- package/apps/desktop-console/dist/renderer/run.mts +6 -5
- package/apps/desktop-console/entry/ui-cli.mjs +672 -0
- package/apps/desktop-console/entry/ui-console.mjs +416 -29
- package/apps/webauto/entry/account.mjs +89 -53
- package/apps/webauto/entry/browser-status.mjs +7 -10
- package/apps/webauto/entry/lib/account-detect.mjs +254 -28
- package/apps/webauto/entry/lib/account-store.mjs +219 -30
- package/apps/webauto/entry/lib/bus-publish.mjs +63 -0
- package/apps/webauto/entry/lib/camo-cli.mjs +93 -0
- package/apps/webauto/entry/lib/profilepool.mjs +14 -5
- package/apps/webauto/entry/lib/quota-status.mjs +23 -0
- package/apps/webauto/entry/lib/schedule-store.mjs +1068 -0
- package/apps/webauto/entry/profilepool.mjs +106 -17
- package/apps/webauto/entry/schedule.mjs +612 -0
- package/apps/webauto/entry/weibo-unified.mjs +134 -0
- package/apps/webauto/entry/xhs-install.mjs +236 -29
- package/apps/webauto/entry/xhs-status.mjs +5 -2
- package/apps/webauto/entry/xhs-unified.mjs +631 -98
- package/apps/webauto/resources/container-library/weibo/weibo_detail_page/comment_item/container.json +40 -0
- package/apps/webauto/resources/container-library/weibo/weibo_detail_page/reply_expand_button/container.json +38 -0
- package/apps/webauto/resources/container-library/weibo/weibo_detail_page/reply_list/container.json +37 -0
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/container.json +8 -3
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/login_anchor/container.json +30 -0
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/search_bar/container.json +47 -0
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/search_button/container.json +39 -0
- package/bin/camoufox-cli.mjs +61 -0
- package/bin/webauto.mjs +301 -54
- package/dist/modules/camo-backend/src/index.js +49 -1
- package/dist/modules/camo-backend/src/internal/BrowserSession.js +572 -3
- package/dist/modules/camo-backend/src/internal/SessionManager.js +13 -1
- package/dist/modules/camo-backend/src/internal/storage-paths.js +6 -0
- package/dist/modules/collection-manager/bloom-filter.js +91 -0
- package/dist/modules/collection-manager/date-utils.js +275 -0
- package/dist/modules/collection-manager/index.js +258 -0
- package/dist/modules/collection-manager/storage.js +195 -0
- package/dist/modules/collection-manager/types.js +47 -0
- package/dist/modules/logging/src/index.js +1 -1
- package/dist/modules/process-registry/index.js +230 -0
- package/dist/modules/rate-limiter/index.js +242 -0
- package/dist/modules/workflow/blocks/ExecuteWeiboSearchBlock.js +128 -0
- package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +7 -3
- package/dist/modules/workflow/blocks/RenderMarkdown.js +4 -1
- package/dist/modules/workflow/blocks/WeiboCollectCommentsBlock.js +282 -0
- package/dist/modules/workflow/blocks/WeiboCollectFromLinksBlock.js +283 -0
- package/dist/modules/workflow/blocks/WeiboCollectSearchLinksBlock.js +208 -0
- package/dist/modules/workflow/blocks/WeiboCollectTimelineListBlock.js +128 -0
- package/dist/modules/workflow/blocks/WeiboCollectUserPostsListBlock.js +127 -0
- package/dist/modules/workflow/blocks/helpers/downloadPaths.js +21 -0
- package/dist/modules/workflow/config/workflowRegistry.js +2 -0
- package/dist/modules/workflow/definitions/weibo-search-workflow-v1.js +47 -0
- package/dist/modules/workflow/src/runner.js +6 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +4 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +2 -2
- package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +123 -0
- package/dist/modules/xiaohongshu/app/src/container-registry/src/index.d.ts +37 -0
- package/dist/modules/xiaohongshu/app/src/container-registry/src/index.js +184 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/AnchorVerificationBlock.d.ts +31 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/AnchorVerificationBlock.js +71 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/DetectPageStateBlock.d.ts +48 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/DetectPageStateBlock.js +259 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/ErrorRecoveryBlock.d.ts +28 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/ErrorRecoveryBlock.js +319 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/WaitSearchPermitBlock.d.ts +36 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/WaitSearchPermitBlock.js +162 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/containerAnchors.d.ts +36 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/containerAnchors.js +301 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/operationLogger.d.ts +29 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/operationLogger.js +195 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/searchPageState.d.ts +25 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/searchPageState.js +164 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/MatchCommentsBlock.d.ts +66 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.d.ts +16 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.d.ts +27 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.d.ts +18 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.d.ts +34 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2SearchBlock.d.ts +17 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.d.ts +15 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.d.ts +26 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.d.ts +29 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.d.ts +38 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.d.ts +30 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.d.ts +23 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.d.ts +32 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.d.ts +35 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.d.ts +34 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase3InteractBlock.d.ts +111 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.d.ts +20 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/ReplyInteractBlock.d.ts +48 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.d.ts +23 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.d.ts +55 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatcher.d.ts +21 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/evidence.d.ts +5 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/sharding.d.ts +37 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/sharding.js +165 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/xhsComments.d.ts +33 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/index.d.ts +9 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/index.js +9 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/checkpoints.d.ts +50 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/checkpoints.js +222 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/controllerAction.d.ts +10 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/controllerAction.js +43 -0
- package/dist/services/shared/serviceProcessLogger.js +1 -1
- package/dist/services/unified-api/server.js +105 -11
- package/modules/camo-backend/src/index.ts +46 -1
- package/modules/camo-backend/src/internal/BrowserSession.ts +619 -3
- package/modules/camo-backend/src/internal/SessionManager.ts +12 -1
- package/modules/camo-backend/src/internal/storage-paths.ts +5 -0
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/comments.mjs +38 -2
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/interaction.mjs +47 -2
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +94 -11
- package/modules/camo-runtime/src/autoscript/action-providers/xhs.mjs +208 -2
- package/modules/camo-runtime/src/autoscript/runtime.mjs +7 -1
- package/modules/camo-runtime/src/autoscript/xhs-unified-template.mjs +76 -43
- package/modules/camo-runtime/src/container/runtime-core/operations/index.mjs +75 -1
- package/modules/camo-runtime/src/container/runtime-core/operations/selector-scripts.mjs +71 -4
- package/modules/camo-runtime/src/container/runtime-core/operations/tab-pool.mjs +183 -27
- package/modules/collection-manager/bloom-filter.ts +112 -0
- package/modules/collection-manager/date-utils.ts +316 -0
- package/modules/collection-manager/index.ts +309 -0
- package/modules/collection-manager/package.json +10 -0
- package/modules/collection-manager/storage.ts +174 -0
- package/modules/collection-manager/types.ts +156 -0
- package/modules/logging/src/index.ts +1 -1
- package/modules/process-registry/index.ts +284 -0
- package/modules/rate-limiter/index.ts +322 -0
- package/modules/state/src/paths.ts +9 -1
- package/modules/task-scheduler/index.ts +293 -0
- package/modules/workflow/blocks/ExecuteWeiboSearchBlock.ts +167 -0
- package/modules/workflow/blocks/PersistXhsNoteBlock.ts +7 -3
- package/modules/workflow/blocks/RenderMarkdown.ts +4 -1
- package/modules/workflow/blocks/WeiboCollectCommentsBlock.ts +339 -0
- package/modules/workflow/blocks/WeiboCollectFromLinksBlock.ts +338 -0
- package/modules/workflow/blocks/helpers/downloadPaths.ts +16 -0
- package/modules/workflow/config/workflowRegistry.ts +2 -0
- package/modules/workflow/definitions/weibo-search-workflow-v1.ts +47 -0
- package/modules/workflow/src/runner.ts +6 -0
- package/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.ts +1 -1
- package/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.ts +4 -0
- package/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.ts +2 -3
- package/modules/xiaohongshu/app/src/blocks/helpers/sharding.ts +152 -0
- package/package.json +13 -4
- package/scripts/postinstall-resources.mjs +62 -0
- package/scripts/test/run-coverage.mjs +76 -0
- package/scripts/weibo/search.ts +49 -0
- package/services/shared/serviceProcessLogger.ts +1 -1
- package/services/unified-api/server.ts +98 -12
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import minimist from 'minimist';
|
|
3
|
+
import { runWorkflowById } from '../../../dist/modules/workflow/src/runner.js';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const WEIBO_HOME_URL = 'https://www.weibo.com';
|
|
7
|
+
const DEFAULT_PROFILE = 'xiaohongshu-batch-1'; // Use shared profile for now
|
|
8
|
+
|
|
9
|
+
async function runCommand(argv) {
|
|
10
|
+
const profile = String(argv.profile || DEFAULT_PROFILE).trim();
|
|
11
|
+
if (!profile) {
|
|
12
|
+
throw new Error('Profile ID is required. Use --profile <id>');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const workflowId = String(argv.workflow || '').trim();
|
|
16
|
+
const keyword = String(argv.keyword || '').trim();
|
|
17
|
+
const targetCount = Number(argv['max-notes'] || argv.target || 50);
|
|
18
|
+
const maxComments = Number(argv['max-comments'] || 0); // 0 means no limit
|
|
19
|
+
|
|
20
|
+
if (!keyword && workflowId === 'weibo-search-v1') {
|
|
21
|
+
throw new Error('Keyword is required for search tasks. Use --keyword <text>');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const env = String(argv.env || 'debug').trim();
|
|
25
|
+
|
|
26
|
+
const initialContext = {
|
|
27
|
+
sessionId: profile,
|
|
28
|
+
keyword,
|
|
29
|
+
env,
|
|
30
|
+
targetCount,
|
|
31
|
+
maxComments,
|
|
32
|
+
// Add other common parameters as needed
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (!workflowId) {
|
|
36
|
+
throw new Error('Workflow ID is required. e.g., --workflow weibo-search-v1');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log(`[Weibo Unified] Running workflow: ${workflowId} with profile: ${profile}`);
|
|
40
|
+
const result = await runWorkflowById(workflowId, initialContext);
|
|
41
|
+
|
|
42
|
+
if (result.success) {
|
|
43
|
+
console.log(`[Weibo Unified] Workflow ${workflowId} completed successfully.`);
|
|
44
|
+
} else {
|
|
45
|
+
console.error(`[Weibo Unified] Workflow ${workflowId} failed: ${result.error}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function main() {
|
|
51
|
+
const argv = minimist(process.argv.slice(2), {
|
|
52
|
+
string: ['profile', 'keyword', 'env', 'workflow'],
|
|
53
|
+
boolean: ['help'],
|
|
54
|
+
alias: { k: 'keyword', t: 'target', h: 'help' },
|
|
55
|
+
default: {
|
|
56
|
+
profile: DEFAULT_PROFILE,
|
|
57
|
+
env: 'debug',
|
|
58
|
+
target: 50,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (argv.help) {
|
|
63
|
+
console.log(`
|
|
64
|
+
Usage: webauto weibo <command> [options]
|
|
65
|
+
|
|
66
|
+
Commands:
|
|
67
|
+
search Perform a Weibo search task.
|
|
68
|
+
|
|
69
|
+
Options:
|
|
70
|
+
--profile <id> Camo profile ID to use (default: ${DEFAULT_PROFILE})
|
|
71
|
+
--keyword <text> Keyword to search for (required for search command)
|
|
72
|
+
--target <n> Target number of posts to collect (default: 50)
|
|
73
|
+
--max-comments <n> Maximum comments to collect per post (default: 0, no limit)
|
|
74
|
+
--env <debug|prod> Environment for data storage (default: debug)
|
|
75
|
+
--help Show this help message
|
|
76
|
+
|
|
77
|
+
Examples:
|
|
78
|
+
webauto weibo search --keyword "AI" --target 100 --profile my-weibo-profile
|
|
79
|
+
webauto weibo search --keyword "大模型" --env prod
|
|
80
|
+
`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const command = argv._[0];
|
|
85
|
+
|
|
86
|
+
switch (command) {
|
|
87
|
+
case 'search':
|
|
88
|
+
await runCommand({ ...argv, workflow: 'weibo-search-v1' });
|
|
89
|
+
break;
|
|
90
|
+
default:
|
|
91
|
+
console.error(`Unknown command: ${command}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const isDirectExec =
|
|
97
|
+
process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
98
|
+
|
|
99
|
+
if (isDirectExec) {
|
|
100
|
+
main().catch((error) => {
|
|
101
|
+
console.error('Error in Weibo Unified:', error.message);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function runWeiboUnified(argv) {
|
|
107
|
+
const workflowId = String(argv.workflow || 'weibo-search-v1').trim();
|
|
108
|
+
const keyword = String(argv.keyword || argv.k || '').trim();
|
|
109
|
+
const profile = String(argv.profile || 'xiaohongshu-batch-1').trim();
|
|
110
|
+
const targetCount = Number(argv['max-notes'] || argv.target || argv['max-notes'] || 50);
|
|
111
|
+
const maxComments = Number(argv['max-comments'] || 0);
|
|
112
|
+
const env = String(argv.env || 'debug').trim();
|
|
113
|
+
|
|
114
|
+
if (!keyword) {
|
|
115
|
+
throw new Error('Keyword is required for Weibo search tasks. Use --keyword <text>');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const initialContext = {
|
|
119
|
+
sessionId: profile,
|
|
120
|
+
keyword,
|
|
121
|
+
env,
|
|
122
|
+
targetCount,
|
|
123
|
+
maxComments,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const result = await runWorkflowById(workflowId, initialContext);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
ok: result.success,
|
|
130
|
+
runId: `weibo-${Date.now()}`,
|
|
131
|
+
summaryPath: null,
|
|
132
|
+
error: result.error,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -3,20 +3,83 @@ import minimist from 'minimist';
|
|
|
3
3
|
import { spawnSync } from 'node:child_process';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import { existsSync } from 'node:fs';
|
|
6
|
+
import { existsSync, rmSync } from 'node:fs';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
7
8
|
|
|
8
9
|
function run(cmd, args) {
|
|
9
|
-
|
|
10
|
+
const lower = String(cmd || '').toLowerCase();
|
|
11
|
+
const spawnOptions = {
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
windowsHide: true,
|
|
14
|
+
timeout: 120000,
|
|
15
|
+
};
|
|
16
|
+
if (process.platform === 'win32' && (lower.endsWith('.cmd') || lower.endsWith('.bat'))) {
|
|
17
|
+
const cmdLine = [quoteCmdArg(cmd), ...args.map(quoteCmdArg)].join(' ');
|
|
18
|
+
return spawnSync('cmd.exe', ['/d', '/s', '/c', cmdLine], spawnOptions);
|
|
19
|
+
}
|
|
20
|
+
if (process.platform === 'win32' && lower.endsWith('.ps1')) {
|
|
21
|
+
return spawnSync(
|
|
22
|
+
'powershell.exe',
|
|
23
|
+
['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', cmd, ...args],
|
|
24
|
+
spawnOptions,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return spawnSync(cmd, args, spawnOptions);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function quoteCmdArg(value) {
|
|
31
|
+
if (!value) return '""';
|
|
32
|
+
if (!/[\s"]/u.test(value)) return value;
|
|
33
|
+
return `"${String(value).replace(/"/g, '""')}"`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveOnPath(candidates, pathEnv = process.env.PATH || process.env.Path || '', delimiter = path.delimiter) {
|
|
37
|
+
const dirs = String(pathEnv)
|
|
38
|
+
.split(delimiter)
|
|
39
|
+
.map((x) => x.trim())
|
|
40
|
+
.filter(Boolean);
|
|
41
|
+
for (const dir of dirs) {
|
|
42
|
+
for (const name of candidates) {
|
|
43
|
+
const full = path.join(dir, name);
|
|
44
|
+
if (existsSync(full)) return full;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function resolveNpxBin(platform = process.platform, pathEnv = process.env.PATH || process.env.Path || '') {
|
|
51
|
+
if (platform !== 'win32') return 'npx';
|
|
52
|
+
const resolved = resolveOnPath(
|
|
53
|
+
['npx.cmd', 'npx.exe', 'npx.bat', 'npx.ps1'],
|
|
54
|
+
pathEnv,
|
|
55
|
+
';',
|
|
56
|
+
);
|
|
57
|
+
return resolved || 'npx.cmd';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveWebautoRoot() {
|
|
61
|
+
const portableRoot = String(process.env.WEBAUTO_PORTABLE_ROOT || process.env.WEBAUTO_ROOT || '').trim();
|
|
62
|
+
if (portableRoot) return path.join(portableRoot, '.webauto');
|
|
63
|
+
return path.join(os.homedir(), '.webauto');
|
|
10
64
|
}
|
|
11
65
|
|
|
12
|
-
function
|
|
13
|
-
return
|
|
66
|
+
function resolveGeoIPPath() {
|
|
67
|
+
return path.join(resolveWebautoRoot(), 'geoip', 'GeoLite2-City.mmdb');
|
|
14
68
|
}
|
|
15
69
|
|
|
16
70
|
function checkCamoufoxInstalled() {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
71
|
+
const candidates =
|
|
72
|
+
process.platform === 'win32'
|
|
73
|
+
? [
|
|
74
|
+
{ cmd: 'python', args: ['-m', 'camoufox', 'path'] },
|
|
75
|
+
{ cmd: 'py', args: ['-3', '-m', 'camoufox', 'path'] },
|
|
76
|
+
]
|
|
77
|
+
: [{ cmd: 'python3', args: ['-m', 'camoufox', 'path'] }];
|
|
78
|
+
for (const candidate of candidates) {
|
|
79
|
+
const ret = run(candidate.cmd, candidate.args);
|
|
80
|
+
if (ret.status === 0) return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
20
83
|
}
|
|
21
84
|
|
|
22
85
|
function installCamoufox() {
|
|
@@ -25,7 +88,7 @@ function installCamoufox() {
|
|
|
25
88
|
}
|
|
26
89
|
|
|
27
90
|
function checkGeoIPInstalled() {
|
|
28
|
-
return existsSync(
|
|
91
|
+
return existsSync(resolveGeoIPPath());
|
|
29
92
|
}
|
|
30
93
|
|
|
31
94
|
function installGeoIP() {
|
|
@@ -33,6 +96,50 @@ function installGeoIP() {
|
|
|
33
96
|
return ret.status === 0;
|
|
34
97
|
}
|
|
35
98
|
|
|
99
|
+
function uninstallCamoufox() {
|
|
100
|
+
const ret = run(resolveNpxBin(), ['--yes', '--package=camoufox', 'camoufox', 'remove']);
|
|
101
|
+
return ret.status === 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function uninstallGeoIP() {
|
|
105
|
+
const geoipDir = path.join(resolveWebautoRoot(), 'geoip');
|
|
106
|
+
try {
|
|
107
|
+
rmSync(geoipDir, { recursive: true, force: true });
|
|
108
|
+
} catch {
|
|
109
|
+
// ignore
|
|
110
|
+
}
|
|
111
|
+
return !checkGeoIPInstalled();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function resolveModeAndSelection(argv = {}) {
|
|
115
|
+
const legacyDownloadBrowser = argv['download-browser'] === true;
|
|
116
|
+
const legacyDownloadGeoip = argv['download-geoip'] === true;
|
|
117
|
+
const checkBrowserOnly = argv['check-browser-only'] === true;
|
|
118
|
+
|
|
119
|
+
let mode = 'check';
|
|
120
|
+
if (argv.auto === true) mode = 'auto';
|
|
121
|
+
else if (argv.reinstall === true) mode = 'reinstall';
|
|
122
|
+
else if (argv.uninstall === true || argv.remove === true) mode = 'uninstall';
|
|
123
|
+
else if (argv.install === true || legacyDownloadBrowser || legacyDownloadGeoip) mode = 'install';
|
|
124
|
+
|
|
125
|
+
const explicitBrowser = argv.browser === true || legacyDownloadBrowser || checkBrowserOnly;
|
|
126
|
+
const explicitGeoip = argv.geoip === true || legacyDownloadGeoip;
|
|
127
|
+
const explicitAll = argv.all === true;
|
|
128
|
+
const explicitAny = explicitBrowser || explicitGeoip || explicitAll;
|
|
129
|
+
|
|
130
|
+
let browser = false;
|
|
131
|
+
let geoip = false;
|
|
132
|
+
if (mode === 'check') {
|
|
133
|
+
browser = explicitBrowser || explicitAll || !explicitAny;
|
|
134
|
+
geoip = explicitGeoip || explicitAll;
|
|
135
|
+
} else {
|
|
136
|
+
browser = explicitBrowser || explicitAll || !explicitAny;
|
|
137
|
+
geoip = explicitGeoip || explicitAll || !explicitAny;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return { mode, browser, geoip };
|
|
141
|
+
}
|
|
142
|
+
|
|
36
143
|
async function checkBackendHealth() {
|
|
37
144
|
try {
|
|
38
145
|
const res = await fetch('http://127.0.0.1:7704/health', { signal: AbortSignal.timeout(3000) });
|
|
@@ -43,19 +150,79 @@ async function checkBackendHealth() {
|
|
|
43
150
|
}
|
|
44
151
|
|
|
45
152
|
async function main() {
|
|
46
|
-
const argv = minimist(process.argv.slice(2)
|
|
47
|
-
|
|
48
|
-
|
|
153
|
+
const argv = minimist(process.argv.slice(2), {
|
|
154
|
+
boolean: [
|
|
155
|
+
'auto',
|
|
156
|
+
'install',
|
|
157
|
+
'uninstall',
|
|
158
|
+
'remove',
|
|
159
|
+
'reinstall',
|
|
160
|
+
'check-browser-only',
|
|
161
|
+
'download-browser',
|
|
162
|
+
'download-geoip',
|
|
163
|
+
'browser',
|
|
164
|
+
'geoip',
|
|
165
|
+
'all',
|
|
166
|
+
'ensure-backend',
|
|
167
|
+
'json',
|
|
168
|
+
],
|
|
169
|
+
});
|
|
170
|
+
const { mode, browser, geoip } = resolveModeAndSelection(argv);
|
|
49
171
|
const ensureBackend = argv['ensure-backend'] === true;
|
|
50
172
|
const provider = String(process.env.WEBAUTO_BROWSER_PROVIDER || 'camo').trim().toLowerCase();
|
|
51
|
-
|
|
52
|
-
|
|
173
|
+
const before = {
|
|
174
|
+
camoufoxInstalled: checkCamoufoxInstalled(),
|
|
175
|
+
geoipInstalled: checkGeoIPInstalled(),
|
|
176
|
+
backendHealthy: await checkBackendHealth(),
|
|
177
|
+
};
|
|
178
|
+
const actions = {
|
|
179
|
+
browserInstalled: false,
|
|
180
|
+
browserUninstalled: false,
|
|
181
|
+
geoipInstalled: false,
|
|
182
|
+
geoipUninstalled: false,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
let camoufoxInstalled = before.camoufoxInstalled;
|
|
186
|
+
let geoipInstalled = before.geoipInstalled;
|
|
187
|
+
let operationError = null;
|
|
188
|
+
|
|
189
|
+
if (mode === 'auto' || mode === 'install') {
|
|
190
|
+
if (browser && !camoufoxInstalled) {
|
|
191
|
+
actions.browserInstalled = installCamoufox();
|
|
192
|
+
camoufoxInstalled = checkCamoufoxInstalled();
|
|
193
|
+
if (!camoufoxInstalled) operationError = operationError || 'camoufox_install_failed';
|
|
194
|
+
}
|
|
195
|
+
if (geoip && !geoipInstalled) {
|
|
196
|
+
actions.geoipInstalled = installGeoIP();
|
|
197
|
+
geoipInstalled = checkGeoIPInstalled();
|
|
198
|
+
if (!geoipInstalled) operationError = operationError || 'geoip_install_failed';
|
|
199
|
+
}
|
|
200
|
+
}
|
|
53
201
|
|
|
54
|
-
if (
|
|
55
|
-
|
|
202
|
+
if (mode === 'uninstall' || mode === 'reinstall') {
|
|
203
|
+
if (browser) {
|
|
204
|
+
actions.browserUninstalled = uninstallCamoufox();
|
|
205
|
+
camoufoxInstalled = checkCamoufoxInstalled();
|
|
206
|
+
if (camoufoxInstalled) operationError = operationError || 'camoufox_uninstall_failed';
|
|
207
|
+
}
|
|
208
|
+
if (geoip) {
|
|
209
|
+
actions.geoipUninstalled = uninstallGeoIP();
|
|
210
|
+
geoipInstalled = checkGeoIPInstalled();
|
|
211
|
+
if (geoipInstalled) operationError = operationError || 'geoip_uninstall_failed';
|
|
212
|
+
}
|
|
56
213
|
}
|
|
57
|
-
|
|
58
|
-
|
|
214
|
+
|
|
215
|
+
if (mode === 'reinstall') {
|
|
216
|
+
if (browser) {
|
|
217
|
+
actions.browserInstalled = installCamoufox();
|
|
218
|
+
camoufoxInstalled = checkCamoufoxInstalled();
|
|
219
|
+
if (!camoufoxInstalled) operationError = operationError || 'camoufox_install_failed';
|
|
220
|
+
}
|
|
221
|
+
if (geoip) {
|
|
222
|
+
actions.geoipInstalled = installGeoIP();
|
|
223
|
+
geoipInstalled = checkGeoIPInstalled();
|
|
224
|
+
if (!geoipInstalled) operationError = operationError || 'geoip_install_failed';
|
|
225
|
+
}
|
|
59
226
|
}
|
|
60
227
|
|
|
61
228
|
let backendEnsured = false;
|
|
@@ -70,27 +237,67 @@ async function main() {
|
|
|
70
237
|
}
|
|
71
238
|
}
|
|
72
239
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
240
|
+
const after = {
|
|
241
|
+
camoufoxInstalled,
|
|
242
|
+
geoipInstalled,
|
|
243
|
+
backendHealthy: await checkBackendHealth(),
|
|
244
|
+
};
|
|
245
|
+
const browserReady =
|
|
246
|
+
mode === 'uninstall'
|
|
247
|
+
? !browser || !after.camoufoxInstalled
|
|
248
|
+
: !browser || after.camoufoxInstalled || after.backendHealthy;
|
|
249
|
+
const geoipReady = mode === 'uninstall' ? !geoip || !after.geoipInstalled : !geoip || after.geoipInstalled;
|
|
250
|
+
const ok =
|
|
251
|
+
browserReady &&
|
|
252
|
+
geoipReady &&
|
|
253
|
+
operationError === null &&
|
|
254
|
+
(!ensureBackend || backendEnsured || after.backendHealthy);
|
|
77
255
|
|
|
78
256
|
const result = {
|
|
79
257
|
ok,
|
|
80
|
-
|
|
258
|
+
mode,
|
|
259
|
+
selection: {
|
|
260
|
+
browser,
|
|
261
|
+
geoip,
|
|
262
|
+
ensureBackend,
|
|
263
|
+
},
|
|
264
|
+
before,
|
|
265
|
+
actions,
|
|
266
|
+
after,
|
|
267
|
+
camoufoxInstalled: after.camoufoxInstalled,
|
|
81
268
|
provider,
|
|
82
269
|
backendEnsured,
|
|
83
270
|
ensureBackendError,
|
|
84
|
-
backendHealthy,
|
|
85
|
-
geoipInstalled,
|
|
86
|
-
|
|
271
|
+
backendHealthy: after.backendHealthy,
|
|
272
|
+
geoipInstalled: after.geoipInstalled,
|
|
273
|
+
operationError,
|
|
274
|
+
message: ok
|
|
275
|
+
? '资源状态就绪'
|
|
276
|
+
: operationError
|
|
277
|
+
? `资源操作失败: ${operationError}`
|
|
278
|
+
: browser && !after.camoufoxInstalled
|
|
279
|
+
? 'Camoufox 未安装'
|
|
280
|
+
: geoip && !after.geoipInstalled
|
|
281
|
+
? 'GeoIP 未安装'
|
|
282
|
+
: '资源状态未就绪',
|
|
87
283
|
};
|
|
88
284
|
|
|
89
285
|
console.log(JSON.stringify(result));
|
|
90
286
|
if (!ok) process.exit(1);
|
|
91
287
|
}
|
|
92
288
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
});
|
|
289
|
+
const isEntrypoint = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
290
|
+
if (isEntrypoint) {
|
|
291
|
+
main().catch((err) => {
|
|
292
|
+
console.error(JSON.stringify({ ok: false, error: err?.message || String(err) }));
|
|
293
|
+
process.exit(1);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export const __internals = {
|
|
298
|
+
resolveOnPath,
|
|
299
|
+
resolveNpxBin,
|
|
300
|
+
resolveWebautoRoot,
|
|
301
|
+
resolveGeoIPPath,
|
|
302
|
+
resolveModeAndSelection,
|
|
303
|
+
};
|
|
@@ -33,6 +33,9 @@ function summarizeTasks(tasks = []) {
|
|
|
33
33
|
const rows = tasks.map((task) => {
|
|
34
34
|
const runId = asText(task?.runId || task?.id || '');
|
|
35
35
|
const status = asText(task?.status || 'unknown').toLowerCase();
|
|
36
|
+
const progressPayload = task?.progress && typeof task.progress === 'object' ? task.progress : null;
|
|
37
|
+
const processed = Number(progressPayload?.processed ?? task?.progress ?? task?.current ?? 0) || 0;
|
|
38
|
+
const total = Number(progressPayload?.total ?? task?.total ?? 0) || 0;
|
|
36
39
|
if (status === 'running' || status === 'starting') totals.running += 1;
|
|
37
40
|
else if (status === 'queued' || status === 'pending') totals.queued += 1;
|
|
38
41
|
else if (status === 'completed' || status === 'success' || status === 'succeeded') totals.succeeded += 1;
|
|
@@ -43,8 +46,8 @@ function summarizeTasks(tasks = []) {
|
|
|
43
46
|
runId,
|
|
44
47
|
status,
|
|
45
48
|
phase: asText(task?.phase || task?.lastPhase || ''),
|
|
46
|
-
progress:
|
|
47
|
-
total
|
|
49
|
+
progress: processed,
|
|
50
|
+
total,
|
|
48
51
|
updatedAt: asText(task?.updatedAt || task?.lastActiveAt || ''),
|
|
49
52
|
error: asText(task?.error || ''),
|
|
50
53
|
};
|