/** * 电子书 Markdown 解析 - 共享模块 */ import { marked } from "marked"; export interface EbookChunk { html: string; estimatedHeight: number; } export interface EbookData { chunks: EbookChunk[]; headers: string[]; } export function parseEbookMarkdown(source: string): EbookData { const html = marked.parse(source, { breaks: true, gfm: true }) as string; const lazyHtml = html.replace(/])/i).filter((c) => c.trim()); if (rawChunks.length <= 1) { rawChunks = lazyHtml.split(/(?=])/i).filter((c) => c.trim()); } const headers: string[] = []; const headerRegex = /]*>(.*?)<\/h1>/gi; let m; while ((m = headerRegex.exec(lazyHtml)) !== null) { headers.push(m[1].replace(/<[^>]+>/g, "")); } if (headers.length === 0) { const h2Regex = /]*>(.*?)<\/h2>/gi; while ((m = h2Regex.exec(lazyHtml)) !== null) { headers.push(m[1].replace(/<[^>]+>/g, "")); } } const chunks: EbookChunk[] = rawChunks.map((chunkHtml) => { const imgCount = (chunkHtml.match(/]+>/g, "").length; const estimatedHeight = Math.max(300, Math.round(textLen * 0.6 + imgCount * 350)); return { html: chunkHtml, estimatedHeight }; }); return { chunks, headers }; } /** 估算阅读时间(字/分钟,中文约 300-500) */ export function estimateReadingMinutes(textLength: number, wpm = 400): number { return Math.max(1, Math.ceil(textLength / wpm)); }