import BLOG from '@/blog.config' import NotionPage from '@/components/NotionPage' import { getPostBlocks } from '@/lib/db/getSiteData' import { Feed } from 'feed' import fs from 'fs' import ReactDOMServer from 'react-dom/server' /** * 生成RSS内容 * @param {*} post * @returns */ const createFeedContent = async post => { // 加密的文章内容只返回摘要 if (post.password && post.password !== '') { return post.summary } const blockMap = await getPostBlocks(post.id, 'rss-content') if (blockMap) { post.blockMap = blockMap const content = ReactDOMServer.renderToString() const regexExp = /
.*?<\/svg>
.*?<\/div><\/div>
.*?<\/div><\/div><\/div><\/div>/g return content.replace(regexExp, '') } } /** * 生成RSS数据 * @param {*} props */ export async function generateRss(props) { const { NOTION_CONFIG, siteInfo, latestPosts } = props const TITLE = siteInfo?.title const DESCRIPTION = siteInfo?.description const LINK = siteInfo?.link const AUTHOR = NOTION_CONFIG?.AUTHOR || BLOG.AUTHOR const LANG = NOTION_CONFIG?.LANG || BLOG.LANG const SUB_PATH = NOTION_CONFIG?.SUB_PATH || BLOG.SUB_PATH const CONTACT_EMAIL = NOTION_CONFIG?.CONTACT_EMAIL || BLOG.CONTACT_EMAIL // 检查 feed 文件是否在10分钟内更新过 if (isFeedRecentlyUpdated('./public/rss/feed.xml', 10)) { return } console.log('[RSS订阅] 生成/rss/feed.xml') const year = new Date().getFullYear() const feed = new Feed({ title: TITLE, description: DESCRIPTION, link: `${LINK}/${SUB_PATH}`, language: LANG, favicon: `${LINK}/favicon.png`, copyright: `All rights reserved ${year}, ${AUTHOR}`, author: { name: AUTHOR, email: CONTACT_EMAIL, link: LINK } }) for (const post of latestPosts) { feed.addItem({ title: post.title, link: `${LINK}/${post.slug}`, description: post.summary, content: await createFeedContent(post), date: new Date(post?.publishDay) }) } try { fs.mkdirSync('./public/rss', { recursive: true }) fs.writeFileSync('./public/rss/feed.xml', feed.rss2()) fs.writeFileSync('./public/rss/atom.xml', feed.atom1()) fs.writeFileSync('./public/rss/feed.json', feed.json1()) } catch (error) { // 在vercel运行环境是只读的,这里会报错; // 但在vercel编译阶段、或VPS等其他平台这行代码会成功执行 // RSS被高频词访问将大量消耗服务端资源,故作为静态文件 } } /** * 检查上次更新,如果60分钟内更新过就不操作。 * @param {*} filePath * @param {*} intervalMinutes * @returns */ function isFeedRecentlyUpdated(filePath, intervalMinutes = 60) { try { const stats = fs.statSync(filePath) const now = new Date() const lastModified = new Date(stats.mtime) const timeDifference = (now - lastModified) / (1000 * 60) // 转换为分钟 return timeDifference < intervalMinutes } catch (error) { // 如果文件不存在,我们需要创建它 return false } }