@@ -12,38 +12,69 @@ import (
1212 "github.com/thinkthinking/cli/internal/core/wechat"
1313)
1414
15- // newWeChatPostCmd 实现 `thinkthinking wechat post`:把 Markdown/HTML 发布为
16- // 微信公众号草稿(自动转换、上传正文本地图片、上传封面)。
15+ // markdownExts / htmlExts 是 post 命令按文件后缀自动判断正文类型的依据。
16+ var (
17+ markdownExts = map [string ]bool {".md" : true , ".markdown" : true , ".mdown" : true , ".mkd" : true }
18+ htmlExts = map [string ]bool {".html" : true , ".htm" : true }
19+ )
20+
21+ // newWeChatPostCmd 实现 `thinkthinking wechat post`:把一篇文章发布为微信公众号草稿
22+ // (自动转换、上传正文本地图片、上传封面)。
1723//
18- // 设计取舍:post 是面向「发一篇文章」的高频命令,刻意收敛参数——
19- // --title / --author / --cover 三者必填,--markdown-file 与 --html-file 二选一,
20- // 由 cobra 的内置校验给出清晰错误(统一包装成 INVALID_INPUT JSON)。
24+ // 设计取舍:post 是「发一篇文章」的高频命令,刻意收敛参数——
25+ // - 正文文件作为位置参数,按后缀自动判断 Markdown / HTML(.md → 转换,.html → 直传),
26+ // 不再要求用户区分 --markdown-file / --html-file。
27+ // - --title / --author / --cover 三者必填,由 cobra 内置校验给出清晰错误
28+ // (统一包装成 INVALID_INPUT JSON)。
2129func newWeChatPostCmd () * cobra.Command {
2230 var (
23- title string
24- markdownFile string
25- htmlFile string
26- theme string
27- author string
28- digest string
29- cover string
30- noUpload bool
31+ title string
32+ theme string
33+ author string
34+ digest string
35+ cover string
36+ noUpload bool
3137 )
3238
3339 cmd := & cobra.Command {
34- Use : "post" ,
35- Short : "把 Markdown/HTML 发布为微信公众号草稿(自动转换 + 上传图片与封面)" ,
40+ Use : "post <file> " ,
41+ Short : "把一篇文章发布为微信公众号草稿(按后缀自动转换 + 上传图片与封面)" ,
3642 Long : `把一篇文章发布为微信公众号草稿。
3743
38- 自动完成:Markdown → 微信兼容 HTML → 上传正文本地图片并回填 URL → 上传封面 → 写入草稿箱。
39- --title / --author / --cover 必填;正文来源 --markdown-file 与 --html-file 二选一。` ,
40- Args : cobra .NoArgs ,
44+ <file> 是正文文件,按后缀自动判断类型:
45+ .md / .markdown → 转换为微信兼容 HTML 后发布
46+ .html / .htm → 直接作为正文发布
47+
48+ 自动完成:(必要时转换)→ 上传正文本地图片并回填 URL → 上传封面 → 写入草稿箱。
49+ --title / --author / --cover 三者必填。
50+
51+ 示例:
52+ thinkthinking wechat post article.md --title "标题" --author "作者" --cover cover.jpg
53+ thinkthinking wechat post article.html --title "标题" --author "作者" --cover cover.jpg` ,
54+ Args : cobra .ExactArgs (1 ),
4155 RunE : func (cmd * cobra.Command , args []string ) error {
56+ file := args [0 ]
57+ ext := strings .ToLower (filepath .Ext (file ))
58+ isMarkdown := markdownExts [ext ]
59+ isHTML := htmlExts [ext ]
60+ if ! isMarkdown && ! isHTML {
61+ return output .Newf (output .CodeInvalidInput ,
62+ "无法从后缀判断文件类型:%s(支持 .md/.markdown 或 .html/.htm)" , file )
63+ }
64+
4265 // 凭证预检:缺失则返回结构化 WECHAT_AUTH_ERROR(不 panic)。
4366 if aerr := checkWeChatCredentials (); aerr != nil {
4467 return aerr
4568 }
4669
70+ data , rerr := os .ReadFile (file )
71+ if rerr != nil {
72+ if os .IsNotExist (rerr ) {
73+ return output .Newf (output .CodeFileNotFound , "file not found: %s" , file )
74+ }
75+ return output .Wrap (rerr , output .CodeInvalidInput )
76+ }
77+
4778 input := wechat.CreateDraftInput {
4879 Title : title ,
4980 Author : author ,
@@ -52,26 +83,12 @@ func newWeChatPostCmd() *cobra.Command {
5283 UploadImages : ! noUpload ,
5384 }
5485
55- if markdownFile != "" {
56- data , rerr := os .ReadFile (markdownFile )
57- if rerr != nil {
58- if os .IsNotExist (rerr ) {
59- return output .Newf (output .CodeFileNotFound , "markdown file not found: %s" , markdownFile )
60- }
61- return output .Wrap (rerr , output .CodeInvalidInput )
62- }
86+ if isMarkdown {
6387 input .Markdown = string (data )
64- input .MarkdownDir = filepath .Dir (markdownFile )
88+ input .MarkdownDir = filepath .Dir (file )
6589 input .ThemeName = firstNonEmpty (theme , container .Config .WeChat .DefaultTheme )
6690 input .ConvertOptions = wechat .DefaultConvertOptions ()
6791 } else {
68- data , rerr := os .ReadFile (htmlFile )
69- if rerr != nil {
70- if os .IsNotExist (rerr ) {
71- return output .Newf (output .CodeFileNotFound , "html file not found: %s" , htmlFile )
72- }
73- return output .Wrap (rerr , output .CodeInvalidInput )
74- }
7592 input .HTML = string (data )
7693 }
7794
@@ -95,19 +112,15 @@ func newWeChatPostCmd() *cobra.Command {
95112 f .StringVar (& title , "title" , "" , "文章标题(必填)" )
96113 f .StringVar (& author , "author" , "" , "作者(必填)" )
97114 f .StringVar (& cover , "cover" , "" , "本地封面图路径,上传为 thumb_media_id(必填)" )
98- f .StringVar (& markdownFile , "markdown-file" , "" , "Markdown 文件路径(与 --html-file 二选一)" )
99- f .StringVar (& htmlFile , "html-file" , "" , "HTML 文件路径(与 --markdown-file 二选一)" )
100- f .StringVarP (& theme , "theme" , "t" , "" , "主题名(仅 markdown 路径,默认读配置 wechat.default_theme)" )
115+ f .StringVarP (& theme , "theme" , "t" , "" , "主题名(仅 .md 正文生效,默认读配置 wechat.default_theme)" )
101116 f .StringVar (& digest , "digest" , "" , "摘要(默认用转换生成的摘要)" )
102117 f .BoolVar (& noUpload , "no-upload-images" , false , "禁用正文本地图片自动上传" )
103118
104- // 必填与互斥约束交给 cobra:校验失败返回的 error 由 Execute() 统一包装成
119+ // 必填约束交给 cobra:校验失败返回的 error 由 Execute() 统一包装成
105120 // INVALID_INPUT 的 JSON envelope,保持 Agent 契约。
106121 _ = cmd .MarkFlagRequired ("title" )
107122 _ = cmd .MarkFlagRequired ("author" )
108123 _ = cmd .MarkFlagRequired ("cover" )
109- cmd .MarkFlagsOneRequired ("markdown-file" , "html-file" )
110- cmd .MarkFlagsMutuallyExclusive ("markdown-file" , "html-file" )
111124 return cmd
112125}
113126
0 commit comments