@iflyrpa/playwright 1.0.9 → 1.0.10-beta.1
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 +181 -55
- package/dist/index.d.cts +31 -4
- package/dist/index.d.mts +31 -4
- package/dist/index.d.ts +31 -4
- package/dist/index.mjs +179 -54
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const path = require('node:path');
|
|
4
3
|
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
5
|
const https = require('node:https');
|
|
6
|
-
const
|
|
6
|
+
const log = require('loglevel');
|
|
7
7
|
const node_child_process = require('node:child_process');
|
|
8
8
|
|
|
9
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
10
10
|
|
|
11
|
-
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
12
11
|
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
12
|
+
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
13
13
|
const https__default = /*#__PURE__*/_interopDefaultCompat(https);
|
|
14
|
+
const log__default = /*#__PURE__*/_interopDefaultCompat(log);
|
|
14
15
|
|
|
15
16
|
const name = "@iflyrpa/playwright";
|
|
16
17
|
const type = "module";
|
|
17
|
-
const version$1 = "1.0.
|
|
18
|
+
const version$1 = "1.0.10-beta.1";
|
|
18
19
|
const description = "";
|
|
19
20
|
const main = "./dist/index.cjs";
|
|
20
21
|
const module$1 = "./dist/index.mjs";
|
|
@@ -32,6 +33,7 @@ const files = [
|
|
|
32
33
|
"dist"
|
|
33
34
|
];
|
|
34
35
|
const dependencies = {
|
|
36
|
+
loglevel: "^1.9.2",
|
|
35
37
|
playwright: "^1.46.1"
|
|
36
38
|
};
|
|
37
39
|
const peerDependencies = {
|
|
@@ -219,7 +221,7 @@ const visibleRangeTexts = {
|
|
|
219
221
|
private: "\u79C1\u5BC6"
|
|
220
222
|
};
|
|
221
223
|
const xiaohongshuPublishAction = async (props) => {
|
|
222
|
-
const { page,
|
|
224
|
+
const { page, tmpCachePath, params } = props;
|
|
223
225
|
const selectAddress = async (selector, address) => {
|
|
224
226
|
const instance = typeof selector === "string" ? page.locator(selector) : selector;
|
|
225
227
|
await instance.click();
|
|
@@ -242,11 +244,13 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
242
244
|
await page.locator("#content-area .menu-container .publish-video a").click().catch(() => {
|
|
243
245
|
throw new Error("\u672A\u627E\u5230\u53D1\u5E03\u7B14\u8BB0\u6309\u94AE");
|
|
244
246
|
});
|
|
245
|
-
await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click()
|
|
247
|
+
await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click().catch(() => {
|
|
248
|
+
throw new Error("\u672A\u627E\u5230\u4E0A\u4F20\u56FE\u6587\u6309\u94AE");
|
|
249
|
+
});
|
|
246
250
|
const images = await Promise.all(
|
|
247
251
|
params.banners.map((url) => {
|
|
248
252
|
const fileName = getFilenameFromUrl(url);
|
|
249
|
-
return downloadImage(url, path__default.join(
|
|
253
|
+
return downloadImage(url, path__default.join(tmpCachePath, fileName));
|
|
250
254
|
})
|
|
251
255
|
);
|
|
252
256
|
const fileChooserPromise = page.waitForEvent("filechooser");
|
|
@@ -336,6 +340,64 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
336
340
|
return response;
|
|
337
341
|
};
|
|
338
342
|
|
|
343
|
+
var __defProp$2 = Object.defineProperty;
|
|
344
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
345
|
+
var __publicField$2 = (obj, key, value) => {
|
|
346
|
+
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
347
|
+
return value;
|
|
348
|
+
};
|
|
349
|
+
const _Logger = class _Logger {
|
|
350
|
+
constructor(cachePath) {
|
|
351
|
+
__publicField$2(this, "stream");
|
|
352
|
+
if (_Logger.instance) {
|
|
353
|
+
return _Logger.instance;
|
|
354
|
+
}
|
|
355
|
+
const logFile = path__default.join(cachePath, "rpa.log");
|
|
356
|
+
this.stream = fs__default.createWriteStream(logFile, { flags: "a" });
|
|
357
|
+
log__default.setLevel("debug");
|
|
358
|
+
log__default.methodFactory = (methodName) => {
|
|
359
|
+
return (message) => {
|
|
360
|
+
this.stream.write(
|
|
361
|
+
`[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
|
|
362
|
+
`
|
|
363
|
+
);
|
|
364
|
+
};
|
|
365
|
+
};
|
|
366
|
+
log__default.setLevel(log__default.getLevel());
|
|
367
|
+
_Logger.instance = this;
|
|
368
|
+
}
|
|
369
|
+
static getInstance(cachePath) {
|
|
370
|
+
if (!_Logger.instance) {
|
|
371
|
+
_Logger.instance = new _Logger(cachePath);
|
|
372
|
+
}
|
|
373
|
+
return _Logger.instance;
|
|
374
|
+
}
|
|
375
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
376
|
+
debug(...msg) {
|
|
377
|
+
log__default.debug(...msg);
|
|
378
|
+
}
|
|
379
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
380
|
+
info(...msg) {
|
|
381
|
+
log__default.info(...msg);
|
|
382
|
+
}
|
|
383
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
384
|
+
warn(...msg) {
|
|
385
|
+
log__default.warn(...msg);
|
|
386
|
+
}
|
|
387
|
+
error(prefix, error) {
|
|
388
|
+
log__default.error(prefix);
|
|
389
|
+
if (error instanceof Error) {
|
|
390
|
+
log__default.error(`${error.message}
|
|
391
|
+
Error stack: ${error.stack}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
close() {
|
|
395
|
+
this.stream.end();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
__publicField$2(_Logger, "instance", null);
|
|
399
|
+
let Logger = _Logger;
|
|
400
|
+
|
|
339
401
|
const template = `
|
|
340
402
|
const { app } = require("electron");
|
|
341
403
|
|
|
@@ -353,14 +415,27 @@ const generateFile = async (dir) => {
|
|
|
353
415
|
return filePath;
|
|
354
416
|
};
|
|
355
417
|
const createElectronApp = async (cachePath, playwrightPackage) => {
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
418
|
+
const logger = Logger.getInstance(cachePath);
|
|
419
|
+
try {
|
|
420
|
+
const executablePath = path__default.join(
|
|
421
|
+
cachePath,
|
|
422
|
+
"node_modules",
|
|
423
|
+
".bin",
|
|
424
|
+
"electron"
|
|
425
|
+
);
|
|
426
|
+
const playwright = await playwrightPackage;
|
|
427
|
+
const mainPath = await generateFile(cachePath);
|
|
428
|
+
const electronApp = await playwright._electron.launch({
|
|
429
|
+
executablePath,
|
|
430
|
+
// 获取 Electron 可执行文件的路径
|
|
431
|
+
args: [mainPath],
|
|
432
|
+
cwd: cachePath
|
|
433
|
+
});
|
|
434
|
+
logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
|
|
435
|
+
return electronApp;
|
|
436
|
+
} catch (error) {
|
|
437
|
+
logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
|
|
438
|
+
}
|
|
364
439
|
};
|
|
365
440
|
|
|
366
441
|
var __defProp$1 = Object.defineProperty;
|
|
@@ -376,8 +451,11 @@ class PackageManager {
|
|
|
376
451
|
__publicField$1(this, "forceUpdate");
|
|
377
452
|
// 是否强制更新
|
|
378
453
|
__publicField$1(this, "initPromise");
|
|
454
|
+
__publicField$1(this, "logger");
|
|
455
|
+
this.logger = Logger.getInstance(params.cacheDir);
|
|
379
456
|
this.cacheDir = params.cacheDir;
|
|
380
457
|
this.forceUpdate = params.forceUpdate || true;
|
|
458
|
+
this.initCacheProject();
|
|
381
459
|
this.initPromise = this.init(params.packageName, params.packageVersion);
|
|
382
460
|
}
|
|
383
461
|
// 在子线程执行 npm 命令
|
|
@@ -385,7 +463,8 @@ class PackageManager {
|
|
|
385
463
|
return new Promise((resolve) => {
|
|
386
464
|
const args = [cmd].concat(modules).concat("--color=always").concat("--save");
|
|
387
465
|
try {
|
|
388
|
-
const
|
|
466
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
467
|
+
const npm = node_child_process.spawn(npmCmd, args, { cwd: where });
|
|
389
468
|
let output = "";
|
|
390
469
|
npm.stdout?.on("data", (data) => {
|
|
391
470
|
output += data;
|
|
@@ -401,11 +480,10 @@ class PackageManager {
|
|
|
401
480
|
}
|
|
402
481
|
});
|
|
403
482
|
npm.on("error", (err) => {
|
|
404
|
-
|
|
405
|
-
console.error(err);
|
|
483
|
+
this.logger.error("npm run error", err);
|
|
406
484
|
});
|
|
407
485
|
} catch (error) {
|
|
408
|
-
|
|
486
|
+
this.logger.error(`npm ${args.join(" ")}: `, error);
|
|
409
487
|
}
|
|
410
488
|
});
|
|
411
489
|
}
|
|
@@ -413,10 +491,12 @@ class PackageManager {
|
|
|
413
491
|
initCacheProject() {
|
|
414
492
|
const packagePath = path__default.join(this.cacheDir, "package.json");
|
|
415
493
|
if (!fs__default.existsSync(packagePath)) {
|
|
494
|
+
this.logger.info("package.json \u4E0D\u5B58\u5728\uFF0C\u6DFB\u52A0\u8BE5\u6587\u4EF6");
|
|
416
495
|
const pkg = {
|
|
417
496
|
name: "rpa-plugins",
|
|
418
497
|
description: "rpa-plugins",
|
|
419
|
-
license: "MIT"
|
|
498
|
+
license: "MIT",
|
|
499
|
+
main: "./src/main.js"
|
|
420
500
|
};
|
|
421
501
|
ensureFileSync(packagePath);
|
|
422
502
|
fs__default.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
|
|
@@ -436,6 +516,7 @@ class PackageManager {
|
|
|
436
516
|
try {
|
|
437
517
|
return require(path__default.join(pluginDir, module));
|
|
438
518
|
} catch (error) {
|
|
519
|
+
this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
|
|
439
520
|
return null;
|
|
440
521
|
}
|
|
441
522
|
}
|
|
@@ -453,20 +534,23 @@ class PackageManager {
|
|
|
453
534
|
return this.execCommand("update", [module]);
|
|
454
535
|
}
|
|
455
536
|
async init(name, version) {
|
|
456
|
-
this.initCacheProject();
|
|
457
537
|
const plugin = this.getPlugin(path__default.join(name, "package.json"));
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
538
|
+
try {
|
|
539
|
+
if (!plugin) {
|
|
540
|
+
await this.install(name, version);
|
|
541
|
+
} else if (this.forceUpdate) {
|
|
542
|
+
const pkInfo = await this.getPluginInfo(name);
|
|
543
|
+
if (!pkInfo)
|
|
544
|
+
return;
|
|
545
|
+
const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
|
|
546
|
+
if (hasNewVersion) {
|
|
547
|
+
await this.install(name, pkInfo.version);
|
|
548
|
+
}
|
|
467
549
|
}
|
|
550
|
+
this.logger.info(`${name} package manager init done!`);
|
|
551
|
+
} catch (error) {
|
|
552
|
+
this.logger.error(`${name} package manager init error`, error);
|
|
468
553
|
}
|
|
469
|
-
console.log("Package manager init done!");
|
|
470
554
|
}
|
|
471
555
|
}
|
|
472
556
|
|
|
@@ -478,18 +562,16 @@ var __publicField = (obj, key, value) => {
|
|
|
478
562
|
};
|
|
479
563
|
const PLAYWRIGHT_VERSION = "1.46.1";
|
|
480
564
|
class LocalAutomateTask {
|
|
481
|
-
constructor(
|
|
565
|
+
constructor({ cachePath, debug }) {
|
|
482
566
|
__publicField(this, "cachePath");
|
|
483
567
|
__publicField(this, "debug");
|
|
484
|
-
__publicField(this, "appWhenReady");
|
|
485
568
|
__publicField(this, "playwrightPackage");
|
|
486
|
-
this
|
|
487
|
-
this
|
|
569
|
+
__publicField(this, "logger");
|
|
570
|
+
__publicField(this, "_electronApp", null);
|
|
571
|
+
this.cachePath = cachePath;
|
|
572
|
+
this.debug = debug || false;
|
|
573
|
+
this.logger = Logger.getInstance(cachePath);
|
|
488
574
|
this.playwrightPackage = this.installPlaywright();
|
|
489
|
-
this.appWhenReady = createElectronApp(
|
|
490
|
-
params.cachePath,
|
|
491
|
-
this.playwrightPackage
|
|
492
|
-
);
|
|
493
575
|
}
|
|
494
576
|
/**
|
|
495
577
|
* 安装 playwright
|
|
@@ -503,19 +585,54 @@ class LocalAutomateTask {
|
|
|
503
585
|
});
|
|
504
586
|
return playwrightPackageManager.getPluginAfterInit("playwright");
|
|
505
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* 启动 Electron
|
|
590
|
+
* @returns
|
|
591
|
+
*/
|
|
592
|
+
async getElectronApp() {
|
|
593
|
+
if (!this._electronApp) {
|
|
594
|
+
this._electronApp = await createElectronApp(
|
|
595
|
+
this.cachePath,
|
|
596
|
+
this.playwrightPackage
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
return this._electronApp;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* 临时文件目录
|
|
603
|
+
* @returns
|
|
604
|
+
*/
|
|
605
|
+
getTmpPath() {
|
|
606
|
+
return path__default.join(this.cachePath, "tmp");
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* 清空临时文件
|
|
610
|
+
*/
|
|
611
|
+
clearTmpPath() {
|
|
612
|
+
const tmpPath = this.getTmpPath();
|
|
613
|
+
return fs__default.rm(tmpPath, { recursive: true, force: true }, (err) => {
|
|
614
|
+
if (err) {
|
|
615
|
+
this.logger.error("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u5931\u8D25\uFF0C", err);
|
|
616
|
+
} else {
|
|
617
|
+
this.logger.info("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u6210\u529F");
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
}
|
|
506
621
|
/**
|
|
507
622
|
* 关闭 playwright 启动的 electron 客户端
|
|
508
623
|
* @returns
|
|
509
624
|
*/
|
|
510
625
|
async close() {
|
|
511
|
-
|
|
626
|
+
this.logger.close();
|
|
627
|
+
this.clearTmpPath();
|
|
628
|
+
const electronApp = await this.getElectronApp();
|
|
512
629
|
return electronApp.close();
|
|
513
630
|
}
|
|
514
631
|
/**
|
|
515
632
|
* 小红书自动化发布
|
|
516
633
|
*/
|
|
517
634
|
async xiaohongshuPublish(params) {
|
|
518
|
-
const electronApp = await this.
|
|
635
|
+
const electronApp = await this.getElectronApp();
|
|
519
636
|
const commonCookies = {
|
|
520
637
|
path: "/",
|
|
521
638
|
sameSite: "lax",
|
|
@@ -555,23 +672,32 @@ class LocalAutomateTask {
|
|
|
555
672
|
{ pageParams }
|
|
556
673
|
)
|
|
557
674
|
]);
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
675
|
+
try {
|
|
676
|
+
const res = await xiaohongshuPublishAction({
|
|
677
|
+
page,
|
|
678
|
+
params,
|
|
679
|
+
tmpCachePath: this.getTmpPath(),
|
|
680
|
+
debug: !!this.debug
|
|
681
|
+
});
|
|
682
|
+
return res;
|
|
683
|
+
} catch (error) {
|
|
684
|
+
this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
|
|
685
|
+
throw error;
|
|
686
|
+
}
|
|
565
687
|
}
|
|
566
688
|
}
|
|
567
689
|
const RpaTask = (params) => {
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
690
|
+
const logger = Logger.getInstance(params.cachePath);
|
|
691
|
+
if (params.forceUpdate) {
|
|
692
|
+
const packageManager = new PackageManager({
|
|
693
|
+
packageName: packageJson.name,
|
|
694
|
+
cacheDir: params.cachePath
|
|
695
|
+
});
|
|
696
|
+
const localPackge = packageManager.getPlugin(packageJson.name);
|
|
697
|
+
if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
|
|
698
|
+
logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
|
|
699
|
+
return new localPackge.LocalAutomateTask(params);
|
|
700
|
+
}
|
|
575
701
|
}
|
|
576
702
|
return new LocalAutomateTask(params);
|
|
577
703
|
};
|
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 {
|
|
@@ -42,18 +53,34 @@ interface XiaohonshuPublishParams
|
|
|
42
53
|
interface TaskParams {
|
|
43
54
|
debug?: boolean;
|
|
44
55
|
cachePath: string;
|
|
56
|
+
forceUpdate?: boolean;
|
|
45
57
|
}
|
|
46
58
|
declare class LocalAutomateTask implements TaskParams {
|
|
47
59
|
cachePath: string;
|
|
48
60
|
debug: boolean;
|
|
49
|
-
appWhenReady: Promise<ElectronApplication>;
|
|
50
61
|
playwrightPackage: Promise<unknown>;
|
|
51
|
-
|
|
62
|
+
logger: Logger;
|
|
63
|
+
private _electronApp;
|
|
64
|
+
constructor({ cachePath, debug }: TaskParams);
|
|
52
65
|
/**
|
|
53
66
|
* 安装 playwright
|
|
54
67
|
* @returns
|
|
55
68
|
*/
|
|
56
|
-
installPlaywright
|
|
69
|
+
private installPlaywright;
|
|
70
|
+
/**
|
|
71
|
+
* 启动 Electron
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
private getElectronApp;
|
|
75
|
+
/**
|
|
76
|
+
* 临时文件目录
|
|
77
|
+
* @returns
|
|
78
|
+
*/
|
|
79
|
+
private getTmpPath;
|
|
80
|
+
/**
|
|
81
|
+
* 清空临时文件
|
|
82
|
+
*/
|
|
83
|
+
private clearTmpPath;
|
|
57
84
|
/**
|
|
58
85
|
* 关闭 playwright 启动的 electron 客户端
|
|
59
86
|
* @returns
|
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 {
|
|
@@ -42,18 +53,34 @@ interface XiaohonshuPublishParams
|
|
|
42
53
|
interface TaskParams {
|
|
43
54
|
debug?: boolean;
|
|
44
55
|
cachePath: string;
|
|
56
|
+
forceUpdate?: boolean;
|
|
45
57
|
}
|
|
46
58
|
declare class LocalAutomateTask implements TaskParams {
|
|
47
59
|
cachePath: string;
|
|
48
60
|
debug: boolean;
|
|
49
|
-
appWhenReady: Promise<ElectronApplication>;
|
|
50
61
|
playwrightPackage: Promise<unknown>;
|
|
51
|
-
|
|
62
|
+
logger: Logger;
|
|
63
|
+
private _electronApp;
|
|
64
|
+
constructor({ cachePath, debug }: TaskParams);
|
|
52
65
|
/**
|
|
53
66
|
* 安装 playwright
|
|
54
67
|
* @returns
|
|
55
68
|
*/
|
|
56
|
-
installPlaywright
|
|
69
|
+
private installPlaywright;
|
|
70
|
+
/**
|
|
71
|
+
* 启动 Electron
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
private getElectronApp;
|
|
75
|
+
/**
|
|
76
|
+
* 临时文件目录
|
|
77
|
+
* @returns
|
|
78
|
+
*/
|
|
79
|
+
private getTmpPath;
|
|
80
|
+
/**
|
|
81
|
+
* 清空临时文件
|
|
82
|
+
*/
|
|
83
|
+
private clearTmpPath;
|
|
57
84
|
/**
|
|
58
85
|
* 关闭 playwright 启动的 electron 客户端
|
|
59
86
|
* @returns
|
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 {
|
|
@@ -42,18 +53,34 @@ interface XiaohonshuPublishParams
|
|
|
42
53
|
interface TaskParams {
|
|
43
54
|
debug?: boolean;
|
|
44
55
|
cachePath: string;
|
|
56
|
+
forceUpdate?: boolean;
|
|
45
57
|
}
|
|
46
58
|
declare class LocalAutomateTask implements TaskParams {
|
|
47
59
|
cachePath: string;
|
|
48
60
|
debug: boolean;
|
|
49
|
-
appWhenReady: Promise<ElectronApplication>;
|
|
50
61
|
playwrightPackage: Promise<unknown>;
|
|
51
|
-
|
|
62
|
+
logger: Logger;
|
|
63
|
+
private _electronApp;
|
|
64
|
+
constructor({ cachePath, debug }: TaskParams);
|
|
52
65
|
/**
|
|
53
66
|
* 安装 playwright
|
|
54
67
|
* @returns
|
|
55
68
|
*/
|
|
56
|
-
installPlaywright
|
|
69
|
+
private installPlaywright;
|
|
70
|
+
/**
|
|
71
|
+
* 启动 Electron
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
private getElectronApp;
|
|
75
|
+
/**
|
|
76
|
+
* 临时文件目录
|
|
77
|
+
* @returns
|
|
78
|
+
*/
|
|
79
|
+
private getTmpPath;
|
|
80
|
+
/**
|
|
81
|
+
* 清空临时文件
|
|
82
|
+
*/
|
|
83
|
+
private clearTmpPath;
|
|
57
84
|
/**
|
|
58
85
|
* 关闭 playwright 启动的 electron 客户端
|
|
59
86
|
* @returns
|
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import https from 'node:https';
|
|
4
|
-
import
|
|
4
|
+
import log from 'loglevel';
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
6
|
|
|
7
7
|
const name = "@iflyrpa/playwright";
|
|
8
8
|
const type = "module";
|
|
9
|
-
const version$1 = "1.0.
|
|
9
|
+
const version$1 = "1.0.10-beta.1";
|
|
10
10
|
const description = "";
|
|
11
11
|
const main = "./dist/index.cjs";
|
|
12
12
|
const module = "./dist/index.mjs";
|
|
@@ -24,6 +24,7 @@ const files = [
|
|
|
24
24
|
"dist"
|
|
25
25
|
];
|
|
26
26
|
const dependencies = {
|
|
27
|
+
loglevel: "^1.9.2",
|
|
27
28
|
playwright: "^1.46.1"
|
|
28
29
|
};
|
|
29
30
|
const peerDependencies = {
|
|
@@ -211,7 +212,7 @@ const visibleRangeTexts = {
|
|
|
211
212
|
private: "\u79C1\u5BC6"
|
|
212
213
|
};
|
|
213
214
|
const xiaohongshuPublishAction = async (props) => {
|
|
214
|
-
const { page,
|
|
215
|
+
const { page, tmpCachePath, params } = props;
|
|
215
216
|
const selectAddress = async (selector, address) => {
|
|
216
217
|
const instance = typeof selector === "string" ? page.locator(selector) : selector;
|
|
217
218
|
await instance.click();
|
|
@@ -234,11 +235,13 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
234
235
|
await page.locator("#content-area .menu-container .publish-video a").click().catch(() => {
|
|
235
236
|
throw new Error("\u672A\u627E\u5230\u53D1\u5E03\u7B14\u8BB0\u6309\u94AE");
|
|
236
237
|
});
|
|
237
|
-
await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click()
|
|
238
|
+
await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click().catch(() => {
|
|
239
|
+
throw new Error("\u672A\u627E\u5230\u4E0A\u4F20\u56FE\u6587\u6309\u94AE");
|
|
240
|
+
});
|
|
238
241
|
const images = await Promise.all(
|
|
239
242
|
params.banners.map((url) => {
|
|
240
243
|
const fileName = getFilenameFromUrl(url);
|
|
241
|
-
return downloadImage(url, path.join(
|
|
244
|
+
return downloadImage(url, path.join(tmpCachePath, fileName));
|
|
242
245
|
})
|
|
243
246
|
);
|
|
244
247
|
const fileChooserPromise = page.waitForEvent("filechooser");
|
|
@@ -328,6 +331,64 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
328
331
|
return response;
|
|
329
332
|
};
|
|
330
333
|
|
|
334
|
+
var __defProp$2 = Object.defineProperty;
|
|
335
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
336
|
+
var __publicField$2 = (obj, key, value) => {
|
|
337
|
+
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
338
|
+
return value;
|
|
339
|
+
};
|
|
340
|
+
const _Logger = class _Logger {
|
|
341
|
+
constructor(cachePath) {
|
|
342
|
+
__publicField$2(this, "stream");
|
|
343
|
+
if (_Logger.instance) {
|
|
344
|
+
return _Logger.instance;
|
|
345
|
+
}
|
|
346
|
+
const logFile = path.join(cachePath, "rpa.log");
|
|
347
|
+
this.stream = fs.createWriteStream(logFile, { flags: "a" });
|
|
348
|
+
log.setLevel("debug");
|
|
349
|
+
log.methodFactory = (methodName) => {
|
|
350
|
+
return (message) => {
|
|
351
|
+
this.stream.write(
|
|
352
|
+
`[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
|
|
353
|
+
`
|
|
354
|
+
);
|
|
355
|
+
};
|
|
356
|
+
};
|
|
357
|
+
log.setLevel(log.getLevel());
|
|
358
|
+
_Logger.instance = this;
|
|
359
|
+
}
|
|
360
|
+
static getInstance(cachePath) {
|
|
361
|
+
if (!_Logger.instance) {
|
|
362
|
+
_Logger.instance = new _Logger(cachePath);
|
|
363
|
+
}
|
|
364
|
+
return _Logger.instance;
|
|
365
|
+
}
|
|
366
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
367
|
+
debug(...msg) {
|
|
368
|
+
log.debug(...msg);
|
|
369
|
+
}
|
|
370
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
371
|
+
info(...msg) {
|
|
372
|
+
log.info(...msg);
|
|
373
|
+
}
|
|
374
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
375
|
+
warn(...msg) {
|
|
376
|
+
log.warn(...msg);
|
|
377
|
+
}
|
|
378
|
+
error(prefix, error) {
|
|
379
|
+
log.error(prefix);
|
|
380
|
+
if (error instanceof Error) {
|
|
381
|
+
log.error(`${error.message}
|
|
382
|
+
Error stack: ${error.stack}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
close() {
|
|
386
|
+
this.stream.end();
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
__publicField$2(_Logger, "instance", null);
|
|
390
|
+
let Logger = _Logger;
|
|
391
|
+
|
|
331
392
|
const template = `
|
|
332
393
|
const { app } = require("electron");
|
|
333
394
|
|
|
@@ -345,14 +406,27 @@ const generateFile = async (dir) => {
|
|
|
345
406
|
return filePath;
|
|
346
407
|
};
|
|
347
408
|
const createElectronApp = async (cachePath, playwrightPackage) => {
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
409
|
+
const logger = Logger.getInstance(cachePath);
|
|
410
|
+
try {
|
|
411
|
+
const executablePath = path.join(
|
|
412
|
+
cachePath,
|
|
413
|
+
"node_modules",
|
|
414
|
+
".bin",
|
|
415
|
+
"electron"
|
|
416
|
+
);
|
|
417
|
+
const playwright = await playwrightPackage;
|
|
418
|
+
const mainPath = await generateFile(cachePath);
|
|
419
|
+
const electronApp = await playwright._electron.launch({
|
|
420
|
+
executablePath,
|
|
421
|
+
// 获取 Electron 可执行文件的路径
|
|
422
|
+
args: [mainPath],
|
|
423
|
+
cwd: cachePath
|
|
424
|
+
});
|
|
425
|
+
logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
|
|
426
|
+
return electronApp;
|
|
427
|
+
} catch (error) {
|
|
428
|
+
logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
|
|
429
|
+
}
|
|
356
430
|
};
|
|
357
431
|
|
|
358
432
|
var __defProp$1 = Object.defineProperty;
|
|
@@ -368,8 +442,11 @@ class PackageManager {
|
|
|
368
442
|
__publicField$1(this, "forceUpdate");
|
|
369
443
|
// 是否强制更新
|
|
370
444
|
__publicField$1(this, "initPromise");
|
|
445
|
+
__publicField$1(this, "logger");
|
|
446
|
+
this.logger = Logger.getInstance(params.cacheDir);
|
|
371
447
|
this.cacheDir = params.cacheDir;
|
|
372
448
|
this.forceUpdate = params.forceUpdate || true;
|
|
449
|
+
this.initCacheProject();
|
|
373
450
|
this.initPromise = this.init(params.packageName, params.packageVersion);
|
|
374
451
|
}
|
|
375
452
|
// 在子线程执行 npm 命令
|
|
@@ -377,7 +454,8 @@ class PackageManager {
|
|
|
377
454
|
return new Promise((resolve) => {
|
|
378
455
|
const args = [cmd].concat(modules).concat("--color=always").concat("--save");
|
|
379
456
|
try {
|
|
380
|
-
const
|
|
457
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
458
|
+
const npm = spawn(npmCmd, args, { cwd: where });
|
|
381
459
|
let output = "";
|
|
382
460
|
npm.stdout?.on("data", (data) => {
|
|
383
461
|
output += data;
|
|
@@ -393,11 +471,10 @@ class PackageManager {
|
|
|
393
471
|
}
|
|
394
472
|
});
|
|
395
473
|
npm.on("error", (err) => {
|
|
396
|
-
|
|
397
|
-
console.error(err);
|
|
474
|
+
this.logger.error("npm run error", err);
|
|
398
475
|
});
|
|
399
476
|
} catch (error) {
|
|
400
|
-
|
|
477
|
+
this.logger.error(`npm ${args.join(" ")}: `, error);
|
|
401
478
|
}
|
|
402
479
|
});
|
|
403
480
|
}
|
|
@@ -405,10 +482,12 @@ class PackageManager {
|
|
|
405
482
|
initCacheProject() {
|
|
406
483
|
const packagePath = path.join(this.cacheDir, "package.json");
|
|
407
484
|
if (!fs.existsSync(packagePath)) {
|
|
485
|
+
this.logger.info("package.json \u4E0D\u5B58\u5728\uFF0C\u6DFB\u52A0\u8BE5\u6587\u4EF6");
|
|
408
486
|
const pkg = {
|
|
409
487
|
name: "rpa-plugins",
|
|
410
488
|
description: "rpa-plugins",
|
|
411
|
-
license: "MIT"
|
|
489
|
+
license: "MIT",
|
|
490
|
+
main: "./src/main.js"
|
|
412
491
|
};
|
|
413
492
|
ensureFileSync(packagePath);
|
|
414
493
|
fs.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
|
|
@@ -428,6 +507,7 @@ class PackageManager {
|
|
|
428
507
|
try {
|
|
429
508
|
return require(path.join(pluginDir, module));
|
|
430
509
|
} catch (error) {
|
|
510
|
+
this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
|
|
431
511
|
return null;
|
|
432
512
|
}
|
|
433
513
|
}
|
|
@@ -445,20 +525,23 @@ class PackageManager {
|
|
|
445
525
|
return this.execCommand("update", [module]);
|
|
446
526
|
}
|
|
447
527
|
async init(name, version) {
|
|
448
|
-
this.initCacheProject();
|
|
449
528
|
const plugin = this.getPlugin(path.join(name, "package.json"));
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
529
|
+
try {
|
|
530
|
+
if (!plugin) {
|
|
531
|
+
await this.install(name, version);
|
|
532
|
+
} else if (this.forceUpdate) {
|
|
533
|
+
const pkInfo = await this.getPluginInfo(name);
|
|
534
|
+
if (!pkInfo)
|
|
535
|
+
return;
|
|
536
|
+
const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
|
|
537
|
+
if (hasNewVersion) {
|
|
538
|
+
await this.install(name, pkInfo.version);
|
|
539
|
+
}
|
|
459
540
|
}
|
|
541
|
+
this.logger.info(`${name} package manager init done!`);
|
|
542
|
+
} catch (error) {
|
|
543
|
+
this.logger.error(`${name} package manager init error`, error);
|
|
460
544
|
}
|
|
461
|
-
console.log("Package manager init done!");
|
|
462
545
|
}
|
|
463
546
|
}
|
|
464
547
|
|
|
@@ -470,18 +553,16 @@ var __publicField = (obj, key, value) => {
|
|
|
470
553
|
};
|
|
471
554
|
const PLAYWRIGHT_VERSION = "1.46.1";
|
|
472
555
|
class LocalAutomateTask {
|
|
473
|
-
constructor(
|
|
556
|
+
constructor({ cachePath, debug }) {
|
|
474
557
|
__publicField(this, "cachePath");
|
|
475
558
|
__publicField(this, "debug");
|
|
476
|
-
__publicField(this, "appWhenReady");
|
|
477
559
|
__publicField(this, "playwrightPackage");
|
|
478
|
-
this
|
|
479
|
-
this
|
|
560
|
+
__publicField(this, "logger");
|
|
561
|
+
__publicField(this, "_electronApp", null);
|
|
562
|
+
this.cachePath = cachePath;
|
|
563
|
+
this.debug = debug || false;
|
|
564
|
+
this.logger = Logger.getInstance(cachePath);
|
|
480
565
|
this.playwrightPackage = this.installPlaywright();
|
|
481
|
-
this.appWhenReady = createElectronApp(
|
|
482
|
-
params.cachePath,
|
|
483
|
-
this.playwrightPackage
|
|
484
|
-
);
|
|
485
566
|
}
|
|
486
567
|
/**
|
|
487
568
|
* 安装 playwright
|
|
@@ -495,19 +576,54 @@ class LocalAutomateTask {
|
|
|
495
576
|
});
|
|
496
577
|
return playwrightPackageManager.getPluginAfterInit("playwright");
|
|
497
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* 启动 Electron
|
|
581
|
+
* @returns
|
|
582
|
+
*/
|
|
583
|
+
async getElectronApp() {
|
|
584
|
+
if (!this._electronApp) {
|
|
585
|
+
this._electronApp = await createElectronApp(
|
|
586
|
+
this.cachePath,
|
|
587
|
+
this.playwrightPackage
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
return this._electronApp;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* 临时文件目录
|
|
594
|
+
* @returns
|
|
595
|
+
*/
|
|
596
|
+
getTmpPath() {
|
|
597
|
+
return path.join(this.cachePath, "tmp");
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* 清空临时文件
|
|
601
|
+
*/
|
|
602
|
+
clearTmpPath() {
|
|
603
|
+
const tmpPath = this.getTmpPath();
|
|
604
|
+
return fs.rm(tmpPath, { recursive: true, force: true }, (err) => {
|
|
605
|
+
if (err) {
|
|
606
|
+
this.logger.error("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u5931\u8D25\uFF0C", err);
|
|
607
|
+
} else {
|
|
608
|
+
this.logger.info("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u6210\u529F");
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
}
|
|
498
612
|
/**
|
|
499
613
|
* 关闭 playwright 启动的 electron 客户端
|
|
500
614
|
* @returns
|
|
501
615
|
*/
|
|
502
616
|
async close() {
|
|
503
|
-
|
|
617
|
+
this.logger.close();
|
|
618
|
+
this.clearTmpPath();
|
|
619
|
+
const electronApp = await this.getElectronApp();
|
|
504
620
|
return electronApp.close();
|
|
505
621
|
}
|
|
506
622
|
/**
|
|
507
623
|
* 小红书自动化发布
|
|
508
624
|
*/
|
|
509
625
|
async xiaohongshuPublish(params) {
|
|
510
|
-
const electronApp = await this.
|
|
626
|
+
const electronApp = await this.getElectronApp();
|
|
511
627
|
const commonCookies = {
|
|
512
628
|
path: "/",
|
|
513
629
|
sameSite: "lax",
|
|
@@ -547,23 +663,32 @@ class LocalAutomateTask {
|
|
|
547
663
|
{ pageParams }
|
|
548
664
|
)
|
|
549
665
|
]);
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
666
|
+
try {
|
|
667
|
+
const res = await xiaohongshuPublishAction({
|
|
668
|
+
page,
|
|
669
|
+
params,
|
|
670
|
+
tmpCachePath: this.getTmpPath(),
|
|
671
|
+
debug: !!this.debug
|
|
672
|
+
});
|
|
673
|
+
return res;
|
|
674
|
+
} catch (error) {
|
|
675
|
+
this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
|
|
676
|
+
throw error;
|
|
677
|
+
}
|
|
557
678
|
}
|
|
558
679
|
}
|
|
559
680
|
const RpaTask = (params) => {
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
681
|
+
const logger = Logger.getInstance(params.cachePath);
|
|
682
|
+
if (params.forceUpdate) {
|
|
683
|
+
const packageManager = new PackageManager({
|
|
684
|
+
packageName: packageJson.name,
|
|
685
|
+
cacheDir: params.cachePath
|
|
686
|
+
});
|
|
687
|
+
const localPackge = packageManager.getPlugin(packageJson.name);
|
|
688
|
+
if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
|
|
689
|
+
logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
|
|
690
|
+
return new localPackge.LocalAutomateTask(params);
|
|
691
|
+
}
|
|
567
692
|
}
|
|
568
693
|
return new LocalAutomateTask(params);
|
|
569
694
|
};
|
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-beta.1",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"files": ["dist"],
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"loglevel": "^1.9.2",
|
|
19
20
|
"playwright": "^1.46.1"
|
|
20
21
|
},
|
|
21
22
|
"peerDependencies": {
|