mirror of
https://github.com/aoout/obsidian-epub-importer.git
synced 2026-07-22 08:50:30 +00:00
fix: booknav no longer fails due to unnormalized note names
This commit is contained in:
parent
3aa3acb88a
commit
1b1d5e008f
5 changed files with 69 additions and 9 deletions
|
|
@ -125,3 +125,30 @@ The parser uses two core classes to organize data:
|
|||
## Summary
|
||||
|
||||
This EPUB parser adopts a modular design, breaking down the complex parsing process into multiple independent steps. Through recursive processing and reasonable data structure design, it effectively handles the hierarchical structure of EPUB format. It also includes necessary error handling and fault tolerance mechanisms, ensuring the stability of the parsing process.
|
||||
|
||||
## Frequently Asked Questions (FAQ)
|
||||
|
||||
### 1. What is the relationship between Chapter and Section?
|
||||
|
||||
In this project, Chapter and Section are two core data structures:
|
||||
- Chapter represents a chapter in the book and can contain multiple Sections
|
||||
- Section represents a specific content fragment
|
||||
|
||||
Each Chapter has one initial Section when created, but more Sections can be added later. This typically happens when processing unmapped files, where the system adds these files as additional Sections to the nearest preceding Chapter.
|
||||
|
||||
### 2. Can a Chapter contain multiple Sections?
|
||||
|
||||
Yes, a Chapter can contain multiple Sections. This situation mainly occurs through the following paths:
|
||||
|
||||
- When processing unmapped files, if a suitable parent Chapter is found, the file will be added as a new Section to this Chapter
|
||||
- When merging chapters (in the `mergeChapters` method), all Sections from child Chapters exceeding the specified level will be merged into the parent Chapter's sections array
|
||||
|
||||
### 3. What is the relationship between the number of notes created and Chapters/Sections?
|
||||
|
||||
The number of notes created equals the number of Chapters, completely independent of the number of Sections. Specifically:
|
||||
|
||||
- Each Chapter generates one note file
|
||||
- All Section contents in a Chapter are merged into the same note
|
||||
- When generating Markdown content, all Section contents from each Chapter are extracted, converted to Markdown, and then joined with blank lines
|
||||
|
||||
Regardless of how many Sections a Chapter contains, only one note file will be created for that Chapter. Section is just an organizational unit for content and does not affect the final number of notes created.
|
||||
|
|
|
|||
|
|
@ -125,3 +125,30 @@ EPUB 格式中最关键的两个文件是:
|
|||
## 总结
|
||||
|
||||
这个 EPUB 解析器采用了模块化的设计,将复杂的解析过程分解为多个独立的步骤。通过递归处理和合理的数据结构设计,很好地处理了 EPUB 格式的层级结构。同时也包含了必要的错误处理和容错机制,确保了解析过程的稳定性。
|
||||
|
||||
## 常见问题解答 (FAQ)
|
||||
|
||||
### 1. Chapter 和 Section 的关系是什么?
|
||||
|
||||
在本项目中,Chapter 和 Section 是两个核心数据结构:
|
||||
- Chapter 代表书籍的一个章节,可以包含多个 Section
|
||||
- Section 代表具体的内容片段
|
||||
|
||||
每个 Chapter 在创建时默认会有一个初始 Section,但后续可以添加更多 Section。这通常发生在处理未映射文件时,系统会将这些文件作为额外的 Section 添加到最近的前置 Chapter 中。
|
||||
|
||||
### 2. 一个 Chapter 可以包含多个 Section 吗?
|
||||
|
||||
是的,一个 Chapter 可以包含多个 Section。这种情况主要通过以下途径产生:
|
||||
|
||||
- 在处理未映射文件时,如果找到了合适的父 Chapter,会将该文件作为新 Section 添加到这个 Chapter 中
|
||||
- 在合并章节时(`mergeChapters` 方法),超过指定层级的子 Chapter 的所有 Section 会被合并到父 Chapter 的 sections 数组中
|
||||
|
||||
### 3. 创建笔记的数量与 Chapter 和 Section 有什么关系?
|
||||
|
||||
创建笔记的数量等同于 Chapter 的数量,与 Section 的数量完全无关。具体来说:
|
||||
|
||||
- 每个 Chapter 会生成一个笔记文件
|
||||
- 一个 Chapter 中的所有 Section 内容会被合并到同一个笔记中
|
||||
- 在生成 Markdown 内容时,会将每个 Chapter 的所有 Section 内容提取出来,转换为 Markdown,然后用空行连接起来
|
||||
|
||||
无论一个 Chapter 包含多少个 Section,最终都只会为这个 Chapter 创建一个笔记文件。Section 只是内容的组织单位,不会影响最终创建的笔记数量。
|
||||
|
|
|
|||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -6,7 +6,7 @@
|
|||
"packages": {
|
||||
"": {
|
||||
"name": "epub-importer",
|
||||
"version": "0.6.6",
|
||||
"version": "0.8.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lisandra-dev/create-obsidian-plugin": "^1.9.1",
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export default class EpubProcessor {
|
|||
private async processChapters(epubName: string, folderPath: string, chapters: Chapter[]) {
|
||||
for (const [i, chapter] of chapters.entries()) {
|
||||
const notePath = await this.createChapterNote(chapter, folderPath, i, chapters);
|
||||
this.bookNote += `${"\t".repeat(chapter.level)}- [[${notePath}|${chapter.name}]]\n`;
|
||||
this.bookNote += `${"\t".repeat(chapter.level)}- [[${notePath}|${chapter.originalName}]]\n`;
|
||||
}
|
||||
await this.createFile(
|
||||
`${folderPath}/${templateWithVariables(this.settings.mocName, { bookName: epubName })}.md`,
|
||||
|
|
@ -93,8 +93,8 @@ private processObsidianLinks(content: string, chapters: Chapter[]): string {
|
|||
const targetChapter = this.findChapterByHref(chapters, href);
|
||||
|
||||
if (targetChapter) {
|
||||
const display = displayText || targetChapter.name;
|
||||
return `[[${normalize(targetChapter.name)}|${display}]]`;
|
||||
const display = displayText || targetChapter.originalName;
|
||||
return `[[${targetChapter.name}|${display}]]`;
|
||||
}
|
||||
|
||||
return match;
|
||||
|
|
@ -149,7 +149,7 @@ private hasHtmlElementWithId(html: string, id: string): boolean {
|
|||
private getChapterPaths(chapter: Chapter): string[] {
|
||||
const paths = this.buildPathArray(chapter);
|
||||
return chapter.level < this.settings.granularity && chapter.subItems.length
|
||||
? [...paths, normalize(chapter.name)]
|
||||
? [...paths, chapter.name]
|
||||
: paths;
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ private hasHtmlElementWithId(html: string, id: string): boolean {
|
|||
const paths: string[] = [];
|
||||
let current: Chapter | undefined = chapter;
|
||||
while (current) {
|
||||
paths.unshift(normalize(current.name));
|
||||
paths.unshift(current.name);
|
||||
current = current.parent;
|
||||
}
|
||||
return paths;
|
||||
|
|
@ -170,7 +170,7 @@ private hasHtmlElementWithId(html: string, id: string): boolean {
|
|||
content,
|
||||
prev: index > 0 ? chapters[index - 1].name : "",
|
||||
next: index < chapters.length - 1 ? chapters[index + 1].name : "",
|
||||
chapter_name: chapter.name,
|
||||
chapter_name: chapter.originalName,
|
||||
chapter_level: chapter.level.toString(),
|
||||
chapter_index: (index + 1).toString(),
|
||||
...this.parser!.meta,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { normalize } from "../../utils/utils";
|
||||
|
||||
export class Section {
|
||||
name: string;
|
||||
url: string;
|
||||
|
|
@ -34,7 +36,11 @@ export class Chapter {
|
|||
this.parent = parent;
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
public get originalName(): string {
|
||||
return this.sections[0].name ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return normalize(this.originalName);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue