diff --git a/docs/programming.md b/docs/programming.md
index b76e86e99a..f6744470ca 100644
--- a/docs/programming.md
+++ b/docs/programming.md
@@ -115,6 +115,10 @@ GitHub 官方也提供了一些 RSS:
+### 打卡
+
+
+
## LinkedKeeper
### 博文
diff --git a/lib/router.js b/lib/router.js
index 0610968f9f..0f13bd9b1d 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1062,6 +1062,7 @@ router.get('/aisixiang/ranking/:type?/:range?', require('./routes/aisixiang/rank
// LeetCode
router.get('/leetcode/articles', require('./routes/leetcode/articles'));
+router.get('/leetcode/submission/:country/:user', require('./routes/leetcode/submission'));
// segmentfault
router.get('/segmentfault/channel/:name', require('./routes/segmentfault/channel'));
diff --git a/lib/routes/leetcode/submission.js b/lib/routes/leetcode/submission.js
new file mode 100644
index 0000000000..d244faa805
--- /dev/null
+++ b/lib/routes/leetcode/submission.js
@@ -0,0 +1,66 @@
+const axios = require('@/utils/axios');
+const cheerio = require('cheerio');
+const util = require('./utils');
+
+module.exports = async (ctx) => {
+ const country = ctx.params.country;
+ const user = ctx.params.user;
+ let url, state, description;
+ if (country === 'cn') {
+ url = 'https://leetcode-cn.com/';
+ } else {
+ url = 'https://leetcode.com/';
+ }
+ const response = await axios({
+ method: 'get',
+ url: url + `${user}`,
+ headers: {
+ Referer: url,
+ },
+ });
+ const data = response.data;
+ const $ = cheerio.load(data);
+ const username = $('div.panel-body')
+ .find('h4')
+ .text();
+ const img = $('div.panel-body')
+ .find('img')
+ .attr('src'); // 用户的头像
+ const src = `
`;
+ const solvedQuestion = $('ul.list-group')
+ .eq(2)
+ .children()
+ .eq(0)
+ .find('span')
+ .text(); // 解决的题目
+ const acceptedSubmission = $('ul.list-group')
+ .eq(2)
+ .children()
+ .eq(1)
+ .find('span')
+ .text(); // 通过的提交
+ const acceptanceRate = $('ul.list-group')
+ .eq(2)
+ .children()
+ .eq(2)
+ .find('span')
+ .text(); // 通过率
+ if (country === 'cn') {
+ state = ' 的刷题动态';
+ description = '解决的题目: ' + solvedQuestion + '
通过的提交: ' + acceptedSubmission + '
通过率: ' + acceptanceRate + '
' + src;
+ } else {
+ state = ' Most recent submissions';
+ description = 'Solved Question: ' + solvedQuestion + '
Accepted Submission: ' + acceptedSubmission + '
Acceptance Rate: ' + acceptanceRate + '
' + src;
+ }
+
+ const list = $('ul.list-group')
+ .eq(-1)
+ .children()
+ .get();
+ const result = await util.ProcessFeed(list, country);
+ ctx.state.data = {
+ title: username + state,
+ description: description,
+ item: result,
+ };
+};
diff --git a/lib/routes/leetcode/utils.js b/lib/routes/leetcode/utils.js
new file mode 100644
index 0000000000..a0717946f5
--- /dev/null
+++ b/lib/routes/leetcode/utils.js
@@ -0,0 +1,82 @@
+const cheerio = require('cheerio');
+
+const ProcessFeed = async (list, country) => {
+ let host;
+ if (country === 'us') {
+ host = 'https://leetcode.com';
+ } else {
+ host = 'https://leetcode-cn.com';
+ }
+ return await Promise.all(
+ list.map(async (item) => {
+ const $ = cheerio.load(item);
+ const $title = $('b');
+ const description =
+ $('span')
+ .eq(0)
+ .text() +
+ $('span')
+ .eq(1)
+ .text();
+ // 还原相对链接为绝对链接
+
+ const pubDate = $('span')
+ .eq(2)
+ .text();
+ const bb = $('a[href]').get()[0];
+ const itemUrl = host + $(bb).attr('href');
+ let n = 0,
+ h = 0;
+ let n1, n2, n3, n4, n5, n6;
+ if (country === 'us') {
+ n1 = pubDate.search(/year/);
+ n2 = pubDate.search(/month/);
+ n3 = pubDate.search(/week/);
+ n4 = pubDate.search(/day/);
+ n5 = pubDate.search(/hour/);
+ n6 = pubDate.search(/minute/);
+ } else {
+ n1 = pubDate.search(/年/);
+ n2 = pubDate.search(/月/);
+ n3 = pubDate.search(/周/);
+ n4 = pubDate.search(/日/);
+ n5 = pubDate.search(/小时/);
+ n6 = pubDate.search(/分钟/);
+ }
+
+ if (n1 !== -1) {
+ n = n + parseInt(pubDate[n1 - 2]) * 365;
+ }
+ if (n2 !== -1) {
+ n = n + parseInt(pubDate[n2 - 2]) * 30;
+ }
+ if (n3 !== -1) {
+ n = n + parseInt(pubDate[n3 - 2]) * 7;
+ }
+ if (n4 !== -1) {
+ n = n + parseInt(pubDate[n4 - 2]) * 1;
+ }
+ if (n5 !== -1) {
+ h = h + parseInt(pubDate[n5 - 2]) * 3600;
+ }
+ if (n6 !== -1) {
+ h = h + parseInt(pubDate[n6 - 2]) * 60;
+ }
+ const now = new Date();
+ const Datenow = new Date(now.getTime() - n * 24 * 3600 * 1000 - h * 1000).toISOString();
+ // 列表上提取到的信息
+ const single = {
+ title: $title.text(),
+ description: description,
+ link: itemUrl,
+ guid: itemUrl,
+ pubDate: Datenow,
+ };
+ return Promise.resolve(Object.assign({}, single));
+ })
+ );
+};
+
+module.exports = {
+ ProcessFeed,
+};