diff --git a/docs/en/programming.md b/docs/en/programming.md
index 21ca5d3645..5766c1ef26 100644
--- a/docs/en/programming.md
+++ b/docs/en/programming.md
@@ -94,6 +94,10 @@ Category
+### Recent actions
+
+
+
## cve.mitre.org
### Search Result
diff --git a/lib/v2/codeforces/maintainer.js b/lib/v2/codeforces/maintainer.js
index 1d57fdfe35..c9f6a65c85 100644
--- a/lib/v2/codeforces/maintainer.js
+++ b/lib/v2/codeforces/maintainer.js
@@ -1,3 +1,4 @@
module.exports = {
'/contests': ['Fatpandac'],
+ '/recent-actions': ['ftiasch'],
};
diff --git a/lib/v2/codeforces/radar.js b/lib/v2/codeforces/radar.js
index 366f1178dd..be65f6aa70 100644
--- a/lib/v2/codeforces/radar.js
+++ b/lib/v2/codeforces/radar.js
@@ -1,6 +1,14 @@
module.exports = {
'codeforces.com': {
_name: 'Codeforces',
+ '.': [
+ {
+ title: 'Recent Actions',
+ docs: 'https://docs.rsshub.app/programming.html#codeforces-recent-actions',
+ source: ['/recent-actions'],
+ target: '/codeforces/recent-actions',
+ },
+ ],
www: [
{
title: '最新比赛',
diff --git a/lib/v2/codeforces/recent_actions.js b/lib/v2/codeforces/recent_actions.js
new file mode 100644
index 0000000000..ef57382bc5
--- /dev/null
+++ b/lib/v2/codeforces/recent_actions.js
@@ -0,0 +1,47 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ const minRating = ctx.params.minrating || 1;
+
+ const rsp = await got.get('https://codeforces.com/api/recentActions?maxCount=100').json();
+
+ const actions = rsp.result.map((action) => {
+ const pubDate = new Date(action.timeSeconds * 1000);
+
+ const blog = action.blogEntry;
+ const blogId = blog.id;
+ const blogTitle = cheerio.load(blog.title).text();
+
+ if (action.comment) {
+ const c = action.comment;
+ return {
+ title: `@${c.commentatorHandle} commented on "${blogTitle}"`,
+ description: cheerio.load(c.text).text(),
+ pubDate,
+ link: `https://codeforces.com/blog/entry/${blogId}?#comment-${c.id}`,
+ rating: c.rating,
+ };
+ }
+ return {
+ title: `@${blog.authorHandle} posted "${blogTitle}"`,
+ description: blogTitle,
+ pubDate,
+ link: `https://codeforces.com/blog/entry/${blogId}`,
+ rating: blog.rating,
+ };
+ });
+
+ ctx.state.data = {
+ title: 'Codeforces - Recent actions',
+ link: 'https://codeforces.com/recent-actions',
+ item: actions
+ .filter((a) => a.rating >= minRating)
+ .map((a) => ({
+ title: a.title,
+ description: a.description,
+ pubDate: a.pubDate,
+ link: a.link,
+ })),
+ };
+};
diff --git a/lib/v2/codeforces/router.js b/lib/v2/codeforces/router.js
index 2c28d05ceb..9ddd47686e 100644
--- a/lib/v2/codeforces/router.js
+++ b/lib/v2/codeforces/router.js
@@ -1,3 +1,4 @@
module.exports = function (router) {
router.get('/contests', require('./contests'));
+ router.get('/recent-actions/:minrating?', require('./recent_actions'));
};