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.
@@ -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
- const { sourceFolder, backupFolder, backupCfgs, quiet } = this.selfData;
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
- let backupPath = path.join(
26
- backupFolder,
27
- backupFilename || filename,
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
- backupCfgs.forEach((cfg) => {
84
- const files = glob
85
- .sync(path.join(sourceFolder, cfg.sourceFilename))
86
- .map((v) => path.relative(sourceFolder, v));
87
- files.forEach((file) => {
88
- backup(cfg, file);
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
- const bakCfg = backupCfgs.find((cfg) => {
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) => {
@@ -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 { readFileSync } = require("node:fs");
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 dst = get_full_path(data.dst, "FILE");
12
- let format = data.format;
13
- if (!format) {
14
- format = dst.split(".").pop();
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
- format = format.toLowerCase();
17
- if (format === "jpg") {
18
- format = "jpeg";
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 options = data.options;
21
- const fileContent = readFileSync(src);
22
- await sharp(fileContent)[format](options).toFile(dst);
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
- tip = `[${this.getDataByKey(data.tip_key)}]`;
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 = {
@@ -70,7 +70,7 @@ class WatchMailCommand extends BaseCommand {
70
70
  } else {
71
71
  this.shareData.mail_data = mailData;
72
72
  }
73
- if (!data.quiet) {
73
+ if (data.verbose) {
74
74
  success("");
75
75
  success(getPrint(mailData));
76
76
  }
@@ -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.quiet || false;
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
- progress(index, files.length, {
46
- desc: `Add ${show_src}`,
47
- depth: 0,
48
- align: true,
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
- progress(files.length, files.length, {
55
- desc: `压缩中...`,
56
- depth: 0,
57
- align: true,
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
- progress(files.length, files.length, {
75
- desc: `压缩完成!`,
76
- depth: 0,
77
- color: "green",
78
- });
79
- info("");
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
 
@@ -30,11 +30,12 @@ class ZipFolderCommand extends BaseCommand {
30
30
  if (!isAccept(filename)) {
31
31
  return false;
32
32
  }
33
- progress(i++, 0, {
34
- desc: `${filename}`,
35
- depth: 0,
36
- align: true,
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 costTime = Date.now() - beginTime;
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 (!shareData.QUIET_MODE) {
165
- // 非代码启动,需要暂停
166
- if (shareData.ALERT_RESULT) {
167
- const title = `${shareData.TITLE || "任务即将结束"}`;
168
- await showAlert(
169
- hasError ? "error" : "info",
170
- hasError ? `✖ 失败, ${lastError}` : "✔ 成功!",
171
- title,
172
- );
173
- } else {
174
- const successIcon =
175
- shareData.SUCCESS_ICON ||
176
- `${shareData.AUTOMATOR_ROOT}/assets/success.png`;
177
- const errorIcon =
178
- shareData.ERROR_ICON ||
179
- `${shareData.AUTOMATOR_ROOT}/assets/error.png`;
180
- await showNotify({
181
- title: `${shareData.TITLE || cfgs}`,
182
- message: hasError ? lastError : `任务即将结束`,
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.26",
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",
@@ -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
- !options.quiet && info("");
287
- !options.quiet &&
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
- !options.quiet &&
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
- !options.quiet && info("");
348
- !options.quiet &&
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
- !options.quiet && info("");
373
- !options.quiet &&
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
- !options.quiet &&
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
- !options.quiet && info("");
436
- !options.quiet &&
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
- !options.quiet && info("");
461
- !options.quiet &&
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
- !options.quiet &&
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
- !options.quiet && info("");
521
- !options.quiet &&
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
- !options.quiet && info("");
534
- !options.quiet &&
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
- !options.quiet && info("");
569
- !options.quiet &&
568
+ options.verbose && info("");
569
+ options.verbose &&
570
570
  whisper(
571
571
  `删除完成 (文件: ${actual_files.length}, 目录: ${dir_num}, 总计: ${srcs.length})`,
572
572
  undefined,
@@ -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
  };
@@ -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.quiet;
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(
@@ -338,7 +338,7 @@ async function select(content, data) {
338
338
  onKeyPress(undefined, { name: "return" });
339
339
  }
340
340
  });
341
- !data.quiet && success(`已选择:${getPrint(selectedOption, true)}`);
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
- !data.quiet && success(`已选择:${getPrint(selectedOptions, true)}`);
631
+ data.verbose && success(`已选择:${getPrint(selectedOptions, true)}`);
632
632
  return selectedOptions;
633
633
  }
634
634
 
@@ -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.quiet;
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 && whisper(`cmd:[${cmd}] cwd:${data.cwd} inputs:${data.inputs}`);
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,
@@ -505,7 +505,10 @@ function formatByteSize(bytes) {
505
505
  if (bytes >= MB) {
506
506
  return `${(bytes / MB).toFixed(2)} MB`;
507
507
  }
508
- return `${(bytes / KB).toFixed(2)} KB`;
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) {