toc.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import logger from "#logger";
  2. import {chapter_insert, searchChapterInfoForPath, getChaptersByBookId, getFileBymd5} from "#db";
  3. import cliProgress from 'cli-progress';
  4. import {EPub} from "epub2";
  5. import path from "node:path";
  6. import fs from "node:fs";
  7. export async function saveToc(epub, uploadPath, book_id, author_id) {
  8. const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
  9. progressBar.start(epub.toc.length, 0);
  10. // 栈用于追踪父章节的 ID
  11. const parentStack = [];
  12. for (const elm of epub.toc) {
  13. try {
  14. const match = `${elm.href}`.match(/\/(.*\.html).*/);
  15. let chapterInfo = {file_id: ''};
  16. let path = '';
  17. if (match) {
  18. path = match[1];
  19. chapterInfo = await searchChapterInfoForPath(path, book_id);
  20. }
  21. const name = `${elm.title}`;
  22. elm.title = '';
  23. // 确定 parent_id
  24. let parent_id = null;
  25. while (parentStack.length > 0 && parentStack[parentStack.length - 1].level >= elm.level) {
  26. parentStack.pop();
  27. }
  28. if (parentStack.length > 0) {
  29. parent_id = parentStack[parentStack.length - 1].id;
  30. }
  31. const params = {
  32. name: name,
  33. book_id: book_id,
  34. author_id: author_id,
  35. content: JSON.stringify(elm),
  36. level: elm.level,
  37. order_index: elm.order,
  38. order_id: chapterInfo.file_id,
  39. old_path: elm.href,
  40. path: `./base_files/${book_id}/Text/${chapterInfo.file_id}.html`,
  41. parent_id: parent_id,
  42. };
  43. logger.info(params);
  44. // 插入数据库并获取新插入的章节 ID
  45. const insertedId = await chapter_insert(params);
  46. // 将当前章节推入栈中
  47. parentStack.push({id: insertedId.insertId, level: elm.level});
  48. } catch (e) {
  49. logger.error(e);
  50. } finally {
  51. progressBar.increment();
  52. }
  53. }
  54. progressBar.stop();
  55. }
  56. function buildTree(data) {
  57. const nodeMap = new Map();
  58. const tree = [];
  59. // 初始化节点映射
  60. data.forEach(node => {
  61. // 确保每个节点都有 children 属性
  62. node.children = [];
  63. nodeMap.set(node.id, node);
  64. });
  65. // 构建树
  66. data.forEach(node => {
  67. if (node.parent_id !== null) {
  68. // 确保 id 和 parent_id 类型一致
  69. const parentNode = nodeMap.get(Number(node.parent_id));
  70. if (parentNode) {
  71. parentNode.children.push(node);
  72. }
  73. } else {
  74. // 顶层节点
  75. tree.push(node);
  76. }
  77. });
  78. return tree;
  79. }
  80. export async function fetchAndBuildTree(book_id) {
  81. // 从数据库中获取所有章节数据
  82. const chapters = await getChaptersByBookId(book_id);
  83. return buildTree(chapters)
  84. }
  85. export async function fetchNextFile(fileId, type) {
  86. // 从数据库中获取所有章节数据
  87. logger.info(`Found ${fileId}`);
  88. const fileRow = await getFileBymd5(fileId);
  89. console.log('fileRow', fileRow);
  90. console.log('\n')
  91. console.log('\n')
  92. const epubPath = `./base_files/${fileRow.book_id}/${fileRow.book_id}.epub`
  93. if (fs.existsSync(epubPath)) {
  94. console.time('chapterIndex')
  95. const epubData = fs.readFileSync(epubPath)
  96. const epub = await EPub.createAsync(epubData, null, "");
  97. console.log("\nSPINE:\n");
  98. console.log('epubFlowLength', epub.flow.length);
  99. // console.log('epubFlowLength', epub.flow[30]);
  100. const chapterIndex = epub.flow.findIndex(elm => elm.id === fileRow.source_id);
  101. console.log(117, epub.flow[chapterIndex - 1], epub.flow[chapterIndex], epub.flow[chapterIndex + 1])
  102. console.timeEnd('chapterIndex')
  103. }
  104. }