-
-
Notifications
You must be signed in to change notification settings - Fork 11.7k
/
Copy pathrss.js
101 lines (95 loc) · 3.31 KB
/
rss.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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 文件是否在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
}
}