@king-3/file-kit 1.0.1 → 1.2.0
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/cli.js +51 -42
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
-
import { confirm, intro, isCancel, outro, password, select, spinner, text } from "@clack/prompts";
|
|
3
2
|
import ansis, { bold, cyan, gray, yellow } from "ansis";
|
|
4
3
|
import { defineCommand, runMain } from "citty";
|
|
5
4
|
import path from "node:path";
|
|
6
5
|
import fs from "node:fs/promises";
|
|
7
6
|
import { Buffer } from "node:buffer";
|
|
8
7
|
import { accessSync, existsSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { confirm, intro, isCancel, outro, password, select, spinner, text } from "@clack/prompts";
|
|
9
9
|
import { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from "node:crypto";
|
|
10
10
|
import path$1 from "node:path/posix";
|
|
11
11
|
import ffmpegPath from "@ffmpeg-installer/ffmpeg";
|
|
@@ -225,7 +225,7 @@ async function base64ToFile(archiveData, outputDir = ".") {
|
|
|
225
225
|
//#endregion
|
|
226
226
|
//#region src/config/defaults.ts
|
|
227
227
|
const CLI_NAME = "File Kit";
|
|
228
|
-
const CLI_VERSION = "1.0
|
|
228
|
+
const CLI_VERSION = "1.1.0";
|
|
229
229
|
const CLI_ALIAS = "fkt";
|
|
230
230
|
/**
|
|
231
231
|
* 默认配置
|
|
@@ -295,25 +295,34 @@ function createCommandContext(rawArgs) {
|
|
|
295
295
|
const isInteractive = Array.isArray(rawArgs) && rawArgs.includes("-i");
|
|
296
296
|
return {
|
|
297
297
|
isInteractive,
|
|
298
|
-
showIntro: () =>
|
|
299
|
-
|
|
300
|
-
},
|
|
301
|
-
showOutro: (message) => {
|
|
302
|
-
outro(bold.green(message));
|
|
303
|
-
},
|
|
298
|
+
showIntro: () => showIntro(!isInteractive),
|
|
299
|
+
showOutro,
|
|
304
300
|
getInput: getInputPath,
|
|
305
301
|
getOutput: getOutputDir,
|
|
306
|
-
loading
|
|
307
|
-
const s = spinner();
|
|
308
|
-
s.start(initialMessage);
|
|
309
|
-
return {
|
|
310
|
-
update: (message) => s.message(message),
|
|
311
|
-
close: (message) => s.stop(message)
|
|
312
|
-
};
|
|
313
|
-
}
|
|
302
|
+
loading
|
|
314
303
|
};
|
|
315
304
|
}
|
|
316
305
|
/**
|
|
306
|
+
* Loading 加载器
|
|
307
|
+
*/
|
|
308
|
+
function loading(initialMessage) {
|
|
309
|
+
const s = spinner();
|
|
310
|
+
s.start(initialMessage);
|
|
311
|
+
return {
|
|
312
|
+
update: (message) => s.message(message),
|
|
313
|
+
close: (message) => s.stop(message)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function showIntro(isShow) {
|
|
317
|
+
if (isShow) {
|
|
318
|
+
console.log("");
|
|
319
|
+
intro(bold.cyan(`🔧 ${CLI_NAME}`));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function showOutro(message) {
|
|
323
|
+
outro(bold.green(message));
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
317
326
|
* 获取并验证输入路径
|
|
318
327
|
*/
|
|
319
328
|
async function getInputPath(providedPath, options) {
|
|
@@ -415,7 +424,7 @@ async function loadArchive(filePath, type) {
|
|
|
415
424
|
var base64_default = defineCommand({
|
|
416
425
|
meta: {
|
|
417
426
|
name: "base64",
|
|
418
|
-
description: "将文件转换为 Base64 JSON"
|
|
427
|
+
description: "将文件转换为 Base64 JSON 文本"
|
|
419
428
|
},
|
|
420
429
|
args: {
|
|
421
430
|
input: {
|
|
@@ -437,10 +446,10 @@ var base64_default = defineCommand({
|
|
|
437
446
|
message: "请输入文件路径",
|
|
438
447
|
placeholder: "file.txt"
|
|
439
448
|
});
|
|
440
|
-
const outputPath = buildOutputPath(inputPath, await ctx.getOutput(typedArgs.output, { defaultDir: path.dirname(inputPath) }), "base64.
|
|
441
|
-
const loading = ctx.loading("正在转换");
|
|
449
|
+
const outputPath = buildOutputPath(inputPath, await ctx.getOutput(typedArgs.output, { defaultDir: path.dirname(inputPath) }), "base64.txt");
|
|
450
|
+
const loading$1 = ctx.loading("正在转换");
|
|
442
451
|
const archiveData = await fileToBase64(inputPath, outputPath);
|
|
443
|
-
loading.close(`文件已保存到: ${cyan(outputPath)}, 共计 ${bold.gray((archiveData.file.size / 1024).toFixed(2))} KB`);
|
|
452
|
+
loading$1.close(`文件已保存到: ${cyan(outputPath)}, 共计 ${bold.gray((archiveData.file.size / 1024).toFixed(2))} KB`);
|
|
444
453
|
ctx.showOutro("📦 转换完成");
|
|
445
454
|
});
|
|
446
455
|
}
|
|
@@ -541,12 +550,12 @@ async function decrypt(archiveData, outputDir = ".", options) {
|
|
|
541
550
|
var decrypt_default = defineCommand({
|
|
542
551
|
meta: {
|
|
543
552
|
name: "decrypt",
|
|
544
|
-
description: "解密文件"
|
|
553
|
+
description: "从 CRYPTO JSON 解密文件"
|
|
545
554
|
},
|
|
546
555
|
args: {
|
|
547
556
|
input: {
|
|
548
557
|
type: "positional",
|
|
549
|
-
description: "加密文件 (*.crypto.
|
|
558
|
+
description: "加密文件 (*.crypto.txt)",
|
|
550
559
|
required: true
|
|
551
560
|
},
|
|
552
561
|
output: {
|
|
@@ -567,14 +576,14 @@ var decrypt_default = defineCommand({
|
|
|
567
576
|
tryCatch(async () => {
|
|
568
577
|
const inputPath = await ctx.getInput(typedArgs.input, {
|
|
569
578
|
message: "请输入文件路径",
|
|
570
|
-
placeholder: "*.crypto.
|
|
571
|
-
validateExtension: ".crypto.
|
|
579
|
+
placeholder: "*.crypto.txt",
|
|
580
|
+
validateExtension: ".crypto.txt"
|
|
572
581
|
});
|
|
573
582
|
const outputDir = await ctx.getOutput(typedArgs.output, { defaultDir: path.dirname(inputPath) });
|
|
574
583
|
const password$2 = await getPassword(typedArgs.password);
|
|
575
|
-
const loading = ctx.loading("正在解密");
|
|
584
|
+
const loading$1 = ctx.loading("正在解密");
|
|
576
585
|
const outputPath = await decrypt(await loadArchive(inputPath, "crypto"), outputDir, { password: password$2 });
|
|
577
|
-
loading.close(`文件已解密到: ${cyan(outputPath)}`);
|
|
586
|
+
loading$1.close(`文件已解密到: ${cyan(outputPath)}`);
|
|
578
587
|
ctx.showOutro("🔓 解密完成");
|
|
579
588
|
});
|
|
580
589
|
}
|
|
@@ -585,7 +594,7 @@ var decrypt_default = defineCommand({
|
|
|
585
594
|
var encrypt_default = defineCommand({
|
|
586
595
|
meta: {
|
|
587
596
|
name: "encrypt",
|
|
588
|
-
description: "
|
|
597
|
+
description: "将文件加密为 CRYPTO JSON 文本"
|
|
589
598
|
},
|
|
590
599
|
args: {
|
|
591
600
|
input: {
|
|
@@ -617,10 +626,10 @@ var encrypt_default = defineCommand({
|
|
|
617
626
|
const password$2 = await getPassword(typedArgs.password);
|
|
618
627
|
console.log(gray("│"));
|
|
619
628
|
logger.warn(yellow("请妥善保管密码,丢失后无法恢复文件!"));
|
|
620
|
-
const outputPath = buildOutputPath(inputPath, outputDir, "crypto.
|
|
621
|
-
const loading = ctx.loading("正在加密");
|
|
629
|
+
const outputPath = buildOutputPath(inputPath, outputDir, "crypto.txt");
|
|
630
|
+
const loading$1 = ctx.loading("正在加密");
|
|
622
631
|
const archiveData = await encrypt(inputPath, outputPath, { password: password$2 });
|
|
623
|
-
loading.close(`文件已加密到: ${cyan(outputPath)}, 共计 ${bold.gray((archiveData.file.size / 1024).toFixed(2))} KB`);
|
|
632
|
+
loading$1.close(`文件已加密到: ${cyan(outputPath)}, 共计 ${bold.gray((archiveData.file.size / 1024).toFixed(2))} KB`);
|
|
624
633
|
ctx.showOutro("🔐 加密完成");
|
|
625
634
|
});
|
|
626
635
|
}
|
|
@@ -636,7 +645,7 @@ var restore_default = defineCommand({
|
|
|
636
645
|
args: {
|
|
637
646
|
input: {
|
|
638
647
|
type: "positional",
|
|
639
|
-
description: "Base64 文件 (*.base64.
|
|
648
|
+
description: "Base64 文件 (*.base64.txt)"
|
|
640
649
|
},
|
|
641
650
|
output: {
|
|
642
651
|
type: "string",
|
|
@@ -651,14 +660,14 @@ var restore_default = defineCommand({
|
|
|
651
660
|
tryCatch(async () => {
|
|
652
661
|
const inputPath = await ctx.getInput(typedArgs.input, {
|
|
653
662
|
message: "请输入文件路径",
|
|
654
|
-
placeholder: "*.base64.
|
|
655
|
-
validateExtension: "base64.
|
|
663
|
+
placeholder: "*.base64.txt",
|
|
664
|
+
validateExtension: "base64.txt"
|
|
656
665
|
});
|
|
657
666
|
const outputDir = await ctx.getOutput(typedArgs.output, { defaultDir: path.dirname(inputPath) });
|
|
658
|
-
const loading = ctx.loading("正在恢复");
|
|
667
|
+
const loading$1 = ctx.loading("正在恢复");
|
|
659
668
|
const archiveData = await loadArchive(inputPath, "base64");
|
|
660
669
|
const restoredPath = await base64ToFile(archiveData, outputDir);
|
|
661
|
-
loading.close(`文件已恢复到: ${cyan(restoredPath)}, 原始创建时间 ${bold.gray(archiveData.createdAt)}`);
|
|
670
|
+
loading$1.close(`文件已恢复到: ${cyan(restoredPath)}, 原始创建时间 ${bold.gray(archiveData.createdAt)}`);
|
|
662
671
|
ctx.showOutro("🔄 恢复完成");
|
|
663
672
|
});
|
|
664
673
|
}
|
|
@@ -915,14 +924,14 @@ var video_to_audio_default = defineCommand({
|
|
|
915
924
|
else if (typedArgs.quality) quality = typedArgs.quality;
|
|
916
925
|
else quality = DEFAULT_CONFIG.videoToAudio.defaultQuality;
|
|
917
926
|
const outputPath = buildOutputPath(inputPath, outputDir, formatConfig.extension);
|
|
918
|
-
const loading = ctx.loading("正在提取音频 0%");
|
|
927
|
+
const loading$1 = ctx.loading("正在提取音频 0%");
|
|
919
928
|
await extractAudio(inputPath, outputPath, {
|
|
920
929
|
format,
|
|
921
930
|
quality
|
|
922
931
|
}, (percent) => {
|
|
923
|
-
loading.update(`正在提取音频 ${percent}%`);
|
|
932
|
+
loading$1.update(`正在提取音频 ${percent}%`);
|
|
924
933
|
});
|
|
925
|
-
loading.close(`音频已提取到: ${cyan(outputPath)}`);
|
|
934
|
+
loading$1.close(`音频已提取到: ${cyan(outputPath)}`);
|
|
926
935
|
ctx.showOutro("🎵 提取完成");
|
|
927
936
|
});
|
|
928
937
|
}
|
|
@@ -989,7 +998,7 @@ function showVersion() {
|
|
|
989
998
|
* 显示帮助信息
|
|
990
999
|
*/
|
|
991
1000
|
function showHelp() {
|
|
992
|
-
console.log(
|
|
1001
|
+
console.log(`\n${ansis.bold(`🔧 ${CLI_NAME}`)}${ansis.dim(` - 多功能文件工具箱 (${CLI_ALIAS} v${CLI_VERSION})`)}\n`);
|
|
993
1002
|
console.log(ansis.bold("用法:"));
|
|
994
1003
|
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.dim("<command> [options]")} 执行指定命令`);
|
|
995
1004
|
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("-i, --interactive")} 进入交互模式`);
|
|
@@ -1003,17 +1012,17 @@ function showHelp() {
|
|
|
1003
1012
|
console.log(` ${ansis.green("decrypt")}${ansis.dim(" 解密文件")}\n`);
|
|
1004
1013
|
console.log(ansis.bold("示例:"));
|
|
1005
1014
|
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("base64")} ${ansis.green("file.txt")} ${ansis.dim("转换文件为 Base64")}`);
|
|
1006
|
-
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("restore")} ${ansis.green("file.
|
|
1015
|
+
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("restore")} ${ansis.green("file.base64.txt")} ${ansis.dim("还原 Base64 文件")}`);
|
|
1007
1016
|
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("v2a")} ${ansis.green("video.mp4")} ${ansis.blue("-f mp3")} ${ansis.dim("提取视频音频为 MP3")}`);
|
|
1008
1017
|
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("encrypt")} ${ansis.green("secret.txt")} ${ansis.blue("-p pwd")} ${ansis.dim("加密文件")}`);
|
|
1009
|
-
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("decrypt")} ${ansis.green("secret.
|
|
1018
|
+
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("decrypt")} ${ansis.green("secret.crypto.txt")} ${ansis.blue("-p pwd")} ${ansis.dim("解密文件")}`);
|
|
1010
1019
|
console.log(` ${ansis.yellow(CLI_ALIAS)} ${ansis.cyan("-i")} ${ansis.dim("交互式选择功能")}\n`);
|
|
1011
1020
|
}
|
|
1012
1021
|
/**
|
|
1013
1022
|
* 交互模式
|
|
1014
1023
|
*/
|
|
1015
1024
|
async function runInteractiveMode() {
|
|
1016
|
-
|
|
1025
|
+
showIntro(true);
|
|
1017
1026
|
const choice = await select$1({
|
|
1018
1027
|
message: "选择功能",
|
|
1019
1028
|
options: INTERACTIVE_OPTIONS
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@king-3/file-kit",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "多功能文件工具箱(Base64 转换 · 视频转音频 · 加密/解密)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"node": ">=20.0.0"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
|
-
"
|
|
62
|
+
"fkt": "node bin/cli.js",
|
|
63
63
|
"dev": "tsx src/cli.ts",
|
|
64
64
|
"build": "tsx scripts/build.ts",
|
|
65
65
|
"format": "prettier --write .",
|