/**
* 电子书 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));
}