node-automator 1.4.27 → 1.4.29

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,11 +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, verbose } =
12
- 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);
13
24
 
14
25
  async function backup(bakCfg, filename) {
15
26
  const {
@@ -18,15 +29,25 @@ class BackupCommand extends BaseCommand {
18
29
  sourceType,
19
30
  backupFormat,
20
31
  backupFilename,
32
+ backupFilenameGenerator,
21
33
  backupRename,
22
34
  backupEncoding,
23
35
  backupPrettify,
24
36
  } = bakCfg;
25
37
  const filepath = path.join(sourceFolder, filename);
26
- let backupPath = path.join(
27
- backupFolder,
28
- backupFilename || filename,
38
+ const fileSize = fs.statSync(filepath).size;
39
+ const fileSizeFormatted = formatByteSize(fileSize).replace(
40
+ /\s/g,
41
+ "",
29
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);
30
51
  let backupData;
31
52
  if (sourceType) {
32
53
  backupData = await parse(
@@ -71,6 +92,13 @@ class BackupCommand extends BaseCommand {
71
92
  fs.writeFileSync(backupPath, backupData, {
72
93
  encoding: backupEncoding,
73
94
  });
95
+ return {
96
+ filepath,
97
+ backupPath,
98
+ backupData,
99
+ fileSize,
100
+ fileSizeFormatted,
101
+ };
74
102
  }
75
103
 
76
104
  backupCfgs.forEach((bakCfg, index) => {
@@ -80,15 +108,55 @@ class BackupCommand extends BaseCommand {
80
108
  };
81
109
  }
82
110
  });
83
- // 首次备份所有
84
- backupCfgs.forEach((cfg) => {
85
- const files = glob
86
- .sync(path.join(sourceFolder, cfg.sourceFilename))
87
- .map((v) => path.relative(sourceFolder, v));
88
- files.forEach((file) => {
89
- 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
+ });
90
120
  });
91
- });
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;
92
160
 
93
161
  // 监听文件夹变化
94
162
  fs.watch(
@@ -98,22 +166,7 @@ class BackupCommand extends BaseCommand {
98
166
  },
99
167
  (eventType, filename) => {
100
168
  if (eventType === "change") {
101
- const bakCfg = backupCfgs.find((cfg) => {
102
- const files = glob
103
- .sync(path.join(sourceFolder, cfg.sourceFilename))
104
- .map((v) => path.relative(sourceFolder, v));
105
- return files.some((file) => file === filename);
106
- });
107
- if (bakCfg) {
108
- backup(bakCfg, filename)
109
- .then(() => {
110
- (verbose || bakCfg.verbose) &&
111
- success(`${filename} 备份成功`);
112
- })
113
- .catch((err) => {
114
- error(`${filename} 备份异常 ${err}`);
115
- });
116
- }
169
+ RealBackupByFilename(filename);
117
170
  }
118
171
  },
119
172
  ).on("error", (err) => {
@@ -2,38 +2,42 @@ const _path = require("node:path");
2
2
  const fs = require("node:fs");
3
3
  const { get_fst_file, get_full_path, move } = require("../utils/file_tool");
4
4
  const { BaseCommand } = require("./base");
5
- const { default: imagemin } = require('imagemin');
6
- const { default: imageminPngquant } = require('imagemin-pngquant');
7
- const { default: imageminMozjpeg } = require('imagemin-mozjpeg');
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");
8
9
 
9
10
  class CompressCommand extends BaseCommand {
10
11
  async execute() {
11
12
  const data = this.selfData;
12
13
  const src = get_fst_file(data.src);
13
14
  const dstFile = get_full_path(data.dst, "FILE");
15
+ fs.copyFileSync(src, dstFile);
14
16
  const dstDir = _path.dirname(dstFile);
15
- const dstName = _path.basename(dstFile);
16
- const tmpFolder = _path.join(this.shareData.AUTOMATOR_SCRATCH, "comporess");
17
- if (!fs.existsSync(tmpFolder)) {
18
- fs.mkdirSync(tmpFolder, { recursive: true });
17
+ if (!fs.existsSync(dstDir)) {
18
+ fs.mkdirSync(dstDir, { recursive: true });
19
+ }
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 && scale != 1) {
27
+ result.scale(scale);
28
+ }
29
+ await result.writeAsync(dstFile);
19
30
  }
20
31
  const quality = data.options?.quality || 80;
21
- await imagemin([src], {
22
- destination: tmpFolder,
32
+ await imagemin([dstFile], {
33
+ destination: dstDir,
23
34
  plugins: [
24
35
  imageminMozjpeg({ quality: quality }), // 压缩 JPG 图片
25
36
  imageminPngquant({
26
- quality: [0.6, quality / 100],
27
- })
28
- ]
37
+ quality: [quality / 100, quality / 100],
38
+ }),
39
+ ],
29
40
  });
30
- const compressedFile = _path.join(tmpFolder, _path.basename(src));
31
- fs.copyFileSync(compressedFile, _path.join(dstDir, dstName));
32
- fs.unlinkSync(compressedFile);
33
- // const sharp = require("sharp");
34
- // const options = data.options;
35
- // const fileContent = readFileSync(src);
36
- // await sharp(fileContent)[format](options).toFile(dst);
37
41
  }
38
42
  }
39
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/mgr.js CHANGED
@@ -135,6 +135,9 @@ 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');
140
+ const { TinifyCommand } = require('./tinify');
138
141
 
139
142
  const globalData = {
140
143
  executed_cfg: [], // 执行过的配置文件
@@ -521,6 +524,9 @@ function init() {
521
524
  register("split_file", SplitFileCommand, false);
522
525
  register("merge_file", MergeFileCommand, false);
523
526
  register("zip_folder", ZipFolderCommand, false);
527
+ register("encrypt", EncryptCommand, false);
528
+ register("decrypt", DecryptCommand, false);
529
+ register("tinify", TinifyCommand, false);
524
530
  }
525
531
 
526
532
  module.exports = {
@@ -0,0 +1,45 @@
1
+ const { BaseCommand } = require("./base");
2
+ const tinify = require("tinify");
3
+ const Jimp = require("jimp");
4
+ const { get_fst_file, get_full_path } = require('../utils/file_tool');
5
+ const { dirname } = require('node:path');
6
+ const fs = require('node:fs');
7
+
8
+ class TinifyCommand extends BaseCommand {
9
+ async execute() {
10
+ const data = this.selfData;
11
+ tinify.key = data.api_key;
12
+ const src = get_fst_file(data.src);
13
+ const dstFile = get_full_path(data.dst, "FILE");
14
+ fs.copyFileSync(src, dstFile);
15
+ const dstDir = dirname(dstFile);
16
+ if (!fs.existsSync(dstDir)) {
17
+ fs.mkdirSync(dstDir, { recursive: true });
18
+ }
19
+ let tinifyData = tinify.fromFile(src);
20
+ if (data.resize) {
21
+ const { w, h, scale } = data.resize;
22
+ if (w && h) {
23
+ tinifyData = tinifyData.resize({
24
+ method: "fit",
25
+ width: w,
26
+ height: h,
27
+ });
28
+ }
29
+ if (scale && scale != 1) {
30
+ const result = await Jimp.read(dstFile);
31
+ const width = result.getWidth();
32
+ tinifyData = tinifyData.scale({
33
+ method: "scale",
34
+ width: width * scale,
35
+ });
36
+ }
37
+ }
38
+ await tinifyData.toFile(dstFile);
39
+ }
40
+
41
+ }
42
+
43
+ module.exports = {
44
+ TinifyCommand,
45
+ };
package/index.js CHANGED
@@ -94,6 +94,7 @@ async function MainProcess() {
94
94
  progress(elapsedTime, estimateTime, {
95
95
  desc: "预计耗时",
96
96
  format_time: true,
97
+ color: _estimateLeft > 0 ? "reset" : "red",
97
98
  });
98
99
  }
99
100
  }, timerInterval);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-automator",
3
- "version": "1.4.27",
3
+ "version": "1.4.29",
4
4
  "description": "Execute automation with yaml configuration(compatible with json)",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -65,6 +65,7 @@
65
65
  "spreadsheet-column": "^1.1.1",
66
66
  "strip-json-comments": "^3.1.1",
67
67
  "temp": "^0.9.4",
68
+ "tinify": "^1.8.2",
68
69
  "typescript-plus": "^3.1.5",
69
70
  "websocket": "^1.0.34",
70
71
  "xlsx": "^0.17.0",
@@ -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
  };
@@ -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) {