@iflyrpa/playwright 1.0.8 → 1.0.10
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/dist/index.cjs +293 -72
- package/dist/index.d.cts +22 -5
- package/dist/index.d.mts +22 -5
- package/dist/index.d.ts +22 -5
- package/dist/index.mjs +289 -67
- package/package.json +3 -12
package/dist/index.cjs
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const semver = require('semver');
|
|
4
3
|
const path = require('node:path');
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const https = require('node:https');
|
|
6
|
+
const log = require('loglevel');
|
|
7
|
+
const node_child_process = require('node:child_process');
|
|
9
8
|
|
|
10
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
11
10
|
|
|
12
|
-
const semver__default = /*#__PURE__*/_interopDefaultCompat(semver);
|
|
13
11
|
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
14
|
-
const axios__default = /*#__PURE__*/_interopDefaultCompat(axios);
|
|
15
12
|
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
16
|
-
const
|
|
13
|
+
const https__default = /*#__PURE__*/_interopDefaultCompat(https);
|
|
14
|
+
const log__default = /*#__PURE__*/_interopDefaultCompat(log);
|
|
17
15
|
|
|
18
16
|
const name = "@iflyrpa/playwright";
|
|
19
17
|
const type = "module";
|
|
20
|
-
const version$1 = "1.0.
|
|
18
|
+
const version$1 = "1.0.10";
|
|
21
19
|
const description = "";
|
|
22
20
|
const main = "./dist/index.cjs";
|
|
23
21
|
const module$1 = "./dist/index.mjs";
|
|
@@ -35,23 +33,14 @@ const files = [
|
|
|
35
33
|
"dist"
|
|
36
34
|
];
|
|
37
35
|
const dependencies = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
deepmerge: "^4.3.1",
|
|
41
|
-
"fs-extra": "^11.2.0",
|
|
42
|
-
playwright: "^1.46.1",
|
|
43
|
-
semver: "^7.6.3"
|
|
36
|
+
loglevel: "^1.9.2",
|
|
37
|
+
playwright: "^1.46.1"
|
|
44
38
|
};
|
|
45
39
|
const peerDependencies = {
|
|
46
40
|
electron: "*"
|
|
47
41
|
};
|
|
48
42
|
const devDependencies = {
|
|
49
|
-
"@types/cross-spawn": "^6.0.6",
|
|
50
|
-
"@types/fs-extra": "^11.0.4",
|
|
51
|
-
"@types/semver": "^7.5.8",
|
|
52
|
-
bumpp: "^9.5.2",
|
|
53
43
|
esno: "^4.7.0",
|
|
54
|
-
"ts-node": "^10.9.2",
|
|
55
44
|
typescript: "^5.5.2",
|
|
56
45
|
unbuild: "^2.0.0"
|
|
57
46
|
};
|
|
@@ -73,25 +62,159 @@ const packageJson = {
|
|
|
73
62
|
devDependencies: devDependencies
|
|
74
63
|
};
|
|
75
64
|
|
|
76
|
-
async function downloadImage(url,
|
|
77
|
-
|
|
78
|
-
url,
|
|
79
|
-
method: "GET",
|
|
80
|
-
responseType: "stream"
|
|
81
|
-
// 重要:设置响应类型为 'stream'
|
|
82
|
-
});
|
|
83
|
-
await fs__default.ensureFile(path2);
|
|
84
|
-
const writer = fs__default.createWriteStream(path2);
|
|
85
|
-
response.data.pipe(writer);
|
|
65
|
+
async function downloadImage(url, savePath) {
|
|
66
|
+
await ensureFile(savePath);
|
|
86
67
|
return new Promise((resolve, reject) => {
|
|
87
|
-
|
|
88
|
-
|
|
68
|
+
https__default.get(url, (response) => {
|
|
69
|
+
if (response.statusCode === 200) {
|
|
70
|
+
const fileStream = fs__default.createWriteStream(savePath);
|
|
71
|
+
response.pipe(fileStream);
|
|
72
|
+
fileStream.on("finish", () => {
|
|
73
|
+
fileStream.close();
|
|
74
|
+
console.log("\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u6587\u4EF6\u5DF2\u4FDD\u5B58\u81F3:", savePath);
|
|
75
|
+
resolve(savePath);
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
console.log("\u56FE\u7247\u4E0B\u8F7D\u5931\u8D25:", response.statusCode);
|
|
79
|
+
response.resume();
|
|
80
|
+
reject();
|
|
81
|
+
}
|
|
82
|
+
}).on("error", (error) => {
|
|
83
|
+
console.error("\u8BF7\u6C42\u56FE\u7247\u65F6\u53D1\u751F\u9519\u8BEF:", error.message);
|
|
84
|
+
reject();
|
|
85
|
+
});
|
|
89
86
|
});
|
|
90
87
|
}
|
|
91
88
|
function getFilenameFromUrl(imageUrl) {
|
|
92
89
|
const parsedUrl = new URL(imageUrl);
|
|
93
90
|
return path__default.basename(parsedUrl.pathname);
|
|
94
91
|
}
|
|
92
|
+
function pathExists(path2) {
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
fs__default.stat(path2, (err) => {
|
|
95
|
+
resolve(!err);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function ensureFile(filePath) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const dirPath = path__default.dirname(filePath);
|
|
102
|
+
fs__default.stat(dirPath, (err, stats) => {
|
|
103
|
+
if (err) {
|
|
104
|
+
if (err.code === "ENOENT") {
|
|
105
|
+
fs__default.mkdir(dirPath, { recursive: true }, (err2) => {
|
|
106
|
+
if (err2) {
|
|
107
|
+
return reject(err2);
|
|
108
|
+
}
|
|
109
|
+
createFile();
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
return reject(err);
|
|
113
|
+
}
|
|
114
|
+
} else if (stats.isDirectory()) {
|
|
115
|
+
checkFile();
|
|
116
|
+
} else {
|
|
117
|
+
reject(new Error(`${dirPath} is not a directory`));
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
function checkFile() {
|
|
121
|
+
fs__default.stat(filePath, (err, stats) => {
|
|
122
|
+
if (err) {
|
|
123
|
+
if (err.code === "ENOENT") {
|
|
124
|
+
createFile();
|
|
125
|
+
} else {
|
|
126
|
+
reject(err);
|
|
127
|
+
}
|
|
128
|
+
} else if (stats.isFile()) {
|
|
129
|
+
resolve();
|
|
130
|
+
} else {
|
|
131
|
+
reject(new Error(`${filePath} is not a file`));
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function createFile() {
|
|
136
|
+
fs__default.writeFile(filePath, "", (err) => {
|
|
137
|
+
if (err) {
|
|
138
|
+
reject(err);
|
|
139
|
+
} else {
|
|
140
|
+
resolve();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function ensureFileSync(filePath) {
|
|
147
|
+
const dirPath = path__default.dirname(filePath);
|
|
148
|
+
try {
|
|
149
|
+
if (!fs__default.existsSync(dirPath)) {
|
|
150
|
+
fs__default.mkdirSync(dirPath, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
if (err instanceof Error) {
|
|
154
|
+
throw new Error(`Error creating directory: ${err.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
if (!fs__default.existsSync(filePath)) {
|
|
159
|
+
fs__default.writeFileSync(filePath, "");
|
|
160
|
+
}
|
|
161
|
+
} catch (err) {
|
|
162
|
+
if (err instanceof Error) {
|
|
163
|
+
throw new Error(`Error creating file: ${err.message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function writeFile(filePath, data) {
|
|
168
|
+
return new Promise((resolve, reject) => {
|
|
169
|
+
fs__default.writeFile(filePath, data, (err) => {
|
|
170
|
+
if (err) {
|
|
171
|
+
console.error("Error writing file:", err);
|
|
172
|
+
reject();
|
|
173
|
+
} else {
|
|
174
|
+
console.log("File written successfully");
|
|
175
|
+
resolve();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function compareVersions(v1, v2) {
|
|
181
|
+
const parts1 = v1.split(".").map(Number);
|
|
182
|
+
const parts2 = v2.split(".").map(Number);
|
|
183
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
184
|
+
const num1 = i < parts1.length ? parts1[i] : 0;
|
|
185
|
+
const num2 = i < parts2.length ? parts2[i] : 0;
|
|
186
|
+
if (num1 > num2)
|
|
187
|
+
return 1;
|
|
188
|
+
if (num1 < num2)
|
|
189
|
+
return -1;
|
|
190
|
+
}
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
const semver = {
|
|
194
|
+
gt: (v1, v2) => compareVersions(v1, v2) === 1
|
|
195
|
+
};
|
|
196
|
+
function fetchJSON(url) {
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
https__default.get(url, (res) => {
|
|
199
|
+
let data = "";
|
|
200
|
+
res.on("data", (chunk) => {
|
|
201
|
+
data += chunk;
|
|
202
|
+
});
|
|
203
|
+
res.on("end", () => {
|
|
204
|
+
try {
|
|
205
|
+
const parsedData = JSON.parse(data);
|
|
206
|
+
resolve(parsedData);
|
|
207
|
+
} catch (e) {
|
|
208
|
+
if (e instanceof Error) {
|
|
209
|
+
reject(new Error(`Error parsing JSON: ${e.message}`));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}).on("error", (err) => {
|
|
214
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
95
218
|
|
|
96
219
|
const visibleRangeTexts = {
|
|
97
220
|
public: "\u516C\u5F00",
|
|
@@ -215,6 +338,65 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
215
338
|
return response;
|
|
216
339
|
};
|
|
217
340
|
|
|
341
|
+
var __defProp$2 = Object.defineProperty;
|
|
342
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
343
|
+
var __publicField$2 = (obj, key, value) => {
|
|
344
|
+
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
345
|
+
return value;
|
|
346
|
+
};
|
|
347
|
+
const _Logger = class _Logger {
|
|
348
|
+
constructor(cachePath) {
|
|
349
|
+
__publicField$2(this, "stream");
|
|
350
|
+
if (_Logger.instance) {
|
|
351
|
+
return _Logger.instance;
|
|
352
|
+
}
|
|
353
|
+
const logFile = path__default.join(cachePath, "rpa.log");
|
|
354
|
+
this.stream = fs__default.createWriteStream(logFile, { flags: "a" });
|
|
355
|
+
log__default.setLevel("debug");
|
|
356
|
+
log__default.methodFactory = (methodName) => {
|
|
357
|
+
return (message) => {
|
|
358
|
+
this.stream.write(
|
|
359
|
+
`[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
|
|
360
|
+
`
|
|
361
|
+
);
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
log__default.setLevel(log__default.getLevel());
|
|
365
|
+
_Logger.instance = this;
|
|
366
|
+
}
|
|
367
|
+
static getInstance(cachePath) {
|
|
368
|
+
if (!_Logger.instance) {
|
|
369
|
+
_Logger.instance = new _Logger(cachePath);
|
|
370
|
+
}
|
|
371
|
+
return _Logger.instance;
|
|
372
|
+
}
|
|
373
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
374
|
+
debug(...msg) {
|
|
375
|
+
log__default.debug(...msg);
|
|
376
|
+
}
|
|
377
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
378
|
+
info(...msg) {
|
|
379
|
+
log__default.info(...msg);
|
|
380
|
+
}
|
|
381
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
382
|
+
warn(...msg) {
|
|
383
|
+
log__default.warn(...msg);
|
|
384
|
+
}
|
|
385
|
+
error(prefix, error) {
|
|
386
|
+
let errorMessage = error;
|
|
387
|
+
if (error instanceof Error) {
|
|
388
|
+
errorMessage = `${error.message}
|
|
389
|
+
Error stack: ${error.stack}`;
|
|
390
|
+
}
|
|
391
|
+
log__default.error(prefix, errorMessage);
|
|
392
|
+
}
|
|
393
|
+
close() {
|
|
394
|
+
this.stream.end();
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
__publicField$2(_Logger, "instance", null);
|
|
398
|
+
let Logger = _Logger;
|
|
399
|
+
|
|
218
400
|
const template = `
|
|
219
401
|
const { app } = require("electron");
|
|
220
402
|
|
|
@@ -224,22 +406,35 @@ app.on("window-all-closed", (e) => e.preventDefault());
|
|
|
224
406
|
`;
|
|
225
407
|
const generateFile = async (dir) => {
|
|
226
408
|
const filePath = path__default.join(dir, "src", "main.js");
|
|
227
|
-
const
|
|
228
|
-
if (!
|
|
229
|
-
await
|
|
230
|
-
await
|
|
409
|
+
const isPathExists = await pathExists(filePath);
|
|
410
|
+
if (!isPathExists) {
|
|
411
|
+
await ensureFile(filePath);
|
|
412
|
+
await writeFile(filePath, template);
|
|
231
413
|
}
|
|
232
414
|
return filePath;
|
|
233
415
|
};
|
|
234
416
|
const createElectronApp = async (cachePath, playwrightPackage) => {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
417
|
+
const logger = Logger.getInstance(cachePath);
|
|
418
|
+
try {
|
|
419
|
+
const executablePath = path__default.join(
|
|
420
|
+
cachePath,
|
|
421
|
+
"node_modules",
|
|
422
|
+
".bin",
|
|
423
|
+
"electron"
|
|
424
|
+
);
|
|
425
|
+
const playwright = await playwrightPackage;
|
|
426
|
+
const mainPath = await generateFile(cachePath);
|
|
427
|
+
const electronApp = await playwright._electron.launch({
|
|
428
|
+
executablePath,
|
|
429
|
+
// 获取 Electron 可执行文件的路径
|
|
430
|
+
args: [mainPath],
|
|
431
|
+
cwd: cachePath
|
|
432
|
+
});
|
|
433
|
+
logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
|
|
434
|
+
return electronApp;
|
|
435
|
+
} catch (error) {
|
|
436
|
+
logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
|
|
437
|
+
}
|
|
243
438
|
};
|
|
244
439
|
|
|
245
440
|
var __defProp$1 = Object.defineProperty;
|
|
@@ -255,8 +450,11 @@ class PackageManager {
|
|
|
255
450
|
__publicField$1(this, "forceUpdate");
|
|
256
451
|
// 是否强制更新
|
|
257
452
|
__publicField$1(this, "initPromise");
|
|
453
|
+
__publicField$1(this, "logger");
|
|
454
|
+
this.logger = Logger.getInstance(params.cacheDir);
|
|
258
455
|
this.cacheDir = params.cacheDir;
|
|
259
456
|
this.forceUpdate = params.forceUpdate || true;
|
|
457
|
+
this.initCacheProject();
|
|
260
458
|
this.initPromise = this.init(params.packageName, params.packageVersion);
|
|
261
459
|
}
|
|
262
460
|
// 在子线程执行 npm 命令
|
|
@@ -264,7 +462,8 @@ class PackageManager {
|
|
|
264
462
|
return new Promise((resolve) => {
|
|
265
463
|
const args = [cmd].concat(modules).concat("--color=always").concat("--save");
|
|
266
464
|
try {
|
|
267
|
-
const
|
|
465
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
466
|
+
const npm = node_child_process.spawn(npmCmd, args, { cwd: where });
|
|
268
467
|
let output = "";
|
|
269
468
|
npm.stdout?.on("data", (data) => {
|
|
270
469
|
output += data;
|
|
@@ -284,6 +483,7 @@ class PackageManager {
|
|
|
284
483
|
console.error(err);
|
|
285
484
|
});
|
|
286
485
|
} catch (error) {
|
|
486
|
+
this.logger.error(`npm ${args.join(" ")}: `, error);
|
|
287
487
|
console.error(error);
|
|
288
488
|
}
|
|
289
489
|
});
|
|
@@ -292,21 +492,23 @@ class PackageManager {
|
|
|
292
492
|
initCacheProject() {
|
|
293
493
|
const packagePath = path__default.join(this.cacheDir, "package.json");
|
|
294
494
|
if (!fs__default.existsSync(packagePath)) {
|
|
495
|
+
this.logger.info("package.json \u4E0D\u5B58\u5728\uFF0C\u6DFB\u52A0\u8BE5\u6587\u4EF6");
|
|
295
496
|
const pkg = {
|
|
296
497
|
name: "rpa-plugins",
|
|
297
498
|
description: "rpa-plugins",
|
|
298
|
-
license: "MIT"
|
|
499
|
+
license: "MIT",
|
|
500
|
+
main: "./src/main.js"
|
|
299
501
|
};
|
|
300
|
-
|
|
502
|
+
ensureFileSync(packagePath);
|
|
301
503
|
fs__default.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
|
|
302
504
|
}
|
|
303
505
|
}
|
|
304
506
|
// 获取依赖信息
|
|
305
507
|
async getPluginInfo(module) {
|
|
306
|
-
const res = await
|
|
508
|
+
const res = await fetchJSON(
|
|
307
509
|
`https://registry.npmjs.com/-/v1/search?text=${module}`
|
|
308
510
|
);
|
|
309
|
-
const packages = res.
|
|
511
|
+
const packages = res.objects;
|
|
310
512
|
return packages.find((it) => it.package.name === module)?.package;
|
|
311
513
|
}
|
|
312
514
|
// 查询本地安装的依赖
|
|
@@ -315,6 +517,7 @@ class PackageManager {
|
|
|
315
517
|
try {
|
|
316
518
|
return require(path__default.join(pluginDir, module));
|
|
317
519
|
} catch (error) {
|
|
520
|
+
this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
|
|
318
521
|
return null;
|
|
319
522
|
}
|
|
320
523
|
}
|
|
@@ -325,27 +528,26 @@ class PackageManager {
|
|
|
325
528
|
// 安装依赖
|
|
326
529
|
install(module, version) {
|
|
327
530
|
const moduleName = version ? `${module}@${version}` : module;
|
|
328
|
-
return this.execCommand("install", [moduleName]);
|
|
531
|
+
return this.execCommand("install", [moduleName, "--save"]);
|
|
329
532
|
}
|
|
330
533
|
// 更新依赖
|
|
331
534
|
update(module) {
|
|
332
535
|
return this.execCommand("update", [module]);
|
|
333
536
|
}
|
|
334
537
|
async init(name, version) {
|
|
335
|
-
this.initCacheProject();
|
|
336
538
|
const plugin = this.getPlugin(path__default.join(name, "package.json"));
|
|
337
539
|
if (!plugin) {
|
|
338
540
|
await this.install(name, version);
|
|
339
541
|
} else if (this.forceUpdate) {
|
|
340
542
|
const pkInfo = await this.getPluginInfo(name);
|
|
341
543
|
if (!pkInfo)
|
|
342
|
-
|
|
343
|
-
const hasNewVersion =
|
|
544
|
+
return;
|
|
545
|
+
const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
|
|
344
546
|
if (hasNewVersion) {
|
|
345
547
|
await this.install(name, pkInfo.version);
|
|
346
548
|
}
|
|
347
549
|
}
|
|
348
|
-
|
|
550
|
+
this.logger.info(`${name} package manager init done!`);
|
|
349
551
|
}
|
|
350
552
|
}
|
|
351
553
|
|
|
@@ -357,18 +559,16 @@ var __publicField = (obj, key, value) => {
|
|
|
357
559
|
};
|
|
358
560
|
const PLAYWRIGHT_VERSION = "1.46.1";
|
|
359
561
|
class LocalAutomateTask {
|
|
360
|
-
constructor(
|
|
562
|
+
constructor({ cachePath, debug }) {
|
|
361
563
|
__publicField(this, "cachePath");
|
|
362
564
|
__publicField(this, "debug");
|
|
363
|
-
__publicField(this, "appWhenReady");
|
|
364
565
|
__publicField(this, "playwrightPackage");
|
|
365
|
-
this
|
|
366
|
-
this
|
|
566
|
+
__publicField(this, "logger");
|
|
567
|
+
__publicField(this, "_electronApp", null);
|
|
568
|
+
this.cachePath = cachePath;
|
|
569
|
+
this.debug = debug || false;
|
|
570
|
+
this.logger = Logger.getInstance(cachePath);
|
|
367
571
|
this.playwrightPackage = this.installPlaywright();
|
|
368
|
-
this.appWhenReady = createElectronApp(
|
|
369
|
-
params.cachePath,
|
|
370
|
-
this.playwrightPackage
|
|
371
|
-
);
|
|
372
572
|
}
|
|
373
573
|
/**
|
|
374
574
|
* 安装 playwright
|
|
@@ -382,19 +582,33 @@ class LocalAutomateTask {
|
|
|
382
582
|
});
|
|
383
583
|
return playwrightPackageManager.getPluginAfterInit("playwright");
|
|
384
584
|
}
|
|
585
|
+
/**
|
|
586
|
+
* 启动 Electron
|
|
587
|
+
* @returns
|
|
588
|
+
*/
|
|
589
|
+
async getElectronApp() {
|
|
590
|
+
if (!this._electronApp) {
|
|
591
|
+
this._electronApp = await createElectronApp(
|
|
592
|
+
this.cachePath,
|
|
593
|
+
this.playwrightPackage
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
return this._electronApp;
|
|
597
|
+
}
|
|
385
598
|
/**
|
|
386
599
|
* 关闭 playwright 启动的 electron 客户端
|
|
387
600
|
* @returns
|
|
388
601
|
*/
|
|
389
602
|
async close() {
|
|
390
|
-
|
|
603
|
+
this.logger.close();
|
|
604
|
+
const electronApp = await this.getElectronApp();
|
|
391
605
|
return electronApp.close();
|
|
392
606
|
}
|
|
393
607
|
/**
|
|
394
608
|
* 小红书自动化发布
|
|
395
609
|
*/
|
|
396
610
|
async xiaohongshuPublish(params) {
|
|
397
|
-
const electronApp = await this.
|
|
611
|
+
const electronApp = await this.getElectronApp();
|
|
398
612
|
const commonCookies = {
|
|
399
613
|
path: "/",
|
|
400
614
|
sameSite: "lax",
|
|
@@ -434,22 +648,29 @@ class LocalAutomateTask {
|
|
|
434
648
|
{ pageParams }
|
|
435
649
|
)
|
|
436
650
|
]);
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
651
|
+
try {
|
|
652
|
+
const res = await xiaohongshuPublishAction({
|
|
653
|
+
page,
|
|
654
|
+
params,
|
|
655
|
+
cachePath: this.cachePath,
|
|
656
|
+
debug: !!this.debug
|
|
657
|
+
});
|
|
658
|
+
return res;
|
|
659
|
+
} catch (error) {
|
|
660
|
+
this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
|
|
661
|
+
return error;
|
|
662
|
+
}
|
|
444
663
|
}
|
|
445
664
|
}
|
|
446
665
|
const RpaTask = (params) => {
|
|
666
|
+
const logger = Logger.getInstance(params.cachePath);
|
|
447
667
|
const packageManager = new PackageManager({
|
|
448
668
|
packageName: packageJson.name,
|
|
449
669
|
cacheDir: params.cachePath
|
|
450
670
|
});
|
|
451
671
|
const localPackge = packageManager.getPlugin(packageJson.name);
|
|
452
|
-
if (localPackge?.LocalAutomateTask && localPackge?.version &&
|
|
672
|
+
if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
|
|
673
|
+
logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
|
|
453
674
|
return new localPackge.LocalAutomateTask(params);
|
|
454
675
|
}
|
|
455
676
|
return new LocalAutomateTask(params);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import { ElectronApplication } from 'playwright';
|
|
2
1
|
import { CookiesSetDetails } from 'electron';
|
|
3
2
|
|
|
3
|
+
declare class Logger {
|
|
4
|
+
static instance: Logger | null;
|
|
5
|
+
private stream;
|
|
6
|
+
constructor(cachePath: string);
|
|
7
|
+
static getInstance(cachePath: string): Logger;
|
|
8
|
+
debug(...msg: any[]): void;
|
|
9
|
+
info(...msg: any[]): void;
|
|
10
|
+
warn(...msg: any[]): void;
|
|
11
|
+
error(prefix: string, error: unknown): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
type CookieMap = CookiesSetDetails[];
|
|
5
16
|
|
|
6
17
|
interface FictionalRendition {
|
|
@@ -46,14 +57,20 @@ interface TaskParams {
|
|
|
46
57
|
declare class LocalAutomateTask implements TaskParams {
|
|
47
58
|
cachePath: string;
|
|
48
59
|
debug: boolean;
|
|
49
|
-
appWhenReady: Promise<ElectronApplication>;
|
|
50
60
|
playwrightPackage: Promise<unknown>;
|
|
51
|
-
|
|
61
|
+
logger: Logger;
|
|
62
|
+
private _electronApp;
|
|
63
|
+
constructor({ cachePath, debug }: TaskParams);
|
|
52
64
|
/**
|
|
53
65
|
* 安装 playwright
|
|
54
66
|
* @returns
|
|
55
67
|
*/
|
|
56
|
-
installPlaywright
|
|
68
|
+
private installPlaywright;
|
|
69
|
+
/**
|
|
70
|
+
* 启动 Electron
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
private getElectronApp;
|
|
57
74
|
/**
|
|
58
75
|
* 关闭 playwright 启动的 electron 客户端
|
|
59
76
|
* @returns
|
|
@@ -62,7 +79,7 @@ declare class LocalAutomateTask implements TaskParams {
|
|
|
62
79
|
/**
|
|
63
80
|
* 小红书自动化发布
|
|
64
81
|
*/
|
|
65
|
-
xiaohongshuPublish(params: XiaohonshuPublishParams): Promise<
|
|
82
|
+
xiaohongshuPublish(params: XiaohonshuPublishParams): Promise<unknown>;
|
|
66
83
|
}
|
|
67
84
|
declare const RpaTask: (params: TaskParams) => LocalAutomateTask;
|
|
68
85
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import { ElectronApplication } from 'playwright';
|
|
2
1
|
import { CookiesSetDetails } from 'electron';
|
|
3
2
|
|
|
3
|
+
declare class Logger {
|
|
4
|
+
static instance: Logger | null;
|
|
5
|
+
private stream;
|
|
6
|
+
constructor(cachePath: string);
|
|
7
|
+
static getInstance(cachePath: string): Logger;
|
|
8
|
+
debug(...msg: any[]): void;
|
|
9
|
+
info(...msg: any[]): void;
|
|
10
|
+
warn(...msg: any[]): void;
|
|
11
|
+
error(prefix: string, error: unknown): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
type CookieMap = CookiesSetDetails[];
|
|
5
16
|
|
|
6
17
|
interface FictionalRendition {
|
|
@@ -46,14 +57,20 @@ interface TaskParams {
|
|
|
46
57
|
declare class LocalAutomateTask implements TaskParams {
|
|
47
58
|
cachePath: string;
|
|
48
59
|
debug: boolean;
|
|
49
|
-
appWhenReady: Promise<ElectronApplication>;
|
|
50
60
|
playwrightPackage: Promise<unknown>;
|
|
51
|
-
|
|
61
|
+
logger: Logger;
|
|
62
|
+
private _electronApp;
|
|
63
|
+
constructor({ cachePath, debug }: TaskParams);
|
|
52
64
|
/**
|
|
53
65
|
* 安装 playwright
|
|
54
66
|
* @returns
|
|
55
67
|
*/
|
|
56
|
-
installPlaywright
|
|
68
|
+
private installPlaywright;
|
|
69
|
+
/**
|
|
70
|
+
* 启动 Electron
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
private getElectronApp;
|
|
57
74
|
/**
|
|
58
75
|
* 关闭 playwright 启动的 electron 客户端
|
|
59
76
|
* @returns
|
|
@@ -62,7 +79,7 @@ declare class LocalAutomateTask implements TaskParams {
|
|
|
62
79
|
/**
|
|
63
80
|
* 小红书自动化发布
|
|
64
81
|
*/
|
|
65
|
-
xiaohongshuPublish(params: XiaohonshuPublishParams): Promise<
|
|
82
|
+
xiaohongshuPublish(params: XiaohonshuPublishParams): Promise<unknown>;
|
|
66
83
|
}
|
|
67
84
|
declare const RpaTask: (params: TaskParams) => LocalAutomateTask;
|
|
68
85
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import { ElectronApplication } from 'playwright';
|
|
2
1
|
import { CookiesSetDetails } from 'electron';
|
|
3
2
|
|
|
3
|
+
declare class Logger {
|
|
4
|
+
static instance: Logger | null;
|
|
5
|
+
private stream;
|
|
6
|
+
constructor(cachePath: string);
|
|
7
|
+
static getInstance(cachePath: string): Logger;
|
|
8
|
+
debug(...msg: any[]): void;
|
|
9
|
+
info(...msg: any[]): void;
|
|
10
|
+
warn(...msg: any[]): void;
|
|
11
|
+
error(prefix: string, error: unknown): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
type CookieMap = CookiesSetDetails[];
|
|
5
16
|
|
|
6
17
|
interface FictionalRendition {
|
|
@@ -46,14 +57,20 @@ interface TaskParams {
|
|
|
46
57
|
declare class LocalAutomateTask implements TaskParams {
|
|
47
58
|
cachePath: string;
|
|
48
59
|
debug: boolean;
|
|
49
|
-
appWhenReady: Promise<ElectronApplication>;
|
|
50
60
|
playwrightPackage: Promise<unknown>;
|
|
51
|
-
|
|
61
|
+
logger: Logger;
|
|
62
|
+
private _electronApp;
|
|
63
|
+
constructor({ cachePath, debug }: TaskParams);
|
|
52
64
|
/**
|
|
53
65
|
* 安装 playwright
|
|
54
66
|
* @returns
|
|
55
67
|
*/
|
|
56
|
-
installPlaywright
|
|
68
|
+
private installPlaywright;
|
|
69
|
+
/**
|
|
70
|
+
* 启动 Electron
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
private getElectronApp;
|
|
57
74
|
/**
|
|
58
75
|
* 关闭 playwright 启动的 electron 客户端
|
|
59
76
|
* @returns
|
|
@@ -62,7 +79,7 @@ declare class LocalAutomateTask implements TaskParams {
|
|
|
62
79
|
/**
|
|
63
80
|
* 小红书自动化发布
|
|
64
81
|
*/
|
|
65
|
-
xiaohongshuPublish(params: XiaohonshuPublishParams): Promise<
|
|
82
|
+
xiaohongshuPublish(params: XiaohonshuPublishParams): Promise<unknown>;
|
|
66
83
|
}
|
|
67
84
|
declare const RpaTask: (params: TaskParams) => LocalAutomateTask;
|
|
68
85
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import semver from 'semver';
|
|
2
1
|
import path from 'node:path';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import spawn from '
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import https from 'node:https';
|
|
4
|
+
import log from 'loglevel';
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
7
6
|
|
|
8
7
|
const name = "@iflyrpa/playwright";
|
|
9
8
|
const type = "module";
|
|
10
|
-
const version$1 = "1.0.
|
|
9
|
+
const version$1 = "1.0.10";
|
|
11
10
|
const description = "";
|
|
12
11
|
const main = "./dist/index.cjs";
|
|
13
12
|
const module = "./dist/index.mjs";
|
|
@@ -25,23 +24,14 @@ const files = [
|
|
|
25
24
|
"dist"
|
|
26
25
|
];
|
|
27
26
|
const dependencies = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
deepmerge: "^4.3.1",
|
|
31
|
-
"fs-extra": "^11.2.0",
|
|
32
|
-
playwright: "^1.46.1",
|
|
33
|
-
semver: "^7.6.3"
|
|
27
|
+
loglevel: "^1.9.2",
|
|
28
|
+
playwright: "^1.46.1"
|
|
34
29
|
};
|
|
35
30
|
const peerDependencies = {
|
|
36
31
|
electron: "*"
|
|
37
32
|
};
|
|
38
33
|
const devDependencies = {
|
|
39
|
-
"@types/cross-spawn": "^6.0.6",
|
|
40
|
-
"@types/fs-extra": "^11.0.4",
|
|
41
|
-
"@types/semver": "^7.5.8",
|
|
42
|
-
bumpp: "^9.5.2",
|
|
43
34
|
esno: "^4.7.0",
|
|
44
|
-
"ts-node": "^10.9.2",
|
|
45
35
|
typescript: "^5.5.2",
|
|
46
36
|
unbuild: "^2.0.0"
|
|
47
37
|
};
|
|
@@ -63,25 +53,159 @@ const packageJson = {
|
|
|
63
53
|
devDependencies: devDependencies
|
|
64
54
|
};
|
|
65
55
|
|
|
66
|
-
async function downloadImage(url,
|
|
67
|
-
|
|
68
|
-
url,
|
|
69
|
-
method: "GET",
|
|
70
|
-
responseType: "stream"
|
|
71
|
-
// 重要:设置响应类型为 'stream'
|
|
72
|
-
});
|
|
73
|
-
await fs.ensureFile(path2);
|
|
74
|
-
const writer = fs.createWriteStream(path2);
|
|
75
|
-
response.data.pipe(writer);
|
|
56
|
+
async function downloadImage(url, savePath) {
|
|
57
|
+
await ensureFile(savePath);
|
|
76
58
|
return new Promise((resolve, reject) => {
|
|
77
|
-
|
|
78
|
-
|
|
59
|
+
https.get(url, (response) => {
|
|
60
|
+
if (response.statusCode === 200) {
|
|
61
|
+
const fileStream = fs.createWriteStream(savePath);
|
|
62
|
+
response.pipe(fileStream);
|
|
63
|
+
fileStream.on("finish", () => {
|
|
64
|
+
fileStream.close();
|
|
65
|
+
console.log("\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u6587\u4EF6\u5DF2\u4FDD\u5B58\u81F3:", savePath);
|
|
66
|
+
resolve(savePath);
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
console.log("\u56FE\u7247\u4E0B\u8F7D\u5931\u8D25:", response.statusCode);
|
|
70
|
+
response.resume();
|
|
71
|
+
reject();
|
|
72
|
+
}
|
|
73
|
+
}).on("error", (error) => {
|
|
74
|
+
console.error("\u8BF7\u6C42\u56FE\u7247\u65F6\u53D1\u751F\u9519\u8BEF:", error.message);
|
|
75
|
+
reject();
|
|
76
|
+
});
|
|
79
77
|
});
|
|
80
78
|
}
|
|
81
79
|
function getFilenameFromUrl(imageUrl) {
|
|
82
80
|
const parsedUrl = new URL(imageUrl);
|
|
83
81
|
return path.basename(parsedUrl.pathname);
|
|
84
82
|
}
|
|
83
|
+
function pathExists(path2) {
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
fs.stat(path2, (err) => {
|
|
86
|
+
resolve(!err);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function ensureFile(filePath) {
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const dirPath = path.dirname(filePath);
|
|
93
|
+
fs.stat(dirPath, (err, stats) => {
|
|
94
|
+
if (err) {
|
|
95
|
+
if (err.code === "ENOENT") {
|
|
96
|
+
fs.mkdir(dirPath, { recursive: true }, (err2) => {
|
|
97
|
+
if (err2) {
|
|
98
|
+
return reject(err2);
|
|
99
|
+
}
|
|
100
|
+
createFile();
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
return reject(err);
|
|
104
|
+
}
|
|
105
|
+
} else if (stats.isDirectory()) {
|
|
106
|
+
checkFile();
|
|
107
|
+
} else {
|
|
108
|
+
reject(new Error(`${dirPath} is not a directory`));
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
function checkFile() {
|
|
112
|
+
fs.stat(filePath, (err, stats) => {
|
|
113
|
+
if (err) {
|
|
114
|
+
if (err.code === "ENOENT") {
|
|
115
|
+
createFile();
|
|
116
|
+
} else {
|
|
117
|
+
reject(err);
|
|
118
|
+
}
|
|
119
|
+
} else if (stats.isFile()) {
|
|
120
|
+
resolve();
|
|
121
|
+
} else {
|
|
122
|
+
reject(new Error(`${filePath} is not a file`));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function createFile() {
|
|
127
|
+
fs.writeFile(filePath, "", (err) => {
|
|
128
|
+
if (err) {
|
|
129
|
+
reject(err);
|
|
130
|
+
} else {
|
|
131
|
+
resolve();
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function ensureFileSync(filePath) {
|
|
138
|
+
const dirPath = path.dirname(filePath);
|
|
139
|
+
try {
|
|
140
|
+
if (!fs.existsSync(dirPath)) {
|
|
141
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
142
|
+
}
|
|
143
|
+
} catch (err) {
|
|
144
|
+
if (err instanceof Error) {
|
|
145
|
+
throw new Error(`Error creating directory: ${err.message}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
if (!fs.existsSync(filePath)) {
|
|
150
|
+
fs.writeFileSync(filePath, "");
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
if (err instanceof Error) {
|
|
154
|
+
throw new Error(`Error creating file: ${err.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function writeFile(filePath, data) {
|
|
159
|
+
return new Promise((resolve, reject) => {
|
|
160
|
+
fs.writeFile(filePath, data, (err) => {
|
|
161
|
+
if (err) {
|
|
162
|
+
console.error("Error writing file:", err);
|
|
163
|
+
reject();
|
|
164
|
+
} else {
|
|
165
|
+
console.log("File written successfully");
|
|
166
|
+
resolve();
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function compareVersions(v1, v2) {
|
|
172
|
+
const parts1 = v1.split(".").map(Number);
|
|
173
|
+
const parts2 = v2.split(".").map(Number);
|
|
174
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
175
|
+
const num1 = i < parts1.length ? parts1[i] : 0;
|
|
176
|
+
const num2 = i < parts2.length ? parts2[i] : 0;
|
|
177
|
+
if (num1 > num2)
|
|
178
|
+
return 1;
|
|
179
|
+
if (num1 < num2)
|
|
180
|
+
return -1;
|
|
181
|
+
}
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
const semver = {
|
|
185
|
+
gt: (v1, v2) => compareVersions(v1, v2) === 1
|
|
186
|
+
};
|
|
187
|
+
function fetchJSON(url) {
|
|
188
|
+
return new Promise((resolve, reject) => {
|
|
189
|
+
https.get(url, (res) => {
|
|
190
|
+
let data = "";
|
|
191
|
+
res.on("data", (chunk) => {
|
|
192
|
+
data += chunk;
|
|
193
|
+
});
|
|
194
|
+
res.on("end", () => {
|
|
195
|
+
try {
|
|
196
|
+
const parsedData = JSON.parse(data);
|
|
197
|
+
resolve(parsedData);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
if (e instanceof Error) {
|
|
200
|
+
reject(new Error(`Error parsing JSON: ${e.message}`));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}).on("error", (err) => {
|
|
205
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
85
209
|
|
|
86
210
|
const visibleRangeTexts = {
|
|
87
211
|
public: "\u516C\u5F00",
|
|
@@ -205,6 +329,65 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
205
329
|
return response;
|
|
206
330
|
};
|
|
207
331
|
|
|
332
|
+
var __defProp$2 = Object.defineProperty;
|
|
333
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
334
|
+
var __publicField$2 = (obj, key, value) => {
|
|
335
|
+
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
336
|
+
return value;
|
|
337
|
+
};
|
|
338
|
+
const _Logger = class _Logger {
|
|
339
|
+
constructor(cachePath) {
|
|
340
|
+
__publicField$2(this, "stream");
|
|
341
|
+
if (_Logger.instance) {
|
|
342
|
+
return _Logger.instance;
|
|
343
|
+
}
|
|
344
|
+
const logFile = path.join(cachePath, "rpa.log");
|
|
345
|
+
this.stream = fs.createWriteStream(logFile, { flags: "a" });
|
|
346
|
+
log.setLevel("debug");
|
|
347
|
+
log.methodFactory = (methodName) => {
|
|
348
|
+
return (message) => {
|
|
349
|
+
this.stream.write(
|
|
350
|
+
`[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
|
|
351
|
+
`
|
|
352
|
+
);
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
log.setLevel(log.getLevel());
|
|
356
|
+
_Logger.instance = this;
|
|
357
|
+
}
|
|
358
|
+
static getInstance(cachePath) {
|
|
359
|
+
if (!_Logger.instance) {
|
|
360
|
+
_Logger.instance = new _Logger(cachePath);
|
|
361
|
+
}
|
|
362
|
+
return _Logger.instance;
|
|
363
|
+
}
|
|
364
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
365
|
+
debug(...msg) {
|
|
366
|
+
log.debug(...msg);
|
|
367
|
+
}
|
|
368
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
369
|
+
info(...msg) {
|
|
370
|
+
log.info(...msg);
|
|
371
|
+
}
|
|
372
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
373
|
+
warn(...msg) {
|
|
374
|
+
log.warn(...msg);
|
|
375
|
+
}
|
|
376
|
+
error(prefix, error) {
|
|
377
|
+
let errorMessage = error;
|
|
378
|
+
if (error instanceof Error) {
|
|
379
|
+
errorMessage = `${error.message}
|
|
380
|
+
Error stack: ${error.stack}`;
|
|
381
|
+
}
|
|
382
|
+
log.error(prefix, errorMessage);
|
|
383
|
+
}
|
|
384
|
+
close() {
|
|
385
|
+
this.stream.end();
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
__publicField$2(_Logger, "instance", null);
|
|
389
|
+
let Logger = _Logger;
|
|
390
|
+
|
|
208
391
|
const template = `
|
|
209
392
|
const { app } = require("electron");
|
|
210
393
|
|
|
@@ -214,22 +397,35 @@ app.on("window-all-closed", (e) => e.preventDefault());
|
|
|
214
397
|
`;
|
|
215
398
|
const generateFile = async (dir) => {
|
|
216
399
|
const filePath = path.join(dir, "src", "main.js");
|
|
217
|
-
const
|
|
218
|
-
if (!
|
|
219
|
-
await
|
|
220
|
-
await
|
|
400
|
+
const isPathExists = await pathExists(filePath);
|
|
401
|
+
if (!isPathExists) {
|
|
402
|
+
await ensureFile(filePath);
|
|
403
|
+
await writeFile(filePath, template);
|
|
221
404
|
}
|
|
222
405
|
return filePath;
|
|
223
406
|
};
|
|
224
407
|
const createElectronApp = async (cachePath, playwrightPackage) => {
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
408
|
+
const logger = Logger.getInstance(cachePath);
|
|
409
|
+
try {
|
|
410
|
+
const executablePath = path.join(
|
|
411
|
+
cachePath,
|
|
412
|
+
"node_modules",
|
|
413
|
+
".bin",
|
|
414
|
+
"electron"
|
|
415
|
+
);
|
|
416
|
+
const playwright = await playwrightPackage;
|
|
417
|
+
const mainPath = await generateFile(cachePath);
|
|
418
|
+
const electronApp = await playwright._electron.launch({
|
|
419
|
+
executablePath,
|
|
420
|
+
// 获取 Electron 可执行文件的路径
|
|
421
|
+
args: [mainPath],
|
|
422
|
+
cwd: cachePath
|
|
423
|
+
});
|
|
424
|
+
logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
|
|
425
|
+
return electronApp;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
|
|
428
|
+
}
|
|
233
429
|
};
|
|
234
430
|
|
|
235
431
|
var __defProp$1 = Object.defineProperty;
|
|
@@ -245,8 +441,11 @@ class PackageManager {
|
|
|
245
441
|
__publicField$1(this, "forceUpdate");
|
|
246
442
|
// 是否强制更新
|
|
247
443
|
__publicField$1(this, "initPromise");
|
|
444
|
+
__publicField$1(this, "logger");
|
|
445
|
+
this.logger = Logger.getInstance(params.cacheDir);
|
|
248
446
|
this.cacheDir = params.cacheDir;
|
|
249
447
|
this.forceUpdate = params.forceUpdate || true;
|
|
448
|
+
this.initCacheProject();
|
|
250
449
|
this.initPromise = this.init(params.packageName, params.packageVersion);
|
|
251
450
|
}
|
|
252
451
|
// 在子线程执行 npm 命令
|
|
@@ -254,7 +453,8 @@ class PackageManager {
|
|
|
254
453
|
return new Promise((resolve) => {
|
|
255
454
|
const args = [cmd].concat(modules).concat("--color=always").concat("--save");
|
|
256
455
|
try {
|
|
257
|
-
const
|
|
456
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
457
|
+
const npm = spawn(npmCmd, args, { cwd: where });
|
|
258
458
|
let output = "";
|
|
259
459
|
npm.stdout?.on("data", (data) => {
|
|
260
460
|
output += data;
|
|
@@ -274,6 +474,7 @@ class PackageManager {
|
|
|
274
474
|
console.error(err);
|
|
275
475
|
});
|
|
276
476
|
} catch (error) {
|
|
477
|
+
this.logger.error(`npm ${args.join(" ")}: `, error);
|
|
277
478
|
console.error(error);
|
|
278
479
|
}
|
|
279
480
|
});
|
|
@@ -282,21 +483,23 @@ class PackageManager {
|
|
|
282
483
|
initCacheProject() {
|
|
283
484
|
const packagePath = path.join(this.cacheDir, "package.json");
|
|
284
485
|
if (!fs.existsSync(packagePath)) {
|
|
486
|
+
this.logger.info("package.json \u4E0D\u5B58\u5728\uFF0C\u6DFB\u52A0\u8BE5\u6587\u4EF6");
|
|
285
487
|
const pkg = {
|
|
286
488
|
name: "rpa-plugins",
|
|
287
489
|
description: "rpa-plugins",
|
|
288
|
-
license: "MIT"
|
|
490
|
+
license: "MIT",
|
|
491
|
+
main: "./src/main.js"
|
|
289
492
|
};
|
|
290
|
-
|
|
493
|
+
ensureFileSync(packagePath);
|
|
291
494
|
fs.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
|
|
292
495
|
}
|
|
293
496
|
}
|
|
294
497
|
// 获取依赖信息
|
|
295
498
|
async getPluginInfo(module) {
|
|
296
|
-
const res = await
|
|
499
|
+
const res = await fetchJSON(
|
|
297
500
|
`https://registry.npmjs.com/-/v1/search?text=${module}`
|
|
298
501
|
);
|
|
299
|
-
const packages = res.
|
|
502
|
+
const packages = res.objects;
|
|
300
503
|
return packages.find((it) => it.package.name === module)?.package;
|
|
301
504
|
}
|
|
302
505
|
// 查询本地安装的依赖
|
|
@@ -305,6 +508,7 @@ class PackageManager {
|
|
|
305
508
|
try {
|
|
306
509
|
return require(path.join(pluginDir, module));
|
|
307
510
|
} catch (error) {
|
|
511
|
+
this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
|
|
308
512
|
return null;
|
|
309
513
|
}
|
|
310
514
|
}
|
|
@@ -315,27 +519,26 @@ class PackageManager {
|
|
|
315
519
|
// 安装依赖
|
|
316
520
|
install(module, version) {
|
|
317
521
|
const moduleName = version ? `${module}@${version}` : module;
|
|
318
|
-
return this.execCommand("install", [moduleName]);
|
|
522
|
+
return this.execCommand("install", [moduleName, "--save"]);
|
|
319
523
|
}
|
|
320
524
|
// 更新依赖
|
|
321
525
|
update(module) {
|
|
322
526
|
return this.execCommand("update", [module]);
|
|
323
527
|
}
|
|
324
528
|
async init(name, version) {
|
|
325
|
-
this.initCacheProject();
|
|
326
529
|
const plugin = this.getPlugin(path.join(name, "package.json"));
|
|
327
530
|
if (!plugin) {
|
|
328
531
|
await this.install(name, version);
|
|
329
532
|
} else if (this.forceUpdate) {
|
|
330
533
|
const pkInfo = await this.getPluginInfo(name);
|
|
331
534
|
if (!pkInfo)
|
|
332
|
-
|
|
535
|
+
return;
|
|
333
536
|
const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
|
|
334
537
|
if (hasNewVersion) {
|
|
335
538
|
await this.install(name, pkInfo.version);
|
|
336
539
|
}
|
|
337
540
|
}
|
|
338
|
-
|
|
541
|
+
this.logger.info(`${name} package manager init done!`);
|
|
339
542
|
}
|
|
340
543
|
}
|
|
341
544
|
|
|
@@ -347,18 +550,16 @@ var __publicField = (obj, key, value) => {
|
|
|
347
550
|
};
|
|
348
551
|
const PLAYWRIGHT_VERSION = "1.46.1";
|
|
349
552
|
class LocalAutomateTask {
|
|
350
|
-
constructor(
|
|
553
|
+
constructor({ cachePath, debug }) {
|
|
351
554
|
__publicField(this, "cachePath");
|
|
352
555
|
__publicField(this, "debug");
|
|
353
|
-
__publicField(this, "appWhenReady");
|
|
354
556
|
__publicField(this, "playwrightPackage");
|
|
355
|
-
this
|
|
356
|
-
this
|
|
557
|
+
__publicField(this, "logger");
|
|
558
|
+
__publicField(this, "_electronApp", null);
|
|
559
|
+
this.cachePath = cachePath;
|
|
560
|
+
this.debug = debug || false;
|
|
561
|
+
this.logger = Logger.getInstance(cachePath);
|
|
357
562
|
this.playwrightPackage = this.installPlaywright();
|
|
358
|
-
this.appWhenReady = createElectronApp(
|
|
359
|
-
params.cachePath,
|
|
360
|
-
this.playwrightPackage
|
|
361
|
-
);
|
|
362
563
|
}
|
|
363
564
|
/**
|
|
364
565
|
* 安装 playwright
|
|
@@ -372,19 +573,33 @@ class LocalAutomateTask {
|
|
|
372
573
|
});
|
|
373
574
|
return playwrightPackageManager.getPluginAfterInit("playwright");
|
|
374
575
|
}
|
|
576
|
+
/**
|
|
577
|
+
* 启动 Electron
|
|
578
|
+
* @returns
|
|
579
|
+
*/
|
|
580
|
+
async getElectronApp() {
|
|
581
|
+
if (!this._electronApp) {
|
|
582
|
+
this._electronApp = await createElectronApp(
|
|
583
|
+
this.cachePath,
|
|
584
|
+
this.playwrightPackage
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
return this._electronApp;
|
|
588
|
+
}
|
|
375
589
|
/**
|
|
376
590
|
* 关闭 playwright 启动的 electron 客户端
|
|
377
591
|
* @returns
|
|
378
592
|
*/
|
|
379
593
|
async close() {
|
|
380
|
-
|
|
594
|
+
this.logger.close();
|
|
595
|
+
const electronApp = await this.getElectronApp();
|
|
381
596
|
return electronApp.close();
|
|
382
597
|
}
|
|
383
598
|
/**
|
|
384
599
|
* 小红书自动化发布
|
|
385
600
|
*/
|
|
386
601
|
async xiaohongshuPublish(params) {
|
|
387
|
-
const electronApp = await this.
|
|
602
|
+
const electronApp = await this.getElectronApp();
|
|
388
603
|
const commonCookies = {
|
|
389
604
|
path: "/",
|
|
390
605
|
sameSite: "lax",
|
|
@@ -424,22 +639,29 @@ class LocalAutomateTask {
|
|
|
424
639
|
{ pageParams }
|
|
425
640
|
)
|
|
426
641
|
]);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
642
|
+
try {
|
|
643
|
+
const res = await xiaohongshuPublishAction({
|
|
644
|
+
page,
|
|
645
|
+
params,
|
|
646
|
+
cachePath: this.cachePath,
|
|
647
|
+
debug: !!this.debug
|
|
648
|
+
});
|
|
649
|
+
return res;
|
|
650
|
+
} catch (error) {
|
|
651
|
+
this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
|
|
652
|
+
return error;
|
|
653
|
+
}
|
|
434
654
|
}
|
|
435
655
|
}
|
|
436
656
|
const RpaTask = (params) => {
|
|
657
|
+
const logger = Logger.getInstance(params.cachePath);
|
|
437
658
|
const packageManager = new PackageManager({
|
|
438
659
|
packageName: packageJson.name,
|
|
439
660
|
cacheDir: params.cachePath
|
|
440
661
|
});
|
|
441
662
|
const localPackge = packageManager.getPlugin(packageJson.name);
|
|
442
663
|
if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
|
|
664
|
+
logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
|
|
443
665
|
return new localPackge.LocalAutomateTask(params);
|
|
444
666
|
}
|
|
445
667
|
return new LocalAutomateTask(params);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iflyrpa/playwright",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.10",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -16,23 +16,14 @@
|
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"files": ["dist"],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"deepmerge": "^4.3.1",
|
|
22
|
-
"fs-extra": "^11.2.0",
|
|
23
|
-
"playwright": "^1.46.1",
|
|
24
|
-
"semver": "^7.6.3"
|
|
19
|
+
"loglevel": "^1.9.2",
|
|
20
|
+
"playwright": "^1.46.1"
|
|
25
21
|
},
|
|
26
22
|
"peerDependencies": {
|
|
27
23
|
"electron": "*"
|
|
28
24
|
},
|
|
29
25
|
"devDependencies": {
|
|
30
|
-
"@types/cross-spawn": "^6.0.6",
|
|
31
|
-
"@types/fs-extra": "^11.0.4",
|
|
32
|
-
"@types/semver": "^7.5.8",
|
|
33
|
-
"bumpp": "^9.5.2",
|
|
34
26
|
"esno": "^4.7.0",
|
|
35
|
-
"ts-node": "^10.9.2",
|
|
36
27
|
"typescript": "^5.5.2",
|
|
37
28
|
"unbuild": "^2.0.0"
|
|
38
29
|
}
|