@duoyun/md-img-pull 1.2.0 → 1.2.2

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.
Files changed (3) hide show
  1. package/README.md +10 -2
  2. package/dist/main.cjs +94 -129
  3. package/package.json +53 -53
package/README.md CHANGED
@@ -87,11 +87,19 @@ node dist/main.cjs
87
87
 
88
88
  ## 更新日志
89
89
 
90
+ ### v1.2.2
91
+
92
+ - **优化**:在 `getFilesRecursive` 中对读取的子项进行自然排序,使数字按数值大小排序(避免 1, 10, 2 的字典序问题)
93
+
94
+ ### v1.2.1
95
+
96
+ - **修复**:优化进度显示稳定性,减少刷新频率,解决抖动问题
97
+ - **优化**:缩短进度条和文件名显示,避免终端换行导致的显示异常
98
+
90
99
  ### v1.2.0
91
100
 
92
101
  - **新功能**:分区输出 - 自动将输出按约 50MB 分割为多个 `part_X` 文件夹,方便管理和传输
93
- - **优化**:全新的单行进度显示,不再闪烁抖动
94
- - **优化**:实时显示分区大小、下载/压缩状态、累计时间
102
+ - **优化**:全新的单行进度显示,实时显示分区大小、下载/压缩状态、累计时间
95
103
  - **优化**:精简日志输出,移除冗余信息
96
104
 
97
105
  ### v1.1.0
package/dist/main.cjs CHANGED
@@ -13789,6 +13789,10 @@ var import_fs_extra = __toESM(require_lib(), 1);
13789
13789
  var import_path = __toESM(require("path"), 1);
13790
13790
  async function getFilesRecursive(dir) {
13791
13791
  const subdirs = await import_fs_extra.default.readdir(dir);
13792
+ subdirs.sort(
13793
+ (a, b) => a.localeCompare(b, void 0, { numeric: true, sensitivity: "base" })
13794
+ );
13795
+ console.log("\u{1F680} ~ getFilesRecursive ~ subdirs:", subdirs);
13792
13796
  const files = await Promise.all(
13793
13797
  //返回数组
13794
13798
  subdirs.map(async (subdir) => {
@@ -23814,13 +23818,13 @@ function remarkStringify(options) {
23814
23818
  }
23815
23819
 
23816
23820
  // utils/processSingleMarkdown.ts
23817
- var import_fs_extra5 = __toESM(require_lib(), 1);
23818
- var import_path4 = __toESM(require("path"), 1);
23821
+ var import_fs_extra4 = __toESM(require_lib(), 1);
23822
+ var import_path3 = __toESM(require("path"), 1);
23819
23823
 
23820
23824
  // utils/downloader.ts
23821
23825
  var import_crypto2 = __toESM(require("crypto"), 1);
23822
- var path4 = __toESM(require("path"), 1);
23823
- var import_fs_extra4 = __toESM(require_lib(), 1);
23826
+ var path3 = __toESM(require("path"), 1);
23827
+ var import_fs_extra3 = __toESM(require_lib(), 1);
23824
23828
 
23825
23829
  // node_modules/.pnpm/axios@1.13.4/node_modules/axios/lib/helpers/bind.js
23826
23830
  function bind(fn, thisArg) {
@@ -30938,32 +30942,6 @@ function ora(options) {
30938
30942
  return new Ora(options);
30939
30943
  }
30940
30944
 
30941
- // utils/getFolderSize.ts
30942
- var import_fs_extra3 = __toESM(require_lib(), 1);
30943
- var import_path3 = __toESM(require("path"), 1);
30944
- async function getFolderSize(folderPath) {
30945
- let totalSize = 0;
30946
- if (!await import_fs_extra3.default.pathExists(folderPath)) {
30947
- return 0;
30948
- }
30949
- const items = await import_fs_extra3.default.readdir(folderPath);
30950
- for (const item of items) {
30951
- const itemPath = import_path3.default.join(folderPath, item);
30952
- const stats = await import_fs_extra3.default.stat(itemPath);
30953
- if (stats.isFile()) {
30954
- totalSize += stats.size;
30955
- } else if (stats.isDirectory()) {
30956
- totalSize += await getFolderSize(itemPath);
30957
- }
30958
- }
30959
- return totalSize;
30960
- }
30961
- function formatSize(bytes) {
30962
- if (bytes < 1024) return `${bytes} B`;
30963
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
30964
- return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
30965
- }
30966
-
30967
30945
  // utils/progressManager.ts
30968
30946
  var ProgressManager = class {
30969
30947
  totalFiles = 0;
@@ -30974,21 +30952,18 @@ var ProgressManager = class {
30974
30952
  currentFileName = "";
30975
30953
  downloadTotal = 0;
30976
30954
  downloadCompleted = 0;
30977
- compressedCount = 0;
30978
30955
  isCompressing = false;
30979
- // 是否正在压缩
30980
30956
  // 分区信息
30981
30957
  partitionIndex = 1;
30982
- partitionPath = "";
30983
- cachedPartitionSize = "0 B";
30984
- // ora spinner 实例
30958
+ partitionSize = "0 B";
30959
+ // ora spinner
30985
30960
  spinner = null;
30986
- // 定时器(用于实时更新时间)
30961
+ // 定时器(只用于更新时间)
30987
30962
  timer = null;
30988
30963
  /**
30989
- * 初始化进度管理器
30964
+ * 初始化
30990
30965
  */
30991
- init(srcPath, distPath, totalFiles) {
30966
+ init(_srcPath, distPath, totalFiles) {
30992
30967
  this.totalFiles = totalFiles;
30993
30968
  this.completedFiles = 0;
30994
30969
  this.startTime = Date.now();
@@ -30996,38 +30971,35 @@ var ProgressManager = class {
30996
30971
  console.log("");
30997
30972
  }
30998
30973
  /**
30999
- * 设置当前分区信息
30974
+ * 设置分区
31000
30975
  */
31001
- setPartition(index2, partitionPath) {
30976
+ setPartition(index2, _path) {
31002
30977
  this.partitionIndex = index2;
31003
- this.partitionPath = partitionPath;
31004
30978
  }
31005
30979
  /**
31006
- * 异步更新分区大小缓存
30980
+ * 设置分区大小
31007
30981
  */
31008
- async updatePartitionSize() {
31009
- if (this.partitionPath) {
31010
- const size = await getFolderSize(this.partitionPath);
31011
- this.cachedPartitionSize = formatSize(size);
31012
- }
30982
+ setPartitionSize(size) {
30983
+ this.partitionSize = size;
31013
30984
  }
31014
30985
  /**
31015
- * 开始处理一个新文件
30986
+ * 开始处理文件
31016
30987
  */
31017
30988
  startFile(fileName, imageCount) {
31018
30989
  this.currentFileName = fileName;
31019
30990
  this.downloadTotal = imageCount;
31020
30991
  this.downloadCompleted = 0;
31021
- this.compressedCount = 0;
31022
30992
  this.isCompressing = false;
31023
30993
  this.fileStartTime = Date.now();
31024
30994
  this.spinner = ora({
31025
- text: this.formatText(),
30995
+ text: this.getText(),
31026
30996
  spinner: "dots"
31027
30997
  }).start();
31028
30998
  this.timer = setInterval(() => {
31029
- this.updateDisplay();
31030
- }, 200);
30999
+ if (this.spinner) {
31000
+ this.spinner.text = this.getText();
31001
+ }
31002
+ }, 500);
31031
31003
  }
31032
31004
  /**
31033
31005
  * 更新下载进度
@@ -31035,22 +31007,27 @@ var ProgressManager = class {
31035
31007
  updateDownload() {
31036
31008
  this.downloadCompleted++;
31037
31009
  this.isCompressing = false;
31038
- this.updateDisplay();
31010
+ if (this.spinner) {
31011
+ this.spinner.text = this.getText();
31012
+ }
31039
31013
  }
31040
31014
  /**
31041
- * 开始压缩(设置压缩状态)
31015
+ * 开始压缩
31042
31016
  */
31043
31017
  startCompress() {
31044
31018
  this.isCompressing = true;
31045
- this.updateDisplay();
31019
+ if (this.spinner) {
31020
+ this.spinner.text = this.getText();
31021
+ }
31046
31022
  }
31047
31023
  /**
31048
- * 更新压缩计数
31024
+ * 完成压缩
31049
31025
  */
31050
31026
  updateCompress() {
31051
- this.compressedCount++;
31052
31027
  this.isCompressing = false;
31053
- this.updateDisplay();
31028
+ if (this.spinner) {
31029
+ this.spinner.text = this.getText();
31030
+ }
31054
31031
  }
31055
31032
  /**
31056
31033
  * 完成当前文件
@@ -31072,78 +31049,37 @@ var ProgressManager = class {
31072
31049
  this.spinner.stop();
31073
31050
  this.spinner = null;
31074
31051
  }
31075
- const totalTime = this.formatTime(Date.now() - this.startTime);
31076
- const progressBar = this.createProgressBar(
31077
- this.totalFiles,
31078
- this.totalFiles
31079
- );
31080
- console.log(
31081
- source_default.green("OK") + ` ${progressBar} ${this.completedFiles}/${this.totalFiles} | ${totalTime}`
31082
- );
31052
+ const time = this.formatTime(Date.now() - this.startTime);
31053
+ const bar = this.getBar(this.totalFiles, this.totalFiles);
31054
+ console.log(source_default.green("OK") + ` ${bar} ${this.completedFiles}/${this.totalFiles} | ${time}`);
31083
31055
  console.log("");
31084
31056
  }
31085
- /**
31086
- * 更新显示(由定时器或事件触发)
31087
- */
31088
- updateDisplay() {
31089
- if (this.spinner) {
31090
- this.spinner.text = this.formatText();
31091
- }
31092
- }
31093
- /**
31094
- * 停止定时器
31095
- */
31096
31057
  stopTimer() {
31097
31058
  if (this.timer) {
31098
31059
  clearInterval(this.timer);
31099
31060
  this.timer = null;
31100
31061
  }
31101
31062
  }
31102
- /**
31103
- * 格式化单行显示文本
31104
- */
31105
- formatText() {
31106
- const totalTime = this.formatTime(Date.now() - this.startTime);
31063
+ getText() {
31064
+ const bar = this.getBar(this.completedFiles, this.totalFiles);
31065
+ const time = this.formatTime(Date.now() - this.startTime);
31107
31066
  const fileTime = this.formatTime(Date.now() - this.fileStartTime);
31108
- const progressBar = this.createProgressBar(
31109
- this.completedFiles,
31110
- this.totalFiles
31111
- );
31112
- let status = "";
31113
- if (this.isCompressing) {
31114
- status = "\u538B\u7F29\u4E2D";
31115
- } else if (this.downloadTotal > 0) {
31116
- status = `\u2193 ${this.downloadCompleted}/${this.downloadTotal}`;
31117
- }
31118
- let text4 = `${progressBar} ${this.completedFiles}/${this.totalFiles}`;
31119
- text4 += ` | \u5206\u533A${this.partitionIndex} (${this.cachedPartitionSize})`;
31120
- text4 += ` | ${this.currentFileName} (${fileTime})`;
31121
- if (status) {
31122
- text4 += ` | ${status}`;
31067
+ let name = this.currentFileName;
31068
+ if (name.length > 25) {
31069
+ name = name.slice(0, 22) + "...";
31123
31070
  }
31124
- text4 += ` | ${totalTime}`;
31125
- return text4;
31071
+ let status = this.isCompressing ? "\u538B\u7F29\u4E2D" : `\u2193${this.downloadCompleted}/${this.downloadTotal}`;
31072
+ return `${bar} ${this.completedFiles}/${this.totalFiles} | \u5206\u533A${this.partitionIndex}(${this.partitionSize}) | ${name}(${fileTime}) | ${status} | ${time}`;
31126
31073
  }
31127
- /**
31128
- * 创建进度条
31129
- */
31130
- createProgressBar(current, total) {
31131
- const width = 20;
31132
- const filled = total > 0 ? Math.round(current / total * width) : 0;
31133
- const empty2 = width - filled;
31134
- return source_default.green("\u2588".repeat(filled)) + source_default.gray("\u2591".repeat(empty2));
31074
+ getBar(cur, total) {
31075
+ const w = 15;
31076
+ const f = total > 0 ? Math.round(cur / total * w) : 0;
31077
+ return source_default.green("\u2588".repeat(f)) + source_default.gray("\u2591".repeat(w - f));
31135
31078
  }
31136
- /**
31137
- * 格式化时间
31138
- */
31139
31079
  formatTime(ms) {
31140
- const seconds = Math.floor(ms / 1e3);
31141
- if (seconds < 60) {
31142
- return `${seconds}s`;
31143
- }
31144
- const minutes = Math.floor(seconds / 60);
31145
- const remainingSeconds = seconds % 60;
31146
- return `${minutes}m${remainingSeconds}s`;
31080
+ const s = Math.floor(ms / 1e3);
31081
+ if (s < 60) return `${s}s`;
31082
+ return `${Math.floor(s / 60)}m${s % 60}s`;
31147
31083
  }
31148
31084
  };
31149
31085
  var progressManager = new ProgressManager();
@@ -31193,7 +31129,7 @@ async function downloadAndLocalize(node2, assetDir) {
31193
31129
  let finalExt = mimeMap[contentType];
31194
31130
  if (!finalExt) {
31195
31131
  const rawPath = (currentUrl.split("?")[0] || "").split("#")[0];
31196
- const rawExt = path4.extname(rawPath || "");
31132
+ const rawExt = path3.extname(rawPath || "");
31197
31133
  finalExt = rawExt === ".image" || !rawExt ? ".png" : rawExt;
31198
31134
  }
31199
31135
  let imageData = Buffer.from(response.data);
@@ -31209,10 +31145,10 @@ async function downloadAndLocalize(node2, assetDir) {
31209
31145
  finalExt = ".webp";
31210
31146
  }
31211
31147
  const fileName = `${hash}${finalExt}`;
31212
- const localPath = path4.join(assetDir, fileName);
31213
- await import_fs_extra4.default.ensureDir(assetDir);
31214
- if (!await import_fs_extra4.default.pathExists(localPath)) {
31215
- await import_fs_extra4.default.writeFile(localPath, imageData);
31148
+ const localPath = path3.join(assetDir, fileName);
31149
+ await import_fs_extra3.default.ensureDir(assetDir);
31150
+ if (!await import_fs_extra3.default.pathExists(localPath)) {
31151
+ await import_fs_extra3.default.writeFile(localPath, imageData);
31216
31152
  }
31217
31153
  progressManager.updateDownload();
31218
31154
  const originalSize = response.data.byteLength;
@@ -31234,11 +31170,11 @@ async function downloadAndLocalize(node2, assetDir) {
31234
31170
 
31235
31171
  // utils/processSingleMarkdown.ts
31236
31172
  async function processSingleMarkdown(srcPath, distPath) {
31237
- const fileName = import_path4.default.basename(srcPath);
31173
+ const fileName = import_path3.default.basename(srcPath);
31238
31174
  imageLog.setCurrentFile(fileName);
31239
- const content3 = await import_fs_extra5.default.readFile(srcPath, "utf-8");
31240
- const targetAssetDir = import_path4.default.join(import_path4.default.dirname(distPath), "assets");
31241
- await import_fs_extra5.default.ensureDir(targetAssetDir);
31175
+ const content3 = await import_fs_extra4.default.readFile(srcPath, "utf-8");
31176
+ const targetAssetDir = import_path3.default.join(import_path3.default.dirname(distPath), "assets");
31177
+ await import_fs_extra4.default.ensureDir(targetAssetDir);
31242
31178
  const processor = unified().use(remarkParse).use(() => async (tree) => {
31243
31179
  const promises = [];
31244
31180
  const imageNodes = [];
@@ -31256,14 +31192,42 @@ async function processSingleMarkdown(srcPath, distPath) {
31256
31192
  progressManager.completeFile();
31257
31193
  }).use(remarkStringify);
31258
31194
  const result = await processor.process(content3);
31259
- await import_fs_extra5.default.ensureDir(import_path4.default.dirname(distPath));
31260
- await import_fs_extra5.default.writeFile(distPath, result.toString());
31195
+ await import_fs_extra4.default.ensureDir(import_path3.default.dirname(distPath));
31196
+ await import_fs_extra4.default.writeFile(distPath, result.toString());
31261
31197
  }
31262
31198
 
31263
31199
  // main.ts
31264
31200
  var readline = __toESM(require("node:readline/promises"), 1);
31265
31201
  var import_fs_extra6 = __toESM(require_lib(), 1);
31266
31202
  var import_node_process8 = require("node:process");
31203
+
31204
+ // utils/getFolderSize.ts
31205
+ var import_fs_extra5 = __toESM(require_lib(), 1);
31206
+ var import_path4 = __toESM(require("path"), 1);
31207
+ async function getFolderSize(folderPath) {
31208
+ let totalSize = 0;
31209
+ if (!await import_fs_extra5.default.pathExists(folderPath)) {
31210
+ return 0;
31211
+ }
31212
+ const items = await import_fs_extra5.default.readdir(folderPath);
31213
+ for (const item of items) {
31214
+ const itemPath = import_path4.default.join(folderPath, item);
31215
+ const stats = await import_fs_extra5.default.stat(itemPath);
31216
+ if (stats.isFile()) {
31217
+ totalSize += stats.size;
31218
+ } else if (stats.isDirectory()) {
31219
+ totalSize += await getFolderSize(itemPath);
31220
+ }
31221
+ }
31222
+ return totalSize;
31223
+ }
31224
+ function formatSize(bytes) {
31225
+ if (bytes < 1024) return `${bytes} B`;
31226
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
31227
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
31228
+ }
31229
+
31230
+ // main.ts
31267
31231
  var log = console.log;
31268
31232
  var PARTITION_SIZE_LIMIT = 50 * 1024 * 1024;
31269
31233
  async function runBatch() {
@@ -31332,8 +31296,8 @@ async function runBatch() {
31332
31296
  }
31333
31297
  const targetMdPath = import_path5.default.join(currentPartitionPath, relativePath);
31334
31298
  await processSingleMarkdown(mdFile, targetMdPath);
31335
- await progressManager.updatePartitionSize();
31336
31299
  const currentPartitionSize = await getFolderSize(currentPartitionPath);
31300
+ progressManager.setPartitionSize(formatSize(currentPartitionSize));
31337
31301
  if (currentPartitionSize >= PARTITION_SIZE_LIMIT) {
31338
31302
  partitionIndex++;
31339
31303
  currentPartitionPath = import_path5.default.join(
@@ -31341,6 +31305,7 @@ async function runBatch() {
31341
31305
  `part_${partitionIndex}`
31342
31306
  );
31343
31307
  progressManager.setPartition(partitionIndex, currentPartitionPath);
31308
+ progressManager.setPartitionSize("0 B");
31344
31309
  }
31345
31310
  }
31346
31311
  progressManager.finish();
package/package.json CHANGED
@@ -1,53 +1,53 @@
1
- {
2
- "name": "@duoyun/md-img-pull",
3
- "version": "1.2.0",
4
- "description": "Markdown 媒体资源本地化与压缩工具",
5
- "main": "./dist/main.cjs",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/518luck/md-img-pull.git"
9
- },
10
- "homepage": "https://github.com/518luck/md-img-pull#readme",
11
- "publishConfig": {
12
- "access": "public",
13
- "registry": "https://registry.npmjs.org/"
14
- },
15
- "bin": {
16
- "md-img-p": "dist/main.cjs"
17
- },
18
- "type": "module",
19
- "files": [
20
- "dist"
21
- ],
22
- "scripts": {
23
- "start": "tsx main.ts",
24
- "build": "esbuild main.ts --bundle --platform=node --format=cjs --outfile=dist/main.cjs --external:sharp --banner:js=\"#!/usr/bin/env node\"",
25
- "test": "echo \"Error: no test specified\" && exit 1"
26
- },
27
- "keywords": [],
28
- "author": "",
29
- "license": "ISC",
30
- "packageManager": "pnpm@10.28.0",
31
- "devDependencies": {
32
- "@types/fs-extra": "^11.0.4",
33
- "@types/node": "^25.2.1",
34
- "esbuild": "^0.27.3",
35
- "ts-node": "^10.9.2",
36
- "tsx": "^4.21.0",
37
- "typescript": "^5.9.3"
38
- },
39
- "dependencies": {
40
- "@types/mdast": "^4.0.4",
41
- "axios": "^1.13.4",
42
- "chalk": "^5.6.2",
43
- "crypto": "^1.0.1",
44
- "fs-extra": "^11.3.3",
45
- "ora": "^9.3.0",
46
- "p-limit": "^7.3.0",
47
- "remark-parse": "^11.0.0",
48
- "remark-stringify": "^11.0.0",
49
- "sharp": "^0.34.5",
50
- "unified": "^11.0.5",
51
- "unist-util-visit": "^5.1.0"
52
- }
53
- }
1
+ {
2
+ "name": "@duoyun/md-img-pull",
3
+ "version": "1.2.2",
4
+ "description": "Markdown 媒体资源本地化与压缩工具",
5
+ "main": "./dist/main.cjs",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/518luck/md-img-pull.git"
9
+ },
10
+ "homepage": "https://github.com/518luck/md-img-pull#readme",
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "registry": "https://registry.npmjs.org/"
14
+ },
15
+ "bin": {
16
+ "md-img-p": "dist/main.cjs"
17
+ },
18
+ "type": "module",
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "start": "tsx main.ts",
24
+ "build": "esbuild main.ts --bundle --platform=node --format=cjs --outfile=dist/main.cjs --external:sharp --banner:js=\"#!/usr/bin/env node\"",
25
+ "test": "echo \"Error: no test specified\" && exit 1"
26
+ },
27
+ "keywords": [],
28
+ "author": "",
29
+ "license": "ISC",
30
+ "packageManager": "pnpm@10.28.0",
31
+ "devDependencies": {
32
+ "@types/fs-extra": "^11.0.4",
33
+ "@types/node": "^25.2.1",
34
+ "esbuild": "^0.27.3",
35
+ "ts-node": "^10.9.2",
36
+ "tsx": "^4.21.0",
37
+ "typescript": "^5.9.3"
38
+ },
39
+ "dependencies": {
40
+ "@types/mdast": "^4.0.4",
41
+ "axios": "^1.13.4",
42
+ "chalk": "^5.6.2",
43
+ "crypto": "^1.0.1",
44
+ "fs-extra": "^11.3.3",
45
+ "ora": "^9.3.0",
46
+ "p-limit": "^7.3.0",
47
+ "remark-parse": "^11.0.0",
48
+ "remark-stringify": "^11.0.0",
49
+ "sharp": "^0.34.5",
50
+ "unified": "^11.0.5",
51
+ "unist-util-visit": "^5.1.0"
52
+ }
53
+ }