From 5df6fe45e8647cd495b34cf0b3786a67afdaed63 Mon Sep 17 00:00:00 2001 From: seaHi Date: Wed, 7 Oct 2026 10:33:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Obsidian=20=E6=8F=92=E4=BB=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=96=87=E7=AB=A0=E5=B0=81=E9=9D=A2=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E4=B8=8E=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/obsidian-plugin/src/api.ts | 29 +++++++ packages/obsidian-plugin/src/main.ts | 90 ++++++---------------- packages/obsidian-plugin/src/pull_modal.ts | 16 +--- 3 files changed, 56 insertions(+), 79 deletions(-) diff --git a/packages/obsidian-plugin/src/api.ts b/packages/obsidian-plugin/src/api.ts index 0e4e0b5..cb57ed7 100644 --- a/packages/obsidian-plugin/src/api.ts +++ b/packages/obsidian-plugin/src/api.ts @@ -11,6 +11,7 @@ export interface PostPayload { title: string; slug: string; content: string; + cover?: string | null; category_slug?: string; series_slug?: string; tags?: string[]; @@ -20,6 +21,7 @@ export interface PostMeta { id: number; slug: string; title: string; + cover?: string | null; published_at: string; category_slug?: string; category_name?: string; @@ -33,6 +35,33 @@ export interface PostDetail extends PostMeta { updated_at: string; } +export function formatPostMarkdown(detail: PostDetail): string { + const frontmatterLines = [ + '---', + `title: "${detail.title.replace(/"/g, '\\"')}"`, + `slug: ${detail.slug}`, + `blogflare_published_slug: ${detail.slug}` + ]; + if (detail.cover) { + frontmatterLines.push(`cover: "${detail.cover.replace(/"/g, '\\"')}"`); + } + if (detail.category_slug) { + frontmatterLines.push(`category_slug: ${detail.category_slug}`); + } + if (detail.series_slug) { + frontmatterLines.push(`series_slug: ${detail.series_slug}`); + } + if (detail.tags && detail.tags.length > 0) { + frontmatterLines.push('tags:'); + for (const t of detail.tags) { + frontmatterLines.push(` - ${t}`); + } + } + frontmatterLines.push('---'); + + return frontmatterLines.join('\n') + '\n\n' + (detail.content || ''); +} + export class BlogFlareAPI { private settings: BlogFlareSettings; diff --git a/packages/obsidian-plugin/src/main.ts b/packages/obsidian-plugin/src/main.ts index dc22213..231f342 100644 --- a/packages/obsidian-plugin/src/main.ts +++ b/packages/obsidian-plugin/src/main.ts @@ -4,7 +4,7 @@ import { DEFAULT_SETTINGS, BlogFlareSettingTab, } from './settings'; -import { BlogFlareAPI } from './api'; +import { BlogFlareAPI, formatPostMarkdown, type PostPayload } from './api'; import { MetaSuggestModal } from './suggest'; import { PullSuggestModal } from './pull_modal'; @@ -169,23 +169,7 @@ export default class BlogFlarePlugin extends Plugin { for (const item of items) { try { const detail = await this.api.getPost(item.slug); - - // 组装 Frontmatter - const frontmatterLines = [ - '---', - `title: "${detail.title.replace(/"/g, '\\"')}"`, - `slug: ${detail.slug}`, - `blogflare_published_slug: ${detail.slug}` - ]; - if (detail.category_slug) { - frontmatterLines.push(`category_slug: ${detail.category_slug}`); - } - if (detail.series_slug) { - frontmatterLines.push(`series_slug: ${detail.series_slug}`); - } - frontmatterLines.push('---'); - - const fileContent = frontmatterLines.join('\n') + '\n\n' + (detail.content || ''); + const fileContent = formatPostMarkdown(detail); const baseName = detail.title.replace(/[/\\:]/g, '-'); let dirPath = ''; @@ -329,29 +313,7 @@ export default class BlogFlarePlugin extends Plugin { for (const item of items) { try { const detail = await this.api.getPost(item.slug); - - // 组装 Frontmatter - const frontmatterLines = [ - '---', - `title: "${detail.title.replace(/"/g, '\\"')}"`, - `slug: ${detail.slug}`, - `blogflare_published_slug: ${detail.slug}` - ]; - if (detail.category_slug) { - frontmatterLines.push(`category_slug: ${detail.category_slug}`); - } - if (detail.series_slug) { - frontmatterLines.push(`series_slug: ${detail.series_slug}`); - } - if (detail.tags && detail.tags.length > 0) { - frontmatterLines.push(`tags:`); - for (const t of detail.tags) { - frontmatterLines.push(` - ${t}`); - } - } - frontmatterLines.push('---'); - - const fileContent = frontmatterLines.join('\n') + '\n\n' + (detail.content || ''); + const fileContent = formatPostMarkdown(detail); const existingFile = slugMap.get(item.slug); if (existingFile) { @@ -418,12 +380,28 @@ export default class BlogFlarePlugin extends Plugin { const series_slug = frontmatter?.series_slug as string | undefined; const publishedSlug = frontmatter?.blogflare_published_slug as string | undefined; + const hasCoverProp = Boolean( + frontmatter && + ('cover' in frontmatter || 'featured_image' in frontmatter || 'banner' in frontmatter) + ); + const coverCandidate: unknown = frontmatter?.cover ?? frontmatter?.featured_image ?? frontmatter?.banner; + let coverVal: string | null | undefined = undefined; + if (hasCoverProp) { + if (typeof coverCandidate === 'string') { + coverVal = coverCandidate.trim() || null; + } else if (typeof coverCandidate === 'number' || typeof coverCandidate === 'boolean') { + coverVal = String(coverCandidate).trim() || null; + } else if (!coverCandidate) { + coverVal = null; + } + } + let tags: string[] | undefined = undefined; if (frontmatter?.tags) { tags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [frontmatter.tags as string]; } - const payload = { + const payload: PostPayload = { title, slug, content, @@ -434,6 +412,9 @@ export default class BlogFlarePlugin extends Plugin { if (publishedSlug) { // 已发布,进行更新 + if (coverVal !== undefined) { + payload.cover = coverVal; + } const res = await this.api.updatePost(publishedSlug, payload); if (res.success) { new Notice('文章更新成功!'); @@ -442,6 +423,7 @@ export default class BlogFlarePlugin extends Plugin { } } else { // 未发布,进行创建 + payload.cover = coverVal ?? null; const res = await this.api.createPost(payload); if (res.success && res.slug) { // 写入 blogflare_published_slug @@ -478,29 +460,7 @@ export default class BlogFlarePlugin extends Plugin { try { new Notice('开始下载文章...'); const detail = await this.api.getPost(publishedSlug); - - // 组装 Frontmatter - const frontmatterLines = [ - '---', - `title: "${detail.title.replace(/"/g, '\\"')}"`, - `slug: ${detail.slug}`, - `blogflare_published_slug: ${detail.slug}` - ]; - if (detail.category_slug) { - frontmatterLines.push(`category_slug: ${detail.category_slug}`); - } - if (detail.series_slug) { - frontmatterLines.push(`series_slug: ${detail.series_slug}`); - } - if (detail.tags && detail.tags.length > 0) { - frontmatterLines.push(`tags:`); - for (const t of detail.tags) { - frontmatterLines.push(` - ${t}`); - } - } - frontmatterLines.push('---'); - - const fileContent = frontmatterLines.join('\n') + '\n\n' + (detail.content || ''); + const fileContent = formatPostMarkdown(detail); await this.app.vault.modify(file, fileContent); new Notice('文章下载并更新成功!'); diff --git a/packages/obsidian-plugin/src/pull_modal.ts b/packages/obsidian-plugin/src/pull_modal.ts index 6a8a7fd..f6c021c 100644 --- a/packages/obsidian-plugin/src/pull_modal.ts +++ b/packages/obsidian-plugin/src/pull_modal.ts @@ -1,5 +1,6 @@ import { App, FuzzySuggestModal, Notice, TFile } from 'obsidian'; import type { PostMeta, BlogFlareAPI } from './api'; +import { formatPostMarkdown } from './api'; export class PullSuggestModal extends FuzzySuggestModal { private items: PostMeta[]; @@ -24,20 +25,7 @@ export class PullSuggestModal extends FuzzySuggestModal { void (async () => { try { const detail = await this.api.getPost(item.slug); - - // 组装 Frontmatter - const frontmatterLines = [ - '---', - `title: "${detail.title.replace(/"/g, '\\"')}"`, - `slug: ${detail.slug}`, - `blogflare_published_slug: ${detail.slug}` - ]; - if (detail.category_slug) { - frontmatterLines.push(`category_slug: ${detail.category_slug}`); - } - frontmatterLines.push('---'); - - const fileContent = frontmatterLines.join('\n') + '\n\n' + (detail.content || ''); + const fileContent = formatPostMarkdown(detail); // 决定文件名 (过滤掉非法字符) const baseName = detail.title.replace(/[/\\:]/g, '-');