image.js 3.5 KB

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