From d5f7821d659f9d64512dbff9d3857f2ae4e341bc Mon Sep 17 00:00:00 2001 From: Marshall <57112423+Xy2002@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:25:20 +0800 Subject: [PATCH] feat(route): add route of obsidian publish (#16872) * feat(route): add route of obsidian publish * feat(obsidian): Improve type safety by using DataItem in publish route * Update lib/routes/obsidian/publish.ts Co-authored-by: Tony * Update lib/routes/obsidian/publish.ts Co-authored-by: Tony * feat(obsidian): improve publish page data extraction * fix(obsidian): remove redundant namespace from route names * Update lib/routes/obsidian/publish.ts --- lib/routes/obsidian/namespace.ts | 6 +++ lib/routes/obsidian/publish.ts | 83 ++++++++++++++++++++++++++++++++ lib/routes/obsidian/utils.ts | 8 +++ 3 files changed, 97 insertions(+) create mode 100644 lib/routes/obsidian/namespace.ts create mode 100644 lib/routes/obsidian/publish.ts create mode 100644 lib/routes/obsidian/utils.ts diff --git a/lib/routes/obsidian/namespace.ts b/lib/routes/obsidian/namespace.ts new file mode 100644 index 000000000..26067fb1e --- /dev/null +++ b/lib/routes/obsidian/namespace.ts @@ -0,0 +1,6 @@ +import type { Namespace } from '@/types'; + +export const namespace: Namespace = { + name: 'Obsidian', + url: 'obsidian.md', +}; diff --git a/lib/routes/obsidian/publish.ts b/lib/routes/obsidian/publish.ts new file mode 100644 index 000000000..c0f237c60 --- /dev/null +++ b/lib/routes/obsidian/publish.ts @@ -0,0 +1,83 @@ +import { Route, DataItem } from '@/types'; +import { load } from 'cheerio'; +import ofetch from '@/utils/ofetch'; +import { getTitle } from './utils'; +import { config } from '@/config'; +import { parseDate } from '@/utils/parse-date'; + +export const route: Route = { + path: '/publish/:id', + categories: ['blog'], + example: '/obsidian/publish/marshallontheroad', + parameters: { id: '网站 id,由Publish持有者自定义' }, + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + radar: [ + { + source: ['publish.obsidian.md/'], + }, + ], + name: 'Publish', + maintainers: ['Xy2002'], + handler, + url: 'publish.obsidian.md/', +}; + +async function handler(ctx) { + const id = ctx.req.param('id'); + const items = await fetchPage(id); + + return { + title: 'Obsidian Publish', + language: 'en-us', + item: items, + link: 'https://publish.obsidian.md/', + }; +} + +async function fetchPage(id: string) { + const baseUrl = `https://publish.obsidian.md/${id}`; + const response = await ofetch(baseUrl); + const $ = load(response); + const preloadCacheUrl = + $('script:contains("preloadCache")') + .text() + .match(/preloadCache\s*=\s*f\("([^"]+)"\);/)?.[1] || ''; + + let preloadCacheResponse: Record }>; + try { + preloadCacheResponse = await ofetch(preloadCacheUrl, { + headers: { + 'User-Agent': config.trueUA, + Referer: 'https://publish.obsidian.md/', + Origin: 'https://publish.obsidian.m/', + }, + }); + } catch { + preloadCacheResponse = {}; + } + + const items: DataItem[] = Object.entries(preloadCacheResponse) + .map(([postKey, post]) => { + if (!post) { + return null; + } + const item: DataItem = { + title: post.frontmatter?.title || getTitle(postKey), + link: `${baseUrl}/${postKey.replaceAll(' ', '+').split('.md')[0]}`, + pubDate: post.frontmatter?.['date created'] ? parseDate(post.frontmatter['date created']) : undefined, + ...post.frontmatter, + }; + + return item; + }) + .filter(Boolean) as DataItem[]; + + return items; +} diff --git a/lib/routes/obsidian/utils.ts b/lib/routes/obsidian/utils.ts new file mode 100644 index 000000000..39dfdee83 --- /dev/null +++ b/lib/routes/obsidian/utils.ts @@ -0,0 +1,8 @@ +const regex = /([^/]+)\.md$/; + +const getTitle = (path: string): string => { + const match = path.match(regex); + return match ? match[1] : ''; +}; + +export { getTitle };