getmdfromleetcode 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +32 -8
- package/lib/markdownFormatter.js +14 -1
- package/lib/problemDataFetcher.js +44 -12
- package/package.json +9 -3
package/index.js
CHANGED
|
@@ -39,13 +39,25 @@ const argv = yargs(hideBin(process.argv))
|
|
|
39
39
|
description: 'Copy output to clipboard',
|
|
40
40
|
default: false
|
|
41
41
|
})
|
|
42
|
+
.option('username', {
|
|
43
|
+
alias: 'n',
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Username for specific solution author',
|
|
46
|
+
default: 'endlesscheng' // 设置默认用户名为endlesscheng
|
|
47
|
+
})
|
|
48
|
+
.option('solutionOnly', {
|
|
49
|
+
alias: 's',
|
|
50
|
+
type: 'boolean',
|
|
51
|
+
description: 'Output solution only',
|
|
52
|
+
default: false
|
|
53
|
+
})
|
|
42
54
|
.help()
|
|
43
55
|
.alias('help', 'h')
|
|
44
56
|
.argv;
|
|
45
57
|
|
|
46
58
|
// 主函数
|
|
47
59
|
async function main() {
|
|
48
|
-
const { url, english, raw, clipboard } = argv;
|
|
60
|
+
const { url, english, raw, clipboard, username, solutionOnly } = argv;
|
|
49
61
|
const language = english ? 'english' : 'chinese';
|
|
50
62
|
const rawOutput = raw;
|
|
51
63
|
|
|
@@ -54,24 +66,36 @@ async function main() {
|
|
|
54
66
|
|
|
55
67
|
// 首先尝试通过GraphQL API获取数据
|
|
56
68
|
try {
|
|
57
|
-
questionData = await fetchProblemDataViaGraphQL(url, language);
|
|
69
|
+
questionData = await fetchProblemDataViaGraphQL(url, language, username);
|
|
58
70
|
} catch (apiError) {
|
|
59
71
|
console.error('Failed to fetch data via GraphQL API, trying to fetch from page...', apiError.message);
|
|
60
72
|
// 如果API获取失败,则尝试从页面获取数据
|
|
61
|
-
questionData = await fetchProblemDataFromPage(url, language);
|
|
73
|
+
questionData = await fetchProblemDataFromPage(url, language, username);
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
// 添加语言信息到 questionData
|
|
65
77
|
questionData.isEnglish = english;
|
|
66
78
|
|
|
67
|
-
//
|
|
68
|
-
|
|
79
|
+
// 根据solutionOnly参数决定输出内容
|
|
80
|
+
let outputContent;
|
|
81
|
+
if (solutionOnly) {
|
|
82
|
+
// 只输出题解
|
|
83
|
+
if (questionData.solution) {
|
|
84
|
+
outputContent = formatAsMarkdown(questionData, rawOutput, true); // 传递solutionOnly标志
|
|
85
|
+
} else {
|
|
86
|
+
console.log('No solution found for the given problem.');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
// 正常输出完整内容
|
|
91
|
+
outputContent = formatAsMarkdown(questionData, rawOutput);
|
|
92
|
+
}
|
|
69
93
|
|
|
70
94
|
// 如果用户指定了复制到剪贴板的选项,则复制内容
|
|
71
95
|
if (clipboard) {
|
|
72
96
|
try {
|
|
73
97
|
// 将内容写入临时文件
|
|
74
|
-
writeFileSync('/tmp/leetcode_content.txt',
|
|
98
|
+
writeFileSync('/tmp/leetcode_content.txt', outputContent);
|
|
75
99
|
|
|
76
100
|
// 根据操作系统使用不同的命令复制到剪贴板
|
|
77
101
|
if (process.platform === 'darwin') {
|
|
@@ -89,11 +113,11 @@ async function main() {
|
|
|
89
113
|
} catch (clipboardError) {
|
|
90
114
|
console.error('Failed to copy content to clipboard:', clipboardError.message);
|
|
91
115
|
// 即使复制到剪贴板失败,仍然输出内容
|
|
92
|
-
console.log(
|
|
116
|
+
console.log(outputContent);
|
|
93
117
|
}
|
|
94
118
|
} else {
|
|
95
119
|
// 正常输出内容
|
|
96
|
-
console.log(
|
|
120
|
+
console.log(outputContent);
|
|
97
121
|
}
|
|
98
122
|
} catch (error) {
|
|
99
123
|
console.error('Error fetching or processing problem data:', error.message);
|
package/lib/markdownFormatter.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as cheerio from 'cheerio';
|
|
6
6
|
|
|
7
7
|
// 将题目内容格式化为Markdown
|
|
8
|
-
function formatAsMarkdown(question, rawOutput = false) {
|
|
8
|
+
function formatAsMarkdown(question, rawOutput = false, solutionOnly = false) {
|
|
9
9
|
const title = question.displayTitle;
|
|
10
10
|
const difficulty = question.difficulty;
|
|
11
11
|
const content = question.displayContent;
|
|
@@ -144,6 +144,17 @@ function formatAsMarkdown(question, rawOutput = false) {
|
|
|
144
144
|
}
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
+
// 如果只输出题解
|
|
148
|
+
if (solutionOnly) {
|
|
149
|
+
if (solution && solution.content) {
|
|
150
|
+
// 直接返回题解内容
|
|
151
|
+
let solutionContent = solution.content || '';
|
|
152
|
+
return solutionContent;
|
|
153
|
+
} else {
|
|
154
|
+
return '没有找到题解';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
147
158
|
// 构建Markdown输出
|
|
148
159
|
let markdown = '';
|
|
149
160
|
if (title) {
|
|
@@ -200,6 +211,8 @@ function formatAsMarkdown(question, rawOutput = false) {
|
|
|
200
211
|
// 处理HTML实体,但保留HTML标签结构
|
|
201
212
|
// solutionContent = solutionContent.replace(/</g, '<').replace(/>/g, '>');
|
|
202
213
|
|
|
214
|
+
// solutionContent = solutionContent.replace(/</g, '<').replace(/>/g, '>');
|
|
215
|
+
|
|
203
216
|
markdown += solutionContent + '\n';
|
|
204
217
|
} else {
|
|
205
218
|
markdown += '\n## 题解\n\n';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
// 使用GraphQL API获取LeetCode题目数据
|
|
6
|
-
async function fetchProblemDataViaGraphQL(url, language = 'chinese') {
|
|
6
|
+
async function fetchProblemDataViaGraphQL(url, language = 'chinese', username = null) {
|
|
7
7
|
// 从URL中提取题目slug
|
|
8
8
|
const match = url.match(/\/problems\/([^/]+)/);
|
|
9
9
|
const slug = match ? match[1] : null;
|
|
@@ -35,8 +35,8 @@ async function fetchProblemDataViaGraphQL(url, language = 'chinese') {
|
|
|
35
35
|
`;
|
|
36
36
|
|
|
37
37
|
const solutionQuery = `
|
|
38
|
-
query solutionData($slug: String
|
|
39
|
-
questionSolutionArticles(first:
|
|
38
|
+
query solutionData($slug: String!, $first: Int) {
|
|
39
|
+
questionSolutionArticles(first: $first, questionSlug: $slug) {
|
|
40
40
|
edges {
|
|
41
41
|
node {
|
|
42
42
|
title
|
|
@@ -85,7 +85,7 @@ async function fetchProblemDataViaGraphQL(url, language = 'chinese') {
|
|
|
85
85
|
},
|
|
86
86
|
body: JSON.stringify({
|
|
87
87
|
query: solutionQuery,
|
|
88
|
-
variables: { slug: slug }
|
|
88
|
+
variables: { slug: slug, first: 20 } // 增加数量以查找特定用户
|
|
89
89
|
})
|
|
90
90
|
});
|
|
91
91
|
|
|
@@ -114,7 +114,23 @@ async function fetchProblemDataViaGraphQL(url, language = 'chinese') {
|
|
|
114
114
|
if (solutionData && solutionData.data && solutionData.data.questionSolutionArticles &&
|
|
115
115
|
solutionData.data.questionSolutionArticles.edges &&
|
|
116
116
|
solutionData.data.questionSolutionArticles.edges.length > 0) {
|
|
117
|
-
|
|
117
|
+
|
|
118
|
+
if (username) {
|
|
119
|
+
// 尝试查找指定用户名的题解
|
|
120
|
+
const userSolution = solutionData.data.questionSolutionArticles.edges.find(edge =>
|
|
121
|
+
edge.node.author && edge.node.author.username === username
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// 如果找到了指定用户的题解,则使用它;否则使用第一个题解
|
|
125
|
+
if (userSolution) {
|
|
126
|
+
question.solution = userSolution.node;
|
|
127
|
+
} else if (solutionData.data.questionSolutionArticles.edges.length > 0) {
|
|
128
|
+
question.solution = solutionData.data.questionSolutionArticles.edges[0].node;
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
// 如果没有指定用户名,则使用第一个题解
|
|
132
|
+
question.solution = solutionData.data.questionSolutionArticles.edges[0].node;
|
|
133
|
+
}
|
|
118
134
|
}
|
|
119
135
|
|
|
120
136
|
// 添加URL到question对象
|
|
@@ -124,7 +140,7 @@ async function fetchProblemDataViaGraphQL(url, language = 'chinese') {
|
|
|
124
140
|
}
|
|
125
141
|
|
|
126
142
|
// 从页面的__NEXT_DATA__中提取题目数据
|
|
127
|
-
async function fetchProblemDataFromPage(url, language = 'chinese') {
|
|
143
|
+
async function fetchProblemDataFromPage(url, language = 'chinese', username = null) {
|
|
128
144
|
// 从URL中提取题目slug
|
|
129
145
|
const match = url.match(/\/problems\/([^/]+)/);
|
|
130
146
|
const slug = match ? match[1] : null;
|
|
@@ -183,7 +199,7 @@ async function fetchProblemDataFromPage(url, language = 'chinese') {
|
|
|
183
199
|
|
|
184
200
|
// 单独获取题解数据,因为页面中可能不包含题解数据
|
|
185
201
|
try {
|
|
186
|
-
const solutionData = await fetchSolutionData(slug);
|
|
202
|
+
const solutionData = await fetchSolutionData(slug, username);
|
|
187
203
|
if (solutionData) {
|
|
188
204
|
question.solution = solutionData;
|
|
189
205
|
}
|
|
@@ -201,12 +217,12 @@ async function fetchProblemDataFromPage(url, language = 'chinese') {
|
|
|
201
217
|
}
|
|
202
218
|
|
|
203
219
|
// 单独获取题解数据
|
|
204
|
-
async function fetchSolutionData(slug) {
|
|
220
|
+
async function fetchSolutionData(slug, username = null) {
|
|
205
221
|
const graphqlUrl = 'https://leetcode.cn/graphql';
|
|
206
222
|
|
|
207
223
|
const solutionQuery = `
|
|
208
|
-
query solutionData($slug: String
|
|
209
|
-
questionSolutionArticles(first:
|
|
224
|
+
query solutionData($slug: String!, $first: Int) {
|
|
225
|
+
questionSolutionArticles(first: $first, questionSlug: $slug) {
|
|
210
226
|
edges {
|
|
211
227
|
node {
|
|
212
228
|
title
|
|
@@ -230,7 +246,7 @@ async function fetchSolutionData(slug) {
|
|
|
230
246
|
},
|
|
231
247
|
body: JSON.stringify({
|
|
232
248
|
query: solutionQuery,
|
|
233
|
-
variables: { slug: slug }
|
|
249
|
+
variables: { slug: slug, first: 20 } // 增加数量以查找特定用户
|
|
234
250
|
})
|
|
235
251
|
});
|
|
236
252
|
|
|
@@ -247,7 +263,23 @@ async function fetchSolutionData(slug) {
|
|
|
247
263
|
if (solutionData.data && solutionData.data.questionSolutionArticles &&
|
|
248
264
|
solutionData.data.questionSolutionArticles.edges &&
|
|
249
265
|
solutionData.data.questionSolutionArticles.edges.length > 0) {
|
|
250
|
-
|
|
266
|
+
|
|
267
|
+
if (username) {
|
|
268
|
+
// 尝试查找指定用户名的题解
|
|
269
|
+
const userSolution = solutionData.data.questionSolutionArticles.edges.find(edge =>
|
|
270
|
+
edge.node.author && edge.node.author.username === username
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// 如果找到了指定用户的题解,则使用它;否则使用第一个题解
|
|
274
|
+
if (userSolution) {
|
|
275
|
+
return userSolution.node;
|
|
276
|
+
} else {
|
|
277
|
+
return solutionData.data.questionSolutionArticles.edges[0].node;
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
// 如果没有指定用户名,则返回第一个题解
|
|
281
|
+
return solutionData.data.questionSolutionArticles.edges[0].node;
|
|
282
|
+
}
|
|
251
283
|
}
|
|
252
284
|
|
|
253
285
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getmdfromleetcode",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "A command line tool to fetch LeetCode problem content and convert it to Markdown",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"start": "node index.js"
|
|
12
12
|
},
|
|
13
|
-
"keywords": [
|
|
13
|
+
"keywords": [
|
|
14
|
+
"leetcode",
|
|
15
|
+
"markdown",
|
|
16
|
+
"cli",
|
|
17
|
+
"solution",
|
|
18
|
+
"algorithm"
|
|
19
|
+
],
|
|
14
20
|
"author": "User",
|
|
15
21
|
"license": "MIT",
|
|
16
22
|
"dependencies": {
|
|
@@ -28,4 +34,4 @@
|
|
|
28
34
|
"engines": {
|
|
29
35
|
"node": ">=14.0.0"
|
|
30
36
|
}
|
|
31
|
-
}
|
|
37
|
+
}
|