Files
lixiyu-net/lib/rss.tsx
2024-04-17 12:48:35 +08:00

95 lines
3.5 KiB
TypeScript

import { CopyrightAnnouncement, LatestPostCountInHomePage, WebsiteURL } from "@/consts/consts";
import { Config } from "@/data/config";
import { Feed } from "feed";
import fs from "fs";
import { JSDOM } from "jsdom";
import { MDXRemote } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize";
import { renderToString } from "react-dom/server";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeMathJax from "rehype-mathjax/svg";
import rehypePresetMinify from "rehype-preset-minify";
import rehypeRaw from "rehype-raw";
import rehypeSlug from "rehype-slug";
import externalLinks from "remark-external-links";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import remarkPrism from "remark-prism";
import { getPostFileContent, sortedPosts } from "./post-process";
const NoticeForRSSReaders = `\n---\n**NOTE:** Different RSS reader may have deficient even no support for svg formulations rendering. If it happens, please read the origin page to have better experience.`;
function minifyHTMLCode(htmlString: string): string {
const dom = new JSDOM(htmlString);
const document = dom.window.document;
const elements = document.querySelectorAll("*");
const unusedElements = document.querySelectorAll("script, style");
// Remove all class attributes.
elements.forEach((element) => {
element.removeAttribute("class");
});
// Remove all script and style tags.
unusedElements.forEach((element) => {
element.parentElement?.removeChild(element);
});
return dom.serialize();
}
/**
* Generate the RSS Feed File in `./public` so it could be visited by https://domain/rss.xml
*/
export const generateRSSFeed = async () => {
const feed = new Feed({
title: Config.SiteTitle,
description: Config.Sentence,
id: Config.SiteDomain,
link: WebsiteURL,
image: Config.PageCovers.websiteCoverURL,
favicon: `https://${Config.SiteDomain}/favcion.ico`,
copyright: CopyrightAnnouncement,
generator: "Node.js Feed",
author: {
name: Config.AuthorName,
email: Config.SocialLinks.email,
link: WebsiteURL,
},
});
for (let i = 0; i < Math.min(LatestPostCountInHomePage, sortedPosts.allPostList.length); i++) {
const post = sortedPosts.allPostList[i];
const postFileContent = `${getPostFileContent(post.id)}${NoticeForRSSReaders}}`;
const dateNumber = post.frontMatter.time.split("-").map((num) => parseInt(num));
const mdxSource = await serialize(postFileContent ?? "", {
parseFrontmatter: true,
mdxOptions: {
remarkPlugins: [remarkPrism, externalLinks, remarkMath, remarkGfm],
rehypePlugins: [rehypeMathJax, rehypeAutolinkHeadings, rehypeSlug, rehypePresetMinify as any, rehypeRaw],
format: "md",
},
});
const htmlContent = minifyHTMLCode(renderToString(<MDXRemote {...mdxSource} />));
feed.addItem({
title: post.frontMatter.title,
id: post.id,
link: `https://${Config.SiteDomain}/blog/${post.id}`,
description: post.frontMatter.summary ?? undefined,
content: htmlContent,
author: [
{
name: Config.AuthorName,
email: Config.SocialLinks.email,
link: `https://${Config.SiteDomain}/about`,
},
],
category: post.frontMatter.tags?.map((tagname) => ({ name: tagname })),
date: new Date(dateNumber[0], dateNumber[1], dateNumber[2]),
image: post.frontMatter.coverURL ?? undefined,
});
}
fs.writeFile("./public/rss.xml", feed.rss2(), "utf-8", (err) => {});
};