diff --git a/docs/programming.md b/docs/programming.md
index 85d117caa..05fcd403a 100644
--- a/docs/programming.md
+++ b/docs/programming.md
@@ -570,6 +570,10 @@ GitHub 官方也提供了一些 RSS:
+### 用户动态
+
+
+
## 码农俱乐部
### 话题
diff --git a/lib/router.js b/lib/router.js
index f4a7e8f64..cb2dc6c8f 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1399,6 +1399,7 @@ router.get('/bjp/apod', require('./routes/bjp/apod'));
// 洛谷
router.get('/luogu/daily/:id?', require('./routes/luogu/daily'));
router.get('/luogu/contest', require('./routes/luogu/contest'));
+router.get('/luogu/user/feed/:uid', require('./routes/luogu/userFeed'));
// 决胜网
router.get('/juesheng', require('./routes/juesheng'));
diff --git a/lib/routes/luogu/userFeed.js b/lib/routes/luogu/userFeed.js
new file mode 100644
index 000000000..17f944c20
--- /dev/null
+++ b/lib/routes/luogu/userFeed.js
@@ -0,0 +1,38 @@
+const got = require('@/utils/got');
+
+module.exports = async (ctx) => {
+ const getUsernameFromUID = async (uid) => {
+ const key = 'luogu-username-from-uid-' + uid;
+ let name = await ctx.cache.get(key);
+ if (!name) {
+ const nameResponse = await got({
+ method: 'get',
+ url: `https://www.luogu.com.cn/user/${uid}?_contentOnly=1`,
+ });
+ name = nameResponse.data.currentData.user.name;
+ ctx.cache.set(key, name);
+ }
+ return name;
+ };
+
+ const uid = ctx.params.uid;
+ const name = await getUsernameFromUID(uid);
+ const response = await got({
+ method: 'get',
+ url: `https://www.luogu.com.cn/api/feed/list?user=${uid}`,
+ });
+ const data = response.data.feeds.result;
+
+ ctx.state.data = {
+ title: `${name} 的洛谷动态`,
+ link: `https://www.luogu.com.cn/user/${uid}#activity`,
+ allowEmpty: true,
+ item: data.map((item) => ({
+ title: item.content,
+ description: item.content,
+ pubDate: new Date(item.time * 1000).toUTCString(),
+ link: `https://www.luogu.com.cn/user/${uid}#activity`,
+ guid: item.id,
+ })),
+ };
+};