@pomelolabs/leads 0.1.5 → 0.2.2
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/client/bundle.js +4 -4
- package/host/browser.js +63 -2
- package/host/index.js +9 -12
- package/package.json +4 -4
package/client/bundle.js
CHANGED
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
// package.json
|
|
123
123
|
var package_default = {
|
|
124
124
|
name: "@pomelolabs/leads",
|
|
125
|
-
version: "0.
|
|
125
|
+
version: "0.2.2",
|
|
126
126
|
description: "\u67DA\u5BA2 Pomelo\uFF1A\u5185\u5BB9\u83B7\u5BA2\u5DE5\u4F5C\u53F0\uFF08DSH \u63D2\u4EF6\uFF09",
|
|
127
127
|
license: "UNLICENSED",
|
|
128
128
|
type: "module",
|
|
@@ -155,8 +155,7 @@
|
|
|
155
155
|
],
|
|
156
156
|
scripts: {
|
|
157
157
|
build: "esbuild client/src/index.jsx --bundle --format=iife --outfile=client/bundle.js --loader:.css=text --loader:.svg=text --jsx=transform --external:react --target=es2022 --log-level=warning",
|
|
158
|
-
dev: "npm run build -- --watch"
|
|
159
|
-
"browser:install": "node ./node_modules/puppeteer/lib/puppeteer/node/cli.js browsers install chrome"
|
|
158
|
+
dev: "npm run build -- --watch"
|
|
160
159
|
},
|
|
161
160
|
devDependencies: {
|
|
162
161
|
"@phosphor-icons/core": "^2.1.1",
|
|
@@ -176,7 +175,8 @@
|
|
|
176
175
|
},
|
|
177
176
|
dependencies: {
|
|
178
177
|
"playwright-core": "^1.64.1",
|
|
179
|
-
puppeteer: "^25.16.0"
|
|
178
|
+
"puppeteer-core": "^25.16.0",
|
|
179
|
+
"@puppeteer/browsers": "^3.2.6"
|
|
180
180
|
},
|
|
181
181
|
publishConfig: {
|
|
182
182
|
access: "public",
|
package/host/browser.js
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
import fs from 'node:fs/promises';
|
|
11
11
|
import os from 'node:os';
|
|
12
12
|
import path from 'node:path';
|
|
13
|
-
import puppeteer from 'puppeteer';
|
|
13
|
+
import puppeteer from 'puppeteer-core';
|
|
14
|
+
import { Browser as BrowserType, detectBrowserPlatform, install as installBrowserBinary, resolveBuildId } from '@puppeteer/browsers';
|
|
14
15
|
|
|
15
16
|
const PLATFORM_URLS = {
|
|
16
17
|
xhs: {
|
|
@@ -106,6 +107,62 @@ async function findPlaywrightChromium() {
|
|
|
106
107
|
return '';
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
async function findCachedChromium() {
|
|
111
|
+
const roots = [
|
|
112
|
+
path.join(homeDir(), 'pomelo', 'browser-cache', 'chrome'),
|
|
113
|
+
path.join(os.homedir(), '.cache', 'puppeteer', 'chrome'),
|
|
114
|
+
];
|
|
115
|
+
for (const root of roots) {
|
|
116
|
+
let names = [];
|
|
117
|
+
try { names = await fs.readdir(root); } catch { continue; }
|
|
118
|
+
for (const name of names.sort().reverse()) {
|
|
119
|
+
const base = path.join(root, name);
|
|
120
|
+
const candidates = process.platform === 'darwin'
|
|
121
|
+
? [
|
|
122
|
+
path.join(base, 'chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing'),
|
|
123
|
+
path.join(base, 'chrome-mac-x64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing'),
|
|
124
|
+
path.join(base, 'chrome-mac/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing'),
|
|
125
|
+
]
|
|
126
|
+
: process.platform === 'win32'
|
|
127
|
+
? [path.join(base, 'chrome-win64', 'chrome.exe'), path.join(base, 'chrome-win32', 'chrome.exe')]
|
|
128
|
+
: [path.join(base, 'chrome-linux64', 'chrome'), path.join(base, 'chrome-linux', 'chrome')];
|
|
129
|
+
for (const candidate of candidates) {
|
|
130
|
+
if (await executableAt(candidate)) return candidate;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let browserInstallPromise = null;
|
|
138
|
+
export async function ensureBrowser(log = async () => {}) {
|
|
139
|
+
const existing = await resolveBrowserExecutable();
|
|
140
|
+
if (existing) return existing;
|
|
141
|
+
if (browserInstallPromise) return browserInstallPromise;
|
|
142
|
+
browserInstallPromise = (async () => {
|
|
143
|
+
const platform = detectBrowserPlatform();
|
|
144
|
+
if (!platform) throw new Error('无法识别当前系统平台');
|
|
145
|
+
await log('未找到采集浏览器,开始下载 Chromium(Chrome for Testing)');
|
|
146
|
+
const buildId = await resolveBuildId(BrowserType.CHROME, platform, 'stable');
|
|
147
|
+
const installed = await installBrowserBinary({
|
|
148
|
+
browser: BrowserType.CHROME,
|
|
149
|
+
buildId,
|
|
150
|
+
cacheDir: path.join(homeDir(), 'pomelo', 'browser-cache'),
|
|
151
|
+
platform,
|
|
152
|
+
});
|
|
153
|
+
const executable = installed?.executablePath || '';
|
|
154
|
+
if (!executable) throw new Error('浏览器下载完成,但没有找到可执行文件');
|
|
155
|
+
process.env.PUPPETEER_EXECUTABLE_PATH = executable;
|
|
156
|
+
await log(`Chromium 下载完成:${executable}`);
|
|
157
|
+
return { executable, source: 'downloaded' };
|
|
158
|
+
})();
|
|
159
|
+
try {
|
|
160
|
+
return await browserInstallPromise;
|
|
161
|
+
} finally {
|
|
162
|
+
browserInstallPromise = null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
109
166
|
async function resolveBrowserExecutable() {
|
|
110
167
|
const explicit = process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_PATH;
|
|
111
168
|
if (explicit && await executableAt(explicit)) {
|
|
@@ -119,8 +176,12 @@ async function resolveBrowserExecutable() {
|
|
|
119
176
|
if (chromium) {
|
|
120
177
|
return { executable: chromium, source: 'playwright-chromium' };
|
|
121
178
|
}
|
|
179
|
+
const cached = await findCachedChromium();
|
|
180
|
+
if (cached) {
|
|
181
|
+
return { executable: cached, source: 'downloaded' };
|
|
182
|
+
}
|
|
122
183
|
try {
|
|
123
|
-
const bundled = await puppeteer.executablePath();
|
|
184
|
+
const bundled = typeof puppeteer.executablePath === 'function' ? await puppeteer.executablePath() : '';
|
|
124
185
|
if (bundled && await executableAt(bundled)) {
|
|
125
186
|
return { executable: bundled, source: 'puppeteer' };
|
|
126
187
|
}
|
package/host/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { promisify } from 'node:util';
|
|
|
9
9
|
import fs from 'node:fs/promises';
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
-
import { browserStatus, openLink, openLogin, searchPeerProfile, searchPublic } from './browser.js';
|
|
12
|
+
import { browserStatus, ensureBrowser, openLink, openLogin, searchPeerProfile, searchPublic } from './browser.js';
|
|
13
13
|
|
|
14
14
|
const execFileAsync = promisify(execFile);
|
|
15
15
|
|
|
@@ -564,21 +564,14 @@ ${comparisonText}
|
|
|
564
564
|
async function installBrowser() {
|
|
565
565
|
const first = await browserStatus();
|
|
566
566
|
if (first.installed) return first;
|
|
567
|
-
const pluginRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..');
|
|
568
|
-
await store.log('开始安装 Chromium(puppeteer)');
|
|
569
567
|
try {
|
|
570
|
-
await
|
|
571
|
-
cwd: pluginRoot,
|
|
572
|
-
timeout: 15 * 60 * 1000,
|
|
573
|
-
maxBuffer: 4 * 1024 * 1024,
|
|
574
|
-
env: process.env,
|
|
575
|
-
});
|
|
568
|
+
await ensureBrowser((message) => store.log(message));
|
|
576
569
|
} catch (error) {
|
|
577
|
-
await store.log(`Chromium
|
|
578
|
-
throw rpcError('BROWSER_INSTALL_FAILED', '
|
|
570
|
+
await store.log(`Chromium 下载失败:${error?.message || error}`);
|
|
571
|
+
throw rpcError('BROWSER_INSTALL_FAILED', '采集浏览器下载失败,请检查网络后重试');
|
|
579
572
|
}
|
|
580
573
|
const next = await browserStatus();
|
|
581
|
-
await store.log(`Chromium
|
|
574
|
+
await store.log(`Chromium 就绪:${next.executable || '未找到路径'}`);
|
|
582
575
|
return next;
|
|
583
576
|
}
|
|
584
577
|
|
|
@@ -1214,12 +1207,15 @@ ${state.profile.answers[key] || '(未填写)'}
|
|
|
1214
1207
|
case 'browser.status':
|
|
1215
1208
|
return browserStatus();
|
|
1216
1209
|
case 'browser.login':
|
|
1210
|
+
await installBrowser();
|
|
1217
1211
|
return openLogin(payload?.platform || '小红书');
|
|
1218
1212
|
case 'browser.install':
|
|
1219
1213
|
return installBrowser();
|
|
1220
1214
|
case 'browser.open':
|
|
1215
|
+
await installBrowser();
|
|
1221
1216
|
return openLink(payload?.url);
|
|
1222
1217
|
case 'search.run': {
|
|
1218
|
+
await installBrowser();
|
|
1223
1219
|
const platform = payload?.platform === '抖音' ? '抖音' : '小红书';
|
|
1224
1220
|
const keyword = cleanText(payload?.keyword, 80);
|
|
1225
1221
|
if (!keyword) throw rpcError('EMPTY_KEYWORD', '请输入关键词');
|
|
@@ -1241,6 +1237,7 @@ ${state.profile.answers[key] || '(未填写)'}
|
|
|
1241
1237
|
case 'peer.history':
|
|
1242
1238
|
return store.snapshot().peerHistory || [];
|
|
1243
1239
|
case 'peer.run': {
|
|
1240
|
+
await installBrowser();
|
|
1244
1241
|
const platform = payload?.platform === '抖音' ? '抖音' : '小红书';
|
|
1245
1242
|
const account = cleanText(payload?.account, 120);
|
|
1246
1243
|
if (!account) throw rpcError('EMPTY_ACCOUNT', '先粘贴同行账号或 ID');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pomelolabs/leads",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "柚客 Pomelo:内容获客工作台(DSH 插件)",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
],
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "esbuild client/src/index.jsx --bundle --format=iife --outfile=client/bundle.js --loader:.css=text --loader:.svg=text --jsx=transform --external:react --target=es2022 --log-level=warning",
|
|
36
|
-
"dev": "npm run build -- --watch"
|
|
37
|
-
"browser:install": "node ./node_modules/puppeteer/lib/puppeteer/node/cli.js browsers install chrome"
|
|
36
|
+
"dev": "npm run build -- --watch"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
39
|
"@phosphor-icons/core": "^2.1.1",
|
|
@@ -54,7 +53,8 @@
|
|
|
54
53
|
},
|
|
55
54
|
"dependencies": {
|
|
56
55
|
"playwright-core": "^1.64.1",
|
|
57
|
-
"puppeteer": "^25.16.0"
|
|
56
|
+
"puppeteer-core": "^25.16.0",
|
|
57
|
+
"@puppeteer/browsers": "^3.2.6"
|
|
58
58
|
},
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public",
|