| 246 | } |
| 247 | |
| 248 | async getPersistedChapterCount(bookId: string): Promise<number> { |
| 249 | const chaptersDir = join(this.bookDir(bookId), "chapters"); |
| 250 | const chapterNumbers = new Set<number>(); |
| 251 | |
| 252 | try { |
| 253 | const files = await readdir(chaptersDir); |
| 254 | for (const file of files) { |
| 255 | const match = file.match(/^(\d+)_.*\.md$/); |
| 256 | if (!match) continue; |
| 257 | chapterNumbers.add(parseInt(match[1]!, 10)); |
| 258 | } |
| 259 | } catch { |
| 260 | return 0; |
| 261 | } |
| 262 | |
| 263 | return chapterNumbers.size; |
| 264 | } |
| 265 | |
| 266 | async loadChapterIndex(bookId: string): Promise<ReadonlyArray<ChapterMeta>> { |
| 267 | const indexPath = join(this.bookDir(bookId), "chapters", "index.json"); |