node-automator 1.4.27 → 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 -29
- package/commands/compress.js +23 -19
- package/commands/decrypt.js +24 -0
- package/commands/encrypt.js +27 -0
- package/commands/mgr.js +4 -0
- package/package.json +1 -1
- package/utils/func_tool.js +23 -0
- package/utils/transform_tool.js +4 -1
package/commands/backup.js
CHANGED
|
@@ -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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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) => {
|
package/commands/compress.js
CHANGED
|
@@ -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(
|
|
6
|
-
const { default: imageminPngquant } = require(
|
|
7
|
-
const { default: imageminMozjpeg } = require(
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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) {
|
|
27
|
+
result.scale(scale);
|
|
28
|
+
}
|
|
29
|
+
await result.writeAsync(dstFile);
|
|
19
30
|
}
|
|
20
31
|
const quality = data.options?.quality || 80;
|
|
21
|
-
await imagemin([
|
|
22
|
-
destination:
|
|
32
|
+
await imagemin([dstFile], {
|
|
33
|
+
destination: dstDir,
|
|
23
34
|
plugins: [
|
|
24
35
|
imageminMozjpeg({ quality: quality }), // 压缩 JPG 图片
|
|
25
36
|
imageminPngquant({
|
|
26
|
-
quality: [
|
|
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,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/package.json
CHANGED
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/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) {
|