image.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import { dirExists } from "#utils";
  2. import { files_insert, files_insert_link_epub } from "#db";
  3. import crypto from "crypto";
  4. import fs from "node:fs";
  5. import logger from "#logger";
  6. import cliProgress from 'cli-progress';
  7. export async function saveImgs(epub, uploadPath, book_id, author_id) {
  8. dirExists(uploadPath + "image/");
  9. const imgs = epub.listImage();
  10. if (imgs.length) {
  11. const imgRes = await Promise.allSettled(
  12. imgs.map((img) => epub.getImageAsync(img.id))
  13. );
  14. const imgs_fulfilled = imgs.map((img, index) => {
  15. const img_fulfilled = imgRes[index];
  16. if (img_fulfilled.status === "fulfilled") {
  17. const [img_data, img_mimeType] = img_fulfilled.value;
  18. return {
  19. ...img,
  20. img_data,
  21. img_mimeType,
  22. };
  23. }
  24. return null;
  25. }).filter(Boolean);
  26. // Initialize the progress bar
  27. const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
  28. progressBar.start(imgs_fulfilled.length, 0);
  29. await Promise.allSettled(
  30. imgs_fulfilled.map(async (elm, index) => {
  31. try {
  32. const img_md5 = await calculateMD5FromBuffer(elm.img_data);
  33. const imgUploadPath = `${uploadPath}image/${img_md5}`;
  34. const params = {
  35. file_id: img_md5,
  36. md5: img_md5,
  37. mimetype: elm.img_mimeType,
  38. size: elm.img_data.length,
  39. name: elm.id,
  40. path: elm.href,
  41. source_id: elm.id,
  42. };
  43. await fs.promises.writeFile(imgUploadPath, elm.img_data);
  44. logger.info("Img data saved to " + img_md5);
  45. await files_insert(params);
  46. await files_insert_link_epub({
  47. file_id: img_md5,
  48. book_id,
  49. author_id,
  50. });
  51. // Update the progress bar
  52. progressBar.update(index + 1);
  53. } catch (err) {
  54. logger.error("Error processing image:", err);
  55. }
  56. })
  57. );
  58. // Update the progress bar
  59. progressBar.update(imgs_fulfilled.length);
  60. // Stop the progress bar
  61. progressBar.stop();
  62. }
  63. }
  64. export function calculateMD5(filePath) {
  65. return new Promise((resolve, reject) => {
  66. try {
  67. const hash = crypto.createHash("md5");
  68. const stream = fs.createReadStream(filePath);
  69. stream.on("data", (chunk) => {
  70. hash.update(chunk);
  71. });
  72. stream.on("end", () => {
  73. resolve(hash.digest("hex"));
  74. });
  75. } catch (err) {
  76. resolve("");
  77. }
  78. });
  79. }
  80. export async function calculateMD5FromStream(fileStream) {
  81. return new Promise((resolve, reject) => {
  82. const hash = crypto.createHash("md5");
  83. // 错误处理
  84. fileStream.on("error", (err) => {
  85. console.error("Error reading file stream:", err);
  86. reject("生成失败!"); // 使用 reject 传递错误信息
  87. });
  88. // 监听 'data' 事件,更新 MD5 哈希
  89. fileStream.on("data", (chunk) => {
  90. hash.update(chunk);
  91. });
  92. // 监听 'end' 事件,文件读取完毕后输出 MD5 值
  93. fileStream.on("end", () => {
  94. const md5 = hash.digest("hex");
  95. resolve(md5); // 正常计算完 MD5 后 resolve
  96. });
  97. });
  98. }
  99. export function calculateMD5FromBuffer(buffer) {
  100. return new Promise((resolve, reject) => {
  101. try {
  102. // 使用 crypto 计算 MD5
  103. const hash = crypto.createHash("md5");
  104. hash.update(buffer); // 直接更新 hash
  105. const md5 = hash.digest("hex"); // 获取最终的 MD5 值
  106. resolve(md5); // 返回 MD5
  107. } catch (err) {
  108. console.error("Error calculating MD5:", err);
  109. reject("生成失败!");
  110. }
  111. });
  112. }
  113. const formatSize = (bytes) => {
  114. if (bytes < 1024) return `${bytes} 字节`;
  115. else if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
  116. else if (bytes < 1024 * 1024 * 1024)
  117. return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
  118. else return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
  119. };