Skip to content

语音朗读"只读一页就停"的问题 #121

@M40

Description

@M40

主要涉及 桌面端 ReaderView.tsx 和 FoliateViewer.tsx 中的 TTS 连续朗读逻辑。核心流程如下:

TTS 连续朗读链路
startPageTTS() (ReaderView.tsx:1903) — 获取当前页可见文本段落,调用 ttsPlay() 播放
播放完毕后,handleTTSPageEnd() (ReaderView.tsx:1747) 被触发
handleTTSPageEnd 调用 getTTSSegmentContext() (FoliateViewer.tsx:776) 查找下一页的第一句话
找到后调用 startPageTTSFromCfi() (ReaderView.tsx:1958) 继续朗读
发现的关键问题
问题出在 getTTSSegmentContext (FoliateViewer.tsx:776-841):

这个函数通过 tts.alignCfi(cfi) 在 TTS 引擎的内部句子列表中定位光标,然后用 tts.collectDetails() 获取后续句子。但 alignCfi 内部使用 严格字符串比较 (candidate === cfi) 来匹配 CFI:

// tts.js:473
alignCfi(cfi) {
return this.#detailFromCfi(cfi, { highlight: false });
}
// tts.js:465
#detailFromCfi(cfi, ...) {
const entry = this.#detailList.find((range) => {
const candidate = this.#getCfi(range.cloneRange());
return candidate === cfi; // 严格字符串匹配
});
}
如果 CFI 不匹配,alignCfi 静默失败,光标不会正确定位,后续 collectDetails 可能返回空数组,导致 handleTTSPageEnd 认为没有更多内容而停止。

CFI 可能不匹配的原因是 两套不同的分段逻辑:

getVisibleTTSSegments (FoliateViewer.tsx:481) 使用 blockSelector(p, h1-h6, li 等)和 Intl.Segmenter 对可见区域进行句子分割
TTS 引擎的 getDetailRanges (tts.js:149) 使用 blockTags(额外包含 div, section 等)对整个文档进行句子分割
不同的块标签集合导致分段边界不同,进而生成的 CFI 可能无法匹配。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions