@duoyun/md-img-pull 1.0.1 → 1.1.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.
Files changed (2) hide show
  1. package/dist/main.cjs +70 -74
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -30846,64 +30846,74 @@ var DownloadProgressManager = class {
30846
30846
  };
30847
30847
  var downloadProgress = new DownloadProgressManager();
30848
30848
 
30849
- // utils/imageCompression.ts
30850
- var SHARP_OPTIONS = {
30851
- animated: true,
30852
- limitInputPixels: false,
30853
- sequentialRead: true
30854
- };
30855
- var DynamicDots = class {
30856
- timer = null;
30857
- dots = "";
30858
- direction = 1;
30859
- // 1 = 增加, -1 = 减少
30860
- spinner;
30861
- baseText;
30862
- constructor(spinner, baseText) {
30863
- this.spinner = spinner;
30864
- this.baseText = baseText;
30865
- }
30849
+ // utils/compressionProgress.ts
30850
+ var CompressionProgressManager = class {
30851
+ spinner = null;
30852
+ activeCount = 0;
30853
+ // 当前正在压缩的任务数
30854
+ currentTask = "";
30855
+ // 当前显示的任务信息
30866
30856
  /**
30867
- * 开始动画
30868
- * @param interval 更新间隔(毫秒),默认 300ms
30857
+ * 开始一个压缩任务
30858
+ * @param taskInfo 任务信息(如 "10.81MB → 转换为 WebP")
30859
+ * @returns 更新函数,用于更新当前任务的进度
30869
30860
  */
30870
- start(interval = 300) {
30871
- this.updateText();
30872
- this.timer = setInterval(() => {
30873
- if (this.direction === 1) {
30874
- this.dots += ".";
30875
- if (this.dots.length >= 3) this.direction = -1;
30876
- } else {
30877
- this.dots = this.dots.slice(0, -1);
30878
- if (this.dots.length <= 0) this.direction = 1;
30861
+ start(taskInfo) {
30862
+ this.activeCount++;
30863
+ if (this.activeCount === 1) {
30864
+ downloadProgress.pause();
30865
+ this.currentTask = taskInfo;
30866
+ this.spinner = ora({
30867
+ text: `\u538B\u7F29\u4E2D: ${taskInfo}`,
30868
+ spinner: "dots",
30869
+ color: "yellow"
30870
+ }).start();
30871
+ }
30872
+ const updateFn = (newInfo) => {
30873
+ if (this.spinner && this.currentTask === taskInfo) {
30874
+ this.currentTask = newInfo;
30875
+ this.spinner.text = `\u538B\u7F29\u4E2D: ${newInfo}`;
30879
30876
  }
30880
- this.updateText();
30881
- }, interval);
30882
- }
30883
- /**
30884
- * 更新显示文字
30885
- */
30886
- updateText() {
30887
- const paddedDots = this.dots.padEnd(3, " ");
30888
- this.spinner.text = `${this.baseText}${paddedDots}`;
30877
+ };
30878
+ return updateFn;
30889
30879
  }
30890
30880
  /**
30891
- * 更新基础文字(不包含省略号)
30881
+ * 完成一个压缩任务
30882
+ * @param successMsg 成功消息
30892
30883
  */
30893
- setBaseText(text4) {
30894
- this.baseText = text4;
30895
- this.updateText();
30884
+ complete(successMsg) {
30885
+ this.activeCount--;
30886
+ if (this.activeCount === 0 && this.spinner) {
30887
+ this.spinner.succeed(successMsg);
30888
+ this.spinner = null;
30889
+ downloadProgress.resume();
30890
+ }
30896
30891
  }
30897
30892
  /**
30898
- * 停止动画
30893
+ * 压缩任务失败
30894
+ * @param errorMsg 错误消息
30899
30895
  */
30900
- stop() {
30901
- if (this.timer) {
30902
- clearInterval(this.timer);
30903
- this.timer = null;
30896
+ fail(errorMsg) {
30897
+ this.activeCount--;
30898
+ if (this.activeCount === 0 && this.spinner) {
30899
+ this.spinner.fail(errorMsg);
30900
+ this.spinner = null;
30901
+ downloadProgress.resume();
30904
30902
  }
30905
30903
  }
30906
30904
  };
30905
+ var compressionProgress = new CompressionProgressManager();
30906
+
30907
+ // utils/imageCompression.ts
30908
+ var SHARP_OPTIONS = {
30909
+ animated: true,
30910
+ limitInputPixels: false,
30911
+ sequentialRead: true
30912
+ };
30913
+ async function convertToWebp(inputBuffer) {
30914
+ const image2 = (0, import_sharp.default)(inputBuffer, SHARP_OPTIONS);
30915
+ return await image2.webp({ quality: 80, effort: 6 }).toBuffer();
30916
+ }
30907
30917
  async function compressImage(inputBuffer) {
30908
30918
  const MAX_SIZE = 10 * 1024 * 1024;
30909
30919
  const image2 = (0, import_sharp.default)(inputBuffer, SHARP_OPTIONS);
@@ -30912,41 +30922,24 @@ async function compressImage(inputBuffer) {
30912
30922
  return inputBuffer;
30913
30923
  }
30914
30924
  const originalSize = (inputBuffer.length / 1024 / 1024).toFixed(2);
30915
- downloadProgress.pause();
30916
- const spinner = ora({
30917
- text: `\u538B\u7F29\u4E2D: ${originalSize}MB \u2192 \u8F6C\u6362\u4E3A WebP`,
30918
- spinner: "dots",
30919
- color: "yellow"
30920
- }).start();
30921
- const dynamicDots = new DynamicDots(
30922
- spinner,
30923
- `\u538B\u7F29\u4E2D: ${originalSize}MB \u2192 \u8F6C\u6362\u4E3A WebP`
30924
- );
30925
- dynamicDots.start(300);
30925
+ const taskInfo = `${originalSize}MB \u2192 \u8F6C\u6362\u4E3A WebP`;
30926
+ const updateProgress = compressionProgress.start(taskInfo);
30926
30927
  try {
30927
30928
  let currentBuffer = await image2.webp({ quality: 80, effort: 6 }).toBuffer();
30928
30929
  if (currentBuffer.length > MAX_SIZE) {
30929
- dynamicDots.setBaseText(
30930
- `\u538B\u7F29\u4E2D: ${originalSize}MB \u2192 \u7F29\u5C0F\u5206\u8FA8\u7387\u81F3 2560px`
30931
- );
30930
+ updateProgress(`${originalSize}MB \u2192 \u7F29\u5C0F\u5206\u8FA8\u7387\u81F3 2560px`);
30932
30931
  currentBuffer = await (0, import_sharp.default)(inputBuffer, SHARP_OPTIONS).resize(2560, void 0, { withoutEnlargement: true }).webp({ quality: 75 }).toBuffer();
30933
30932
  }
30934
30933
  if (currentBuffer.length > MAX_SIZE) {
30935
- dynamicDots.setBaseText(
30936
- `\u538B\u7F29\u4E2D: ${originalSize}MB \u2192 \u6781\u9650\u538B\u7F29 (quality: 60)`
30937
- );
30934
+ updateProgress(`${originalSize}MB \u2192 \u6781\u9650\u538B\u7F29 (quality: 60)`);
30938
30935
  currentBuffer = await (0, import_sharp.default)(currentBuffer, SHARP_OPTIONS).webp({ quality: 60 }).toBuffer();
30939
30936
  }
30940
- dynamicDots.stop();
30941
30937
  const finalSize = (currentBuffer.length / 1024 / 1024).toFixed(2);
30942
- spinner.succeed(`\u538B\u7F29\u5B8C\u6210: ${originalSize}MB \u2192 ${finalSize}MB`);
30938
+ compressionProgress.complete(`\u538B\u7F29\u5B8C\u6210: ${originalSize}MB \u2192 ${finalSize}MB`);
30943
30939
  return currentBuffer;
30944
30940
  } catch (error2) {
30945
- dynamicDots.stop();
30946
- spinner.fail(`\u538B\u7F29\u5931\u8D25: ${error2}`);
30941
+ compressionProgress.fail(`\u538B\u7F29\u5931\u8D25: ${error2}`);
30947
30942
  throw error2;
30948
- } finally {
30949
- downloadProgress.resume();
30950
30943
  }
30951
30944
  }
30952
30945
 
@@ -31124,7 +31117,8 @@ var mimeMap = {
31124
31117
  "image/jpeg": ".jpg",
31125
31118
  "image/png": ".png",
31126
31119
  "image/gif": ".gif",
31127
- "image/svg+xml": ".svg"
31120
+ "image/svg+xml": ".svg",
31121
+ "image/webp": ".webp"
31128
31122
  };
31129
31123
  async function downloadAndLocalize(node2, assetDir) {
31130
31124
  const currentUrl = node2.url;
@@ -31168,10 +31162,12 @@ async function downloadAndLocalize(node2, assetDir) {
31168
31162
  }
31169
31163
  let imageData = Buffer.from(response.data);
31170
31164
  const MAX_SIZE = 10 * 1024 * 1024;
31171
- if (imageData.length > MAX_SIZE && contentType !== "image/svg+xml") {
31172
- imageData = await compressImage(imageData);
31173
- }
31174
- if (imageData.length !== response.data.byteLength) {
31165
+ if (contentType !== "image/svg+xml") {
31166
+ if (imageData.length > MAX_SIZE) {
31167
+ imageData = await compressImage(imageData);
31168
+ } else {
31169
+ imageData = await convertToWebp(imageData);
31170
+ }
31175
31171
  finalExt = ".webp";
31176
31172
  }
31177
31173
  const fileName = `${hash}${finalExt}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duoyun/md-img-pull",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Markdown 媒体资源本地化与压缩工具",
5
5
  "main": "./dist/main.cjs",
6
6
  "repository": {