wechat-article-uploader 0.1.0__tar.gz
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.
- wechat_article_uploader-0.1.0/LICENSE +21 -0
- wechat_article_uploader-0.1.0/PKG-INFO +220 -0
- wechat_article_uploader-0.1.0/README.md +196 -0
- wechat_article_uploader-0.1.0/pyproject.toml +52 -0
- wechat_article_uploader-0.1.0/setup.cfg +4 -0
- wechat_article_uploader-0.1.0/src/wechat_article_uploader.egg-info/PKG-INFO +220 -0
- wechat_article_uploader-0.1.0/src/wechat_article_uploader.egg-info/SOURCES.txt +21 -0
- wechat_article_uploader-0.1.0/src/wechat_article_uploader.egg-info/dependency_links.txt +1 -0
- wechat_article_uploader-0.1.0/src/wechat_article_uploader.egg-info/entry_points.txt +2 -0
- wechat_article_uploader-0.1.0/src/wechat_article_uploader.egg-info/requires.txt +6 -0
- wechat_article_uploader-0.1.0/src/wechat_article_uploader.egg-info/top_level.txt +1 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/__init__.py +3 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/__main__.py +5 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/assets/__init__.py +1 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/assets/wechat_style.css +269 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/cli.py +319 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/config.py +249 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/parser.py +198 -0
- wechat_article_uploader-0.1.0/src/wechat_uploader/wechat_client.py +196 -0
- wechat_article_uploader-0.1.0/tests/test_cli.py +31 -0
- wechat_article_uploader-0.1.0/tests/test_config.py +63 -0
- wechat_article_uploader-0.1.0/tests/test_parser.py +36 -0
- wechat_article_uploader-0.1.0/tests/test_wechat_client.py +67 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wechat-article-uploader
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Upload local Markdown or text articles to WeChat Official Accounts drafts.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: wechat,weixin,cli,markdown
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Utilities
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
20
|
+
Requires-Dist: markdown>=3.6
|
|
21
|
+
Requires-Dist: requests>=2.31
|
|
22
|
+
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# wechat-article-uploader
|
|
26
|
+
|
|
27
|
+
把本地 `md` / `txt` 文章上传到微信公众号草稿箱的命令行工具。
|
|
28
|
+
|
|
29
|
+
它会自动完成这些事:
|
|
30
|
+
|
|
31
|
+
- 解析本地文章标题、正文和摘要
|
|
32
|
+
- 把正文里的本地图片先上传到公众号素材库,再替换为远程 URL
|
|
33
|
+
- 自动套用内置公众号样式,并转换为行内样式,降低微信编辑器兼容问题
|
|
34
|
+
- 支持单文件上传、目录批量上传和 `dry-run` 预演
|
|
35
|
+
|
|
36
|
+
## 安装
|
|
37
|
+
|
|
38
|
+
发布到 PyPI 后,直接安装:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python3 -m pip install wechat-article-uploader
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
如果你是在仓库里本地开发:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv sync --dev
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
执行命令时,推荐统一走 `uv run`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run wechat-article-uploader --help
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 配置文件
|
|
57
|
+
|
|
58
|
+
这个项目已经改为使用 `config.toml`,不再依赖 `.env`。
|
|
59
|
+
|
|
60
|
+
你可以用下面两种方式提供配置:
|
|
61
|
+
|
|
62
|
+
1. 在当前运行目录放一个 `config.toml`
|
|
63
|
+
2. 放到系统默认配置路径
|
|
64
|
+
|
|
65
|
+
查看默认配置路径:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv run wechat-article-uploader --print-config-path
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
创建配置文件最简单的方法:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cp config.example.toml config.toml
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
配置内容示例:
|
|
78
|
+
|
|
79
|
+
```toml
|
|
80
|
+
[wechat_article_uploader]
|
|
81
|
+
app_id = "your_app_id"
|
|
82
|
+
app_secret = "your_app_secret"
|
|
83
|
+
default_author = ""
|
|
84
|
+
default_thumb_media_id = ""
|
|
85
|
+
default_content_source_url = ""
|
|
86
|
+
default_need_open_comment = 0
|
|
87
|
+
default_only_fans_can_comment = 0
|
|
88
|
+
request_timeout = 20
|
|
89
|
+
retry_times = 3
|
|
90
|
+
retry_backoff_seconds = 1.5
|
|
91
|
+
token_cache_file = ""
|
|
92
|
+
style_file = ""
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
字段说明:
|
|
96
|
+
|
|
97
|
+
- `app_id`:公众号 AppID
|
|
98
|
+
- `app_secret`:公众号 AppSecret
|
|
99
|
+
- `default_author`:默认作者,可留空
|
|
100
|
+
- `default_thumb_media_id`:默认封面素材 ID,可留空;留空时会自动使用正文里第一张成功上传到素材库的本地图片
|
|
101
|
+
- `default_content_source_url`:原文链接,可留空
|
|
102
|
+
- `default_need_open_comment`:默认评论开关,`0` 或 `1`
|
|
103
|
+
- `default_only_fans_can_comment`:默认仅粉丝评论,`0` 或 `1`
|
|
104
|
+
- `request_timeout`:接口超时秒数
|
|
105
|
+
- `retry_times`:失败重试次数
|
|
106
|
+
- `retry_backoff_seconds`:每次重试的退避间隔倍率
|
|
107
|
+
- `token_cache_file`:token 缓存文件路径;留空时使用系统缓存目录
|
|
108
|
+
- `style_file`:自定义 CSS 文件路径;留空时使用包内默认样式
|
|
109
|
+
|
|
110
|
+
## 用法
|
|
111
|
+
|
|
112
|
+
### 单文件上传
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
uv run wechat-article-uploader --file "/path/to/article.md"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 目录批量上传
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv run wechat-article-uploader --dir "/path/to/articles"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 指定配置文件
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
uv run wechat-article-uploader --config "/path/to/config.toml" --file "/path/to/article.md"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 预演模式
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uv run wechat-article-uploader --dir "/path/to/articles" --dry-run
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`dry-run` 不会调用微信接口,适合先检查标题、解析和日志输出。
|
|
137
|
+
|
|
138
|
+
如果没有显式传 `--thumb-media-id`,也没有在配置文件中设置 `default_thumb_media_id`,程序会默认使用正文里第一张成功上传到素材库的本地图片作为封面。
|
|
139
|
+
|
|
140
|
+
### 常用覆盖参数
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
uv run wechat-article-uploader \
|
|
144
|
+
--file "/path/to/article.md" \
|
|
145
|
+
--author "作者名" \
|
|
146
|
+
--thumb-media-id "封面素材ID" \
|
|
147
|
+
--digest "摘要文本" \
|
|
148
|
+
--content-source-url "https://example.com/source" \
|
|
149
|
+
--need-open-comment 0 \
|
|
150
|
+
--only-fans-can-comment 0
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
如果你还在仓库里直接运行,也可以继续用兼容入口:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
uv run python main.py --file "/path/to/article.md"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 输入规则
|
|
160
|
+
|
|
161
|
+
- 支持后缀:`md`、`txt`
|
|
162
|
+
- Markdown:
|
|
163
|
+
- 首个非空行为 `# 标题` 或 `## 标题` 时,会作为文章标题
|
|
164
|
+
- 否则使用文件名作为标题
|
|
165
|
+
- Text:
|
|
166
|
+
- 首个非空行作为标题
|
|
167
|
+
- 后续内容作为正文
|
|
168
|
+
|
|
169
|
+
## 日志与失败重试
|
|
170
|
+
|
|
171
|
+
每次运行会在 `logs/` 生成:
|
|
172
|
+
|
|
173
|
+
- `upload_results_时间戳.json`:完整结果
|
|
174
|
+
- `failed.json`:仅失败项
|
|
175
|
+
|
|
176
|
+
你可以根据 `failed.json` 中的文件路径做二次重传。
|
|
177
|
+
|
|
178
|
+
## 开发与发布
|
|
179
|
+
|
|
180
|
+
本项目已经整理为标准 Python 包结构,支持构建 wheel 和 sdist:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
uv build
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
本地测试:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
uv run pytest
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
如果你准备正式发 GitHub Release 和 PyPI,完整流程见 `RELEASING.md`。
|
|
193
|
+
|
|
194
|
+
如果你刚克隆仓库,推荐流程是:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
uv sync --dev
|
|
198
|
+
uv run pytest
|
|
199
|
+
uv build
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 常见错误
|
|
203
|
+
|
|
204
|
+
- `未找到配置文件`:先创建 `config.toml`,或通过 `--config` 指定
|
|
205
|
+
- `缺少配置项`:检查 `app_id`、`app_secret` 是否填写
|
|
206
|
+
- `未提供封面 thumb_media_id,且自动获取失败`:检查素材库权限、IP 白名单,或手动填写 `default_thumb_media_id`
|
|
207
|
+
- `加载样式文件失败`:检查 `style_file` 路径是否正确、文件是否为空
|
|
208
|
+
- `创建草稿失败 errcode=...`:检查公众号权限、素材 ID 是否有效、内容是否符合微信限制
|
|
209
|
+
- `上传素材库图片失败`:检查本地图片路径、公众号素材权限、图片格式与大小限制
|
|
210
|
+
|
|
211
|
+
## 已知限制
|
|
212
|
+
|
|
213
|
+
- 微信 `draft/add` 接口当前不支持通过 API 设置“原创声明”和“创作来源”
|
|
214
|
+
- 若需要这两项,请在公众号后台草稿编辑页手动设置后再发布
|
|
215
|
+
|
|
216
|
+
## 发布说明
|
|
217
|
+
|
|
218
|
+
- 项目许可证已设为 `MIT`
|
|
219
|
+
- PyPI 自动发布工作流已配置在 `.github/workflows/publish-pypi.yml`
|
|
220
|
+
- 首次公开前,仍建议轮换一次公众号密钥
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# wechat-article-uploader
|
|
2
|
+
|
|
3
|
+
把本地 `md` / `txt` 文章上传到微信公众号草稿箱的命令行工具。
|
|
4
|
+
|
|
5
|
+
它会自动完成这些事:
|
|
6
|
+
|
|
7
|
+
- 解析本地文章标题、正文和摘要
|
|
8
|
+
- 把正文里的本地图片先上传到公众号素材库,再替换为远程 URL
|
|
9
|
+
- 自动套用内置公众号样式,并转换为行内样式,降低微信编辑器兼容问题
|
|
10
|
+
- 支持单文件上传、目录批量上传和 `dry-run` 预演
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
发布到 PyPI 后,直接安装:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python3 -m pip install wechat-article-uploader
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
如果你是在仓库里本地开发:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
uv sync --dev
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
执行命令时,推荐统一走 `uv run`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv run wechat-article-uploader --help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 配置文件
|
|
33
|
+
|
|
34
|
+
这个项目已经改为使用 `config.toml`,不再依赖 `.env`。
|
|
35
|
+
|
|
36
|
+
你可以用下面两种方式提供配置:
|
|
37
|
+
|
|
38
|
+
1. 在当前运行目录放一个 `config.toml`
|
|
39
|
+
2. 放到系统默认配置路径
|
|
40
|
+
|
|
41
|
+
查看默认配置路径:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv run wechat-article-uploader --print-config-path
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
创建配置文件最简单的方法:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cp config.example.toml config.toml
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
配置内容示例:
|
|
54
|
+
|
|
55
|
+
```toml
|
|
56
|
+
[wechat_article_uploader]
|
|
57
|
+
app_id = "your_app_id"
|
|
58
|
+
app_secret = "your_app_secret"
|
|
59
|
+
default_author = ""
|
|
60
|
+
default_thumb_media_id = ""
|
|
61
|
+
default_content_source_url = ""
|
|
62
|
+
default_need_open_comment = 0
|
|
63
|
+
default_only_fans_can_comment = 0
|
|
64
|
+
request_timeout = 20
|
|
65
|
+
retry_times = 3
|
|
66
|
+
retry_backoff_seconds = 1.5
|
|
67
|
+
token_cache_file = ""
|
|
68
|
+
style_file = ""
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
字段说明:
|
|
72
|
+
|
|
73
|
+
- `app_id`:公众号 AppID
|
|
74
|
+
- `app_secret`:公众号 AppSecret
|
|
75
|
+
- `default_author`:默认作者,可留空
|
|
76
|
+
- `default_thumb_media_id`:默认封面素材 ID,可留空;留空时会自动使用正文里第一张成功上传到素材库的本地图片
|
|
77
|
+
- `default_content_source_url`:原文链接,可留空
|
|
78
|
+
- `default_need_open_comment`:默认评论开关,`0` 或 `1`
|
|
79
|
+
- `default_only_fans_can_comment`:默认仅粉丝评论,`0` 或 `1`
|
|
80
|
+
- `request_timeout`:接口超时秒数
|
|
81
|
+
- `retry_times`:失败重试次数
|
|
82
|
+
- `retry_backoff_seconds`:每次重试的退避间隔倍率
|
|
83
|
+
- `token_cache_file`:token 缓存文件路径;留空时使用系统缓存目录
|
|
84
|
+
- `style_file`:自定义 CSS 文件路径;留空时使用包内默认样式
|
|
85
|
+
|
|
86
|
+
## 用法
|
|
87
|
+
|
|
88
|
+
### 单文件上传
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
uv run wechat-article-uploader --file "/path/to/article.md"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 目录批量上传
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
uv run wechat-article-uploader --dir "/path/to/articles"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 指定配置文件
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
uv run wechat-article-uploader --config "/path/to/config.toml" --file "/path/to/article.md"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 预演模式
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run wechat-article-uploader --dir "/path/to/articles" --dry-run
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`dry-run` 不会调用微信接口,适合先检查标题、解析和日志输出。
|
|
113
|
+
|
|
114
|
+
如果没有显式传 `--thumb-media-id`,也没有在配置文件中设置 `default_thumb_media_id`,程序会默认使用正文里第一张成功上传到素材库的本地图片作为封面。
|
|
115
|
+
|
|
116
|
+
### 常用覆盖参数
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv run wechat-article-uploader \
|
|
120
|
+
--file "/path/to/article.md" \
|
|
121
|
+
--author "作者名" \
|
|
122
|
+
--thumb-media-id "封面素材ID" \
|
|
123
|
+
--digest "摘要文本" \
|
|
124
|
+
--content-source-url "https://example.com/source" \
|
|
125
|
+
--need-open-comment 0 \
|
|
126
|
+
--only-fans-can-comment 0
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
如果你还在仓库里直接运行,也可以继续用兼容入口:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
uv run python main.py --file "/path/to/article.md"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 输入规则
|
|
136
|
+
|
|
137
|
+
- 支持后缀:`md`、`txt`
|
|
138
|
+
- Markdown:
|
|
139
|
+
- 首个非空行为 `# 标题` 或 `## 标题` 时,会作为文章标题
|
|
140
|
+
- 否则使用文件名作为标题
|
|
141
|
+
- Text:
|
|
142
|
+
- 首个非空行作为标题
|
|
143
|
+
- 后续内容作为正文
|
|
144
|
+
|
|
145
|
+
## 日志与失败重试
|
|
146
|
+
|
|
147
|
+
每次运行会在 `logs/` 生成:
|
|
148
|
+
|
|
149
|
+
- `upload_results_时间戳.json`:完整结果
|
|
150
|
+
- `failed.json`:仅失败项
|
|
151
|
+
|
|
152
|
+
你可以根据 `failed.json` 中的文件路径做二次重传。
|
|
153
|
+
|
|
154
|
+
## 开发与发布
|
|
155
|
+
|
|
156
|
+
本项目已经整理为标准 Python 包结构,支持构建 wheel 和 sdist:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
uv build
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
本地测试:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
uv run pytest
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
如果你准备正式发 GitHub Release 和 PyPI,完整流程见 `RELEASING.md`。
|
|
169
|
+
|
|
170
|
+
如果你刚克隆仓库,推荐流程是:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
uv sync --dev
|
|
174
|
+
uv run pytest
|
|
175
|
+
uv build
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## 常见错误
|
|
179
|
+
|
|
180
|
+
- `未找到配置文件`:先创建 `config.toml`,或通过 `--config` 指定
|
|
181
|
+
- `缺少配置项`:检查 `app_id`、`app_secret` 是否填写
|
|
182
|
+
- `未提供封面 thumb_media_id,且自动获取失败`:检查素材库权限、IP 白名单,或手动填写 `default_thumb_media_id`
|
|
183
|
+
- `加载样式文件失败`:检查 `style_file` 路径是否正确、文件是否为空
|
|
184
|
+
- `创建草稿失败 errcode=...`:检查公众号权限、素材 ID 是否有效、内容是否符合微信限制
|
|
185
|
+
- `上传素材库图片失败`:检查本地图片路径、公众号素材权限、图片格式与大小限制
|
|
186
|
+
|
|
187
|
+
## 已知限制
|
|
188
|
+
|
|
189
|
+
- 微信 `draft/add` 接口当前不支持通过 API 设置“原创声明”和“创作来源”
|
|
190
|
+
- 若需要这两项,请在公众号后台草稿编辑页手动设置后再发布
|
|
191
|
+
|
|
192
|
+
## 发布说明
|
|
193
|
+
|
|
194
|
+
- 项目许可证已设为 `MIT`
|
|
195
|
+
- PyPI 自动发布工作流已配置在 `.github/workflows/publish-pypi.yml`
|
|
196
|
+
- 首次公开前,仍建议轮换一次公众号密钥
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wechat-article-uploader"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Upload local Markdown or text articles to WeChat Official Accounts drafts."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"beautifulsoup4>=4.12",
|
|
15
|
+
"markdown>=3.6",
|
|
16
|
+
"requests>=2.31",
|
|
17
|
+
"tomli>=2.0.1; python_version < '3.11'",
|
|
18
|
+
]
|
|
19
|
+
keywords = ["wechat", "weixin", "cli", "markdown"]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 3 - Alpha",
|
|
22
|
+
"Environment :: Console",
|
|
23
|
+
"Intended Audience :: End Users/Desktop",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Topic :: Utilities",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
wechat-article-uploader = "wechat_uploader.cli:main"
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"build>=1.2",
|
|
38
|
+
"pytest>=8.0",
|
|
39
|
+
"twine>=5.0",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.uv]
|
|
43
|
+
package = true
|
|
44
|
+
|
|
45
|
+
[tool.setuptools]
|
|
46
|
+
package-dir = {"" = "src"}
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.packages.find]
|
|
49
|
+
where = ["src"]
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
wechat_uploader = ["assets/*.css"]
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wechat-article-uploader
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Upload local Markdown or text articles to WeChat Official Accounts drafts.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: wechat,weixin,cli,markdown
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Utilities
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
20
|
+
Requires-Dist: markdown>=3.6
|
|
21
|
+
Requires-Dist: requests>=2.31
|
|
22
|
+
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# wechat-article-uploader
|
|
26
|
+
|
|
27
|
+
把本地 `md` / `txt` 文章上传到微信公众号草稿箱的命令行工具。
|
|
28
|
+
|
|
29
|
+
它会自动完成这些事:
|
|
30
|
+
|
|
31
|
+
- 解析本地文章标题、正文和摘要
|
|
32
|
+
- 把正文里的本地图片先上传到公众号素材库,再替换为远程 URL
|
|
33
|
+
- 自动套用内置公众号样式,并转换为行内样式,降低微信编辑器兼容问题
|
|
34
|
+
- 支持单文件上传、目录批量上传和 `dry-run` 预演
|
|
35
|
+
|
|
36
|
+
## 安装
|
|
37
|
+
|
|
38
|
+
发布到 PyPI 后,直接安装:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python3 -m pip install wechat-article-uploader
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
如果你是在仓库里本地开发:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv sync --dev
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
执行命令时,推荐统一走 `uv run`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run wechat-article-uploader --help
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 配置文件
|
|
57
|
+
|
|
58
|
+
这个项目已经改为使用 `config.toml`,不再依赖 `.env`。
|
|
59
|
+
|
|
60
|
+
你可以用下面两种方式提供配置:
|
|
61
|
+
|
|
62
|
+
1. 在当前运行目录放一个 `config.toml`
|
|
63
|
+
2. 放到系统默认配置路径
|
|
64
|
+
|
|
65
|
+
查看默认配置路径:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv run wechat-article-uploader --print-config-path
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
创建配置文件最简单的方法:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cp config.example.toml config.toml
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
配置内容示例:
|
|
78
|
+
|
|
79
|
+
```toml
|
|
80
|
+
[wechat_article_uploader]
|
|
81
|
+
app_id = "your_app_id"
|
|
82
|
+
app_secret = "your_app_secret"
|
|
83
|
+
default_author = ""
|
|
84
|
+
default_thumb_media_id = ""
|
|
85
|
+
default_content_source_url = ""
|
|
86
|
+
default_need_open_comment = 0
|
|
87
|
+
default_only_fans_can_comment = 0
|
|
88
|
+
request_timeout = 20
|
|
89
|
+
retry_times = 3
|
|
90
|
+
retry_backoff_seconds = 1.5
|
|
91
|
+
token_cache_file = ""
|
|
92
|
+
style_file = ""
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
字段说明:
|
|
96
|
+
|
|
97
|
+
- `app_id`:公众号 AppID
|
|
98
|
+
- `app_secret`:公众号 AppSecret
|
|
99
|
+
- `default_author`:默认作者,可留空
|
|
100
|
+
- `default_thumb_media_id`:默认封面素材 ID,可留空;留空时会自动使用正文里第一张成功上传到素材库的本地图片
|
|
101
|
+
- `default_content_source_url`:原文链接,可留空
|
|
102
|
+
- `default_need_open_comment`:默认评论开关,`0` 或 `1`
|
|
103
|
+
- `default_only_fans_can_comment`:默认仅粉丝评论,`0` 或 `1`
|
|
104
|
+
- `request_timeout`:接口超时秒数
|
|
105
|
+
- `retry_times`:失败重试次数
|
|
106
|
+
- `retry_backoff_seconds`:每次重试的退避间隔倍率
|
|
107
|
+
- `token_cache_file`:token 缓存文件路径;留空时使用系统缓存目录
|
|
108
|
+
- `style_file`:自定义 CSS 文件路径;留空时使用包内默认样式
|
|
109
|
+
|
|
110
|
+
## 用法
|
|
111
|
+
|
|
112
|
+
### 单文件上传
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
uv run wechat-article-uploader --file "/path/to/article.md"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 目录批量上传
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv run wechat-article-uploader --dir "/path/to/articles"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 指定配置文件
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
uv run wechat-article-uploader --config "/path/to/config.toml" --file "/path/to/article.md"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 预演模式
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uv run wechat-article-uploader --dir "/path/to/articles" --dry-run
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`dry-run` 不会调用微信接口,适合先检查标题、解析和日志输出。
|
|
137
|
+
|
|
138
|
+
如果没有显式传 `--thumb-media-id`,也没有在配置文件中设置 `default_thumb_media_id`,程序会默认使用正文里第一张成功上传到素材库的本地图片作为封面。
|
|
139
|
+
|
|
140
|
+
### 常用覆盖参数
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
uv run wechat-article-uploader \
|
|
144
|
+
--file "/path/to/article.md" \
|
|
145
|
+
--author "作者名" \
|
|
146
|
+
--thumb-media-id "封面素材ID" \
|
|
147
|
+
--digest "摘要文本" \
|
|
148
|
+
--content-source-url "https://example.com/source" \
|
|
149
|
+
--need-open-comment 0 \
|
|
150
|
+
--only-fans-can-comment 0
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
如果你还在仓库里直接运行,也可以继续用兼容入口:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
uv run python main.py --file "/path/to/article.md"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 输入规则
|
|
160
|
+
|
|
161
|
+
- 支持后缀:`md`、`txt`
|
|
162
|
+
- Markdown:
|
|
163
|
+
- 首个非空行为 `# 标题` 或 `## 标题` 时,会作为文章标题
|
|
164
|
+
- 否则使用文件名作为标题
|
|
165
|
+
- Text:
|
|
166
|
+
- 首个非空行作为标题
|
|
167
|
+
- 后续内容作为正文
|
|
168
|
+
|
|
169
|
+
## 日志与失败重试
|
|
170
|
+
|
|
171
|
+
每次运行会在 `logs/` 生成:
|
|
172
|
+
|
|
173
|
+
- `upload_results_时间戳.json`:完整结果
|
|
174
|
+
- `failed.json`:仅失败项
|
|
175
|
+
|
|
176
|
+
你可以根据 `failed.json` 中的文件路径做二次重传。
|
|
177
|
+
|
|
178
|
+
## 开发与发布
|
|
179
|
+
|
|
180
|
+
本项目已经整理为标准 Python 包结构,支持构建 wheel 和 sdist:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
uv build
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
本地测试:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
uv run pytest
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
如果你准备正式发 GitHub Release 和 PyPI,完整流程见 `RELEASING.md`。
|
|
193
|
+
|
|
194
|
+
如果你刚克隆仓库,推荐流程是:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
uv sync --dev
|
|
198
|
+
uv run pytest
|
|
199
|
+
uv build
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 常见错误
|
|
203
|
+
|
|
204
|
+
- `未找到配置文件`:先创建 `config.toml`,或通过 `--config` 指定
|
|
205
|
+
- `缺少配置项`:检查 `app_id`、`app_secret` 是否填写
|
|
206
|
+
- `未提供封面 thumb_media_id,且自动获取失败`:检查素材库权限、IP 白名单,或手动填写 `default_thumb_media_id`
|
|
207
|
+
- `加载样式文件失败`:检查 `style_file` 路径是否正确、文件是否为空
|
|
208
|
+
- `创建草稿失败 errcode=...`:检查公众号权限、素材 ID 是否有效、内容是否符合微信限制
|
|
209
|
+
- `上传素材库图片失败`:检查本地图片路径、公众号素材权限、图片格式与大小限制
|
|
210
|
+
|
|
211
|
+
## 已知限制
|
|
212
|
+
|
|
213
|
+
- 微信 `draft/add` 接口当前不支持通过 API 设置“原创声明”和“创作来源”
|
|
214
|
+
- 若需要这两项,请在公众号后台草稿编辑页手动设置后再发布
|
|
215
|
+
|
|
216
|
+
## 发布说明
|
|
217
|
+
|
|
218
|
+
- 项目许可证已设为 `MIT`
|
|
219
|
+
- PyPI 自动发布工作流已配置在 `.github/workflows/publish-pypi.yml`
|
|
220
|
+
- 首次公开前,仍建议轮换一次公众号密钥
|