node-automator 1.4.26 → 1.4.28
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/commands/backup.js +82 -28
- package/commands/compress.js +30 -12
- package/commands/decrypt.js +24 -0
- package/commands/encrypt.js +27 -0
- package/commands/loop.js +2 -1
- package/commands/mgr.js +4 -0
- package/commands/watch_mail.js +1 -1
- package/commands/web_socket.js +1 -1
- package/commands/zip.js +19 -16
- package/commands/zip_folder.js +6 -5
- package/index.js +21 -23
- package/package.json +4 -2
- package/utils/file_tool.js +20 -20
- package/utils/func_tool.js +23 -0
- package/utils/request_tool.js +1 -1
- package/utils/selection_tool.js +2 -2
- package/utils/shell_tool.js +2 -2
- package/utils/transform_tool.js +4 -1
package/commands/backup.js
CHANGED
|
@@ -5,10 +5,22 @@ const fs = require("node:fs");
|
|
|
5
5
|
const path = require("node:path");
|
|
6
6
|
const { success, error, warn } = require("../utils/log_tool");
|
|
7
7
|
const { parse, stringify, processRename } = require("../utils/file_tool");
|
|
8
|
+
const { eval_code, get_full_path } = require("./share_data");
|
|
9
|
+
const { formatByteSize } = require("../utils/transform_tool");
|
|
10
|
+
const { debounce, throttle } = require("../utils/func_tool");
|
|
8
11
|
|
|
9
12
|
class BackupCommand extends BaseCommand {
|
|
10
13
|
async execute() {
|
|
11
|
-
|
|
14
|
+
let {
|
|
15
|
+
sourceFolder,
|
|
16
|
+
backupFolder,
|
|
17
|
+
backupCfgs,
|
|
18
|
+
verbose,
|
|
19
|
+
throttleDelay,
|
|
20
|
+
immediately = true,
|
|
21
|
+
} = this.selfData;
|
|
22
|
+
sourceFolder = get_full_path(sourceFolder);
|
|
23
|
+
backupFolder = get_full_path(backupFolder);
|
|
12
24
|
|
|
13
25
|
async function backup(bakCfg, filename) {
|
|
14
26
|
const {
|
|
@@ -17,15 +29,25 @@ class BackupCommand extends BaseCommand {
|
|
|
17
29
|
sourceType,
|
|
18
30
|
backupFormat,
|
|
19
31
|
backupFilename,
|
|
32
|
+
backupFilenameGenerator,
|
|
20
33
|
backupRename,
|
|
21
34
|
backupEncoding,
|
|
22
35
|
backupPrettify,
|
|
23
36
|
} = bakCfg;
|
|
24
37
|
const filepath = path.join(sourceFolder, filename);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
const fileSize = fs.statSync(filepath).size;
|
|
39
|
+
const fileSizeFormatted = formatByteSize(fileSize).replace(
|
|
40
|
+
/\s/g,
|
|
41
|
+
"",
|
|
28
42
|
);
|
|
43
|
+
const backName = backupFilenameGenerator
|
|
44
|
+
? eval_code(backupFilenameGenerator)({
|
|
45
|
+
filepath,
|
|
46
|
+
fileSize,
|
|
47
|
+
fileSizeFormatted,
|
|
48
|
+
})
|
|
49
|
+
: backupFilename || filename;
|
|
50
|
+
let backupPath = path.join(backupFolder, backName);
|
|
29
51
|
let backupData;
|
|
30
52
|
if (sourceType) {
|
|
31
53
|
backupData = await parse(
|
|
@@ -70,6 +92,13 @@ class BackupCommand extends BaseCommand {
|
|
|
70
92
|
fs.writeFileSync(backupPath, backupData, {
|
|
71
93
|
encoding: backupEncoding,
|
|
72
94
|
});
|
|
95
|
+
return {
|
|
96
|
+
filepath,
|
|
97
|
+
backupPath,
|
|
98
|
+
backupData,
|
|
99
|
+
fileSize,
|
|
100
|
+
fileSizeFormatted,
|
|
101
|
+
};
|
|
73
102
|
}
|
|
74
103
|
|
|
75
104
|
backupCfgs.forEach((bakCfg, index) => {
|
|
@@ -79,15 +108,55 @@ class BackupCommand extends BaseCommand {
|
|
|
79
108
|
};
|
|
80
109
|
}
|
|
81
110
|
});
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
111
|
+
// 首次备份所有文件
|
|
112
|
+
if (immediately) {
|
|
113
|
+
backupCfgs.forEach((cfg) => {
|
|
114
|
+
const files = glob
|
|
115
|
+
.sync(path.join(sourceFolder, cfg.sourceFilename))
|
|
116
|
+
.map((v) => path.relative(sourceFolder, v));
|
|
117
|
+
files.forEach((file) => {
|
|
118
|
+
backup(cfg, file);
|
|
119
|
+
});
|
|
89
120
|
});
|
|
90
|
-
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const BackupByFilename = (filename) => {
|
|
124
|
+
const bakCfg = backupCfgs.find((cfg) => {
|
|
125
|
+
const files = glob
|
|
126
|
+
.sync(path.join(sourceFolder, cfg.sourceFilename))
|
|
127
|
+
.map((v) => path.relative(sourceFolder, v));
|
|
128
|
+
return files.some((file) => file === filename);
|
|
129
|
+
});
|
|
130
|
+
if (bakCfg) {
|
|
131
|
+
backup(bakCfg, filename)
|
|
132
|
+
.then((result) => {
|
|
133
|
+
if (!result) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const {
|
|
137
|
+
filepath,
|
|
138
|
+
backupPath,
|
|
139
|
+
backupData,
|
|
140
|
+
fileSize,
|
|
141
|
+
fileSizeFormatted,
|
|
142
|
+
} = result;
|
|
143
|
+
(verbose || bakCfg.verbose) &&
|
|
144
|
+
success(
|
|
145
|
+
`${filename} (${fileSizeFormatted}) 备份成功`,
|
|
146
|
+
undefined,
|
|
147
|
+
undefined,
|
|
148
|
+
true,
|
|
149
|
+
);
|
|
150
|
+
})
|
|
151
|
+
.catch((err) => {
|
|
152
|
+
error(`${filename} 备份异常 ${err}`);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const RealBackupByFilename = throttleDelay
|
|
158
|
+
? throttle(BackupByFilename, throttleDelay)
|
|
159
|
+
: BackupByFilename;
|
|
91
160
|
|
|
92
161
|
// 监听文件夹变化
|
|
93
162
|
fs.watch(
|
|
@@ -97,22 +166,7 @@ class BackupCommand extends BaseCommand {
|
|
|
97
166
|
},
|
|
98
167
|
(eventType, filename) => {
|
|
99
168
|
if (eventType === "change") {
|
|
100
|
-
|
|
101
|
-
const files = glob
|
|
102
|
-
.sync(path.join(sourceFolder, cfg.sourceFilename))
|
|
103
|
-
.map((v) => path.relative(sourceFolder, v));
|
|
104
|
-
return files.some((file) => file === filename);
|
|
105
|
-
});
|
|
106
|
-
if (bakCfg) {
|
|
107
|
-
backup(bakCfg, filename)
|
|
108
|
-
.then(() => {
|
|
109
|
-
!(quiet || bakCfg.quiet) &&
|
|
110
|
-
success(`${filename} 备份成功`);
|
|
111
|
-
})
|
|
112
|
-
.catch((err) => {
|
|
113
|
-
error(`${filename} 备份异常 ${err}`);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
169
|
+
RealBackupByFilename(filename);
|
|
116
170
|
}
|
|
117
171
|
},
|
|
118
172
|
).on("error", (err) => {
|
package/commands/compress.js
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
const _path = require("node:path");
|
|
2
|
+
const fs = require("node:fs");
|
|
2
3
|
const { get_fst_file, get_full_path, move } = require("../utils/file_tool");
|
|
3
4
|
const { BaseCommand } = require("./base");
|
|
4
|
-
const {
|
|
5
|
+
const { default: imagemin } = require("imagemin");
|
|
6
|
+
const { default: imageminPngquant } = require("imagemin-pngquant");
|
|
7
|
+
const { default: imageminMozjpeg } = require("imagemin-mozjpeg");
|
|
8
|
+
const Jimp = require("jimp");
|
|
5
9
|
|
|
6
10
|
class CompressCommand extends BaseCommand {
|
|
7
11
|
async execute() {
|
|
8
|
-
const sharp = require("sharp");
|
|
9
12
|
const data = this.selfData;
|
|
10
13
|
const src = get_fst_file(data.src);
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const dstFile = get_full_path(data.dst, "FILE");
|
|
15
|
+
fs.copyFileSync(src, dstFile);
|
|
16
|
+
const dstDir = _path.dirname(dstFile);
|
|
17
|
+
if (!fs.existsSync(dstDir)) {
|
|
18
|
+
fs.mkdirSync(dstDir, { recursive: true });
|
|
15
19
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
if (data.resize) {
|
|
21
|
+
const { w, h, scale } = data.resize;
|
|
22
|
+
const result = await Jimp.read(dstFile);
|
|
23
|
+
if (w && h) {
|
|
24
|
+
result.resize(w, h);
|
|
25
|
+
}
|
|
26
|
+
if (scale) {
|
|
27
|
+
result.scale(scale);
|
|
28
|
+
}
|
|
29
|
+
await result.writeAsync(dstFile);
|
|
19
30
|
}
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
const quality = data.options?.quality || 80;
|
|
32
|
+
await imagemin([dstFile], {
|
|
33
|
+
destination: dstDir,
|
|
34
|
+
plugins: [
|
|
35
|
+
imageminMozjpeg({ quality: quality }), // 压缩 JPG 图片
|
|
36
|
+
imageminPngquant({
|
|
37
|
+
quality: [quality / 100, quality / 100],
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
});
|
|
23
41
|
}
|
|
24
42
|
}
|
|
25
43
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { BaseCommand } = require("./base");
|
|
2
|
+
const crypto = require('node:crypto');
|
|
3
|
+
|
|
4
|
+
class DecryptCommand extends BaseCommand {
|
|
5
|
+
async execute() {
|
|
6
|
+
const content = this.content;
|
|
7
|
+
const { password, salt, algorithm = 'aes-256-cbc', keylen = 32 } = this.selfData;
|
|
8
|
+
const key = crypto.scryptSync(password, salt, keylen);
|
|
9
|
+
// 从 Buffer 中提取 IV(前 16 字节)和密文
|
|
10
|
+
const iv = content.slice(0, 16);
|
|
11
|
+
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
12
|
+
let decrypted = decipher.update(content.slice(16)); // Buffer
|
|
13
|
+
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
|
14
|
+
return decrypted;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getRequireContent() {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
DecryptCommand,
|
|
24
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const { BaseCommand } = require("./base");
|
|
2
|
+
const crypto = require('node:crypto');
|
|
3
|
+
|
|
4
|
+
class EncryptCommand extends BaseCommand {
|
|
5
|
+
async execute() {
|
|
6
|
+
const content = this.content;
|
|
7
|
+
const { password, salt, algorithm = 'aes-256-cbc', keylen = 32 } = this.selfData;
|
|
8
|
+
const key = crypto.scryptSync(password, salt, keylen);
|
|
9
|
+
const iv = crypto.randomBytes(16);
|
|
10
|
+
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
11
|
+
// 直接输出二进制 Buffer
|
|
12
|
+
const encrypted = Buffer.concat([
|
|
13
|
+
iv, // 将 IV 放在密文前面,方便解密时使用
|
|
14
|
+
cipher.update(content), // 不指定输出编码 = 返回 Buffer
|
|
15
|
+
cipher.final() // 返回 Buffer
|
|
16
|
+
]);
|
|
17
|
+
return encrypted;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getRequireContent() {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
EncryptCommand,
|
|
27
|
+
};
|
package/commands/loop.js
CHANGED
|
@@ -67,7 +67,8 @@ class LoopCommand extends BaseCommand {
|
|
|
67
67
|
if (typeof data.tip_key === "boolean") {
|
|
68
68
|
tip = `[${loop_data}]`;
|
|
69
69
|
} else {
|
|
70
|
-
|
|
70
|
+
const tipKeys = _transform_tool.toArray(data.tip_key);
|
|
71
|
+
tip = `[${tipKeys.map(key => this.getDataByKey(key)).join("/")}]`;
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
if (show_progress) {
|
package/commands/mgr.js
CHANGED
|
@@ -135,6 +135,8 @@ const { ObfuscateCommand } = require("./obfuscate");
|
|
|
135
135
|
const { SplitFileCommand } = require("./split_file");
|
|
136
136
|
const { MergeFileCommand } = require("./merge_file");
|
|
137
137
|
const { ZipFolderCommand } = require("./zip_folder");
|
|
138
|
+
const { EncryptCommand } = require('./encrypt');
|
|
139
|
+
const { DecryptCommand } = require('./decrypt');
|
|
138
140
|
|
|
139
141
|
const globalData = {
|
|
140
142
|
executed_cfg: [], // 执行过的配置文件
|
|
@@ -521,6 +523,8 @@ function init() {
|
|
|
521
523
|
register("split_file", SplitFileCommand, false);
|
|
522
524
|
register("merge_file", MergeFileCommand, false);
|
|
523
525
|
register("zip_folder", ZipFolderCommand, false);
|
|
526
|
+
register("encrypt", EncryptCommand, false);
|
|
527
|
+
register("decrypt", DecryptCommand, false);
|
|
524
528
|
}
|
|
525
529
|
|
|
526
530
|
module.exports = {
|
package/commands/watch_mail.js
CHANGED
package/commands/web_socket.js
CHANGED
|
@@ -37,7 +37,7 @@ class WebSocketCommand extends BaseCommand {
|
|
|
37
37
|
let receivedUTF8Total = 0;
|
|
38
38
|
let receivedIndex = 0;
|
|
39
39
|
const timeout = this.selfData.timeout || 0;
|
|
40
|
-
const quiet = this.selfData.
|
|
40
|
+
const quiet = !this.selfData.verbose || true;
|
|
41
41
|
const _endianSuffix = little_endian ? "LE" : "BE";
|
|
42
42
|
|
|
43
43
|
let rl;
|
package/commands/zip.js
CHANGED
|
@@ -42,20 +42,22 @@ class ZipCommand extends BaseCommand {
|
|
|
42
42
|
let entryName = path.join(zipPath, path.basename(file));
|
|
43
43
|
entryName = processRename(entryName, data.options?.rename);
|
|
44
44
|
const show_src = entryName;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
data.verbose &&
|
|
46
|
+
progress(index, files.length, {
|
|
47
|
+
desc: `Add ${show_src}`,
|
|
48
|
+
depth: 0,
|
|
49
|
+
align: true,
|
|
50
|
+
});
|
|
50
51
|
// zip.addLocalFile(file, zipPath);
|
|
51
52
|
zip.addFile(entryName, fs.readFileSync(file));
|
|
52
53
|
}
|
|
53
54
|
clearLine();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
data.verbose &&
|
|
56
|
+
progress(files.length, files.length, {
|
|
57
|
+
desc: `压缩中...`,
|
|
58
|
+
depth: 0,
|
|
59
|
+
align: true,
|
|
60
|
+
});
|
|
59
61
|
// or write everything to disk
|
|
60
62
|
if (data.dst) {
|
|
61
63
|
const dst = get_full_path(data.dst);
|
|
@@ -71,12 +73,13 @@ class ZipCommand extends BaseCommand {
|
|
|
71
73
|
const buffer = zip.toBuffer();
|
|
72
74
|
return buffer;
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
data.verbose &&
|
|
77
|
+
progress(files.length, files.length, {
|
|
78
|
+
desc: `压缩完成!`,
|
|
79
|
+
depth: 0,
|
|
80
|
+
color: "green",
|
|
81
|
+
});
|
|
82
|
+
data.verbose && info("");
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
85
|
|
package/commands/zip_folder.js
CHANGED
|
@@ -30,11 +30,12 @@ class ZipFolderCommand extends BaseCommand {
|
|
|
30
30
|
if (!isAccept(filename)) {
|
|
31
31
|
return false;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
data.verbose &&
|
|
34
|
+
progress(i++, 0, {
|
|
35
|
+
desc: `${filename}`,
|
|
36
|
+
depth: 0,
|
|
37
|
+
align: true,
|
|
38
|
+
});
|
|
38
39
|
return true;
|
|
39
40
|
});
|
|
40
41
|
// or write everything to disk
|
package/index.js
CHANGED
|
@@ -120,7 +120,8 @@ async function MainProcess() {
|
|
|
120
120
|
} catch (err) {
|
|
121
121
|
lastError = err.message || err;
|
|
122
122
|
}
|
|
123
|
-
const
|
|
123
|
+
const endTime = shareData.AUTOMATOR_END_TIME || Date.now();
|
|
124
|
+
const costTime = endTime - beginTime;
|
|
124
125
|
if (enableTimer) {
|
|
125
126
|
clearInterval(timer);
|
|
126
127
|
info("");
|
|
@@ -161,28 +162,25 @@ async function MainProcess() {
|
|
|
161
162
|
lastError,
|
|
162
163
|
);
|
|
163
164
|
}
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
icon: hasError ? errorIcon : successIcon,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
165
|
+
if (shareData.ALERT_RESULT) {
|
|
166
|
+
const title = `${shareData.TITLE || "任务即将结束"}`;
|
|
167
|
+
await showAlert(
|
|
168
|
+
hasError ? "error" : "info",
|
|
169
|
+
hasError ? `✖ 失败, ${lastError}` : "✔ 成功!",
|
|
170
|
+
title,
|
|
171
|
+
);
|
|
172
|
+
} else if (shareData.NOTIFY_RESULT) {
|
|
173
|
+
const successIcon =
|
|
174
|
+
shareData.SUCCESS_ICON ||
|
|
175
|
+
`${shareData.AUTOMATOR_ROOT}/assets/success.png`;
|
|
176
|
+
const errorIcon =
|
|
177
|
+
shareData.ERROR_ICON ||
|
|
178
|
+
`${shareData.AUTOMATOR_ROOT}/assets/error.png`;
|
|
179
|
+
await showNotify({
|
|
180
|
+
title: `${shareData.TITLE || cfgs}`,
|
|
181
|
+
message: hasError ? lastError : `任务即将结束`,
|
|
182
|
+
icon: hasError ? errorIcon : successIcon,
|
|
183
|
+
});
|
|
186
184
|
}
|
|
187
185
|
// 手动调用 exit, 会导致异步的定时器事件失效
|
|
188
186
|
if (shareData.EXIT_IMMEDIATELY) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-automator",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.28",
|
|
4
4
|
"description": "Execute automation with yaml configuration(compatible with json)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
"html-to-text": "^8.2.0",
|
|
40
40
|
"iconv-lite": "^0.6.2",
|
|
41
41
|
"image-size": "^1.0.0",
|
|
42
|
+
"imagemin": "^9.0.1",
|
|
43
|
+
"imagemin-mozjpeg": "^10.0.0",
|
|
44
|
+
"imagemin-pngquant": "^10.0.0",
|
|
42
45
|
"javascript-obfuscator": "^4.1.1",
|
|
43
46
|
"jimp": "^0.22.12",
|
|
44
47
|
"json-stable-stringify": "^1.0.1",
|
|
@@ -58,7 +61,6 @@
|
|
|
58
61
|
"pinyin": "^4.0.0",
|
|
59
62
|
"request": "^2.88.2",
|
|
60
63
|
"request-progress": "^3.0.0",
|
|
61
|
-
"sharp": "^0.34.3",
|
|
62
64
|
"split-file": "^2.3.0",
|
|
63
65
|
"spreadsheet-column": "^1.1.1",
|
|
64
66
|
"strip-json-comments": "^3.1.1",
|
package/utils/file_tool.js
CHANGED
|
@@ -283,8 +283,8 @@ async function copy(src, dst, base, options) {
|
|
|
283
283
|
options,
|
|
284
284
|
);
|
|
285
285
|
const filesize = get_files_size(srcs);
|
|
286
|
-
|
|
287
|
-
|
|
286
|
+
options.verbose && info("");
|
|
287
|
+
options.verbose &&
|
|
288
288
|
whisper(
|
|
289
289
|
`复制 ${srcs[0]} 等 ${srcs.length} 个文件(夹) ${format_bytes(filesize)} ${options.overwrite ? "[覆盖现有文件]" : "[不覆盖现有文件]"} 到 ${dsts} options: ${JSON.stringify(options)}`,
|
|
290
290
|
undefined,
|
|
@@ -299,7 +299,7 @@ async function copy(src, dst, base, options) {
|
|
|
299
299
|
++dir_num;
|
|
300
300
|
continue;
|
|
301
301
|
}
|
|
302
|
-
|
|
302
|
+
options.verbose &&
|
|
303
303
|
display_tool.progress(srcIndex + 1, srcs.length, {
|
|
304
304
|
desc: `Copy ${show_src}`,
|
|
305
305
|
depth: 0,
|
|
@@ -344,8 +344,8 @@ async function copy(src, dst, base, options) {
|
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
-
|
|
348
|
-
|
|
347
|
+
options.verbose && info("");
|
|
348
|
+
options.verbose &&
|
|
349
349
|
whisper(
|
|
350
350
|
`复制完成 (文件: ${actual_files.length}, 目录: ${dir_num}, 总计: ${srcs.length})`,
|
|
351
351
|
undefined,
|
|
@@ -369,8 +369,8 @@ async function move(src, dst, base, options) {
|
|
|
369
369
|
options,
|
|
370
370
|
);
|
|
371
371
|
const filesize = get_files_size(srcs);
|
|
372
|
-
|
|
373
|
-
|
|
372
|
+
options.verbose && info("");
|
|
373
|
+
options.verbose &&
|
|
374
374
|
whisper(
|
|
375
375
|
`移动 ${srcs[0]} 等 ${srcs.length} 个文件(夹) ${format_bytes(filesize)} ${options.overwrite ? "[覆盖现有文件]" : "[不覆盖现有文件]"} 到 ${dsts} options: ${JSON.stringify(options)}`,
|
|
376
376
|
undefined,
|
|
@@ -385,7 +385,7 @@ async function move(src, dst, base, options) {
|
|
|
385
385
|
++dir_num;
|
|
386
386
|
continue;
|
|
387
387
|
}
|
|
388
|
-
|
|
388
|
+
options.verbose &&
|
|
389
389
|
display_tool.progress(srcIndex + 1, srcs.length, {
|
|
390
390
|
desc: `Move ${show_src}`,
|
|
391
391
|
depth: 0,
|
|
@@ -432,8 +432,8 @@ async function move(src, dst, base, options) {
|
|
|
432
432
|
fs.unlinkSync(src);
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
-
|
|
436
|
-
|
|
435
|
+
options.verbose && info("");
|
|
436
|
+
options.verbose &&
|
|
437
437
|
whisper(
|
|
438
438
|
`移动完成 (文件: ${actual_files.length}, 目录: ${dir_num}, 总计: ${srcs.length})`,
|
|
439
439
|
undefined,
|
|
@@ -457,8 +457,8 @@ async function move_local(src, dst, base, options) {
|
|
|
457
457
|
options,
|
|
458
458
|
);
|
|
459
459
|
const filesize = get_files_size(srcs);
|
|
460
|
-
|
|
461
|
-
|
|
460
|
+
options.verbose && info("");
|
|
461
|
+
options.verbose &&
|
|
462
462
|
whisper(
|
|
463
463
|
`移动 ${srcs[0]} 等 ${srcs.length} 个文件(夹) ${format_bytes(filesize)} ${options.overwrite ? "[覆盖现有文件]" : "[不覆盖现有文件]"} 到 ${dsts} options: ${JSON.stringify(options)}`,
|
|
464
464
|
undefined,
|
|
@@ -472,7 +472,7 @@ async function move_local(src, dst, base, options) {
|
|
|
472
472
|
if (fs.lstatSync(src).isDirectory()) {
|
|
473
473
|
++dir_num;
|
|
474
474
|
}
|
|
475
|
-
|
|
475
|
+
options.verbose &&
|
|
476
476
|
display_tool.progress(srcIndex + 1, srcs.length, {
|
|
477
477
|
desc: `Rename ${show_src}`,
|
|
478
478
|
depth: 0,
|
|
@@ -517,8 +517,8 @@ async function move_local(src, dst, base, options) {
|
|
|
517
517
|
}
|
|
518
518
|
}
|
|
519
519
|
|
|
520
|
-
|
|
521
|
-
|
|
520
|
+
options.verbose && info("");
|
|
521
|
+
options.verbose &&
|
|
522
522
|
whisper(
|
|
523
523
|
`移动完成 (文件: ${actual_files.length}, 目录: ${dir_num}, 总计: ${srcs.length})`,
|
|
524
524
|
undefined,
|
|
@@ -530,8 +530,8 @@ async function remove(src, options) {
|
|
|
530
530
|
srcs = get_file_list(src);
|
|
531
531
|
options = Object.assign({ recursive: true }, options);
|
|
532
532
|
const filesize = get_files_size(srcs);
|
|
533
|
-
|
|
534
|
-
|
|
533
|
+
options.verbose && info("");
|
|
534
|
+
options.verbose &&
|
|
535
535
|
whisper(
|
|
536
536
|
`删除 ${srcs[0]} 等 ${srcs.length} 个文件(夹) ${format_bytes(filesize)} options: ${JSON.stringify(options)}`,
|
|
537
537
|
undefined,
|
|
@@ -543,7 +543,7 @@ async function remove(src, options) {
|
|
|
543
543
|
const src = srcs[srcIndex];
|
|
544
544
|
const show_src = src;
|
|
545
545
|
try {
|
|
546
|
-
display_tool.progress(srcIndex + 1, srcs.length, {
|
|
546
|
+
options.verbose && display_tool.progress(srcIndex + 1, srcs.length, {
|
|
547
547
|
desc: `Remove ${show_src}`,
|
|
548
548
|
depth: 0,
|
|
549
549
|
color: "cyan",
|
|
@@ -565,8 +565,8 @@ async function remove(src, options) {
|
|
|
565
565
|
}
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
-
|
|
569
|
-
|
|
568
|
+
options.verbose && info("");
|
|
569
|
+
options.verbose &&
|
|
570
570
|
whisper(
|
|
571
571
|
`删除完成 (文件: ${actual_files.length}, 目录: ${dir_num}, 总计: ${srcs.length})`,
|
|
572
572
|
undefined,
|
package/utils/func_tool.js
CHANGED
|
@@ -99,7 +99,30 @@ function queueAsync(tasks, limit, onProgress) {
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
function debounce(fn, delay) {
|
|
103
|
+
let timer = null;
|
|
104
|
+
return function (...args) {
|
|
105
|
+
if (timer) clearTimeout(timer);
|
|
106
|
+
timer = setTimeout(() => {
|
|
107
|
+
fn.apply(this, args);
|
|
108
|
+
}, delay);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function throttle(fn, delay) {
|
|
113
|
+
let timer = null;
|
|
114
|
+
return function (...args) {
|
|
115
|
+
if (timer) return;
|
|
116
|
+
timer = setTimeout(() => {
|
|
117
|
+
fn.apply(this, args);
|
|
118
|
+
timer = null;
|
|
119
|
+
}, delay);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
102
123
|
module.exports = {
|
|
103
124
|
queue,
|
|
104
125
|
queueAsync,
|
|
126
|
+
debounce,
|
|
127
|
+
throttle,
|
|
105
128
|
};
|
package/utils/request_tool.js
CHANGED
|
@@ -41,7 +41,7 @@ async function doRequest(data) {
|
|
|
41
41
|
}
|
|
42
42
|
let result;
|
|
43
43
|
const useCache = enable_http_cache && http_cache;
|
|
44
|
-
const quiet = data.
|
|
44
|
+
const quiet = !data.verbose;
|
|
45
45
|
!quiet && info(`[${options.method}] ${url}${useCache ? "[缓存]" : ""}`);
|
|
46
46
|
let hasProgress = false;
|
|
47
47
|
const fileDst = get_full_path(
|
package/utils/selection_tool.js
CHANGED
|
@@ -338,7 +338,7 @@ async function select(content, data) {
|
|
|
338
338
|
onKeyPress(undefined, { name: "return" });
|
|
339
339
|
}
|
|
340
340
|
});
|
|
341
|
-
|
|
341
|
+
data.verbose && success(`已选择:${getPrint(selectedOption, true)}`);
|
|
342
342
|
return selectedOption;
|
|
343
343
|
}
|
|
344
344
|
|
|
@@ -628,7 +628,7 @@ async function multiSelect(content, data) {
|
|
|
628
628
|
onKeyPress(undefined, { name: "return" });
|
|
629
629
|
}
|
|
630
630
|
});
|
|
631
|
-
|
|
631
|
+
data.verbose && success(`已选择:${getPrint(selectedOptions, true)}`);
|
|
632
632
|
return selectedOptions;
|
|
633
633
|
}
|
|
634
634
|
|
package/utils/shell_tool.js
CHANGED
|
@@ -25,7 +25,7 @@ async function exec_shell(data) {
|
|
|
25
25
|
const instant_stdout = data.instant_stdout;
|
|
26
26
|
const capture_stdout = isStdOut() || data.capture_stdout;
|
|
27
27
|
const acceptableErrors = data.acceptableErrors || [];
|
|
28
|
-
const quiet = data.
|
|
28
|
+
const quiet = !data.verbose;
|
|
29
29
|
const result = await new Promise((resolve, _reject) => {
|
|
30
30
|
/** @type {string[]} */
|
|
31
31
|
let cmd = data.cmd;
|
|
@@ -59,7 +59,7 @@ async function exec_shell(data) {
|
|
|
59
59
|
const errors = [];
|
|
60
60
|
const encoding = data.encoding || "cp936";
|
|
61
61
|
const raw_output = encoding === "raw";
|
|
62
|
-
!quiet &&
|
|
62
|
+
!quiet && info(`cmd:[${cmd}] cwd:${data.cwd} inputs:${data.inputs}`);
|
|
63
63
|
options.stdio = [
|
|
64
64
|
"pipe",
|
|
65
65
|
capture_stdout ? "pipe" : process.stdout,
|
package/utils/transform_tool.js
CHANGED
|
@@ -505,7 +505,10 @@ function formatByteSize(bytes) {
|
|
|
505
505
|
if (bytes >= MB) {
|
|
506
506
|
return `${(bytes / MB).toFixed(2)} MB`;
|
|
507
507
|
}
|
|
508
|
-
|
|
508
|
+
if (bytes >= KB) {
|
|
509
|
+
return `${(bytes / KB).toFixed(2)} KB`;
|
|
510
|
+
}
|
|
511
|
+
return `${bytes} B`;
|
|
509
512
|
}
|
|
510
513
|
|
|
511
514
|
function getByteSize(formatedStr) {
|