@iflyrpa/share 0.0.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 +178 -0
- package/dist/index.mjs +162 -0
- package/package.json +21 -0
- package/src/index.ts +3 -0
- package/src/types.ts +75 -0
- package/src/utils.ts +211 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const https = require('node:https');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
8
|
+
|
|
9
|
+
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
10
|
+
const https__default = /*#__PURE__*/_interopDefaultCompat(https);
|
|
11
|
+
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
12
|
+
|
|
13
|
+
function pathExists(path2) {
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
fs__default.stat(path2, (err) => {
|
|
16
|
+
resolve(!err);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function ensureFileSync(filePath) {
|
|
21
|
+
const dirPath = path__default.dirname(filePath);
|
|
22
|
+
try {
|
|
23
|
+
if (!fs__default.existsSync(dirPath)) {
|
|
24
|
+
fs__default.mkdirSync(dirPath, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
} catch (err) {
|
|
27
|
+
if (err instanceof Error) {
|
|
28
|
+
throw new Error(`Error creating directory: ${err.message}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
if (!fs__default.existsSync(filePath)) {
|
|
33
|
+
fs__default.writeFileSync(filePath, "");
|
|
34
|
+
}
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err instanceof Error) {
|
|
37
|
+
throw new Error(`Error creating file: ${err.message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function writeFile(filePath, data) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
fs__default.writeFile(filePath, data, (err) => {
|
|
44
|
+
if (err) {
|
|
45
|
+
console.error("Error writing file:", err);
|
|
46
|
+
reject();
|
|
47
|
+
} else {
|
|
48
|
+
console.log("File written successfully");
|
|
49
|
+
resolve();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function compareVersions(v1, v2) {
|
|
55
|
+
const parts1 = v1.split(".").map(Number);
|
|
56
|
+
const parts2 = v2.split(".").map(Number);
|
|
57
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
58
|
+
const num1 = i < parts1.length ? parts1[i] : 0;
|
|
59
|
+
const num2 = i < parts2.length ? parts2[i] : 0;
|
|
60
|
+
if (num1 > num2)
|
|
61
|
+
return 1;
|
|
62
|
+
if (num1 < num2)
|
|
63
|
+
return -1;
|
|
64
|
+
}
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
const semver = {
|
|
68
|
+
gt: (v1, v2) => compareVersions(v1, v2) === 1
|
|
69
|
+
};
|
|
70
|
+
function fetchJSON(url) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
https__default.get(url, (res) => {
|
|
73
|
+
let data = "";
|
|
74
|
+
res.on("data", (chunk) => {
|
|
75
|
+
data += chunk;
|
|
76
|
+
});
|
|
77
|
+
res.on("end", () => {
|
|
78
|
+
try {
|
|
79
|
+
const parsedData = JSON.parse(data);
|
|
80
|
+
resolve(parsedData);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
if (e instanceof Error) {
|
|
83
|
+
reject(new Error(`Error parsing JSON: ${e.message}`));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}).on("error", (err) => {
|
|
88
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function isNil(value) {
|
|
93
|
+
return value === null || value === void 0;
|
|
94
|
+
}
|
|
95
|
+
function ensureFile(filePath) {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
const dirPath = path__default.dirname(filePath);
|
|
98
|
+
fs__default.stat(dirPath, (err, stats) => {
|
|
99
|
+
if (err) {
|
|
100
|
+
if (err.code === "ENOENT") {
|
|
101
|
+
fs__default.mkdir(dirPath, { recursive: true }, (err2) => {
|
|
102
|
+
if (err2) {
|
|
103
|
+
return reject(err2);
|
|
104
|
+
}
|
|
105
|
+
createFile();
|
|
106
|
+
});
|
|
107
|
+
} else {
|
|
108
|
+
return reject(err);
|
|
109
|
+
}
|
|
110
|
+
} else if (stats.isDirectory()) {
|
|
111
|
+
checkFile();
|
|
112
|
+
} else {
|
|
113
|
+
reject(new Error(`${dirPath} is not a directory`));
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
function checkFile() {
|
|
117
|
+
fs__default.stat(filePath, (err, stats) => {
|
|
118
|
+
if (err) {
|
|
119
|
+
if (err.code === "ENOENT") {
|
|
120
|
+
createFile();
|
|
121
|
+
} else {
|
|
122
|
+
reject(err);
|
|
123
|
+
}
|
|
124
|
+
} else if (stats.isFile()) {
|
|
125
|
+
resolve();
|
|
126
|
+
} else {
|
|
127
|
+
reject(new Error(`${filePath} is not a file`));
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function createFile() {
|
|
132
|
+
fs__default.writeFile(filePath, "", (err) => {
|
|
133
|
+
if (err) {
|
|
134
|
+
reject(err);
|
|
135
|
+
} else {
|
|
136
|
+
resolve();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
async function downloadImage(url, savePath) {
|
|
143
|
+
await ensureFile(savePath);
|
|
144
|
+
return new Promise((resolve, reject) => {
|
|
145
|
+
https__default.get(url, (response) => {
|
|
146
|
+
if (response.statusCode === 200) {
|
|
147
|
+
const fileStream = fs__default.createWriteStream(savePath);
|
|
148
|
+
response.pipe(fileStream);
|
|
149
|
+
fileStream.on("finish", () => {
|
|
150
|
+
fileStream.close();
|
|
151
|
+
console.log("\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u6587\u4EF6\u5DF2\u4FDD\u5B58\u81F3:", savePath);
|
|
152
|
+
resolve(savePath);
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
console.log("\u56FE\u7247\u4E0B\u8F7D\u5931\u8D25:", response.statusCode);
|
|
156
|
+
response.resume();
|
|
157
|
+
reject();
|
|
158
|
+
}
|
|
159
|
+
}).on("error", (error) => {
|
|
160
|
+
console.error("\u8BF7\u6C42\u56FE\u7247\u65F6\u53D1\u751F\u9519\u8BEF:", error.message);
|
|
161
|
+
reject();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function getFilenameFromUrl(imageUrl) {
|
|
166
|
+
const parsedUrl = new URL(imageUrl);
|
|
167
|
+
return path__default.basename(parsedUrl.pathname);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
exports.downloadImage = downloadImage;
|
|
171
|
+
exports.ensureFile = ensureFile;
|
|
172
|
+
exports.ensureFileSync = ensureFileSync;
|
|
173
|
+
exports.fetchJSON = fetchJSON;
|
|
174
|
+
exports.getFilenameFromUrl = getFilenameFromUrl;
|
|
175
|
+
exports.isNil = isNil;
|
|
176
|
+
exports.pathExists = pathExists;
|
|
177
|
+
exports.semver = semver;
|
|
178
|
+
exports.writeFile = writeFile;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import https from 'node:https';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
function pathExists(path2) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
fs.stat(path2, (err) => {
|
|
8
|
+
resolve(!err);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function ensureFileSync(filePath) {
|
|
13
|
+
const dirPath = path.dirname(filePath);
|
|
14
|
+
try {
|
|
15
|
+
if (!fs.existsSync(dirPath)) {
|
|
16
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
} catch (err) {
|
|
19
|
+
if (err instanceof Error) {
|
|
20
|
+
throw new Error(`Error creating directory: ${err.message}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
if (!fs.existsSync(filePath)) {
|
|
25
|
+
fs.writeFileSync(filePath, "");
|
|
26
|
+
}
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if (err instanceof Error) {
|
|
29
|
+
throw new Error(`Error creating file: ${err.message}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function writeFile(filePath, data) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
fs.writeFile(filePath, data, (err) => {
|
|
36
|
+
if (err) {
|
|
37
|
+
console.error("Error writing file:", err);
|
|
38
|
+
reject();
|
|
39
|
+
} else {
|
|
40
|
+
console.log("File written successfully");
|
|
41
|
+
resolve();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function compareVersions(v1, v2) {
|
|
47
|
+
const parts1 = v1.split(".").map(Number);
|
|
48
|
+
const parts2 = v2.split(".").map(Number);
|
|
49
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
50
|
+
const num1 = i < parts1.length ? parts1[i] : 0;
|
|
51
|
+
const num2 = i < parts2.length ? parts2[i] : 0;
|
|
52
|
+
if (num1 > num2)
|
|
53
|
+
return 1;
|
|
54
|
+
if (num1 < num2)
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
const semver = {
|
|
60
|
+
gt: (v1, v2) => compareVersions(v1, v2) === 1
|
|
61
|
+
};
|
|
62
|
+
function fetchJSON(url) {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
https.get(url, (res) => {
|
|
65
|
+
let data = "";
|
|
66
|
+
res.on("data", (chunk) => {
|
|
67
|
+
data += chunk;
|
|
68
|
+
});
|
|
69
|
+
res.on("end", () => {
|
|
70
|
+
try {
|
|
71
|
+
const parsedData = JSON.parse(data);
|
|
72
|
+
resolve(parsedData);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
if (e instanceof Error) {
|
|
75
|
+
reject(new Error(`Error parsing JSON: ${e.message}`));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}).on("error", (err) => {
|
|
80
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function isNil(value) {
|
|
85
|
+
return value === null || value === void 0;
|
|
86
|
+
}
|
|
87
|
+
function ensureFile(filePath) {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const dirPath = path.dirname(filePath);
|
|
90
|
+
fs.stat(dirPath, (err, stats) => {
|
|
91
|
+
if (err) {
|
|
92
|
+
if (err.code === "ENOENT") {
|
|
93
|
+
fs.mkdir(dirPath, { recursive: true }, (err2) => {
|
|
94
|
+
if (err2) {
|
|
95
|
+
return reject(err2);
|
|
96
|
+
}
|
|
97
|
+
createFile();
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
return reject(err);
|
|
101
|
+
}
|
|
102
|
+
} else if (stats.isDirectory()) {
|
|
103
|
+
checkFile();
|
|
104
|
+
} else {
|
|
105
|
+
reject(new Error(`${dirPath} is not a directory`));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
function checkFile() {
|
|
109
|
+
fs.stat(filePath, (err, stats) => {
|
|
110
|
+
if (err) {
|
|
111
|
+
if (err.code === "ENOENT") {
|
|
112
|
+
createFile();
|
|
113
|
+
} else {
|
|
114
|
+
reject(err);
|
|
115
|
+
}
|
|
116
|
+
} else if (stats.isFile()) {
|
|
117
|
+
resolve();
|
|
118
|
+
} else {
|
|
119
|
+
reject(new Error(`${filePath} is not a file`));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function createFile() {
|
|
124
|
+
fs.writeFile(filePath, "", (err) => {
|
|
125
|
+
if (err) {
|
|
126
|
+
reject(err);
|
|
127
|
+
} else {
|
|
128
|
+
resolve();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async function downloadImage(url, savePath) {
|
|
135
|
+
await ensureFile(savePath);
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
https.get(url, (response) => {
|
|
138
|
+
if (response.statusCode === 200) {
|
|
139
|
+
const fileStream = fs.createWriteStream(savePath);
|
|
140
|
+
response.pipe(fileStream);
|
|
141
|
+
fileStream.on("finish", () => {
|
|
142
|
+
fileStream.close();
|
|
143
|
+
console.log("\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u6587\u4EF6\u5DF2\u4FDD\u5B58\u81F3:", savePath);
|
|
144
|
+
resolve(savePath);
|
|
145
|
+
});
|
|
146
|
+
} else {
|
|
147
|
+
console.log("\u56FE\u7247\u4E0B\u8F7D\u5931\u8D25:", response.statusCode);
|
|
148
|
+
response.resume();
|
|
149
|
+
reject();
|
|
150
|
+
}
|
|
151
|
+
}).on("error", (error) => {
|
|
152
|
+
console.error("\u8BF7\u6C42\u56FE\u7247\u65F6\u53D1\u751F\u9519\u8BEF:", error.message);
|
|
153
|
+
reject();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function getFilenameFromUrl(imageUrl) {
|
|
158
|
+
const parsedUrl = new URL(imageUrl);
|
|
159
|
+
return path.basename(parsedUrl.pathname);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export { downloadImage, ensureFile, ensureFileSync, fetchJSON, getFilenameFromUrl, isNil, pathExists, semver, writeFile };
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iflyrpa/share",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"author": "bijinfeng",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"playwright-core": "1.46.1",
|
|
15
|
+
"unbuild": "^2.0.0"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "unbuild",
|
|
19
|
+
"dev": "unbuild --stub"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Page } from "playwright";
|
|
2
|
+
|
|
3
|
+
export type { Locator, Response, ElectronApplication } from "playwright-core";
|
|
4
|
+
|
|
5
|
+
export interface CookiesSetDetails {
|
|
6
|
+
/**
|
|
7
|
+
* The URL to associate the cookie with. The promise will be rejected if the URL is
|
|
8
|
+
* invalid.
|
|
9
|
+
*/
|
|
10
|
+
url: string;
|
|
11
|
+
/**
|
|
12
|
+
* The name of the cookie. Empty by default if omitted.
|
|
13
|
+
*/
|
|
14
|
+
name?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The value of the cookie. Empty by default if omitted.
|
|
17
|
+
*/
|
|
18
|
+
value?: string;
|
|
19
|
+
/**
|
|
20
|
+
* The domain of the cookie; this will be normalized with a preceding dot so that
|
|
21
|
+
* it's also valid for subdomains. Empty by default if omitted.
|
|
22
|
+
*/
|
|
23
|
+
domain?: string;
|
|
24
|
+
/**
|
|
25
|
+
* The path of the cookie. Empty by default if omitted.
|
|
26
|
+
*/
|
|
27
|
+
path?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Whether the cookie should be marked as Secure. Defaults to false unless Same
|
|
30
|
+
* Site=None attribute is used.
|
|
31
|
+
*/
|
|
32
|
+
secure?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the cookie should be marked as HTTP only. Defaults to false.
|
|
35
|
+
*/
|
|
36
|
+
httpOnly?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The expiration date of the cookie as the number of seconds since the UNIX epoch.
|
|
39
|
+
* If omitted then the cookie becomes a session cookie and will not be retained
|
|
40
|
+
* between sessions.
|
|
41
|
+
*/
|
|
42
|
+
expirationDate?: number;
|
|
43
|
+
/**
|
|
44
|
+
* The Same Site policy to apply to this cookie. Can be `unspecified`,
|
|
45
|
+
* `no_restriction`, `lax` or `strict`. Default is `lax`.
|
|
46
|
+
*/
|
|
47
|
+
sameSite?: "unspecified" | "no_restriction" | "lax" | "strict";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type CookieMap = CookiesSetDetails[];
|
|
51
|
+
|
|
52
|
+
export interface PageParams {
|
|
53
|
+
cookies?: CookieMap;
|
|
54
|
+
url: string;
|
|
55
|
+
show?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface LoggerImplement {
|
|
59
|
+
debug(...msg: unknown[]): void;
|
|
60
|
+
info(...msg: unknown[]): void;
|
|
61
|
+
warn(...msg: unknown[]): void;
|
|
62
|
+
error(prefix: string, err?: unknown): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface AutomateTask {
|
|
66
|
+
debug?: boolean; // debug 模式下可视化展示所有操作
|
|
67
|
+
cachePath: string; // 缓存目录
|
|
68
|
+
forceUpdate?: boolean; // 是否使用远程最新版本
|
|
69
|
+
logger: LoggerImplement;
|
|
70
|
+
|
|
71
|
+
getTmpPath(): string;
|
|
72
|
+
createPage(pageParams: PageParams): Promise<Page>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type CommonAction<T, D> = (task: AutomateTask, params: T) => Promise<D>;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import https from "node:https";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
export function pathExists(path: string) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
fs.stat(path, (err) => {
|
|
8
|
+
resolve(!err);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ensureFileSync(filePath: string) {
|
|
14
|
+
const dirPath = path.dirname(filePath);
|
|
15
|
+
|
|
16
|
+
// 检查目录是否存在
|
|
17
|
+
try {
|
|
18
|
+
if (!fs.existsSync(dirPath)) {
|
|
19
|
+
// 目录不存在,需要创建
|
|
20
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
} catch (err) {
|
|
23
|
+
if (err instanceof Error) {
|
|
24
|
+
throw new Error(`Error creating directory: ${err.message}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 检查文件是否存在
|
|
29
|
+
try {
|
|
30
|
+
if (!fs.existsSync(filePath)) {
|
|
31
|
+
// 文件不存在,创建文件
|
|
32
|
+
fs.writeFileSync(filePath, "");
|
|
33
|
+
}
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (err instanceof Error) {
|
|
36
|
+
throw new Error(`Error creating file: ${err.message}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function writeFile(filePath: string, data: string) {
|
|
42
|
+
return new Promise<void>((resolve, reject) => {
|
|
43
|
+
fs.writeFile(filePath, data, (err) => {
|
|
44
|
+
if (err) {
|
|
45
|
+
console.error("Error writing file:", err);
|
|
46
|
+
reject();
|
|
47
|
+
} else {
|
|
48
|
+
console.log("File written successfully");
|
|
49
|
+
resolve();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function compareVersions(v1: string, v2: string) {
|
|
56
|
+
// 将两个版本号分割成数字数组
|
|
57
|
+
const parts1 = v1.split(".").map(Number);
|
|
58
|
+
const parts2 = v2.split(".").map(Number);
|
|
59
|
+
|
|
60
|
+
// 比较每个分割后的数字
|
|
61
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
62
|
+
// 如果某个版本号在这一段没有数字(即该段默认为0)
|
|
63
|
+
const num1 = i < parts1.length ? parts1[i] : 0;
|
|
64
|
+
const num2 = i < parts2.length ? parts2[i] : 0;
|
|
65
|
+
|
|
66
|
+
// 比较两个数字
|
|
67
|
+
if (num1 > num2) return 1;
|
|
68
|
+
if (num1 < num2) return -1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 如果所有的数字都相等,那么版本号相同
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const semver = {
|
|
76
|
+
gt: (v1: string, v2: string) => compareVersions(v1, v2) === 1,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export function fetchJSON<T>(url: string) {
|
|
80
|
+
return new Promise<T>((resolve, reject) => {
|
|
81
|
+
https
|
|
82
|
+
.get(url, (res) => {
|
|
83
|
+
let data = "";
|
|
84
|
+
|
|
85
|
+
res.on("data", (chunk) => {
|
|
86
|
+
data += chunk;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
res.on("end", () => {
|
|
90
|
+
try {
|
|
91
|
+
const parsedData = JSON.parse(data);
|
|
92
|
+
resolve(parsedData);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
if (e instanceof Error) {
|
|
95
|
+
reject(new Error(`Error parsing JSON: ${e.message}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
})
|
|
100
|
+
.on("error", (err) => {
|
|
101
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function isNil(value: unknown): value is null | undefined {
|
|
107
|
+
return value === null || value === undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function ensureFile(filePath: string) {
|
|
111
|
+
return new Promise<void>((resolve, reject) => {
|
|
112
|
+
const dirPath = path.dirname(filePath);
|
|
113
|
+
|
|
114
|
+
// 检查目录是否存在
|
|
115
|
+
fs.stat(dirPath, (err, stats) => {
|
|
116
|
+
if (err) {
|
|
117
|
+
if (err.code === "ENOENT") {
|
|
118
|
+
// 目录不存在,需要创建
|
|
119
|
+
fs.mkdir(dirPath, { recursive: true }, (err) => {
|
|
120
|
+
if (err) {
|
|
121
|
+
return reject(err);
|
|
122
|
+
}
|
|
123
|
+
createFile();
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
return reject(err);
|
|
127
|
+
}
|
|
128
|
+
} else if (stats.isDirectory()) {
|
|
129
|
+
// 目录已存在,检查文件
|
|
130
|
+
checkFile();
|
|
131
|
+
} else {
|
|
132
|
+
// 路径不是目录
|
|
133
|
+
reject(new Error(`${dirPath} is not a directory`));
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
function checkFile() {
|
|
138
|
+
fs.stat(filePath, (err, stats) => {
|
|
139
|
+
if (err) {
|
|
140
|
+
if (err.code === "ENOENT") {
|
|
141
|
+
// 文件不存在,创建文件
|
|
142
|
+
createFile();
|
|
143
|
+
} else {
|
|
144
|
+
reject(err);
|
|
145
|
+
}
|
|
146
|
+
} else if (stats.isFile()) {
|
|
147
|
+
// 文件已存在
|
|
148
|
+
resolve();
|
|
149
|
+
} else {
|
|
150
|
+
// 路径存在,但不是文件
|
|
151
|
+
reject(new Error(`${filePath} is not a file`));
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function createFile() {
|
|
157
|
+
fs.writeFile(filePath, "", (err) => {
|
|
158
|
+
if (err) {
|
|
159
|
+
reject(err);
|
|
160
|
+
} else {
|
|
161
|
+
resolve();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 下载图片并保存到指定路径
|
|
169
|
+
export async function downloadImage(
|
|
170
|
+
url: string,
|
|
171
|
+
savePath: string,
|
|
172
|
+
): Promise<string> {
|
|
173
|
+
await ensureFile(savePath);
|
|
174
|
+
|
|
175
|
+
return new Promise<string>((resolve, reject) => {
|
|
176
|
+
https
|
|
177
|
+
.get(url, (response) => {
|
|
178
|
+
// 检查响应状态码是否表明成功接收图片
|
|
179
|
+
if (response.statusCode === 200) {
|
|
180
|
+
// 创建文件写入流
|
|
181
|
+
const fileStream = fs.createWriteStream(savePath);
|
|
182
|
+
// 将响应流重定向到文件写入流
|
|
183
|
+
response.pipe(fileStream);
|
|
184
|
+
|
|
185
|
+
// 文件结束写入后关闭文件流
|
|
186
|
+
fileStream.on("finish", () => {
|
|
187
|
+
fileStream.close();
|
|
188
|
+
console.log("下载完成,文件已保存至:", savePath);
|
|
189
|
+
resolve(savePath);
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
// 如果响应状态码不是 200,打印错误信息
|
|
193
|
+
console.log("图片下载失败:", response.statusCode);
|
|
194
|
+
// 消费响应数据以释放内存
|
|
195
|
+
response.resume();
|
|
196
|
+
reject();
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
.on("error", (error) => {
|
|
200
|
+
// 如果请求过程中出现错误,打印错误信息并确保文件流关闭
|
|
201
|
+
console.error("请求图片时发生错误:", error.message);
|
|
202
|
+
reject();
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 从 URL 中获取文件名
|
|
208
|
+
export function getFilenameFromUrl(imageUrl: string) {
|
|
209
|
+
const parsedUrl = new URL(imageUrl); // 使用 URL 构造函数解析完整的 URL
|
|
210
|
+
return path.basename(parsedUrl.pathname); // 获取路径名的最后一部分作为文件名
|
|
211
|
+
}
|