dsh-web-search-pro 0.1.0
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/LICENSE +21 -0
- package/LOGIN.md +67 -0
- package/README.md +123 -0
- package/cordis.patch.yml +21 -0
- package/lib/browser-service.d.ts +68 -0
- package/lib/browser-service.js +8 -0
- package/lib/browser-service.js.map +1 -0
- package/lib/config.d.ts +91 -0
- package/lib/config.js +72 -0
- package/lib/config.js.map +1 -0
- package/lib/deps.d.ts +34 -0
- package/lib/deps.js +90 -0
- package/lib/deps.js.map +1 -0
- package/lib/engines.d.ts +71 -0
- package/lib/engines.js +562 -0
- package/lib/engines.js.map +1 -0
- package/lib/extract.d.ts +40 -0
- package/lib/extract.js +243 -0
- package/lib/extract.js.map +1 -0
- package/lib/fetch.d.ts +42 -0
- package/lib/fetch.js +175 -0
- package/lib/fetch.js.map +1 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.js +117 -0
- package/lib/index.js.map +1 -0
- package/lib/memory-cache.d.ts +18 -0
- package/lib/memory-cache.js +42 -0
- package/lib/memory-cache.js.map +1 -0
- package/lib/platform-search.d.ts +34 -0
- package/lib/platform-search.js +61 -0
- package/lib/platform-search.js.map +1 -0
- package/lib/playwright.d.ts +71 -0
- package/lib/playwright.js +165 -0
- package/lib/playwright.js.map +1 -0
- package/lib/router.d.ts +66 -0
- package/lib/router.js +332 -0
- package/lib/router.js.map +1 -0
- package/lib/store.d.ts +117 -0
- package/lib/store.js +223 -0
- package/lib/store.js.map +1 -0
- package/lib/tools.d.ts +28 -0
- package/lib/tools.js +542 -0
- package/lib/tools.js.map +1 -0
- package/lib/util.d.ts +73 -0
- package/lib/util.js +220 -0
- package/lib/util.js.map +1 -0
- package/package.json +59 -0
- package/scripts/save-login.mjs +77 -0
package/lib/util.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the dsh-web-search-pro plugin (published bundle).
|
|
3
|
+
* Dependencies (js-yaml, jsdom) are normal npm imports; playwright resolves
|
|
4
|
+
* from the global npm root or config playwright.modulePath.
|
|
5
|
+
* @module dsh-web-search-pro/util
|
|
6
|
+
*/
|
|
7
|
+
/** js-yaml parser (npm dep). */
|
|
8
|
+
export declare const jsYaml: {
|
|
9
|
+
load(input: string): unknown;
|
|
10
|
+
};
|
|
11
|
+
/** jsdom constructor (npm dep) for HTML parsing in extraction rules. */
|
|
12
|
+
export declare const jsdom: {
|
|
13
|
+
new (html: string, options?: Record<string, unknown>): {
|
|
14
|
+
window: {
|
|
15
|
+
document: any;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
/** Resolve the playwright module: explicit config path first, then the global npm root. */
|
|
20
|
+
export declare function resolvePlaywright(modulePath?: string): any;
|
|
21
|
+
/** npm root -g, computed once. */
|
|
22
|
+
export declare function globalNpmRoot(): string;
|
|
23
|
+
export declare function uid(): string;
|
|
24
|
+
export declare function sha1(input: string): string;
|
|
25
|
+
/** Normalize a query for cache keys: collapse whitespace, lowercase. */
|
|
26
|
+
export declare function normQuery(query: string): string;
|
|
27
|
+
export declare function userAgent(): string;
|
|
28
|
+
export interface HttpResult {
|
|
29
|
+
status: number;
|
|
30
|
+
ok: boolean;
|
|
31
|
+
text: string;
|
|
32
|
+
finalUrl: string;
|
|
33
|
+
contentType?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* One HTTP request (GET by default) with UA spoofing, cooperative timeout,
|
|
37
|
+
* and abort forwarding. Supports method/body for API POSTs.
|
|
38
|
+
*/
|
|
39
|
+
export declare function httpGet(url: string, opts?: {
|
|
40
|
+
headers?: Record<string, string>;
|
|
41
|
+
signal: AbortSignal | undefined;
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
redirect?: 'follow' | 'error';
|
|
44
|
+
method?: string;
|
|
45
|
+
body?: string;
|
|
46
|
+
}): Promise<HttpResult>;
|
|
47
|
+
/** Decode bytes honoring charset; UTF-8 first with GBK fallback on garbage. */
|
|
48
|
+
export declare function decodeText(buf: Buffer, contentType?: string): string;
|
|
49
|
+
/** Decode common HTML entities in a string. */
|
|
50
|
+
export declare function htmlDecode(input: string): string;
|
|
51
|
+
/** Strip HTML tags (used for titles / snippets inside already-scoped strings). */
|
|
52
|
+
export declare function stripTags(input: string): string;
|
|
53
|
+
export interface CliResult {
|
|
54
|
+
code: number;
|
|
55
|
+
stdout: string;
|
|
56
|
+
stderr: string;
|
|
57
|
+
timedOut: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run an external CLI (opencli / gh / bili / yt-dlp / agent-reach / npm).
|
|
61
|
+
* Windows cmd wrappers are handled via ComSpec.
|
|
62
|
+
*/
|
|
63
|
+
export declare function runCli(bin: string, args: string[], opts?: {
|
|
64
|
+
timeoutMs?: number;
|
|
65
|
+
signal: AbortSignal | undefined;
|
|
66
|
+
env?: Record<string, string>;
|
|
67
|
+
cwd?: string;
|
|
68
|
+
maxOutput?: number;
|
|
69
|
+
}): Promise<CliResult>;
|
|
70
|
+
/** Extract the first URL from a DuckDuckGo / Google style redirect parameter. */
|
|
71
|
+
export declare function decodeRedirectUrl(href: string): string;
|
|
72
|
+
/** Cap a string to maxChars while keeping whole lines near the boundary. */
|
|
73
|
+
export declare function capText(text: string, maxChars: number): string;
|
package/lib/util.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the dsh-web-search-pro plugin (published bundle).
|
|
3
|
+
* Dependencies (js-yaml, jsdom) are normal npm imports; playwright resolves
|
|
4
|
+
* from the global npm root or config playwright.modulePath.
|
|
5
|
+
* @module dsh-web-search-pro/util
|
|
6
|
+
*/
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
9
|
+
import crypto from 'node:crypto';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { load as yamlLoad } from 'js-yaml';
|
|
12
|
+
import { JSDOM } from 'jsdom';
|
|
13
|
+
/** js-yaml parser (npm dep). */
|
|
14
|
+
export const jsYaml = { load: (input) => yamlLoad(input) };
|
|
15
|
+
/** jsdom constructor (npm dep) for HTML parsing in extraction rules. */
|
|
16
|
+
export const jsdom = JSDOM;
|
|
17
|
+
let cachedPlaywright;
|
|
18
|
+
/** Resolve the playwright module: explicit config path first, then the global npm root. */
|
|
19
|
+
export function resolvePlaywright(modulePath) {
|
|
20
|
+
if (cachedPlaywright)
|
|
21
|
+
return cachedPlaywright;
|
|
22
|
+
const anchors = [];
|
|
23
|
+
if (modulePath)
|
|
24
|
+
anchors.push(path.join(modulePath, 'package.json'));
|
|
25
|
+
anchors.push(path.join(globalNpmRoot(), 'playwright', 'package.json'));
|
|
26
|
+
for (const anchor of anchors) {
|
|
27
|
+
try {
|
|
28
|
+
const req = createRequire(anchor);
|
|
29
|
+
cachedPlaywright = req('playwright');
|
|
30
|
+
return cachedPlaywright;
|
|
31
|
+
}
|
|
32
|
+
catch { /* try next anchor */ }
|
|
33
|
+
}
|
|
34
|
+
throw new Error('dsh-web-search-pro: playwright not found; install it globally (npm i -g playwright) or set config playwright.modulePath');
|
|
35
|
+
}
|
|
36
|
+
let cachedNpmRoot;
|
|
37
|
+
/** npm root -g, computed once. */
|
|
38
|
+
export function globalNpmRoot() {
|
|
39
|
+
if (cachedNpmRoot)
|
|
40
|
+
return cachedNpmRoot;
|
|
41
|
+
try {
|
|
42
|
+
cachedNpmRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', windowsHide: true, timeout: 15000 }).trim();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
cachedNpmRoot = path.join(process.env.APPDATA ?? '', 'npm', 'node_modules');
|
|
46
|
+
}
|
|
47
|
+
return cachedNpmRoot;
|
|
48
|
+
}
|
|
49
|
+
export function uid() {
|
|
50
|
+
return crypto.randomUUID();
|
|
51
|
+
}
|
|
52
|
+
export function sha1(input) {
|
|
53
|
+
return crypto.createHash('sha1').update(input).digest('hex');
|
|
54
|
+
}
|
|
55
|
+
/** Normalize a query for cache keys: collapse whitespace, lowercase. */
|
|
56
|
+
export function normQuery(query) {
|
|
57
|
+
return query.trim().replace(/\s+/g, ' ').toLowerCase();
|
|
58
|
+
}
|
|
59
|
+
/** Rotating browser user agents. */
|
|
60
|
+
const USER_AGENTS = [
|
|
61
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
62
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0',
|
|
63
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15',
|
|
64
|
+
];
|
|
65
|
+
let uaIndex = 0;
|
|
66
|
+
export function userAgent() {
|
|
67
|
+
uaIndex = (uaIndex + 1) % USER_AGENTS.length;
|
|
68
|
+
return USER_AGENTS[uaIndex];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* One HTTP request (GET by default) with UA spoofing, cooperative timeout,
|
|
72
|
+
* and abort forwarding. Supports method/body for API POSTs.
|
|
73
|
+
*/
|
|
74
|
+
export async function httpGet(url, opts = { signal: undefined }) {
|
|
75
|
+
const controller = new AbortController();
|
|
76
|
+
const timer = opts.timeoutMs ? setTimeout(() => controller.abort(new Error('dsh-web-search-pro: request timed out')), opts.timeoutMs) : undefined;
|
|
77
|
+
const onAbort = () => controller.abort(opts.signal?.reason ?? new Error('aborted'));
|
|
78
|
+
if (opts.signal?.aborted)
|
|
79
|
+
onAbort();
|
|
80
|
+
else
|
|
81
|
+
opts.signal?.addEventListener('abort', onAbort);
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch(url, {
|
|
84
|
+
redirect: opts.redirect ?? 'follow',
|
|
85
|
+
signal: controller.signal,
|
|
86
|
+
method: opts.method ?? 'GET',
|
|
87
|
+
...opts.body !== undefined ? { body: opts.body } : {},
|
|
88
|
+
headers: {
|
|
89
|
+
'user-agent': userAgent(),
|
|
90
|
+
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,text/plain;q=0.8,*/*;q=0.7',
|
|
91
|
+
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
|
92
|
+
...opts.headers,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
96
|
+
const contentType = res.headers.get('content-type');
|
|
97
|
+
const text = decodeText(buf, contentType ?? undefined);
|
|
98
|
+
return {
|
|
99
|
+
status: res.status,
|
|
100
|
+
ok: res.ok,
|
|
101
|
+
text,
|
|
102
|
+
finalUrl: res.url,
|
|
103
|
+
...contentType != null ? { contentType } : {},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
clearTimeout(timer);
|
|
108
|
+
opts.signal?.removeEventListener('abort', onAbort);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Decode bytes honoring charset; UTF-8 first with GBK fallback on garbage. */
|
|
112
|
+
export function decodeText(buf, contentType) {
|
|
113
|
+
const charset = /charset=([\w-]+)/i.exec(contentType ?? '')?.[1]?.toLowerCase();
|
|
114
|
+
const candidates = charset ? [charset] : ['utf-8', 'gbk'];
|
|
115
|
+
for (const enc of candidates) {
|
|
116
|
+
try {
|
|
117
|
+
const text = new TextDecoder(enc).decode(buf);
|
|
118
|
+
if (enc === 'utf-8' || !text.includes('\uFFFD'))
|
|
119
|
+
return text;
|
|
120
|
+
}
|
|
121
|
+
catch { /* unsupported encoding */ }
|
|
122
|
+
}
|
|
123
|
+
return new TextDecoder('utf-8').decode(buf);
|
|
124
|
+
}
|
|
125
|
+
/** Decode common HTML entities in a string. */
|
|
126
|
+
export function htmlDecode(input) {
|
|
127
|
+
return input
|
|
128
|
+
.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"')
|
|
129
|
+
.replace(/'/g, "'").replace(/'/g, "'").replace(/ /g, ' ')
|
|
130
|
+
.replace(/&/g, '&')
|
|
131
|
+
.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))
|
|
132
|
+
.replace(/&#(\d+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10)));
|
|
133
|
+
}
|
|
134
|
+
/** Strip HTML tags (used for titles / snippets inside already-scoped strings). */
|
|
135
|
+
export function stripTags(input) {
|
|
136
|
+
return htmlDecode(input.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim());
|
|
137
|
+
}
|
|
138
|
+
/** Quote one argument for cmd.exe /c command lines. */
|
|
139
|
+
function quoteArg(arg) {
|
|
140
|
+
if (/[^\w@%+=:,./-]/.test(arg)) {
|
|
141
|
+
return '"' + arg.replace(/"/g, '\\"') + '"';
|
|
142
|
+
}
|
|
143
|
+
return arg;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Run an external CLI (opencli / gh / bili / yt-dlp / agent-reach / npm).
|
|
147
|
+
* Windows cmd wrappers are handled via ComSpec.
|
|
148
|
+
*/
|
|
149
|
+
export function runCli(bin, args, opts = { signal: undefined }) {
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
const maxOutput = opts.maxOutput ?? 4 * 1024 * 1024;
|
|
152
|
+
let stdout = '';
|
|
153
|
+
let stderr = '';
|
|
154
|
+
let child;
|
|
155
|
+
let settled = false;
|
|
156
|
+
const finish = (code, timedOut) => {
|
|
157
|
+
if (settled)
|
|
158
|
+
return;
|
|
159
|
+
settled = true;
|
|
160
|
+
clearTimeout(timer);
|
|
161
|
+
opts.signal?.removeEventListener('abort', onAbort);
|
|
162
|
+
if (child.exitCode === null)
|
|
163
|
+
child.kill();
|
|
164
|
+
resolve({ code, stdout, stderr, timedOut });
|
|
165
|
+
};
|
|
166
|
+
const timer = opts.timeoutMs ? setTimeout(() => finish(-1, true), opts.timeoutMs) : undefined;
|
|
167
|
+
const onAbort = () => {
|
|
168
|
+
if (child.exitCode === null)
|
|
169
|
+
child.kill();
|
|
170
|
+
finish(-1, false);
|
|
171
|
+
};
|
|
172
|
+
if (process.platform === 'win32') {
|
|
173
|
+
const cmd = [quoteArg(bin), ...args.map(quoteArg)].join(' ');
|
|
174
|
+
child = spawn(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', cmd], {
|
|
175
|
+
windowsVerbatimArguments: true,
|
|
176
|
+
env: { ...process.env, ...opts.env },
|
|
177
|
+
cwd: opts.cwd,
|
|
178
|
+
windowsHide: true,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
child = spawn(bin, args, { env: { ...process.env, ...opts.env }, cwd: opts.cwd });
|
|
183
|
+
}
|
|
184
|
+
child.stdout?.on('data', (d) => { if (stdout.length < maxOutput)
|
|
185
|
+
stdout += d.toString('utf8'); });
|
|
186
|
+
child.stderr?.on('data', (d) => { if (stderr.length < maxOutput)
|
|
187
|
+
stderr += d.toString('utf8'); });
|
|
188
|
+
child.on('error', () => finish(-1, false));
|
|
189
|
+
child.on('close', (code) => finish(code ?? -1, false));
|
|
190
|
+
if (opts.signal?.aborted)
|
|
191
|
+
onAbort();
|
|
192
|
+
else
|
|
193
|
+
opts.signal?.addEventListener('abort', onAbort);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/** Extract the first URL from a DuckDuckGo / Google style redirect parameter. */
|
|
197
|
+
export function decodeRedirectUrl(href) {
|
|
198
|
+
const m = /[?&]uddg=([^&]+)/.exec(href);
|
|
199
|
+
if (m) {
|
|
200
|
+
try {
|
|
201
|
+
return decodeURIComponent(m[1]);
|
|
202
|
+
}
|
|
203
|
+
catch { /* fall through */ }
|
|
204
|
+
}
|
|
205
|
+
const g = /[?&]url=([^&]+)/.exec(href);
|
|
206
|
+
if (g) {
|
|
207
|
+
try {
|
|
208
|
+
return decodeURIComponent(g[1]);
|
|
209
|
+
}
|
|
210
|
+
catch { /* fall through */ }
|
|
211
|
+
}
|
|
212
|
+
return href;
|
|
213
|
+
}
|
|
214
|
+
/** Cap a string to maxChars while keeping whole lines near the boundary. */
|
|
215
|
+
export function capText(text, maxChars) {
|
|
216
|
+
if (text.length <= maxChars)
|
|
217
|
+
return text;
|
|
218
|
+
return text.slice(0, maxChars) + '\n\n(Content truncated at ' + maxChars + ' characters.)';
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=util.js.map
|
package/lib/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-web-search-pro",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Enhanced, persistent web search plugin for DeepSeek Harness — multi-engine routing (DeepSeek/Exa/DDG/Bing/Jina + GitHub/B站/YouTube/V2EX/小红书/Twitter/Reddit/RSS), SQLite+LRU cache, userscript-style extraction, and Playwright rendering.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"types": "lib/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./lib/index.d.ts",
|
|
12
|
+
"default": "./lib/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"lib",
|
|
19
|
+
"cordis.patch.yml",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LOGIN.md",
|
|
22
|
+
"scripts",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": "^22.19 || >=24"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@deepseek-ai/cordis": "^4.0.1"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@deepseek-ai/schemastery": "^3.18.1",
|
|
33
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
34
|
+
"@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
|
|
35
|
+
"@deepseek-ai/dsh-credentials": "^0.1.0-rc.6",
|
|
36
|
+
"js-yaml": "^4.1.0",
|
|
37
|
+
"jsdom": "^30.0.0",
|
|
38
|
+
"dsh-browser": "^0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"typescript": "^5.6.0",
|
|
42
|
+
"@types/node": "^22.0.0",
|
|
43
|
+
"@types/js-yaml": "^4.0.9",
|
|
44
|
+
"@deepseek-ai/dsh-web": "^0.1.0-rc.6",
|
|
45
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6"
|
|
46
|
+
},
|
|
47
|
+
"dsh": {
|
|
48
|
+
"bundle": {
|
|
49
|
+
"patch": "./cordis.patch.yml"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/anweat/dsh-web-search-pro.git"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc -p tsconfig.json"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* save-login.mjs — 登录一次,把浏览器登录态保存为 Playwright storageState JSON。
|
|
3
|
+
*
|
|
4
|
+
* 用法(在插件包目录内):
|
|
5
|
+
* node scripts/save-login.mjs [platform] [output.json]
|
|
6
|
+
* 例:node scripts/save-login.mjs zhihu login-state.json
|
|
7
|
+
* 例:node scripts/save-login.mjs all login-state.json # 依次登录所有平台,合并到一个文件
|
|
8
|
+
*
|
|
9
|
+
* 会打开一个可见浏览器窗口;请在窗口里完成登录(扫码/账号密码),回到终端按回车,
|
|
10
|
+
* 再继续下一个平台。结束后把输出文件路径填到 settings.yaml:
|
|
11
|
+
* playwright.storageStatePath: 'login-state.json'
|
|
12
|
+
* 之后 web_platform_search 的中文社区平台(zhihu/weibo/douban/tieba/douyin/kuaishou)
|
|
13
|
+
* 就会复用这份登录态驱动搜索结果页。
|
|
14
|
+
*/
|
|
15
|
+
import { createRequire } from 'node:module'
|
|
16
|
+
import { execFileSync } from 'node:child_process'
|
|
17
|
+
import fs from 'node:fs'
|
|
18
|
+
import path from 'node:path'
|
|
19
|
+
import readline from 'node:readline'
|
|
20
|
+
|
|
21
|
+
const LOGIN_PAGES = {
|
|
22
|
+
zhihu: 'https://www.zhihu.com/signin',
|
|
23
|
+
weibo: 'https://weibo.com/login.php',
|
|
24
|
+
douban: 'https://accounts.douban.com/passport/login',
|
|
25
|
+
tieba: 'https://tieba.baidu.com',
|
|
26
|
+
douyin: 'https://www.douyin.com',
|
|
27
|
+
kuaishou: 'https://www.kuaishou.com',
|
|
28
|
+
xiaohongshu: 'https://www.xiaohongshu.com',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function globalNpmRoot() {
|
|
32
|
+
try { return execFileSync('npm', ['root', '-g'], { encoding: 'utf8', windowsHide: true }).trim() }
|
|
33
|
+
catch { return path.join(process.env.APPDATA || '', 'npm', 'node_modules') }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolvePlaywright() {
|
|
37
|
+
const anchors = [
|
|
38
|
+
path.join(globalNpmRoot(), 'playwright', 'package.json'),
|
|
39
|
+
'playwright/package.json',
|
|
40
|
+
]
|
|
41
|
+
for (const anchor of anchors) {
|
|
42
|
+
try { return createRequire(anchor)('playwright') } catch { /* next */ }
|
|
43
|
+
}
|
|
44
|
+
throw new Error('未找到 playwright,先运行:npm i -g playwright && playwright install chromium')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function waitForEnter(question) {
|
|
48
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
rl.question(question + ' ', () => { rl.close(); resolve() })
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function main() {
|
|
55
|
+
const which = process.argv[2] || 'all'
|
|
56
|
+
const out = path.resolve(process.argv[3] || 'login-state.json')
|
|
57
|
+
const { chromium } = resolvePlaywright()
|
|
58
|
+
const browser = await chromium.launch({ headless: false, channel: 'msedge' })
|
|
59
|
+
const context = await browser.newContext()
|
|
60
|
+
const platforms = which === 'all' ? Object.keys(LOGIN_PAGES) : [which]
|
|
61
|
+
for (const p of platforms) {
|
|
62
|
+
if (!LOGIN_PAGES[p]) { console.error('未知平台 ' + p + ',可选: ' + Object.keys(LOGIN_PAGES).join(', ')); process.exit(1) }
|
|
63
|
+
const page = await context.newPage()
|
|
64
|
+
await page.goto(LOGIN_PAGES[p], { waitUntil: 'domcontentloaded', timeout: 60000 })
|
|
65
|
+
console.log('请在浏览器里完成「' + p + '」登录,登录成功后回到终端……')
|
|
66
|
+
await waitForEnter('按回车继续下一个平台:')
|
|
67
|
+
await page.close()
|
|
68
|
+
}
|
|
69
|
+
const state = await context.storageState()
|
|
70
|
+
fs.writeFileSync(out, JSON.stringify(state, null, 2), 'utf8')
|
|
71
|
+
console.log('已保存登录态到 ' + out)
|
|
72
|
+
console.log('在 $DSH_HOME/settings.yaml 里设置:')
|
|
73
|
+
console.log(' playwright.storageStatePath: ' + out)
|
|
74
|
+
await browser.close()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
main().catch((e) => { console.error(String(e)); process.exit(1) })
|