wechat-media-writer 2.2.11 → 2.2.13

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 CHANGED
@@ -145,7 +145,7 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
145
145
 
146
146
  <!-- 章节(无数字编号,直接标题) -->
147
147
  <p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
148
- <span>作者背景与创作时代</span>
148
+ <span>先搞懂写书的这个人</span>
149
149
  </p>
150
150
  <p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
151
151
  <span>正文段落。所有段落必须有 text-indent:2em。</span>
@@ -185,7 +185,7 @@ Token 缓存在 `~/.wechat/token_cache.json`(自动管理,2小时有效期
185
185
  3. **`<img>` 必须包裹在 `<p>` 中**,且 `style="width:100%;display:block;border-radius:4px;"`
186
186
  4. **行高统一 `line-height:2`** — 阅读舒适
187
187
  5. **引用块用 `<p>` + `background` + `border-radius:8px`** — 圆角浅背景卡片样式,不要左侧竖条
188
- 6. **章节标题不使用数字编号** — 直接用"作者背景与创作时代",不用"壹"
188
+ 6. **章节标题不使用数字编号** — 直接用"先搞懂写书的这个人",不用"壹"
189
189
  7. **强调文字用 `<strong style="color:{T};">`** — 不是加粗或改色
190
190
  8. **重点语句/概念高亮**:用 `<strong style="color:{T};background:{CBG};padding:1px 6px;border-radius:3px;">` 或 `<span style="color:{T2};font-weight:bold;">` — 让主题色贯穿全文
191
191
  9. **星标用 `<span>★★★★☆</span>`** — `font-size:28px;color:{T2}`
@@ -219,11 +219,22 @@ urls = download_theme_images("books", "/tmp/images", count=6)
219
219
  3. **分辨率**:宽高乘积
220
220
  4. **色彩多样性**:RGB 通道差值(避免纯灰/单色图)
221
221
 
222
- 下载 6 张主题图后会自动按美学评分降序重命名为 `img_1.jpg` ~ `img_6.jpg`,
222
+ ### 内容图比例要求
223
+
224
+ 公众号正文配图应使用**横向图**(宽 > 高),与微信文章阅读体验最佳:
225
+
226
+ | 优先级 | 比例 | 备注 |
227
+ | --- | --- | --- |
228
+ | ⭐⭐⭐ 优先 | 4:3 (1.33) | 视觉最舒适,公众号默认容器适配 |
229
+ | ⭐⭐ 次选 | 3:2 (1.50) | 经典相机比例,普适性强 |
230
+ | ⭐ 备选 | 16:9 (1.78) | 偏宽,电影感 |
231
+ | ❌ 避免 | 竖向 (h > w) | 微信展示高度 > 600px 显突兀 |
232
+
233
+ 下载时会自动跳过竖向图和比例异常的候选。下载 6 张主题图后会自动按美学评分降序重命名为 `img_1.jpg` ~ `img_6.jpg`,
223
234
  其中 `img_1.jpg` 就是评分最高的,被 `pick_best_cover()` 选中裁剪为 900x500 封面。
224
235
 
225
236
  **支持的主题**:`abstract` / `books` / `nature` / `technology` / `business`
226
- 每个主题预存 8 张精选 Pexels 候选(见 `THEME_CANDIDATES`),实地测试可用率 100%。
237
+ 每个主题预存 8 张精选 Pexels 候选(见 `THEME_CANDIDATES`),按 4:3 > 3:2 > 16:9 优先级排序。
227
238
 
228
239
  ### 第三步:上传图片到微信
229
240
 
@@ -344,7 +355,7 @@ python3 scripts/publish.py --title "标题" --content-file content.html --cover-
344
355
  | 星级评分 | 400-500 |
345
356
  | **总计** | **4000-6000** |
346
357
 
347
- ## 星级评分与适配人群排版规范
358
+ ## 值不值得花时间读排版规范
348
359
 
349
360
  星级评分部分必须按照以下格式排版,**不使用壹贰叁编号**:
350
361
 
@@ -352,15 +363,16 @@ python3 scripts/publish.py --title "标题" --content-file content.html --cover-
352
363
  <p style="font-size:14px;color:#ccc;text-align:center;letter-spacing:8px;margin:20px 0;">· · · · · ·</p>
353
364
 
354
365
  <p style="font-size:18px;font-weight:bold;color:{T};text-align:center;margin:0 0 16px;line-height:1em;">
355
- <span>星级评分与适配人群</span>
366
+ <span>值不值得花时间读</span>
356
367
  </p>
357
368
 
369
+ <!-- 星级评分(支持 0.1 精度:用透明度表达小数部分,0.3 倍 = 0.7 星) -->
358
370
  <p style="font-size:28px;text-align:center;margin:0 0 8px;">
359
- <span style="color:{T2};">★★★★☆</span>
371
+ <span style="color:{T2};">★</span><span style="color:{T2};">★</span><span style="color:{T2};">★</span><span style="color:{T2};">★</span><span style="color:{T2};opacity:0.3;">★</span>
360
372
  </p>
361
373
 
362
374
  <p style="font-size:16px;color:{BODY};text-align:center;margin:0 0 16px;">
363
- <span>4 / 5 星</span>
375
+ <span>4.7 / 5 星</span>
364
376
  </p>
365
377
 
366
378
  <p style="font-size:16px;line-height:2;color:{BODY};margin:0 0 16px;text-indent:2em;">
@@ -394,10 +406,13 @@ python3 scripts/publish.py --title "标题" --content-file content.html --cover-
394
406
  <p style="font-size:14px;color:{BODY};text-align:center;margin:0 0 4px;line-height:1.6;">
395
407
  <span>作者 · 读书笔记</span>
396
408
  </p>
397
- <p style="font-size:14px;color:{T2};text-align:center;margin:0 0 4px;line-height:1.8;font-weight:bold;">
409
+ <p style="font-size:14px;color:{T2};text-align:center;margin:0 0 24px;line-height:1.8;font-weight:bold;">
398
410
  <span>「 一句话总结:核心洞察 」</span>
399
411
  </p>
400
- <p style="text-align:center;margin:24px 0 0;color:#ccc;">· END ·</p>
412
+ <p style="font-size:13px;color:#999;text-align:center;margin:16px 0 24px;letter-spacing:6px;font-weight:bold;">
413
+ <span>— · END · —</span>
414
+ </p>
415
+ <p style="margin:0;height:1px;line-height:1px;">&nbsp;</p>
401
416
  ```
402
417
 
403
418
  ### 评分格式要求
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wechat-media-writer",
3
- "version": "2.2.11",
3
+ "version": "2.2.13",
4
4
  "description": "微信公众号书评、影评文章自动生成与发布 - Skill",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -2,8 +2,8 @@
2
2
  """
3
3
  图片下载模块
4
4
  - 每个主题预存 8-10 张精选 Pexels 候选 ID(已实地测试可用)
5
- - 下载时跳过 404 候选
6
- - 提供 aestheTics_score() 函数评估图片"精美度",便于封面自动挑选
5
+ - 下载时跳过 404 候选,并校验宽高比(优先 4:3 / 3:2 横向图)
6
+ - 提供 aesthetics_score() 函数评估图片"精美度",便于封面自动挑选
7
7
  """
8
8
 
9
9
  import os
@@ -14,20 +14,23 @@ from PIL import Image, ImageStat
14
14
 
15
15
 
16
16
  # 精选 Pexels 候选 ID(每个主题 8-10 张,实地下载验证)
17
- # 选择标准:构图饱满、色彩丰富、主题鲜明、与书评/影评审美契合
17
+ # 选择标准:
18
+ # 1) 比例优先 4:3 (1.33) 其次 3:2 (1.5) 横向构图(宽 > 高)
19
+ # 2) 主题契合(书评/影评主题)
20
+ # 3) 构图饱满、色彩丰富、画面精美
18
21
  THEME_CANDIDATES = {
19
22
  "books": [
20
- # Pexels 搜索"book"结果中精选的高质量图
21
- 415078, # 草地上开本书(封面候选极佳)
22
- 433333, # 书堆黑白(封面候选极佳,构图饱满)
23
- 4861364, # 两人读书
24
- 5913138, # 书+花+咖啡
25
- 6001171, # 床上读书
26
- 7034613, # 书架书+植物
27
- 1792734, # 阳光读书
28
- 11197155, # 古书桌上
29
- 13580974, # 翻开的书页
30
- 904616, # 咖啡+书+花俯拍
23
+ # 横向 3:2 主力 - 已实地下载验证为"读书/书"主题
24
+ 415078, # 3:2 - 草地上开本书(封面候选极佳)
25
+ 904616, # 3:2 - 咖啡+书+花俯拍
26
+ 1319854, # 3:2 - 图书馆书墙(精装)
27
+ 4974915, # 3:2 - 翻书动作
28
+ 2228547, # 3:2 - 翻书
29
+ 1370295, # 3:2 - 开本书
30
+ 2099683, # 16:9 - 翻书动作
31
+ # 已剔除:以下 ID 在 Pexels 搜索结果中出现但主题不契合(风景、人物特写、粉背景等)
32
+ # 4239031 (电脑前背影)、36729918 (粉背景酒杯)、2820896 (街舞)、
33
+ # 1444442 (手部彩绘)、261949 (报纸)、1438072 (笔记本咖啡不够书主题)
31
34
  ],
32
35
  "abstract": [
33
36
  1108572, # 抽象光影
@@ -164,6 +167,30 @@ def aesthetics_score(image_path):
164
167
  return round(total, 2)
165
168
 
166
169
 
170
+ def is_valid_landscape(image_path, min_ratio=1.2, max_ratio=2.0):
171
+ """校验图片是横向图且比例在合理范围
172
+
173
+ 横向比例:1.2 ~ 2.0
174
+ 排除:竖向图、纯单色图(细节过低)
175
+ """
176
+ try:
177
+ img = Image.open(image_path)
178
+ w, h = img.size
179
+ if w < h:
180
+ return False
181
+ ratio = w / h
182
+ if not (min_ratio <= ratio <= max_ratio):
183
+ return False
184
+ # 校验不是纯色图(stddev 极低 = 纯色/几乎无细节)
185
+ stat = ImageStat.Stat(img.convert("RGB"))
186
+ avg_stddev = sum(stat.stddev) / 3
187
+ if avg_stddev < 15: # 几乎纯色,丢弃
188
+ return False
189
+ return True
190
+ except Exception:
191
+ return False
192
+
193
+
167
194
  def download_theme_images(theme, output_dir, count=6):
168
195
  """根据主题下载多张精美图片
169
196
 
@@ -176,13 +203,24 @@ def download_theme_images(theme, output_dir, count=6):
176
203
  downloaded = [] # 临时文件列表
177
204
  failed_pids = []
178
205
 
179
- # 1) 全部下载到临时文件
206
+ # 1) 全部下载到临时文件(仅保留横向图:1.2 ≤ ratio ≤ 2.0)
180
207
  for i, pid in enumerate(candidates):
181
208
  if len(downloaded) >= count:
182
209
  break
183
210
  tmp_path = os.path.join(output_dir, f"_tmp_{theme}_{i}_{pid}.jpg")
184
211
  if download_pexels_image(pid, tmp_path):
185
- downloaded.append(tmp_path)
212
+ if is_valid_landscape(tmp_path):
213
+ downloaded.append(tmp_path)
214
+ else:
215
+ # 不是横向图或纯色图,丢弃
216
+ try:
217
+ img = Image.open(tmp_path)
218
+ w, h = img.size
219
+ ratio = w / h if h > 0 else 0
220
+ print(f" 跳过 {pid}({w}x{h},比例 {ratio:.2f} 不符合横向规范)")
221
+ except Exception:
222
+ print(f" 跳过 {pid}(无法校验)")
223
+ os.remove(tmp_path)
186
224
  else:
187
225
  failed_pids.append(pid)
188
226