any2card 0.1.0
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/package.json +26 -0
- package/wechat-publish.mjs +108 -0
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "any2card",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Any2Card 微信公众号发布 CLI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"any2card": "./wechat-publish.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"wechat-publish.mjs"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"any2card",
|
|
18
|
+
"wechat",
|
|
19
|
+
"cli",
|
|
20
|
+
"markdown"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"axios": "^1.14.0",
|
|
24
|
+
"commander": "^14.0.3"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Any2Card 微信发布 CLI 工具
|
|
5
|
+
* 用法: node wechat-publish.mjs --file <md_file> --preset <preset_id_or_name> --title <title>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import axios from 'axios';
|
|
11
|
+
import { program } from 'commander';
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name('any2card')
|
|
15
|
+
.description('Any2Card 微信公众号发布 CLI')
|
|
16
|
+
.requiredOption('-f, --file <path>', 'Markdown 文件路径')
|
|
17
|
+
.requiredOption('-t, --title <title>', '文章标题')
|
|
18
|
+
.requiredOption('-c, --cover <cover>', '封面图片路径 (必填)')
|
|
19
|
+
.option('-p, --preset <preset>', '模板预设 ID 或名称', 'default')
|
|
20
|
+
.option('-a, --author <author>', '文章作者', '')
|
|
21
|
+
.option('-d, --digest <digest>', '文章摘要', '')
|
|
22
|
+
.option('-k, --key <key>', 'API 密钥', process.env.ANY2CARD_API_KEY)
|
|
23
|
+
.option('-u, --url <url>', 'API 基础地址', process.env.ANY2CARD_API_URL || 'http://localhost:8089/api')
|
|
24
|
+
.option('--appid <appid>', '微信公众号 AppID')
|
|
25
|
+
.option('--secret <secret>', '微信公众号 AppSecret')
|
|
26
|
+
.parse(process.argv);
|
|
27
|
+
|
|
28
|
+
const options = program.opts();
|
|
29
|
+
|
|
30
|
+
// 检查是否提供了 API 密钥
|
|
31
|
+
if (!options.key) {
|
|
32
|
+
console.error('错误: 需要 API 密钥。请设置 ANY2CARD_API_KEY 环境变量或使用 --key 参数。');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const run = async () => {
|
|
37
|
+
try {
|
|
38
|
+
// 解析并检查 Markdown 文件是否存在
|
|
39
|
+
const filePath = path.resolve(options.file);
|
|
40
|
+
if (!fs.existsSync(filePath)) {
|
|
41
|
+
console.error(`错误: 未找到文件: ${filePath}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 读取 Markdown 内容
|
|
46
|
+
const markdownContent = fs.readFileSync(filePath, 'utf-8');
|
|
47
|
+
|
|
48
|
+
// 获取封面图片 Base64
|
|
49
|
+
const coverPath = path.resolve(options.cover);
|
|
50
|
+
if (!fs.existsSync(coverPath)) {
|
|
51
|
+
console.error(`错误: 未找到封面图片文件: ${coverPath}`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
const coverBase64 = fs.readFileSync(coverPath).toString('base64');
|
|
55
|
+
const coverName = path.basename(coverPath);
|
|
56
|
+
|
|
57
|
+
// 构建请求数据
|
|
58
|
+
const requestData = {
|
|
59
|
+
title: options.title,
|
|
60
|
+
author: options.author,
|
|
61
|
+
digest: options.digest,
|
|
62
|
+
markdownContent: markdownContent,
|
|
63
|
+
coverBase64: coverBase64,
|
|
64
|
+
coverName: coverName,
|
|
65
|
+
isOriginal: true, // 默认设为原创
|
|
66
|
+
wxAppId: options.appid,
|
|
67
|
+
wxSecret: options.secret
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// 判断 preset 是 ID 还是名称
|
|
71
|
+
if (/^\d+$/.test(options.preset)) {
|
|
72
|
+
requestData.presetId = parseInt(options.preset);
|
|
73
|
+
} else {
|
|
74
|
+
requestData.presetName = options.preset;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(`正在将 "${options.title}" 发布到微信公众号...`);
|
|
78
|
+
|
|
79
|
+
// 调用后端发布接口
|
|
80
|
+
const response = await axios.post(`${options.url}/wechat/publish`, requestData, {
|
|
81
|
+
headers: {
|
|
82
|
+
'x-api-key': options.key,
|
|
83
|
+
'Content-Type': 'application/json'
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// 处理响应结果
|
|
88
|
+
if (response.data.code === 0) {
|
|
89
|
+
console.log('\n✅ 成功! 文章已发布到微信草稿箱。');
|
|
90
|
+
console.log(`草稿 Media ID: ${response.data.data.mediaId}`);
|
|
91
|
+
if (response.data.data.thumbUrl) {
|
|
92
|
+
console.log(`封面图 URL: ${response.data.data.thumbUrl}`);
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
console.error(`\n❌ 失败: ${response.data.message}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(`\n❌ 错误: ${error.message}`);
|
|
100
|
+
// 打印详细的后端错误响应内容
|
|
101
|
+
if (error.response && error.response.data) {
|
|
102
|
+
console.error('响应内容:', JSON.stringify(error.response.data, null, 2));
|
|
103
|
+
}
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
run();
|