Files
NotionNext/lib/rss.js
2024-05-15 15:52:04 +08:00

102 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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(<NotionPage post={post} />)
const regexExp =
/<div class="notion-collection-row"><div class="notion-collection-row-body"><div class="notion-collection-row-property"><div class="notion-collection-column-title"><svg.*?class="notion-collection-column-title-icon">.*?<\/svg><div class="notion-collection-column-title-body">.*?<\/div><\/div><div class="notion-collection-row-value">.*?<\/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 文件是否在30分钟内更新过
if (isFeedRecentlyUpdated('./public/rss/feed.xml', 60)) {
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
}
}