update at 2025-09-22 16:49:33

This commit is contained in:
douboer
2025-09-22 16:49:33 +08:00
parent 9b8ec73c83
commit 81c6f52b69
8 changed files with 742 additions and 7 deletions

View File

@@ -54,6 +54,7 @@ export class ArticleRender implements MDRendererCallback {
markedParser: MarkedParser;
cachedElements: Map<string, string> = new Map();
debouncedRenderMarkdown: (...args: any[]) => void;
originalMarkdown: string | null = null; // 保存去除前处理前的原始 Markdown
constructor(app: App, itemView: ItemView, styleEl: HTMLElement, articleDiv: HTMLDivElement) {
this.app = app;
@@ -162,10 +163,28 @@ export class ArticleRender implements MDRendererCallback {
else {
md = '没有可渲染的笔记或文件不支持渲染';
}
this.originalMarkdown = md; // 保存原始内容(含 frontmatter供封面/摘要自动提取
if (md.startsWith('---')) {
md = md.replace(FRONT_MATTER_REGEX, '');
}
// 将标准 markdown 图片语法转为 wikilink 语法,便于现有 LocalImageManager 识别
if (this.settings.enableMarkdownImageToWikilink) {
// 匹配 ![alt](path/to/name.ext);不跨行;忽略包含空格的 URL 末尾注释
// 捕获路径和文件名,文件名取最后一段
md = md.replace(/!\[[^\]]*\]\(([^)\s]+)\)/g, (full, p1) => {
try {
// 去掉可能的 query/hash
const clean = p1.split('#')[0].split('?')[0];
const filename = clean.split('/').pop();
if (!filename) return full; // 无法解析
// 仅当是常见图片扩展时才替换
if (!filename.match(/\.(png|jpe?g|gif|bmp|webp|svg|tiff)$/i)) return full;
return `![[${filename}]]`;
} catch { return full; }
});
}
this.articleHTML = await this.markedParser.parse(md);
this.setStyle(this.getCSS());
this.setArticle(this.articleHTML);
@@ -233,11 +252,14 @@ export class ArticleRender implements MDRendererCallback {
if (metadata?.frontmatter) {
const keys = this.assetsManager.expertSettings.frontmatter;
const frontmatter = metadata.frontmatter;
res.title = this.getFrontmatterValue(frontmatter, keys.title);
res.author = this.getFrontmatterValue(frontmatter, keys.author);
// frontmatter 优先:如果存在 title/author 则直接取之
const fmTitle = this.getFrontmatterValue(frontmatter, keys.title) || frontmatter['title'];
const fmAuthor = this.getFrontmatterValue(frontmatter, keys.author) || frontmatter['author'];
if (fmTitle) res.title = fmTitle;
if (fmAuthor) res.author = fmAuthor;
res.digest = this.getFrontmatterValue(frontmatter, keys.digest);
res.content_source_url = this.getFrontmatterValue(frontmatter, keys.content_source_url);
res.cover = this.getFrontmatterValue(frontmatter, keys.cover);
res.cover = this.getFrontmatterValue(frontmatter, keys.cover) || frontmatter['cover'] || frontmatter['image'];
res.thumb_media_id = this.getFrontmatterValue(frontmatter, keys.thumb_media_id);
res.need_open_comment = frontmatter[keys.need_open_comment] ? 1 : undefined;
res.only_fans_can_comment = frontmatter[keys.only_fans_can_comment] ? 1 : undefined;
@@ -252,6 +274,41 @@ export class ArticleRender implements MDRendererCallback {
res.pic_crop_1_1 = '0_0.525_0.404_1';
}
}
// 如果未显式指定封面,尝试从正文首图( markdown 或 wikilink ) 提取,按出现顺序优先
if (!res.cover && this.originalMarkdown) {
let body = this.originalMarkdown;
if (body.startsWith('---')) body = body.replace(FRONT_MATTER_REGEX, '');
// 同时匹配两种形式并比较 index
const mdImgPattern = /!\[[^\]]*\]\(([^)\s]+)\)/g; // group1 为路径
const wikilinkPattern = /!\[\[(.+?)\]\]/g; // group1 为文件名或 path
interface Candidate { idx:number; basename:string; }
const candidates: Candidate[] = [];
let m: RegExpExecArray | null;
while ((m = mdImgPattern.exec(body)) !== null) {
const rawPath = m[1];
if (/^https?:\/\//i.test(rawPath)) continue; // 跳过远程
const clean = rawPath.split('#')[0].split('?')[0];
const basename = clean.split('/').pop();
if (basename && /\.(png|jpe?g|gif|bmp|webp|svg|tiff)$/i.test(basename)) {
candidates.push({ idx: m.index, basename });
}
}
while ((m = wikilinkPattern.exec(body)) !== null) {
const inner = m[1].trim();
const clean = inner.split('#')[0].split('?')[0];
const basename = clean.split('/').pop();
if (basename && /\.(png|jpe?g|gif|bmp|webp|svg|tiff)$/i.test(basename)) {
candidates.push({ idx: m.index, basename });
}
}
if (candidates.length > 0) {
candidates.sort((a,b)=> a.idx - b.idx);
res.cover = `![[${candidates[0].basename}]]`;
}
}
return res;
}