wechat-media-writer 2.2.3 → 2.2.4
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/SKILL.md +79 -38
- package/bin/cli.js +9 -15
- package/package.json +1 -1
- package/references/publish_template.py +105 -24
- package/scripts/__pycache__/book_cover.cpython-314.pyc +0 -0
- package/scripts/__pycache__/image_downloader.cpython-314.pyc +0 -0
- package/scripts/book_cover.py +61 -12
- package/scripts/publish.py +49 -59
package/SKILL.md
CHANGED
|
@@ -137,9 +137,9 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
|
|
|
137
137
|
<span>副标题(一句话点睛)</span>
|
|
138
138
|
</p>
|
|
139
139
|
|
|
140
|
-
<!--
|
|
140
|
+
<!-- 主题配图(第一张图,使用主题贴图,非书籍原图) -->
|
|
141
141
|
<p style="margin:0 0 20px;text-align:center;">
|
|
142
|
-
<img src="{
|
|
142
|
+
<img src="{THEME_IMG_1}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图" />
|
|
143
143
|
</p>
|
|
144
144
|
|
|
145
145
|
<!-- 章节(无数字编号,直接标题) -->
|
|
@@ -150,11 +150,26 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
|
|
|
150
150
|
<span>正文段落。所有段落必须有 text-indent:2em。</span>
|
|
151
151
|
</p>
|
|
152
152
|
|
|
153
|
-
<!--
|
|
153
|
+
<!-- 主题配图(章节间穿插,与文风统一) -->
|
|
154
|
+
<p style="margin:0 0 20px;text-align:center;">
|
|
155
|
+
<img src="{THEME_IMG_2}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图" />
|
|
156
|
+
</p>
|
|
157
|
+
|
|
158
|
+
<!-- 金句引用块(用主题色高亮,加左侧色条) -->
|
|
154
159
|
<p
|
|
155
|
-
style="font-size:17px;line-height:1.9;color:
|
|
160
|
+
style="font-size:17px;line-height:1.9;color:{T};font-weight:bold;text-indent:2em;margin:0 0 20px;padding:14px 18px;background:{CBG};border-left:4px solid {T2};border-radius:6px;"
|
|
156
161
|
>
|
|
157
|
-
<span
|
|
162
|
+
<span style="color:{T2};">▍</span> 金句或核心观点引用。整段用主题主色加粗,加左侧强调色条,与正文形成视觉对比。
|
|
163
|
+
</p>
|
|
164
|
+
|
|
165
|
+
<!-- 重点启发语句(行内主题色 + 强调色高亮) -->
|
|
166
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
167
|
+
<span>正文段落中关键句子用 <strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">主题主色高亮</strong>,核心概念用 <span style="color:{T2};font-weight:bold;">强调色加粗</span>,让读者一眼锁定重点。</span>
|
|
168
|
+
</p>
|
|
169
|
+
|
|
170
|
+
<!-- 主题配图(章节中段) -->
|
|
171
|
+
<p style="margin:0 0 20px;text-align:center;">
|
|
172
|
+
<img src="{THEME_IMG_3}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图" />
|
|
158
173
|
</p>
|
|
159
174
|
|
|
160
175
|
<!-- 分隔符(章节之间) -->
|
|
@@ -162,54 +177,59 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
|
|
|
162
177
|
</section>
|
|
163
178
|
```
|
|
164
179
|
|
|
165
|
-
### 关键排版规则
|
|
180
|
+
### 关键排版规则
|
|
166
181
|
|
|
167
182
|
1. **所有正文段落必须有 `text-indent:2em`** — 首行缩进
|
|
168
183
|
2. **图片URL必须用完整的 `mmbiz.qpic.cn` 硬编码URL** — 不用模板变量
|
|
169
184
|
3. **`<img>` 必须包裹在 `<p>` 中**,且 `style="width:100%;display:block;border-radius:4px;"`
|
|
170
185
|
4. **行高统一 `line-height:2`** — 阅读舒适
|
|
171
|
-
5. **引用块用 `<p>` + `background` + `border-radius:8px
|
|
186
|
+
5. **引用块用 `<p>` + `background` + `border-radius:8px` + 左侧 `border-left:4px solid {T2}` 色条** — 不是 `<blockquote>`
|
|
172
187
|
6. **章节标题不使用数字编号** — 直接用"作者背景与创作时代",不用"壹"
|
|
173
188
|
7. **强调文字用 `<strong style="color:{T};">`** — 不是加粗或改色
|
|
174
|
-
8.
|
|
175
|
-
9.
|
|
176
|
-
10.
|
|
189
|
+
8. **重点语句/概念高亮**:用 `<strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">` 或 `<span style="color:{T2};font-weight:bold;">` — 让主题色贯穿全文
|
|
190
|
+
9. **星标用 `<span>★★★★☆</span>`** — `font-size:28px;color:{T2}`
|
|
191
|
+
10. **每篇文章只在一个 `<section>` 内** — 不嵌套多个 section
|
|
192
|
+
11. **全文插图统一为主题贴图** — 不再使用书籍原封面(书籍原图往往与文章主题风格不搭),全部用主题贴图
|
|
193
|
+
12. **图片在章节间穿插** — 每 1-2 段正文插一张图,避免长段无图的视觉疲劳
|
|
177
194
|
|
|
178
195
|
## 图片工作流
|
|
179
196
|
|
|
180
|
-
###
|
|
197
|
+
### 第一步:准备主题贴图(不再使用书籍原图作为正文配图)
|
|
181
198
|
|
|
182
|
-
|
|
199
|
+
**书评文章的所有插图统一为主题贴图**(Pexels 等无版权图库),与文章主题、章节氛围贴合。
|
|
200
|
+
不推荐使用书籍原图作为正文封面——书籍封面图风格往往与内容图不一致,且某些封面图清晰度/分辨率不适合正文展示。
|
|
183
201
|
|
|
184
|
-
使用 `scripts/
|
|
202
|
+
使用 `scripts/image_downloader.py` 下载主题贴图:
|
|
185
203
|
|
|
186
204
|
```python
|
|
187
|
-
from
|
|
188
|
-
|
|
189
|
-
# 自动获取封面URL(Google Books -> Open Library -> 豆瓣)
|
|
190
|
-
cover_url = fetch_book_cover("书名", "作者", "ISBN")
|
|
205
|
+
from image_downloader import download_theme_images
|
|
191
206
|
|
|
192
|
-
#
|
|
193
|
-
|
|
194
|
-
cover_path, cover_900_path = download_and_process_cover(cover_url, "/tmp/output")
|
|
207
|
+
# 根据主题下载 6-8 张贴图(用于正文穿插)
|
|
208
|
+
urls = download_theme_images("books", "/tmp/images", count=6)
|
|
195
209
|
```
|
|
196
210
|
|
|
197
|
-
|
|
198
|
-
- 文章内封面:宽度 600px,高度按比例缩放
|
|
199
|
-
- 公众号封面:900x500px(用于文章列表展示)
|
|
200
|
-
|
|
201
|
-
### 第二步:下载主题插图
|
|
211
|
+
### 第二步:制作公众号封面图
|
|
202
212
|
|
|
203
|
-
|
|
213
|
+
公众号封面(`cover_900x500.jpg`)用主题贴图中的一张裁剪为 900x500 比例:
|
|
204
214
|
|
|
205
215
|
```python
|
|
206
|
-
from
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
216
|
+
from PIL import Image
|
|
217
|
+
img = Image.open("img_1.jpg")
|
|
218
|
+
w, h = img.size
|
|
219
|
+
target_ratio = 900 / 500
|
|
220
|
+
if w / h > target_ratio:
|
|
221
|
+
new_w = int(h * target_ratio)
|
|
222
|
+
left = (w - new_w) // 2
|
|
223
|
+
img = img.crop((left, 0, left + new_w, h))
|
|
224
|
+
else:
|
|
225
|
+
new_h = int(w / target_ratio)
|
|
226
|
+
top = (h - new_h) // 2
|
|
227
|
+
img = img.crop((0, top, w, top + new_h))
|
|
228
|
+
img = img.resize((900, 500), Image.LANCZOS)
|
|
229
|
+
img.save("cover_900x500.jpg", "JPEG", quality=85)
|
|
210
230
|
```
|
|
211
231
|
|
|
212
|
-
|
|
232
|
+
`scripts/book_cover.py` 的 `download_and_process_cover()` 函数会从主题贴图(`img_1.jpg`)裁剪生成 900x500 封面。
|
|
213
233
|
|
|
214
234
|
### 第三步:上传图片到微信
|
|
215
235
|
|
|
@@ -230,6 +250,8 @@ img_url = upload_content_image(token, "image.jpg")
|
|
|
230
250
|
将上传后的 media_id 和 mmbiz URL **硬编码到发布脚本中**,不用模板变量。
|
|
231
251
|
这是因为微信图片URL有时效性,硬编码已验证的URL最可靠。
|
|
232
252
|
|
|
253
|
+
每篇文章需要:1张公众号封面 + 6-8张正文主题贴图。
|
|
254
|
+
|
|
233
255
|
## 微信 API 集成
|
|
234
256
|
|
|
235
257
|
### API 列表
|
|
@@ -354,15 +376,32 @@ python3 scripts/publish.py --title "标题" --content-file content.html --cover-
|
|
|
354
376
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;text-indent:2em;">
|
|
355
377
|
<strong style="color:{T};">适合人群:</strong>
|
|
356
378
|
</p>
|
|
357
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;
|
|
358
|
-
<span
|
|
379
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
380
|
+
<span>✅ 创业者/管理者——具体理由<br />✅ 陷入职业倦怠期的人——具体理由<br />✅ 对某领域感兴趣的读者——具体理由</span>
|
|
359
381
|
</p>
|
|
360
382
|
|
|
361
383
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;text-indent:2em;">
|
|
362
384
|
<strong style="color:{T};">不适合人群:</strong>
|
|
363
385
|
</p>
|
|
364
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;
|
|
365
|
-
<span
|
|
386
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
387
|
+
<span>🚫 已读过类似书籍的人——内容高度重复<br />🚫 讨厌某种风格的人——具体理由<br />🚫 寻找其他类型内容的人——具体理由</span>
|
|
388
|
+
</p>
|
|
389
|
+
|
|
390
|
+
<!-- 结尾页(与正文风格延续,使用主题色) -->
|
|
391
|
+
<p style="margin:0 0 16px;text-align:center;">
|
|
392
|
+
<img src="{THEME_IMG_END}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图" />
|
|
393
|
+
</p>
|
|
394
|
+
|
|
395
|
+
<p style="font-size:14px;color:#ccc;text-align:center;letter-spacing:8px;margin:24px 0 16px;">· · · · · ·</p>
|
|
396
|
+
|
|
397
|
+
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 8px;line-height:1.6;">
|
|
398
|
+
<span>📖 《书名》</span>
|
|
399
|
+
</p>
|
|
400
|
+
<p style="font-size:14px;color:{BODY};text-align:center;margin:0 0 4px;line-height:1.6;">
|
|
401
|
+
<span>作者 · 读书笔记</span>
|
|
402
|
+
</p>
|
|
403
|
+
<p style="font-size:14px;color:{T2};text-align:center;margin:0 0 4px;line-height:1.8;font-weight:bold;">
|
|
404
|
+
<span>「 一句话总结:核心洞察 」</span>
|
|
366
405
|
</p>
|
|
367
406
|
```
|
|
368
407
|
|
|
@@ -371,6 +410,8 @@ python3 scripts/publish.py --title "标题" --content-file content.html --cover-
|
|
|
371
410
|
1. **星级显示**:`font-size:28px;color:{T2}`,居中
|
|
372
411
|
2. **分数显示**:`4 / 5 星`,在星标下方
|
|
373
412
|
3. **评分理由**:1-2句话解释为什么给这个分数
|
|
374
|
-
4. **适合人群**:用
|
|
375
|
-
5. **不适合人群**:用
|
|
376
|
-
6.
|
|
413
|
+
4. **适合人群**:用 `✅ ` 标记,每条用——连接理由
|
|
414
|
+
5. **不适合人群**:用 `🚫 ` 标记,每条用——连接理由
|
|
415
|
+
6. **人群列表与首行对齐**:用 `text-indent:2em`(不用 `padding-left`),保证列表项与"适合人群:"首行视觉对齐
|
|
416
|
+
7. **结尾页**:用主题主色显示书名+作者,强调色显示一句话总结,配一张主题贴图作收尾
|
|
417
|
+
8. **不要直接放链接**——所有内容用文案表达
|
package/bin/cli.js
CHANGED
|
@@ -43,9 +43,9 @@ function showHelp() {
|
|
|
43
43
|
npx wechat-media-writer <command> [options]
|
|
44
44
|
|
|
45
45
|
命令:
|
|
46
|
-
cover <书名/电影名> [作者] [ISBN]
|
|
47
|
-
download <主题> [数量]
|
|
48
|
-
publish
|
|
46
|
+
cover <书名/电影名> [作者] [ISBN] 获取书籍原封面(仅用于书籍插图占位)
|
|
47
|
+
download <主题> [数量] [输出目录] 下载主题贴图
|
|
48
|
+
publish 发布文章到微信(主题贴图/封面缺失会自动补齐)
|
|
49
49
|
help 显示帮助信息
|
|
50
50
|
|
|
51
51
|
publish 选项:
|
|
@@ -55,20 +55,14 @@ publish 选项:
|
|
|
55
55
|
--author <作者> 文章作者,默认"读书笔记"
|
|
56
56
|
--digest <摘要> 文章摘要
|
|
57
57
|
--theme <主题> 图片主题:abstract/books/nature/technology/business,默认 abstract
|
|
58
|
-
--image-count <数量>
|
|
59
|
-
--book-title <书名> 书籍标题(封面缺失时自动获取)
|
|
60
|
-
--book-author <作者> 书籍作者
|
|
61
|
-
--book-isbn <ISBN> 书籍ISBN
|
|
58
|
+
--image-count <数量> 主题贴图数量,默认 6(5正文 + 1结尾)
|
|
62
59
|
|
|
63
60
|
示例:
|
|
64
|
-
npx wechat-media-writer
|
|
65
|
-
npx wechat-media-writer
|
|
66
|
-
|
|
67
|
-
--
|
|
68
|
-
--
|
|
69
|
-
--cover-dir /tmp/wx \\
|
|
70
|
-
--book-title "人类简史" \\
|
|
71
|
-
--book-author "尤瓦尔·赫拉利" \\
|
|
61
|
+
npx wechat-media-writer download books 6
|
|
62
|
+
npx wechat-media-writer publish ^
|
|
63
|
+
--title "《人类简史》全书深度拆解" ^
|
|
64
|
+
--content-file content.html ^
|
|
65
|
+
--cover-dir /tmp/wx ^
|
|
72
66
|
--theme books
|
|
73
67
|
|
|
74
68
|
配置:
|
package/package.json
CHANGED
|
@@ -5,14 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
用法:
|
|
7
7
|
1. 填写下方的变量(标题、摘要、HTML内容等)
|
|
8
|
-
2. 确保封面图已准备好(使用 scripts/
|
|
8
|
+
2. 确保封面图已准备好(使用 scripts/image_downloader.py 下载主题贴图)
|
|
9
9
|
3. 运行: python3 references/publish_template.py
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
13
|
import sys
|
|
14
14
|
|
|
15
|
-
# 添加 scripts 目录到模块搜索路径
|
|
16
15
|
scripts_dir = os.path.join(
|
|
17
16
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scripts"
|
|
18
17
|
)
|
|
@@ -23,12 +22,11 @@ from wechat_api import load_config, get_access_token, upload_cover, create_draft
|
|
|
23
22
|
|
|
24
23
|
# ========== 替换以下内容 ==========
|
|
25
24
|
|
|
26
|
-
# 标题和摘要
|
|
27
25
|
TITLE = "《书名》全书深度拆解:犀利洞察"
|
|
28
26
|
AUTHOR = "读书笔记"
|
|
29
27
|
DIGEST = "摘要文本,不超过120字。"
|
|
30
28
|
|
|
31
|
-
# 封面图目录(包含 cover_900x500.jpg
|
|
29
|
+
# 封面图目录(包含 cover_900x500.jpg + img_*.jpg 主题贴图)
|
|
32
30
|
COVER_DIR = "/tmp/book_output"
|
|
33
31
|
|
|
34
32
|
# 主题色:主色(深色)+ 强调色(暖/亮色)
|
|
@@ -37,7 +35,16 @@ T2 = "#D4A24C" # 强调色
|
|
|
37
35
|
BODY = "#555" # 正文色
|
|
38
36
|
CBG = "#F0EDE5" # 引用块背景
|
|
39
37
|
|
|
40
|
-
#
|
|
38
|
+
# 图片 URL(替换为上传微信后返回的 mmbiz.qpic.cn URL)
|
|
39
|
+
# 通过 publish.py 自动上传后,从 upload_result.json 中获取
|
|
40
|
+
THEME_IMG_1 = "http://mmbiz.qpic.cn/REPLACE_WITH_THEME_IMG_1"
|
|
41
|
+
THEME_IMG_2 = "http://mmbiz.qpic.cn/REPLACE_WITH_THEME_IMG_2"
|
|
42
|
+
THEME_IMG_3 = "http://mmbiz.qpic.cn/REPLACE_WITH_THEME_IMG_3"
|
|
43
|
+
THEME_IMG_4 = "http://mmbiz.qpic.cn/REPLACE_WITH_THEME_IMG_4"
|
|
44
|
+
THEME_IMG_5 = "http://mmbiz.qpic.cn/REPLACE_WITH_THEME_IMG_5"
|
|
45
|
+
THEME_IMG_END = "http://mmbiz.qpic.cn/REPLACE_WITH_THEME_IMG_END"
|
|
46
|
+
|
|
47
|
+
# 文章 HTML 内容(7段式,无数字编号,全文主题贴图穿插)
|
|
41
48
|
HTML = f"""<section style="margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;color:#333;background:#FBF8FC;">
|
|
42
49
|
|
|
43
50
|
<p style="font-size:12px;color:{T2};text-align:center;letter-spacing:4px;margin:24px 0 8px;line-height:3em;">
|
|
@@ -52,25 +59,94 @@ HTML = f"""<section style="margin:0;padding:0;font-family:-apple-system,BlinkMac
|
|
|
52
59
|
<span>副标题(一句话点睛)</span>
|
|
53
60
|
</p>
|
|
54
61
|
|
|
55
|
-
<!--
|
|
62
|
+
<!-- 主题配图1(头部) -->
|
|
56
63
|
<p style="margin:0 0 20px;text-align:center;">
|
|
57
|
-
<img src="
|
|
64
|
+
<img src="{THEME_IMG_1}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
58
65
|
</p>
|
|
59
66
|
|
|
60
|
-
<!--
|
|
67
|
+
<!-- 作者背景与创作时代 -->
|
|
61
68
|
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
62
69
|
<span>作者背景与创作时代</span>
|
|
63
70
|
</p>
|
|
71
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
72
|
+
<span>正文段落。所有段落必须有 text-indent:2em。重点句用 <strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">主题主色高亮</strong>,核心概念用 <span style="color:{T2};font-weight:bold;">强调色加粗</span>。</span>
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
<!-- 主题配图2(作者背景后) -->
|
|
76
|
+
<p style="margin:0 0 20px;text-align:center;">
|
|
77
|
+
<img src="{THEME_IMG_2}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
78
|
+
</p>
|
|
79
|
+
|
|
80
|
+
<!-- 金句引用块(左侧色条 + 主题色加粗) -->
|
|
81
|
+
<p style="font-size:17px;line-height:1.9;color:{T};font-weight:bold;text-indent:2em;margin:0 0 20px;padding:14px 18px;background:{CBG};border-left:4px solid {T2};border-radius:6px;">
|
|
82
|
+
<span style="color:{T2};">▍</span> 金句或核心观点。整段用主题主色加粗,加左侧强调色条与正文形成视觉对比。
|
|
83
|
+
</p>
|
|
84
|
+
|
|
85
|
+
<!-- 全书完整逻辑思维导图 -->
|
|
86
|
+
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
87
|
+
<span>全书完整逻辑思维导图</span>
|
|
88
|
+
</p>
|
|
89
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
90
|
+
<span>本章按章节脉络梳理<strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">全书核心逻辑</strong>,用文字框图提炼主线。</span>
|
|
91
|
+
</p>
|
|
92
|
+
|
|
93
|
+
<!-- 主题配图3(逻辑导图后) -->
|
|
94
|
+
<p style="margin:0 0 20px;text-align:center;">
|
|
95
|
+
<img src="{THEME_IMG_3}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
96
|
+
</p>
|
|
97
|
+
|
|
98
|
+
<!-- 三大颠覆性核心论点 -->
|
|
99
|
+
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
100
|
+
<span>三大颠覆性核心论点</span>
|
|
101
|
+
</p>
|
|
102
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
103
|
+
<span><span style="color:{T2};font-weight:bold;">论点一:</span><strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">核心颠覆性观点</strong>,附书中具体案例支撑。</span>
|
|
104
|
+
</p>
|
|
105
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
106
|
+
<span><span style="color:{T2};font-weight:bold;">论点二:</span><strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">核心颠覆性观点</strong>,附书中具体案例支撑。</span>
|
|
107
|
+
</p>
|
|
108
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
109
|
+
<span><span style="color:{T2};font-weight:bold;">论点三:</span><strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">核心颠覆性观点</strong>,附书中具体案例支撑。</span>
|
|
110
|
+
</p>
|
|
111
|
+
|
|
112
|
+
<!-- 主题配图4(论点后) -->
|
|
113
|
+
<p style="margin:0 0 20px;text-align:center;">
|
|
114
|
+
<img src="{THEME_IMG_4}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
115
|
+
</p>
|
|
64
116
|
|
|
117
|
+
<!-- 批判性客观评析 -->
|
|
118
|
+
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
119
|
+
<span>批判性客观评析</span>
|
|
120
|
+
</p>
|
|
65
121
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
66
|
-
<span
|
|
122
|
+
<span>短板一:客观指出书中局限。<br/>短板二:逻辑漏洞分析。<br/>短板三:适用边界。<br/>短板四:时代局限。</span>
|
|
67
123
|
</p>
|
|
68
124
|
|
|
69
|
-
|
|
70
|
-
|
|
125
|
+
<!-- 金句二 -->
|
|
126
|
+
<p style="font-size:17px;line-height:1.9;color:{T};font-weight:bold;text-indent:2em;margin:0 0 20px;padding:14px 18px;background:{CBG};border-left:4px solid {T2};border-radius:6px;">
|
|
127
|
+
<span style="color:{T2};">▍</span> 第二个金句或关键启发。
|
|
71
128
|
</p>
|
|
72
129
|
|
|
73
|
-
<!--
|
|
130
|
+
<!-- 收获与成长 -->
|
|
131
|
+
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
132
|
+
<span>收获与成长</span>
|
|
133
|
+
</p>
|
|
134
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
135
|
+
<span>读完能带走的<strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">三样东西</strong>,从个人成长视角展开。</span>
|
|
136
|
+
</p>
|
|
137
|
+
|
|
138
|
+
<!-- 主题配图5(收获与成长后) -->
|
|
139
|
+
<p style="margin:0 0 20px;text-align:center;">
|
|
140
|
+
<img src="{THEME_IMG_5}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
141
|
+
</p>
|
|
142
|
+
|
|
143
|
+
<!-- 现实落地应用方案 -->
|
|
144
|
+
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
145
|
+
<span>现实落地应用方案</span>
|
|
146
|
+
</p>
|
|
147
|
+
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
148
|
+
<span>方案一:具体执行步骤。<br/>方案二:可操作建议。<br/>方案三:拿来就用的行动项。</span>
|
|
149
|
+
</p>
|
|
74
150
|
|
|
75
151
|
<p style="font-size:14px;color:#ccc;text-align:center;letter-spacing:8px;margin:20px 0;">· · · · · ·</p>
|
|
76
152
|
|
|
@@ -88,30 +164,38 @@ HTML = f"""<section style="margin:0;padding:0;font-family:-apple-system,BlinkMac
|
|
|
88
164
|
</p>
|
|
89
165
|
|
|
90
166
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
91
|
-
<span>为什么给X
|
|
167
|
+
<span>为什么给X星?简要说明评分理由,诚实评价,3-4星是常态,5星极少。</span>
|
|
92
168
|
</p>
|
|
93
169
|
|
|
94
170
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;text-indent:2em;">
|
|
95
171
|
<strong style="color:{T};">适合人群:</strong>
|
|
96
172
|
</p>
|
|
97
173
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
98
|
-
<span
|
|
174
|
+
<span>✅ 创业者/管理者——理解系统脆弱性和反脆弱设计<br />✅ 对个人成长感兴趣的读者——掌握从压力中受益的方法<br />✅ 对决策科学感兴趣的读者——理解非线性风险的本质</span>
|
|
99
175
|
</p>
|
|
100
176
|
|
|
101
177
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;text-indent:2em;">
|
|
102
178
|
<strong style="color:{T};">不适合人群:</strong>
|
|
103
179
|
</p>
|
|
104
180
|
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
105
|
-
<span
|
|
181
|
+
<span>🚫 已读过类似书籍的人——内容高度重复<br />🚫 讨厌抽象论证的人——本书充满概念性思维<br />🚫 寻找具体操作手册的人——本书偏哲学思辨</span>
|
|
106
182
|
</p>
|
|
107
183
|
|
|
108
|
-
|
|
184
|
+
<!-- 结尾页:主题配图 + 书名 + 作者 + 核心总结 -->
|
|
185
|
+
<p style="margin:0 0 16px;text-align:center;">
|
|
186
|
+
<img src="{THEME_IMG_END}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
187
|
+
</p>
|
|
109
188
|
|
|
110
|
-
<p style="font-size:
|
|
111
|
-
|
|
189
|
+
<p style="font-size:14px;color:#ccc;text-align:center;letter-spacing:8px;margin:24px 0 16px;">· · · · · ·</p>
|
|
190
|
+
|
|
191
|
+
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 8px;line-height:1.6;">
|
|
192
|
+
<span>📖 《书名》</span>
|
|
193
|
+
</p>
|
|
194
|
+
<p style="font-size:14px;color:{BODY};text-align:center;margin:0 0 4px;line-height:1.6;">
|
|
195
|
+
<span>作者 · 读书笔记</span>
|
|
112
196
|
</p>
|
|
113
|
-
<p style="font-size:14px;color
|
|
114
|
-
<span
|
|
197
|
+
<p style="font-size:14px;color:{T2};text-align:center;margin:0 0 24px;line-height:1.8;font-weight:bold;">
|
|
198
|
+
<span>「 一句话总结:核心洞察 」</span>
|
|
115
199
|
</p>
|
|
116
200
|
|
|
117
201
|
</section>"""
|
|
@@ -122,22 +206,19 @@ def main():
|
|
|
122
206
|
print("微信公众号 - 书名 发布")
|
|
123
207
|
print("=" * 50)
|
|
124
208
|
|
|
125
|
-
# 1. 加载配置和获取token
|
|
126
209
|
config = load_config()
|
|
127
210
|
token = get_access_token(config)
|
|
128
211
|
print("\n✓ Token 已获取\n")
|
|
129
212
|
|
|
130
|
-
# 2. 上传封面图
|
|
131
213
|
cover_900_path = os.path.join(COVER_DIR, "cover_900x500.jpg")
|
|
132
214
|
if not os.path.exists(cover_900_path):
|
|
133
215
|
print(f"错误: 封面图不存在 {cover_900_path}", file=sys.stderr)
|
|
134
|
-
print("
|
|
216
|
+
print("请先运行主题贴图下载与封面裁剪流程", file=sys.stderr)
|
|
135
217
|
sys.exit(1)
|
|
136
218
|
|
|
137
219
|
print("上传封面图...")
|
|
138
220
|
cover_mid = upload_cover(token, cover_900_path)
|
|
139
221
|
|
|
140
|
-
# 3. 创建草稿
|
|
141
222
|
print("\n创建草稿...")
|
|
142
223
|
draft_id = create_draft(token, TITLE, AUTHOR, DIGEST, HTML, cover_mid)
|
|
143
224
|
|
|
Binary file
|
|
Binary file
|
package/scripts/book_cover.py
CHANGED
|
@@ -97,7 +97,12 @@ def fetch_book_cover_douban(book_title, author=""):
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
def fetch_book_cover(book_title, author="", isbn=""):
|
|
100
|
-
"""
|
|
100
|
+
"""按优先级尝试获取书籍封面(书籍原图),最后回退到占位图
|
|
101
|
+
|
|
102
|
+
注意:此函数返回的是书籍原图,仅用于 article 内首图占位。
|
|
103
|
+
公众号封面(cover_900x500.jpg)现在改用主题贴图,与正文风格统一。
|
|
104
|
+
如需主题封面,请调用 fetch_theme_cover()。
|
|
105
|
+
"""
|
|
101
106
|
cover_url = None
|
|
102
107
|
|
|
103
108
|
print(f"尝试从 Google Books 获取《{book_title}》封面...")
|
|
@@ -112,15 +117,29 @@ def fetch_book_cover(book_title, author="", isbn=""):
|
|
|
112
117
|
cover_url = fetch_book_cover_douban(book_title, author)
|
|
113
118
|
|
|
114
119
|
if not cover_url:
|
|
115
|
-
print("⚠️
|
|
120
|
+
print("⚠️ 三个数据源均未返回书籍封面,回退到占位图")
|
|
116
121
|
cover_url = "https://images.pexels.com/photos/159711/books-bookstore-book-reading-159711.jpeg?auto=compress&cs=tinysrgb&w=600"
|
|
117
122
|
|
|
118
|
-
print(f"✓
|
|
123
|
+
print(f"✓ 书籍封面URL: {cover_url}")
|
|
119
124
|
return cover_url
|
|
120
125
|
|
|
121
126
|
|
|
127
|
+
def fetch_theme_cover(theme="abstract"):
|
|
128
|
+
"""从 Pexels CDN 获取与主题贴图一致的主题封面(推荐使用)"""
|
|
129
|
+
theme_urls = {
|
|
130
|
+
"abstract": "https://images.pexels.com/photos/2693208/pexels-photo-2693208.jpeg?auto=compress&cs=tinysrgb&w=1080",
|
|
131
|
+
"books": "https://images.pexels.com/photos/159711/books-bookstore-book-reading-159711.jpeg?auto=compress&cs=tinysrgb&w=1080",
|
|
132
|
+
"nature": "https://images.pexels.com/photos/2387873/pexels-photo-2387873.jpeg?auto=compress&cs=tinysrgb&w=1080",
|
|
133
|
+
"technology": "https://images.pexels.com/photos/3568520/pexels-photo-3568520.jpeg?auto=compress&cs=tinysrgb&w=1080",
|
|
134
|
+
"business": "https://images.pexels.com/photos/3184292/pexels-photo-3184292.jpeg?auto=compress&cs=tinysrgb&w=1080",
|
|
135
|
+
}
|
|
136
|
+
url = theme_urls.get(theme, theme_urls["abstract"])
|
|
137
|
+
print(f"✓ 主题封面URL ({theme}): {url}")
|
|
138
|
+
return url
|
|
139
|
+
|
|
140
|
+
|
|
122
141
|
def download_and_process_cover(cover_url, output_dir):
|
|
123
|
-
"""
|
|
142
|
+
"""从主题贴图URL下载并处理为 900x500 公众号封面 + 600px 文章封面"""
|
|
124
143
|
from PIL import Image
|
|
125
144
|
|
|
126
145
|
ctx = ssl.create_default_context()
|
|
@@ -131,10 +150,11 @@ def download_and_process_cover(cover_url, output_dir):
|
|
|
131
150
|
data = urllib.request.urlopen(req, context=ctx, timeout=15).read()
|
|
132
151
|
|
|
133
152
|
os.makedirs(output_dir, exist_ok=True)
|
|
134
|
-
original_path = os.path.join(output_dir, "
|
|
153
|
+
original_path = os.path.join(output_dir, "theme_cover_original.jpg")
|
|
135
154
|
with open(original_path, "wb") as f:
|
|
136
155
|
f.write(data)
|
|
137
156
|
|
|
157
|
+
# 文章内配图(600px 宽)
|
|
138
158
|
img = Image.open(original_path)
|
|
139
159
|
w, h = img.size
|
|
140
160
|
if w > 600:
|
|
@@ -142,10 +162,40 @@ def download_and_process_cover(cover_url, output_dir):
|
|
|
142
162
|
new_w = 600
|
|
143
163
|
new_h = int(h * ratio)
|
|
144
164
|
img = img.resize((new_w, new_h), Image.LANCZOS)
|
|
165
|
+
img.save(os.path.join(output_dir, "theme_cover_600.jpg"), "JPEG", quality=90)
|
|
145
166
|
|
|
146
|
-
|
|
147
|
-
|
|
167
|
+
# 公众号封面(900x500)
|
|
168
|
+
img2 = Image.open(original_path)
|
|
169
|
+
w, h = img2.size
|
|
170
|
+
target_ratio = 900 / 500
|
|
171
|
+
if w / h > target_ratio:
|
|
172
|
+
new_w = int(h * target_ratio)
|
|
173
|
+
left = (w - new_w) // 2
|
|
174
|
+
img2 = img2.crop((left, 0, left + new_w, h))
|
|
175
|
+
else:
|
|
176
|
+
new_h = int(w / target_ratio)
|
|
177
|
+
top = (h - new_h) // 2
|
|
178
|
+
img2 = img2.crop((0, top, w, top + new_h))
|
|
179
|
+
img2 = img2.resize((900, 500), Image.LANCZOS)
|
|
180
|
+
cover_900_path = os.path.join(output_dir, "cover_900x500.jpg")
|
|
181
|
+
img2.save(cover_900_path, "JPEG", quality=90)
|
|
148
182
|
|
|
183
|
+
print(f"✓ 主题封面已保存: theme_cover_600.jpg")
|
|
184
|
+
print(f"✓ 公众号封面已保存: {cover_900_path}")
|
|
185
|
+
|
|
186
|
+
return os.path.join(output_dir, "theme_cover_600.jpg"), cover_900_path
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def crop_cover_from_local(source_path, output_dir):
|
|
190
|
+
"""从本地主题贴图裁剪为 900x500 公众号封面(用于已有主题图但缺封面图的情况)"""
|
|
191
|
+
from PIL import Image
|
|
192
|
+
|
|
193
|
+
if not os.path.exists(source_path):
|
|
194
|
+
print(f"错误: 源图不存在 {source_path}", file=sys.stderr)
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
198
|
+
img = Image.open(source_path)
|
|
149
199
|
w, h = img.size
|
|
150
200
|
target_ratio = 900 / 500
|
|
151
201
|
if w / h > target_ratio:
|
|
@@ -160,11 +210,10 @@ def download_and_process_cover(cover_url, output_dir):
|
|
|
160
210
|
|
|
161
211
|
cover_900_path = os.path.join(output_dir, "cover_900x500.jpg")
|
|
162
212
|
img.save(cover_900_path, "JPEG", quality=90)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return cover_path, cover_900_path
|
|
213
|
+
print(
|
|
214
|
+
f"✓ 公众号封面已生成(基于 {os.path.basename(source_path)}): {cover_900_path}"
|
|
215
|
+
)
|
|
216
|
+
return cover_900_path
|
|
168
217
|
|
|
169
218
|
|
|
170
219
|
if __name__ == "__main__":
|
package/scripts/publish.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
3
|
微信公众号读书拆解发布脚本
|
|
4
|
-
|
|
4
|
+
完整流程:准备主题贴图 -> 裁剪公众号封面 -> 上传图片 -> 创建草稿
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import argparse
|
|
@@ -12,7 +12,7 @@ import sys
|
|
|
12
12
|
# 添加当前目录到模块搜索路径
|
|
13
13
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
14
14
|
|
|
15
|
-
from book_cover import
|
|
15
|
+
from book_cover import crop_cover_from_local, fetch_theme_cover
|
|
16
16
|
from image_downloader import download_theme_images
|
|
17
17
|
from wechat_api import (
|
|
18
18
|
load_config,
|
|
@@ -23,34 +23,12 @@ from wechat_api import (
|
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def
|
|
27
|
-
"""
|
|
28
|
-
cover_900_path = os.path.join(cover_dir, "cover_900x500.jpg")
|
|
29
|
-
book_cover_path = os.path.join(cover_dir, "book_cover.jpg")
|
|
30
|
-
|
|
31
|
-
if os.path.exists(cover_900_path) and os.path.exists(book_cover_path):
|
|
32
|
-
print("✓ 封面图已存在,跳过获取")
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
if not book_title:
|
|
36
|
-
print(
|
|
37
|
-
f"⚠️ 缺少封面图且未提供 --book-title,无法自动获取。\n"
|
|
38
|
-
f" 期望路径: {cover_900_path}",
|
|
39
|
-
file=sys.stderr,
|
|
40
|
-
)
|
|
41
|
-
sys.exit(1)
|
|
26
|
+
def ensure_theme_images(cover_dir, theme="abstract", count=6):
|
|
27
|
+
"""确保主题插图存在,缺失则自动下载
|
|
42
28
|
|
|
43
|
-
|
|
29
|
+
默认 6 张:用于正文穿插(5 张)+ 结尾页(1 张)= 6 张
|
|
30
|
+
"""
|
|
44
31
|
os.makedirs(cover_dir, exist_ok=True)
|
|
45
|
-
cover_url = fetch_book_cover(book_title, book_author, book_isbn)
|
|
46
|
-
if not cover_url:
|
|
47
|
-
print("错误: 无法获取书籍封面URL", file=sys.stderr)
|
|
48
|
-
sys.exit(1)
|
|
49
|
-
download_and_process_cover(cover_url, cover_dir)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def ensure_theme_images(cover_dir, theme="abstract", count=5):
|
|
53
|
-
"""确保主题插图存在,缺失则自动下载"""
|
|
54
32
|
existing = [
|
|
55
33
|
f
|
|
56
34
|
for f in os.listdir(cover_dir)
|
|
@@ -64,6 +42,32 @@ def ensure_theme_images(cover_dir, theme="abstract", count=5):
|
|
|
64
42
|
download_theme_images(theme, cover_dir, count)
|
|
65
43
|
|
|
66
44
|
|
|
45
|
+
def ensure_cover_image(cover_dir, theme="abstract"):
|
|
46
|
+
"""确保公众号封面(900x500)存在,缺失则从主题图裁剪"""
|
|
47
|
+
cover_900_path = os.path.join(cover_dir, "cover_900x500.jpg")
|
|
48
|
+
if os.path.exists(cover_900_path):
|
|
49
|
+
print("✓ 公众号封面已存在,跳过裁剪")
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
# 优先用本地第一张主题图裁剪;否则从主题URL下载
|
|
53
|
+
candidates = sorted(
|
|
54
|
+
[
|
|
55
|
+
f
|
|
56
|
+
for f in os.listdir(cover_dir)
|
|
57
|
+
if f.startswith("img_") and f.endswith((".jpg", ".jpeg", ".png"))
|
|
58
|
+
]
|
|
59
|
+
)
|
|
60
|
+
if candidates:
|
|
61
|
+
crop_cover_from_local(os.path.join(cover_dir, candidates[0]), cover_dir)
|
|
62
|
+
else:
|
|
63
|
+
# 极少见:连主题图都没有的情况
|
|
64
|
+
print("主题图与封面均缺失,从网络拉取主题封面...")
|
|
65
|
+
from book_cover import download_and_process_cover
|
|
66
|
+
|
|
67
|
+
url = fetch_theme_cover(theme)
|
|
68
|
+
download_and_process_cover(url, cover_dir)
|
|
69
|
+
|
|
70
|
+
|
|
67
71
|
def publish_article(
|
|
68
72
|
title,
|
|
69
73
|
author,
|
|
@@ -71,41 +75,38 @@ def publish_article(
|
|
|
71
75
|
content_html,
|
|
72
76
|
cover_dir,
|
|
73
77
|
theme="abstract",
|
|
74
|
-
image_count=
|
|
75
|
-
book_title="",
|
|
76
|
-
book_author="",
|
|
77
|
-
book_isbn="",
|
|
78
|
+
image_count=6,
|
|
78
79
|
):
|
|
79
|
-
"""
|
|
80
|
+
"""完整发布流程:准备主题贴图 -> 裁剪公众号封面 -> 上传图片 -> 创建草稿"""
|
|
80
81
|
print("=" * 50)
|
|
81
82
|
print("微信公众号 - 书评发布")
|
|
82
83
|
print("=" * 50)
|
|
83
84
|
|
|
84
85
|
os.makedirs(cover_dir, exist_ok=True)
|
|
85
86
|
|
|
86
|
-
# 1.
|
|
87
|
-
print("\n[1/4]
|
|
88
|
-
ensure_book_cover(cover_dir, book_title, book_author, book_isbn)
|
|
89
|
-
|
|
90
|
-
# 2. 确保主题插图存在
|
|
91
|
-
print("\n[2/4] 准备主题插图...")
|
|
87
|
+
# 1. 准备主题贴图
|
|
88
|
+
print("\n[1/4] 准备主题贴图...")
|
|
92
89
|
ensure_theme_images(cover_dir, theme, image_count)
|
|
93
90
|
|
|
94
|
-
#
|
|
91
|
+
# 2. 准备公众号封面(900x500)
|
|
92
|
+
print("\n[2/4] 准备公众号封面...")
|
|
93
|
+
ensure_cover_image(cover_dir, theme)
|
|
94
|
+
|
|
95
|
+
# 3. 加载配置和获取 token
|
|
95
96
|
config = load_config()
|
|
96
97
|
token = get_access_token(config)
|
|
97
98
|
print("\n✓ Token 已获取\n")
|
|
98
99
|
|
|
99
|
-
# 4.
|
|
100
|
+
# 4. 上传公众号封面
|
|
100
101
|
cover_900_path = os.path.join(cover_dir, "cover_900x500.jpg")
|
|
101
102
|
if not os.path.exists(cover_900_path):
|
|
102
103
|
print(f"错误: 封面图不存在 {cover_900_path}", file=sys.stderr)
|
|
103
104
|
sys.exit(1)
|
|
104
105
|
|
|
105
|
-
print("
|
|
106
|
+
print("上传公众号封面...")
|
|
106
107
|
cover_mid = upload_cover(token, cover_900_path)
|
|
107
108
|
|
|
108
|
-
# 5.
|
|
109
|
+
# 5. 上传内容图片(img_*.jpg)
|
|
109
110
|
print("\n上传内容图片...")
|
|
110
111
|
image_urls = {}
|
|
111
112
|
for fname in sorted(os.listdir(cover_dir)):
|
|
@@ -116,14 +117,7 @@ def publish_article(
|
|
|
116
117
|
name = os.path.splitext(fname)[0]
|
|
117
118
|
image_urls[name] = url
|
|
118
119
|
|
|
119
|
-
# 6.
|
|
120
|
-
book_cover_path = os.path.join(cover_dir, "book_cover.jpg")
|
|
121
|
-
if os.path.exists(book_cover_path):
|
|
122
|
-
book_cover_url = upload_content_image(token, book_cover_path)
|
|
123
|
-
if book_cover_url:
|
|
124
|
-
image_urls["book_cover"] = book_cover_url
|
|
125
|
-
|
|
126
|
-
# 7. 保存上传结果
|
|
120
|
+
# 6. 保存上传结果
|
|
127
121
|
result_path = os.path.join(cover_dir, "upload_result.json")
|
|
128
122
|
with open(result_path, "w") as f:
|
|
129
123
|
json.dump(
|
|
@@ -137,7 +131,7 @@ def publish_article(
|
|
|
137
131
|
)
|
|
138
132
|
print(f"\n✓ 上传结果已保存: {result_path}")
|
|
139
133
|
|
|
140
|
-
#
|
|
134
|
+
# 7. 创建草稿
|
|
141
135
|
print("\n创建草稿...")
|
|
142
136
|
draft_id = create_draft(token, title, author, digest, content_html, cover_mid)
|
|
143
137
|
|
|
@@ -161,10 +155,9 @@ def main():
|
|
|
161
155
|
parser.add_argument("--content-file", required=True, help="HTML内容文件路径")
|
|
162
156
|
parser.add_argument("--cover-dir", required=True, help="封面和图片目录")
|
|
163
157
|
parser.add_argument("--theme", default="abstract", help="图片主题")
|
|
164
|
-
parser.add_argument(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
parser.add_argument("--book-isbn", default="", help="书籍ISBN")
|
|
158
|
+
parser.add_argument(
|
|
159
|
+
"--image-count", type=int, default=6, help="主题插图数量(默认6:5正文+1结尾)"
|
|
160
|
+
)
|
|
168
161
|
args = parser.parse_args()
|
|
169
162
|
|
|
170
163
|
with open(args.content_file, "r", encoding="utf-8") as f:
|
|
@@ -178,9 +171,6 @@ def main():
|
|
|
178
171
|
args.cover_dir,
|
|
179
172
|
args.theme,
|
|
180
173
|
args.image_count,
|
|
181
|
-
args.book_title,
|
|
182
|
-
args.book_author,
|
|
183
|
-
args.book_isbn,
|
|
184
174
|
)
|
|
185
175
|
|
|
186
176
|
|