feat(route): 增加leetcode每日一题题解 (#10499)

* feat(route): 增加leetcode每日一题题解

* fix: leetcode每日一题题解

* fix: leetcode每日一题题解
This commit is contained in:
Albert Cai
2022-08-17 00:44:47 +08:00
committed by GitHub
parent a627bd6eb6
commit 792624e899
7 changed files with 341 additions and 0 deletions
+4
View File
@@ -309,6 +309,10 @@ Subscribe to the updates (threads and submission) from a paritcular Hacker News
<RouteEn author="NavePnow" example="/leetcode/dailyquestion/en" path="/leetcode/dailyquestion/:lang" :paramsDesc="['site, Chines(cn) and Engligh(en)']"/>
### Daily Question Solution
<RouteEn author="woaidouya123" example="/leetcode/dailyquestion/solution/en" path="/leetcode/dailyquestion/solution/:lang" :paramsDesc="['site, Chines(cn) and Engligh(en)']"/>
## Linux Patchwork
### Patch Comments
+4
View File
@@ -459,6 +459,10 @@ GitHub 官方也提供了一些 RSS:
<Route author="NavePnow" example="/leetcode/dailyquestion/en" path="/leetcode/dailyquestion/:lang" :paramsDesc="['站点,中文(cn)和英文(en)']"/>
### 每日一题题解
<Route author="woaidouya123" example="/leetcode/dailyquestion/solution/cn" path="/leetcode/dailyquestion/solution/:lang" :paramsDesc="['站点,中文(cn)和英文(en)']"/>
## LinkedKeeper
### 博文
@@ -0,0 +1,183 @@
const got = require('@/utils/got');
const showdown = require('showdown');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
module.exports = async (ctx) => {
const baseurl = `https://leetcode.cn`;
const url = `${baseurl}/graphql/`;
const headers = {
'content-type': 'application/json',
};
const emoji = {
Medium: '🟡',
Easy: '🟢',
Hard: '🔴',
};
// 获取每日一题
const data = (
await got({
method: 'post',
url,
json: {
operationName: 'questionOfToday',
query: `query questionOfToday {
todayRecord {
date
userStatus
question {
questionId
frontendQuestionId: questionFrontendId
difficulty
title
titleCn: translatedTitle
titleSlug
}
}
}`,
variables: {},
},
headers,
})
).data.data;
const questionTitle = data.todayRecord[0].question.titleSlug;
const questionUrl = `${baseurl}/problems/${questionTitle}/`;
// 获取题目内容
const question = (
await got({
method: 'post',
url,
json: {
operationName: 'questionData',
query: `query questionData($titleSlug: String!) {
question(titleSlug: $titleSlug) {
questionId
questionFrontendId
categoryTitle
boundTopicId
title
titleSlug
content
translatedTitle
translatedContent
isPaidOnly
difficulty
likes
}
}`,
variables: {
titleSlug: questionTitle,
},
},
headers,
})
).data.data.question;
const diffEmoji = emoji[question.difficulty] || '';
// 获取题解(点赞前3)
const articles = (
await got({
method: 'post',
url,
json: {
operationName: 'questionSolutionArticles',
query: `query questionSolutionArticles($questionSlug: String!, $skip: Int, $first: Int, $orderBy: SolutionArticleOrderBy, $userInput: String, $tagSlugs: [String!]) {
questionSolutionArticles(questionSlug: $questionSlug, skip: $skip, first: $first, orderBy: $orderBy, userInput: $userInput, tagSlugs: $tagSlugs) {
totalNum
edges {
node {
...solutionArticle
__typename
}
__typename
}
__typename
}
}
fragment solutionArticle on SolutionArticleNode {
uuid
title
slug
createdAt
thumbnail
author {
username
}
summary
}`,
variables: {
questionSlug: questionTitle,
first: 3,
skip: 0,
orderBy: 'MOST_UPVOTE',
},
},
headers,
})
).data.data.questionSolutionArticles.edges;
// 获取题解内容
const articleContent = (
await Promise.all(
articles.map((art) =>
got({
method: 'post',
url,
json: {
operationName: 'solutionDetailArticle',
query: `query solutionDetailArticle($slug: String!, $orderBy: SolutionArticleOrderBy!) {
solutionArticle(slug: $slug, orderBy: $orderBy) {
...solutionArticle
content
question {
questionTitleSlug
__typename
}
}
}
fragment solutionArticle on SolutionArticleNode {
uuid
title
slug
createdAt
thumbnail
author {
username
}
summary
}`,
variables: {
slug: art.node.slug,
orderBy: 'DEFAULT',
},
},
headers,
})
)
)
).map((v) => v.data.data.solutionArticle);
const converter = new showdown.Converter();
const handleText = (s) => {
// 处理多语言代码展示问题
s = s.replace(/(```)([a-zA-Z0-9-+#]+)\s*?(\[.*?\])?\n/g, '\r\n###$2\r\n$1$2\r\n');
return s;
};
ctx.state.data = {
title: 'LeetCode 每日一题题解',
description: 'LeetCode 每日一题题解',
link: questionUrl,
item: [
{
title: `每日一题-${question.translatedTitle}${diffEmoji}`,
link: questionUrl,
description: question.translatedContent,
pubDate: timezone(parseDate(data.todayRecord[0].date), +8),
},
...articleContent.map((art, i) => ({
title: art.title,
link: `${questionUrl}/solution/${art.slug}`,
description: converter.makeHtml(handleText(art.content)),
pubDate: timezone(parseDate(articles[i].node.createdAt), +8),
author: art.author.username,
})),
],
};
};
@@ -0,0 +1,135 @@
const got = require('@/utils/got');
const showdown = require('showdown');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
module.exports = async (ctx) => {
const baseurl = `https://leetcode.com`;
const url = `${baseurl}/graphql/`;
const headers = {
'content-type': 'application/json',
};
const emoji = {
Medium: '🟡',
Easy: '🟢',
Hard: '🔴',
};
// 获取每日一题
const data = (
await got({
method: 'post',
url,
json: {
operationName: 'questionOfToday',
query: `query questionOfToday {
activeDailyCodingChallengeQuestion {
date
link
question {
frontendQuestionId: questionFrontendId
titleSlug
}
}
}`,
variables: {},
},
headers,
})
).data.data;
const questionTitle = data.activeDailyCodingChallengeQuestion.question.titleSlug;
const questionUrl = `${baseurl}/problems/${questionTitle}/`;
// 获取题目内容
const question = (
await got({
method: 'post',
url,
json: {
operationName: 'questionData',
query: `query questionData($titleSlug: String!) {
question(titleSlug: $titleSlug) {
questionId
questionFrontendId
categoryTitle
boundTopicId
title
titleSlug
content
translatedTitle
translatedContent
isPaidOnly
difficulty
likes
}
}`,
variables: {
titleSlug: questionTitle,
},
},
headers,
})
).data.data.question;
const diffEmoji = emoji[question.difficulty] || '';
// 获取题解(en网站仅一个题解)
const article = (
await got({
method: 'post',
url,
json: {
operationName: 'QuestionNote',
query: `query QuestionNote($titleSlug: String!) {
question(titleSlug: $titleSlug) {
questionId
article
solution {
id
content
contentTypeId
canSeeDetail
paidOnly
hasVideoSolution
paidOnlyVideo
rating {
id
count
average
userRating {
score
}
}
}
}
}`,
variables: {
titleSlug: questionTitle,
},
},
headers,
})
).data.data.question.solution;
const converter = new showdown.Converter();
const handleText = (s) => {
// 处理多语言代码展示问题
s = s.replace(/(```)([a-zA-Z0-9-+#]+)\s*?(\[.*?\])?\n/g, '\r\n###$2\r\n$1$2\r\n');
return s;
};
ctx.state.data = {
title: 'LeetCode DailyQuestion Solution',
description: 'LeetCode DailyQuestion Solution',
link: questionUrl,
item: [
{
title: `DailyQuestion-${question.title}${diffEmoji}`,
link: questionUrl,
description: question.content,
pubDate: timezone(parseDate(data.activeDailyCodingChallengeQuestion.date), +8),
},
{
title: `Solution-${question.title}`,
link: `${questionUrl}solution/`,
description: converter.makeHtml(handleText(article.content)),
pubDate: timezone(parseDate(data.activeDailyCodingChallengeQuestion.date), +8),
author: 'leetcode',
},
],
};
};
+1
View File
@@ -1,5 +1,6 @@
module.exports = {
'/articles': ['LogicJake'],
'/dailyquestion/:lang': ['NavePnow'],
'/dailyquestion/solution/:lang': ['woaidouya123'],
'/submission/:country/:user': ['NathanDai'],
};
+12
View File
@@ -24,6 +24,12 @@ module.exports = {
source: ['/'],
target: '/leetcode/dailyquestion/en',
},
{
title: '每日一题题解',
docs: 'https://docs.rsshub.app/programming.html#leetcode',
source: ['/'],
target: '/leetcode/dailyquestion/solution/en',
},
],
},
'leetcode.cn': {
@@ -45,6 +51,12 @@ module.exports = {
source: ['/'],
target: '/leetcode/dailyquestion/cn',
},
{
title: '每日一题题解',
docs: 'https://docs.rsshub.app/programming.html#leetcode',
source: ['/'],
target: '/leetcode/dailyquestion/solution/cn',
},
],
},
};
+2
View File
@@ -2,4 +2,6 @@ module.exports = function (router) {
router.get('/articles', require('./articles'));
router.get('/dailyquestion/cn', require('./dailyquestion-cn'));
router.get('/dailyquestion/en', require('./dailyquestion-en'));
router.get('/dailyquestion/solution/cn', require('./dailyquestion-solution-cn'));
router.get('/dailyquestion/solution/en', require('./dailyquestion-solution-en'));
};