wechat-media-writer 2.2.8 → 2.2.10
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/README.md +2 -4
- package/SKILL.md +5 -4
- package/package.json +1 -2
- package/scripts/image_downloader.py +32 -12
- package/scripts/publish.py +7 -1
- package/references/publish_template.py +0 -248
package/README.md
CHANGED
|
@@ -122,12 +122,10 @@ wechat-media-writer/
|
|
|
122
122
|
│ └── cli.js # CLI 入口
|
|
123
123
|
├── scripts/
|
|
124
124
|
│ ├── book_cover.py # 书籍封面获取
|
|
125
|
-
│ ├── image_downloader.py #
|
|
125
|
+
│ ├── image_downloader.py # 主题插图下载(含美学评分挑选封面)
|
|
126
126
|
│ ├── wechat_api.py # 微信 API 封装(token/上传/草稿)
|
|
127
127
|
│ ├── publish.py # 一键发布主脚本(含封面/插图自动补齐)
|
|
128
|
-
│ └── install.js # npm postinstall(检查 Python/Pillow)
|
|
129
|
-
└── references/
|
|
130
|
-
└── publish_template.py # 发布脚本模板
|
|
128
|
+
│ └── install.js # npm postinstall(检查 Python/Pillow + 注册 Skill)
|
|
131
129
|
```
|
|
132
130
|
|
|
133
131
|
## 发布到 npm
|
package/SKILL.md
CHANGED
|
@@ -140,7 +140,7 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
|
|
|
140
140
|
|
|
141
141
|
<!-- 主题配图(第一张图,使用主题贴图,非书籍原图) -->
|
|
142
142
|
<p style="margin:0 0 20px;text-align:center;">
|
|
143
|
-
<img src="{THEME_IMG_1}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="
|
|
143
|
+
<img src="{THEME_IMG_1}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="" />
|
|
144
144
|
</p>
|
|
145
145
|
|
|
146
146
|
<!-- 章节(无数字编号,直接标题) -->
|
|
@@ -153,7 +153,7 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
|
|
|
153
153
|
|
|
154
154
|
<!-- 主题配图(章节间穿插,与文风统一) -->
|
|
155
155
|
<p style="margin:0 0 20px;text-align:center;">
|
|
156
|
-
<img src="{THEME_IMG_2}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="
|
|
156
|
+
<img src="{THEME_IMG_2}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="" />
|
|
157
157
|
</p>
|
|
158
158
|
|
|
159
159
|
<!-- 金句引用块(圆角浅背景,无左侧竖条) -->
|
|
@@ -170,7 +170,7 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
|
|
|
170
170
|
|
|
171
171
|
<!-- 主题配图(章节中段) -->
|
|
172
172
|
<p style="margin:0 0 20px;text-align:center;">
|
|
173
|
-
<img src="{THEME_IMG_3}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="
|
|
173
|
+
<img src="{THEME_IMG_3}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="" />
|
|
174
174
|
</p>
|
|
175
175
|
|
|
176
176
|
<!-- 分隔符(章节之间) -->
|
|
@@ -383,7 +383,7 @@ python3 scripts/publish.py --title "标题" --content-file content.html --cover-
|
|
|
383
383
|
|
|
384
384
|
<!-- 结尾页(与正文风格延续,使用主题色) -->
|
|
385
385
|
<p style="margin:0 0 16px;text-align:center;">
|
|
386
|
-
<img src="{THEME_IMG_END}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="
|
|
386
|
+
<img src="{THEME_IMG_END}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="" />
|
|
387
387
|
</p>
|
|
388
388
|
|
|
389
389
|
<p style="font-size:14px;color:#ccc;text-align:center;letter-spacing:8px;margin:24px 0 16px;">· · · · · ·</p>
|
|
@@ -397,6 +397,7 @@ python3 scripts/publish.py --title "标题" --content-file content.html --cover-
|
|
|
397
397
|
<p style="font-size:14px;color:{T2};text-align:center;margin:0 0 4px;line-height:1.8;font-weight:bold;">
|
|
398
398
|
<span>「 一句话总结:核心洞察 」</span>
|
|
399
399
|
</p>
|
|
400
|
+
<p style="text-align:center;margin:24px 0 0;color:#ccc;">· END ·</p>
|
|
400
401
|
```
|
|
401
402
|
|
|
402
403
|
### 评分格式要求
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wechat-media-writer",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.10",
|
|
4
4
|
"description": "微信公众号书评、影评文章自动生成与发布 - Skill",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
11
|
"scripts/",
|
|
12
|
-
"references/",
|
|
13
12
|
"SKILL.md",
|
|
14
13
|
"README.md"
|
|
15
14
|
],
|
|
@@ -74,22 +74,35 @@ THEME_CANDIDATES = {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
def download_image(url, output_path):
|
|
78
|
-
"""
|
|
77
|
+
def download_image(url, output_path, retries=3, retry_delay=1):
|
|
78
|
+
"""下载图片到指定路径,带重试机制"""
|
|
79
|
+
import time
|
|
80
|
+
|
|
79
81
|
ctx = ssl.create_default_context()
|
|
80
82
|
ctx.check_hostname = False
|
|
81
83
|
ctx.verify_mode = ssl.CERT_NONE
|
|
82
84
|
|
|
83
85
|
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
87
|
+
|
|
88
|
+
for attempt in range(1, retries + 1):
|
|
89
|
+
try:
|
|
90
|
+
data = urllib.request.urlopen(req, context=ctx, timeout=20).read()
|
|
91
|
+
# 验证下载到的是真实图片(> 5KB 且 magic bytes 正确)
|
|
92
|
+
if len(data) < 5000:
|
|
93
|
+
raise ValueError(f"下载文件过小: {len(data)} bytes")
|
|
94
|
+
if not data[:3] in (b"\xff\xd8\xff", b"\x89PN", b"GIF"):
|
|
95
|
+
raise ValueError(f"非图片格式: {data[:8]!r}")
|
|
96
|
+
with open(output_path, "wb") as f:
|
|
97
|
+
f.write(data)
|
|
98
|
+
return True
|
|
99
|
+
except Exception as e:
|
|
100
|
+
if attempt < retries:
|
|
101
|
+
time.sleep(retry_delay * attempt)
|
|
102
|
+
continue
|
|
103
|
+
print(f"下载失败(重试 {retries} 次后放弃): {e}")
|
|
104
|
+
return False
|
|
105
|
+
return False
|
|
93
106
|
|
|
94
107
|
|
|
95
108
|
def download_pexels_image(pid, output_path, w=1200):
|
|
@@ -154,12 +167,14 @@ def aesthetics_score(image_path):
|
|
|
154
167
|
def download_theme_images(theme, output_dir, count=6):
|
|
155
168
|
"""根据主题下载多张精美图片
|
|
156
169
|
|
|
157
|
-
自动跳过 404
|
|
170
|
+
自动跳过 404/失败候选(带 3 次重试),下载到临时文件名,
|
|
171
|
+
再按美学评分重命名为 img_1.jpg ~ img_N.jpg
|
|
158
172
|
返回: 已下载图片路径列表(按美学评分降序)
|
|
159
173
|
"""
|
|
160
174
|
os.makedirs(output_dir, exist_ok=True)
|
|
161
175
|
candidates = THEME_CANDIDATES.get(theme, THEME_CANDIDATES["books"])
|
|
162
176
|
downloaded = [] # 临时文件列表
|
|
177
|
+
failed_pids = []
|
|
163
178
|
|
|
164
179
|
# 1) 全部下载到临时文件
|
|
165
180
|
for i, pid in enumerate(candidates):
|
|
@@ -168,8 +183,13 @@ def download_theme_images(theme, output_dir, count=6):
|
|
|
168
183
|
tmp_path = os.path.join(output_dir, f"_tmp_{theme}_{i}_{pid}.jpg")
|
|
169
184
|
if download_pexels_image(pid, tmp_path):
|
|
170
185
|
downloaded.append(tmp_path)
|
|
186
|
+
else:
|
|
187
|
+
failed_pids.append(pid)
|
|
171
188
|
|
|
189
|
+
if failed_pids:
|
|
190
|
+
print(f" ⚠️ 候选 {failed_pids} 下载失败(共 {len(failed_pids)} 张)")
|
|
172
191
|
if not downloaded:
|
|
192
|
+
print(f" ❌ 主题 {theme} 所有候选图下载失败")
|
|
173
193
|
return []
|
|
174
194
|
|
|
175
195
|
# 2) 按美学评分排序
|
package/scripts/publish.py
CHANGED
|
@@ -40,7 +40,13 @@ def ensure_theme_images(cover_dir, theme="books", count=6):
|
|
|
40
40
|
return
|
|
41
41
|
|
|
42
42
|
print(f"主题插图不足,自动下载 {count} 张(主题: {theme})...")
|
|
43
|
-
download_theme_images(theme, cover_dir, count)
|
|
43
|
+
result = download_theme_images(theme, cover_dir, count)
|
|
44
|
+
|
|
45
|
+
if len(result) < count:
|
|
46
|
+
print(
|
|
47
|
+
f"⚠️ 实际下载 {len(result)}/{count} 张,建议换其他主题或重试",
|
|
48
|
+
file=sys.stderr,
|
|
49
|
+
)
|
|
44
50
|
|
|
45
51
|
|
|
46
52
|
def ensure_cover_image(cover_dir):
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
微信公众号读书拆解发布脚本模板
|
|
4
|
-
使用 scripts/ 目录下的模块
|
|
5
|
-
|
|
6
|
-
用法:
|
|
7
|
-
1. 填写下方的变量(标题、摘要、HTML内容等)
|
|
8
|
-
2. 确保封面图已准备好(使用 scripts/image_downloader.py 下载主题贴图)
|
|
9
|
-
3. 运行: python3 references/publish_template.py
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import os
|
|
13
|
-
import sys
|
|
14
|
-
|
|
15
|
-
scripts_dir = os.path.join(
|
|
16
|
-
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scripts"
|
|
17
|
-
)
|
|
18
|
-
sys.path.insert(0, scripts_dir)
|
|
19
|
-
|
|
20
|
-
from wechat_api import load_config, get_access_token, upload_cover, create_draft
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# ========== 替换以下内容 ==========
|
|
24
|
-
|
|
25
|
-
TITLE = "《书名》全书深度拆解:犀利洞察"
|
|
26
|
-
AUTHOR = "读书笔记"
|
|
27
|
-
DIGEST = "摘要文本,不超过120字。"
|
|
28
|
-
|
|
29
|
-
# 封面图目录(包含 cover_900x500.jpg + img_*.jpg 主题贴图)
|
|
30
|
-
COVER_DIR = "/tmp/book_output"
|
|
31
|
-
|
|
32
|
-
# 主题色:主色(深色)+ 强调色(暖/亮色)
|
|
33
|
-
T = "#2E5266" # 主色
|
|
34
|
-
T2 = "#D4A24C" # 强调色
|
|
35
|
-
BODY = "#555" # 正文色
|
|
36
|
-
CBG = "#F0EDE5" # 引用块背景
|
|
37
|
-
|
|
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段式,无数字编号,全文主题贴图穿插)
|
|
48
|
-
HTML = f"""<section style="margin:0;padding:0 0 48px;font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;color:#333;background:#FBF8FC;">
|
|
49
|
-
|
|
50
|
-
<p style="font-size:12px;color:{T2};text-align:center;letter-spacing:4px;margin:24px 0 8px;line-height:3em;">
|
|
51
|
-
<span>📖 读书拆解</span>
|
|
52
|
-
</p>
|
|
53
|
-
|
|
54
|
-
<p style="font-size:22px;font-weight:bold;color:{T};text-align:center;margin:0 0 6px;line-height:1.5;">
|
|
55
|
-
<span>《书名》全书深度拆解</span>
|
|
56
|
-
</p>
|
|
57
|
-
|
|
58
|
-
<p style="font-size:14px;color:#999;text-align:center;margin:0 0 20px;line-height:3em;">
|
|
59
|
-
<span>副标题(一句话点睛)</span>
|
|
60
|
-
</p>
|
|
61
|
-
|
|
62
|
-
<!-- 主题配图1(头部) -->
|
|
63
|
-
<p style="margin:0 0 20px;text-align:center;">
|
|
64
|
-
<img src="{THEME_IMG_1}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
65
|
-
</p>
|
|
66
|
-
|
|
67
|
-
<!-- 先搞懂写书的这个人 -->
|
|
68
|
-
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
69
|
-
<span>先搞懂写书的这个人</span>
|
|
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:16px 20px;background:{CBG};border-radius:8px;">
|
|
82
|
-
<span>金句或核心观点。整段用主题主色加粗,圆角浅背景与正文形成视觉对比。</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>
|
|
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>
|
|
121
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
122
|
-
<span>短板一:客观指出书中局限。<br/>短板二:逻辑漏洞分析。<br/>短板三:适用边界。<br/>短板四:时代局限。</span>
|
|
123
|
-
</p>
|
|
124
|
-
|
|
125
|
-
<!-- 金句二 -->
|
|
126
|
-
<p style="font-size:17px;line-height:1.9;color:{T};font-weight:bold;text-indent:2em;margin:0 0 20px;padding:16px 20px;background:{CBG};border-radius:8px;">
|
|
127
|
-
<span>第二个金句或关键启发。</span>
|
|
128
|
-
</p>
|
|
129
|
-
|
|
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>
|
|
150
|
-
|
|
151
|
-
<p style="font-size:14px;color:#ccc;text-align:center;letter-spacing:8px;margin:20px 0;">· · · · · ·</p>
|
|
152
|
-
|
|
153
|
-
<!-- 值不值得花时间读 -->
|
|
154
|
-
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
|
|
155
|
-
<span>值不值得花时间读</span>
|
|
156
|
-
</p>
|
|
157
|
-
|
|
158
|
-
<p style="font-size:28px;text-align:center;margin:0 0 8px;">
|
|
159
|
-
<span style="color:{T2};">★★★★☆</span>
|
|
160
|
-
</p>
|
|
161
|
-
|
|
162
|
-
<p style="font-size:16px;color:{BODY};text-align:center;margin:0 0 16px;">
|
|
163
|
-
<span>4 / 5 星</span>
|
|
164
|
-
</p>
|
|
165
|
-
|
|
166
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
|
|
167
|
-
<span>为什么给X星?简要说明评分理由,诚实评价,3-4星是常态,5星极少。</span>
|
|
168
|
-
</p>
|
|
169
|
-
|
|
170
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;text-indent:2em;">
|
|
171
|
-
<strong style="color:{T};">适合人群:</strong>
|
|
172
|
-
</p>
|
|
173
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;padding-left:2em;">
|
|
174
|
-
<span>✅ 创业者/管理者——理解系统脆弱性和反脆弱设计</span>
|
|
175
|
-
</p>
|
|
176
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;padding-left:2em;">
|
|
177
|
-
<span>✅ 对个人成长感兴趣的读者——掌握从压力中受益的方法</span>
|
|
178
|
-
</p>
|
|
179
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;padding-left:2em;">
|
|
180
|
-
<span>✅ 对决策科学感兴趣的读者——理解非线性风险的本质</span>
|
|
181
|
-
</p>
|
|
182
|
-
|
|
183
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;text-indent:2em;">
|
|
184
|
-
<strong style="color:{T};">不适合人群:</strong>
|
|
185
|
-
</p>
|
|
186
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;padding-left:2em;">
|
|
187
|
-
<span>🚫 已读过类似书籍的人——内容高度重复</span>
|
|
188
|
-
</p>
|
|
189
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 8px;padding-left:2em;">
|
|
190
|
-
<span>🚫 讨厌抽象论证的人——本书充满概念性思维</span>
|
|
191
|
-
</p>
|
|
192
|
-
<p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 24px;padding-left:2em;">
|
|
193
|
-
<span>🚫 寻找具体操作手册的人——本书偏哲学思辨</span>
|
|
194
|
-
</p>
|
|
195
|
-
|
|
196
|
-
<!-- 结尾页:主题配图 + 书名 + 作者 + 核心总结 -->
|
|
197
|
-
<p style="margin:0 0 16px;text-align:center;">
|
|
198
|
-
<img src="{THEME_IMG_END}" style="width:100%;max-width:600px;display:block;margin:0 auto;border-radius:4px;" alt="主题配图"/>
|
|
199
|
-
</p>
|
|
200
|
-
|
|
201
|
-
<p style="font-size:14px;color:#ccc;text-align:center;letter-spacing:8px;margin:24px 0 16px;">· · · · · ·</p>
|
|
202
|
-
|
|
203
|
-
<p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 8px;line-height:1.6;">
|
|
204
|
-
<span>📖 《书名》</span>
|
|
205
|
-
</p>
|
|
206
|
-
<p style="font-size:14px;color:{BODY};text-align:center;margin:0 0 4px;line-height:1.6;">
|
|
207
|
-
<span>作者 · 读书笔记</span>
|
|
208
|
-
</p>
|
|
209
|
-
<p style="font-size:14px;color:{T2};text-align:center;margin:8px 0 32px;line-height:1.8;font-weight:bold;">
|
|
210
|
-
<span>「 一句话总结:核心洞察 」</span>
|
|
211
|
-
</p>
|
|
212
|
-
|
|
213
|
-
</section>"""
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def main():
|
|
217
|
-
print("=" * 50)
|
|
218
|
-
print("微信公众号 - 书名 发布")
|
|
219
|
-
print("=" * 50)
|
|
220
|
-
|
|
221
|
-
config = load_config()
|
|
222
|
-
token = get_access_token(config)
|
|
223
|
-
print("\n✓ Token 已获取\n")
|
|
224
|
-
|
|
225
|
-
cover_900_path = os.path.join(COVER_DIR, "cover_900x500.jpg")
|
|
226
|
-
if not os.path.exists(cover_900_path):
|
|
227
|
-
print(f"错误: 封面图不存在 {cover_900_path}", file=sys.stderr)
|
|
228
|
-
print("请先运行主题贴图下载与封面裁剪流程", file=sys.stderr)
|
|
229
|
-
sys.exit(1)
|
|
230
|
-
|
|
231
|
-
print("上传封面图...")
|
|
232
|
-
cover_mid = upload_cover(token, cover_900_path)
|
|
233
|
-
|
|
234
|
-
print("\n创建草稿...")
|
|
235
|
-
draft_id = create_draft(token, TITLE, AUTHOR, DIGEST, HTML, cover_mid)
|
|
236
|
-
|
|
237
|
-
print("\n" + "=" * 50)
|
|
238
|
-
print("发布成功!")
|
|
239
|
-
print("=" * 50)
|
|
240
|
-
print(f"标题: {TITLE}")
|
|
241
|
-
print(f"作者: {AUTHOR}")
|
|
242
|
-
print(f"草稿ID: {draft_id}")
|
|
243
|
-
print(f"\n请前往微信公众平台查看草稿:")
|
|
244
|
-
print(f"https://mp.weixin.qq.com")
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if __name__ == "__main__":
|
|
248
|
-
main()
|