From e4ba0c302e9b1fb9a48b196e7c7c5dc4e91e5266 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Tue, 13 May 2025 16:21:47 +0800 Subject: [PATCH] fix: segment txt with paragraph count if no chapter titles are parsed, closes #1134 (#1139) --- apps/readest-app/src/utils/txt.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/readest-app/src/utils/txt.ts b/apps/readest-app/src/utils/txt.ts index 281c0921..ec4f495d 100644 --- a/apps/readest-app/src/utils/txt.ts +++ b/apps/readest-app/src/utils/txt.ts @@ -21,6 +21,7 @@ interface Txt2EpubOptions { interface ExtractChapterOptions { linesBetweenSegments: number; + paragraphsPerChapter?: number; } interface ConversionResult { @@ -78,6 +79,12 @@ export class TxtToEpubConverter { break; } } + if (chapters.length === 1) { + chapters = this.extractChapters(txtContent, metadata, { + linesBetweenSegments: 4, + paragraphsPerChapter: 100, + }); + } const blob = await this.createEpub(chapters, metadata); return { @@ -94,7 +101,7 @@ export class TxtToEpubConverter { option: ExtractChapterOptions, ): Chapter[] { const { language } = metadata; - const { linesBetweenSegments } = option; + const { linesBetweenSegments, paragraphsPerChapter } = option; const segmentRegex = new RegExp(`(?:\\r?\\n){${linesBetweenSegments},}|-{8,}\r?\n`); let chapterRegex: RegExp; if (language === 'zh') { @@ -111,7 +118,7 @@ export class TxtToEpubConverter { ); } else { chapterRegex = - /(?:^|\n|\s)(Chapter [0-9]+(?:[: ][^\n]*)?(?!\S)|Part [0-9]+(?:[: ][^\n]*)?(?!\S)|Prologue(?:[: ][^\n]*)?(?!\S)|Introduction(?:[: ][^\n]*)?(?!\S))/g; + /(?:^|\n|\s)(?:(Chapter|Part)\s+(\d+|[IVXLCDM]+)(?:[:.\-–—]?\s+[^\n]*)?|(?:Prologue|Epilogue|Introduction|Foreword)(?:[:.\-–—]?\s+[^\n]*)?)(?=\s|$)/gi; } const formatSegment = (segment: string): string => { @@ -148,6 +155,19 @@ export class TxtToEpubConverter { const trimmedSegment = segment.replace(//g, '').trim(); if (!trimmedSegment) continue; + if (paragraphsPerChapter && paragraphsPerChapter > 0) { + const paragraphs = trimmedSegment.split(/\n+/); + const totalParagraphs = paragraphs.length; + for (let i = 0; i < totalParagraphs; i += paragraphsPerChapter) { + const chunks = paragraphs.slice(i, i + paragraphsPerChapter); + const formattedSegment = formatSegment(chunks.join('\n')); + const title = `${chapters.length + 1}`; + const content = `

${title}

${formattedSegment}

`; + chapters.push({ title, content }); + } + continue; + } + const segmentChapters = []; const matches = joinAroundUndefined(trimmedSegment.split(chapterRegex)); for (let j = 1; j < matches.length; j += 2) {