image.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { dirExists } from "#utils";
  2. import { files_insert } from "#db";
  3. import crypto from "crypto";
  4. import fs from "node:fs";
  5. import logger from "#logger";
  6. export async function saveImgs(epub) {
  7. dirExists("./base_files/");
  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 uploadPath = "./base_files/" + 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(uploadPath, 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. return await files_insert(params);
  52. })
  53. );
  54. }
  55. }
  56. function calculateMD5(filePath) {
  57. const hash = crypto.createHash("md5");
  58. const stream = fs.createReadStream(filePath);
  59. stream.on("data", (chunk) => {
  60. hash.update(chunk);
  61. });
  62. stream.on("end", () => {
  63. console.log("MD5 hash:", hash.digest("hex"));
  64. });
  65. }
  66. export async function calculateMD5FromStream(fileStream) {
  67. return new Promise((resolve, reject) => {
  68. const hash = crypto.createHash("md5");
  69. // 错误处理
  70. fileStream.on("error", (err) => {
  71. console.error("Error reading file stream:", err);
  72. reject("生成失败!"); // 使用 reject 传递错误信息
  73. });
  74. // 监听 'data' 事件,更新 MD5 哈希
  75. fileStream.on("data", (chunk) => {
  76. hash.update(chunk);
  77. });
  78. // 监听 'end' 事件,文件读取完毕后输出 MD5 值
  79. fileStream.on("end", () => {
  80. const md5 = hash.digest("hex");
  81. resolve(md5); // 正常计算完 MD5 后 resolve
  82. });
  83. });
  84. }
  85. export function calculateMD5FromBuffer(buffer) {
  86. return new Promise((resolve, reject) => {
  87. try {
  88. // 使用 crypto 计算 MD5
  89. const hash = crypto.createHash("md5");
  90. hash.update(buffer); // 直接更新 hash
  91. const md5 = hash.digest("hex"); // 获取最终的 MD5 值
  92. resolve(md5); // 返回 MD5
  93. } catch (err) {
  94. console.error("Error calculating MD5:", err);
  95. reject("生成失败!");
  96. }
  97. });
  98. }
  99. const formatSize = (bytes) => {
  100. if (bytes < 1024) return `${bytes} 字节`;
  101. else if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
  102. else if (bytes < 1024 * 1024 * 1024)
  103. return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
  104. else return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
  105. };