aiconductor-cli 1.2.1 → 1.2.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/CLAUDE.md +76 -0
- package/README.md +266 -108
- package/package.json +4 -3
- package/src/api.js +42 -26
- package/src/commands/douyin.js +109 -151
- package/src/commands/html_publish.js +54 -91
- package/src/commands/md_publish.js +87 -118
- package/src/commands/web_search.js +84 -120
- package/src/lib/cli-utils.js +80 -0
- package/AGENTS.md +0 -79
- package/AIC /346/212/226/351/237/263/347/263/273/345/210/227API/346/216/245/345/217/243.txt" +0 -417
- package/CODEBUDDY.md +0 -79
package/src/commands/douyin.js
CHANGED
|
@@ -1,151 +1,109 @@
|
|
|
1
|
-
const {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} = require("../
|
|
11
|
-
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
process.exit(0);
|
|
111
|
-
} catch (err) { handleError(err, format); process.exit(1); }
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async function videoSearchCommand(keyword, options = {}) {
|
|
115
|
-
const format = options.format || "json";
|
|
116
|
-
const key = resolveKey(options.apiKey, format);
|
|
117
|
-
try {
|
|
118
|
-
const maxPages = options.maxPages ? parseInt(options.maxPages, 10) : undefined;
|
|
119
|
-
const maxSeconds = options.maxSeconds ? parseInt(options.maxSeconds, 10) : undefined;
|
|
120
|
-
const result = await douyinVideoSearch(key, keyword, {
|
|
121
|
-
maxPages,
|
|
122
|
-
maxSeconds,
|
|
123
|
-
sortType: options.sortType,
|
|
124
|
-
publishTime: options.publishTime,
|
|
125
|
-
filterDuration: options.filterDuration,
|
|
126
|
-
contentType: options.contentType,
|
|
127
|
-
});
|
|
128
|
-
outputResult(result, format);
|
|
129
|
-
process.exit(0);
|
|
130
|
-
} catch (err) { handleError(err, format); process.exit(1); }
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async function linkToTextCommand(videoUrl, options = {}) {
|
|
134
|
-
const format = options.format || "json";
|
|
135
|
-
const key = resolveKey(options.apiKey, format);
|
|
136
|
-
try {
|
|
137
|
-
const result = await douyinLinkToText(key, videoUrl);
|
|
138
|
-
outputResult(result, format);
|
|
139
|
-
process.exit(0);
|
|
140
|
-
} catch (err) { handleError(err, format); process.exit(1); }
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
module.exports = {
|
|
144
|
-
videoInfoCommand,
|
|
145
|
-
videoCommentsCommand,
|
|
146
|
-
userVideosCommand,
|
|
147
|
-
userDetailCommand,
|
|
148
|
-
userSearchCommand,
|
|
149
|
-
videoSearchCommand,
|
|
150
|
-
linkToTextCommand,
|
|
151
|
-
};
|
|
1
|
+
const {
|
|
2
|
+
douyinVideoInfo,
|
|
3
|
+
douyinVideoComments,
|
|
4
|
+
douyinUserVideos,
|
|
5
|
+
douyinUserDetail,
|
|
6
|
+
douyinUserSearch,
|
|
7
|
+
douyinVideoSearch,
|
|
8
|
+
douyinLinkToText,
|
|
9
|
+
} = require("../api");
|
|
10
|
+
const { outputResult, resolveKeyOrExit, handleApiError, safeParseInt } = require("../lib/cli-utils");
|
|
11
|
+
|
|
12
|
+
async function videoInfoCommand(shareUrl, options = {}) {
|
|
13
|
+
const format = options.format || "json";
|
|
14
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
15
|
+
try {
|
|
16
|
+
const result = await douyinVideoInfo(apiKey, shareUrl);
|
|
17
|
+
outputResult(result, format);
|
|
18
|
+
process.exit(0);
|
|
19
|
+
} catch (err) { handleApiError(err, format); process.exit(1); }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function videoCommentsCommand(videoUrl, options = {}) {
|
|
23
|
+
const format = options.format || "json";
|
|
24
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
25
|
+
try {
|
|
26
|
+
const maxCount = safeParseInt(options.maxCount, undefined);
|
|
27
|
+
const result = await douyinVideoComments(apiKey, videoUrl, maxCount);
|
|
28
|
+
outputResult(result, format);
|
|
29
|
+
process.exit(0);
|
|
30
|
+
} catch (err) { handleApiError(err, format); process.exit(1); }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function userVideosCommand(homePage, options = {}) {
|
|
34
|
+
const format = options.format || "json";
|
|
35
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
36
|
+
try {
|
|
37
|
+
const maxSeconds = safeParseInt(options.maxSeconds, undefined);
|
|
38
|
+
const maxPages = safeParseInt(options.maxPages, undefined);
|
|
39
|
+
const result = await douyinUserVideos(apiKey, homePage, maxSeconds, maxPages);
|
|
40
|
+
outputResult(result, format);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
} catch (err) { handleApiError(err, format); process.exit(1); }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function userDetailCommand(homePage, options = {}) {
|
|
46
|
+
const format = options.format || "json";
|
|
47
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
48
|
+
try {
|
|
49
|
+
const result = await douyinUserDetail(apiKey, homePage);
|
|
50
|
+
outputResult(result, format);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
} catch (err) { handleApiError(err, format); process.exit(1); }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function userSearchCommand(keyword, options = {}) {
|
|
56
|
+
const format = options.format || "json";
|
|
57
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
58
|
+
try {
|
|
59
|
+
const maxPages = safeParseInt(options.maxPages, undefined);
|
|
60
|
+
const maxSeconds = safeParseInt(options.maxSeconds, undefined);
|
|
61
|
+
const result = await douyinUserSearch(apiKey, keyword, {
|
|
62
|
+
maxPages,
|
|
63
|
+
maxSeconds,
|
|
64
|
+
fansRange: options.fansRange,
|
|
65
|
+
userType: options.userType,
|
|
66
|
+
});
|
|
67
|
+
outputResult(result, format);
|
|
68
|
+
process.exit(0);
|
|
69
|
+
} catch (err) { handleApiError(err, format); process.exit(1); }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function videoSearchCommand(keyword, options = {}) {
|
|
73
|
+
const format = options.format || "json";
|
|
74
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
75
|
+
try {
|
|
76
|
+
const maxPages = safeParseInt(options.maxPages, undefined);
|
|
77
|
+
const maxSeconds = safeParseInt(options.maxSeconds, undefined);
|
|
78
|
+
const result = await douyinVideoSearch(apiKey, keyword, {
|
|
79
|
+
maxPages,
|
|
80
|
+
maxSeconds,
|
|
81
|
+
sortType: options.sortType,
|
|
82
|
+
publishTime: options.publishTime,
|
|
83
|
+
filterDuration: options.filterDuration,
|
|
84
|
+
contentType: options.contentType,
|
|
85
|
+
});
|
|
86
|
+
outputResult(result, format);
|
|
87
|
+
process.exit(0);
|
|
88
|
+
} catch (err) { handleApiError(err, format); process.exit(1); }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function linkToTextCommand(videoUrl, options = {}) {
|
|
92
|
+
const format = options.format || "json";
|
|
93
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
94
|
+
try {
|
|
95
|
+
const result = await douyinLinkToText(apiKey, videoUrl);
|
|
96
|
+
outputResult(result, format);
|
|
97
|
+
process.exit(0);
|
|
98
|
+
} catch (err) { handleApiError(err, format); process.exit(1); }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
videoInfoCommand,
|
|
103
|
+
videoCommentsCommand,
|
|
104
|
+
userVideosCommand,
|
|
105
|
+
userDetailCommand,
|
|
106
|
+
userSearchCommand,
|
|
107
|
+
videoSearchCommand,
|
|
108
|
+
linkToTextCommand,
|
|
109
|
+
};
|
|
@@ -1,91 +1,54 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
const filePath = path.resolve(trimmed);
|
|
15
|
-
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
16
|
-
return fs.readFileSync(filePath, "utf-8");
|
|
17
|
-
}
|
|
18
|
-
} catch (_) {
|
|
19
|
-
// 不是文件路径,按原始字符串处理
|
|
20
|
-
}
|
|
21
|
-
return trimmed;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
process.
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* publish 命令(子命令模式)
|
|
56
|
-
* @param {string} htmlCode - HTML 代码或文件路径
|
|
57
|
-
* @param {{ apiKey?: string, format?: string, title?: string }} options
|
|
58
|
-
*/
|
|
59
|
-
async function publishCommand(htmlCode, options = {}) {
|
|
60
|
-
const format = options.format || "json";
|
|
61
|
-
const resolvedKey = resolveApiKey(options.apiKey);
|
|
62
|
-
|
|
63
|
-
if (!resolvedKey) {
|
|
64
|
-
outputError(
|
|
65
|
-
{ message: "缺少 API Key。请通过 -k 参数、AICONDUCTOR_API_KEY 环境变量或 .env 文件提供。" },
|
|
66
|
-
format
|
|
67
|
-
);
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
const code = resolveHtmlInput(htmlCode);
|
|
73
|
-
const result = await publishHtml(resolvedKey, code, options.title);
|
|
74
|
-
outputResult(result, format);
|
|
75
|
-
process.exit(0);
|
|
76
|
-
} catch (err) {
|
|
77
|
-
if (err.type === "http_error") {
|
|
78
|
-
outputError(
|
|
79
|
-
{ message: `API 返回错误 (HTTP ${err.statusCode}): ${err.body?.message || JSON.stringify(err.body)}` },
|
|
80
|
-
format
|
|
81
|
-
);
|
|
82
|
-
} else if (err.type === "network_error") {
|
|
83
|
-
outputError({ message: `网络错误: ${err.message}` }, format);
|
|
84
|
-
} else {
|
|
85
|
-
outputError({ message: `未知错误: ${err.message || err}` }, format);
|
|
86
|
-
}
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
module.exports = { publishCommand };
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { publishHtml } = require("../api");
|
|
4
|
+
const { outputResult, outputError, resolveKeyOrExit, handleApiError } = require("../lib/cli-utils");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 智能解析输入:如果是已存在的文件路径则读取,否则当作原始 HTML 字符串
|
|
8
|
+
* @param {string} input
|
|
9
|
+
* @returns {string}
|
|
10
|
+
*/
|
|
11
|
+
function resolveHtmlInput(input) {
|
|
12
|
+
const trimmed = input.trim();
|
|
13
|
+
try {
|
|
14
|
+
const filePath = path.resolve(trimmed);
|
|
15
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
16
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
17
|
+
}
|
|
18
|
+
} catch (_) {
|
|
19
|
+
// 不是文件路径,按原始字符串处理
|
|
20
|
+
}
|
|
21
|
+
return trimmed;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** text 模式的自定义格式化 */
|
|
25
|
+
function formatPublishText(data) {
|
|
26
|
+
let out = "✓ 发布成功\n";
|
|
27
|
+
out += ` URL: ${data.online_url}\n`;
|
|
28
|
+
if (data.message) {
|
|
29
|
+
out += ` 信息: ${data.message}\n`;
|
|
30
|
+
}
|
|
31
|
+
return out.trimEnd();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* publish 命令(子命令模式)
|
|
36
|
+
* @param {string} htmlCode - HTML 代码或文件路径
|
|
37
|
+
* @param {{ apiKey?: string, format?: string, title?: string }} options
|
|
38
|
+
*/
|
|
39
|
+
async function publishCommand(htmlCode, options = {}) {
|
|
40
|
+
const format = options.format || "json";
|
|
41
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const code = resolveHtmlInput(htmlCode);
|
|
45
|
+
const result = await publishHtml(apiKey, code, options.title);
|
|
46
|
+
outputResult(result, format, formatPublishText);
|
|
47
|
+
process.exit(0);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
handleApiError(err, format);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = { publishCommand };
|
|
@@ -1,118 +1,87 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*
|
|
24
|
-
* @param {string
|
|
25
|
-
* @
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (filePath) {
|
|
30
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
31
|
-
if (ext === ".md" || ext === ".markdown") return "md";
|
|
32
|
-
if (ext === ".html" || ext === ".htm") return "html";
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
process.exit(
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
type = detectType(content, filePath);
|
|
89
|
-
} else if (type !== "md" && type !== "html") {
|
|
90
|
-
outputError({ message: `无效的 --type 值: "${type}",可选: md 或 html` }, format);
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
let result;
|
|
95
|
-
if (type === "html") {
|
|
96
|
-
result = await publishHtml(resolvedKey, content, options.title);
|
|
97
|
-
} else {
|
|
98
|
-
const addCopyButton = options.copyButton === true;
|
|
99
|
-
result = await publishMdToHtml(resolvedKey, content, options.title, addCopyButton);
|
|
100
|
-
}
|
|
101
|
-
outputResult(result, format);
|
|
102
|
-
process.exit(0);
|
|
103
|
-
} catch (err) {
|
|
104
|
-
if (err.type === "http_error") {
|
|
105
|
-
outputError(
|
|
106
|
-
{ message: `API 返回错误 (HTTP ${err.statusCode}): ${err.body?.message || JSON.stringify(err.body)}` },
|
|
107
|
-
format
|
|
108
|
-
);
|
|
109
|
-
} else if (err.type === "network_error") {
|
|
110
|
-
outputError({ message: `网络错误: ${err.message}` }, format);
|
|
111
|
-
} else {
|
|
112
|
-
outputError({ message: `未知错误: ${err.message || err}` }, format);
|
|
113
|
-
}
|
|
114
|
-
process.exit(1);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
module.exports = { publishCommand };
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { publishHtml, publishMdToHtml } = require("../api");
|
|
4
|
+
const { outputResult, outputError, resolveKeyOrExit, handleApiError } = require("../lib/cli-utils");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 解析输入内容:如果是已存在的文件路径则读取,否则当作原始字符串
|
|
8
|
+
* @param {string} input
|
|
9
|
+
* @returns {{ content: string, filePath: string|null }}
|
|
10
|
+
*/
|
|
11
|
+
function resolveInput(input) {
|
|
12
|
+
const trimmed = input.trim();
|
|
13
|
+
try {
|
|
14
|
+
const filePath = path.resolve(trimmed);
|
|
15
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
16
|
+
return { content: fs.readFileSync(filePath, "utf-8"), filePath };
|
|
17
|
+
}
|
|
18
|
+
} catch (_) {}
|
|
19
|
+
return { content: trimmed, filePath: null };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 自动检测内容类型:Markdown 或 HTML
|
|
24
|
+
* @param {string} content
|
|
25
|
+
* @param {string|null} filePath
|
|
26
|
+
* @returns {"md"|"html"}
|
|
27
|
+
*/
|
|
28
|
+
function detectType(content, filePath) {
|
|
29
|
+
if (filePath) {
|
|
30
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
31
|
+
if (ext === ".md" || ext === ".markdown") return "md";
|
|
32
|
+
if (ext === ".html" || ext === ".htm") return "html";
|
|
33
|
+
}
|
|
34
|
+
const trimmed = content.trim();
|
|
35
|
+
if (trimmed.startsWith("<!DOCTYPE") || trimmed.startsWith("<html") || trimmed.startsWith("<head")) {
|
|
36
|
+
return "html";
|
|
37
|
+
}
|
|
38
|
+
if (trimmed.startsWith("<") && /<\w+[^>]*>/.test(trimmed.substring(0, 200))) {
|
|
39
|
+
return "html";
|
|
40
|
+
}
|
|
41
|
+
return "md";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** text 模式的自定义格式化 */
|
|
45
|
+
function formatPublishText(data) {
|
|
46
|
+
let out = "✓ 发布成功\n";
|
|
47
|
+
out += ` URL: ${data.online_url}\n`;
|
|
48
|
+
if (data.message) {
|
|
49
|
+
out += ` 信息: ${data.message}\n`;
|
|
50
|
+
}
|
|
51
|
+
return out.trimEnd();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* webpage publish 命令 — 统一发布 Markdown 或 HTML 为在线网页
|
|
56
|
+
* @param {string} input - Markdown/HTML 代码或文件路径
|
|
57
|
+
* @param {{ apiKey?: string, format?: string, title?: string, copyButton?: boolean, type?: string }} options
|
|
58
|
+
*/
|
|
59
|
+
async function publishCommand(input, options = {}) {
|
|
60
|
+
const format = options.format || "json";
|
|
61
|
+
const apiKey = resolveKeyOrExit(options.apiKey, format);
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const { content, filePath } = resolveInput(input);
|
|
65
|
+
let type = options.type;
|
|
66
|
+
if (!type) {
|
|
67
|
+
type = detectType(content, filePath);
|
|
68
|
+
} else if (type !== "md" && type !== "html") {
|
|
69
|
+
outputError({ message: `无效的 --type 值: "${type}",可选: md 或 html` }, format);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let result;
|
|
74
|
+
if (type === "html") {
|
|
75
|
+
result = await publishHtml(apiKey, content, options.title);
|
|
76
|
+
} else {
|
|
77
|
+
result = await publishMdToHtml(apiKey, content, options.title, options.copyButton === true);
|
|
78
|
+
}
|
|
79
|
+
outputResult(result, format, formatPublishText);
|
|
80
|
+
process.exit(0);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
handleApiError(err, format);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { publishCommand };
|