diff --git a/docs/social-media.md b/docs/social-media.md
index debb7a081..ff520fbde 100644
--- a/docs/social-media.md
+++ b/docs/social-media.md
@@ -784,6 +784,20 @@ rule
+## 小红书
+
+### 用户笔记和专辑
+
+
+
+### 用户专辑
+
+
+
+### 专辑
+
+
+
## 知乎
### 收藏夹
diff --git a/lib/router.js b/lib/router.js
index 501b7d5f6..e78588945 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1953,6 +1953,10 @@ router.get('/zhanqi/room/:id', require('./routes/zhanqi/room'));
// 酒云网
router.get('/wineyun/:category', require('./routes/wineyun'));
+// 小红书
+router.get('/xiaohongshu/user/:user_id/:category', require('./routes/xiaohongshu/user'));
+router.get('/xiaohongshu/board/:board_id', require('./routes/xiaohongshu/board'));
+
// 重磅原创-每经网
router.get('/nbd/daily', require('./routes/nbd/article'));
diff --git a/lib/routes/xiaohongshu/board.js b/lib/routes/xiaohongshu/board.js
new file mode 100644
index 000000000..903594ef2
--- /dev/null
+++ b/lib/routes/xiaohongshu/board.js
@@ -0,0 +1,28 @@
+const { getContent } = require('@/routes/xiaohongshu/util');
+
+const JSON5 = require('json5');
+
+module.exports = async (ctx) => {
+ const url = `https://www.xiaohongshu.com/board/${ctx.params.board_id}`;
+ const content = await getContent(url);
+ const regex = /_SSR_STATE__\S*=([\s\S]+)<\/script>/gm;
+ const match = regex.exec(content);
+ const main = JSON5.parse(match[1]).Main;
+
+ const albumInfo = main.albumInfo;
+ const title = `${albumInfo.name}`;
+ const description = `${albumInfo.desc}`;
+
+ const list = main.notesDetail;
+ const resultItem = list.map((item) => ({
+ title: `${item.title}`,
+ link: `https://www.xiaohongshu.com/discovery/item/${item.id}`,
+ description: `
${item.title}`,
+ }));
+ ctx.state.data = {
+ title: title,
+ link: url,
+ item: resultItem,
+ description: description,
+ };
+};
diff --git a/lib/routes/xiaohongshu/user.js b/lib/routes/xiaohongshu/user.js
new file mode 100644
index 000000000..047020ec2
--- /dev/null
+++ b/lib/routes/xiaohongshu/user.js
@@ -0,0 +1,49 @@
+const { getContent } = require('@/routes/xiaohongshu/util');
+
+const cheerio = require('cheerio');
+const JSON5 = require('json5');
+
+module.exports = async (ctx) => {
+ const userId = ctx.params.user_id;
+ const category = ctx.params.category;
+ const url = `https://www.xiaohongshu.com/user/profile/${userId}`;
+
+ const content = await getContent(url);
+ const $ = cheerio.load(content);
+ const description = $('head title');
+ const regex = /_SSR_STATE__\S*=([\s\S]+)<\/script>/gm;
+ const match = regex.exec(content);
+ const main = JSON5.parse(match[1]).Main;
+ const userDetail = main.userDetail;
+ if (category === 'notes') {
+ const list = main.notesDetail;
+ const resultItem = list.map((item) => ({
+ title: `${item.title}`,
+ link: `${item.link}`,
+ description: `
${item.title}`,
+ }));
+
+ const title = `小红书-${userDetail.nickname}-笔记`;
+ ctx.state.data = {
+ title: title,
+ link: url,
+ item: resultItem,
+ description: description,
+ };
+ } else if (category === 'album') {
+ const list = main.albumDetail;
+ const resultItem = list.map((item) => ({
+ title: `${item.title}`,
+ link: `https://www.xiaohongshu.com/board/${item.id}`,
+ description: item.images.map((it) => `
`).join(`
`),
+ }));
+
+ const title = `小红书-${userDetail.nickname}-专辑`;
+ ctx.state.data = {
+ title: title,
+ link: url,
+ item: resultItem,
+ description: description,
+ };
+ }
+};
diff --git a/lib/routes/xiaohongshu/util.js b/lib/routes/xiaohongshu/util.js
new file mode 100644
index 000000000..ad18262ff
--- /dev/null
+++ b/lib/routes/xiaohongshu/util.js
@@ -0,0 +1,18 @@
+const delay = (timeout = 1000) => new Promise((resolve) => setTimeout(resolve, timeout));
+
+async function getContent(url) {
+ const browser = await require('@/utils/puppeteer')();
+ try {
+ const page = await browser.newPage();
+ await page.goto(url);
+ await delay(1000);
+ const content = await page.content();
+ return content.replace('"RedAppLayout":undefined,', ''); // fix json parse
+ } finally {
+ browser.close();
+ }
+}
+
+module.exports = {
+ getContent,
+};