@@ -25,20 +25,22 @@ import (
2525 "time"
2626)
2727
28+ // S3 配置及全局变量
2829var (
29- Endpoint = "s3.bitiful.net"
30- Region = "cn-east-1"
31- SVC * s3.S3
32- update bool
33- file string
34- name string
35- HttpClient * http.Client
36- versionData string
37- fileName string
38- imageType bool
39- err error
30+ Endpoint = "s3.bitiful.net" // S3 终端节点
31+ Region = "cn-east-1" // S3 区域
32+ SVC * s3.S3 // S3 客户端
33+ file string // 文件路径或URL
34+ name string // 指定上传后的文件名
35+ verbose bool // 是否显示详细日志
36+ HttpClient * http.Client // 全局 HTTP 客户端
37+ versionData string // 版本信息
38+ fileName string // 实际上传到S3的文件名
39+ imageType bool // 是否为本地文件(true=本地,false=URL)
40+ err error // 全局错误变量
4041)
4142
43+ // 初始化配置和HTTP客户端
4244func init () {
4345 dir , err := os .UserConfigDir ()
4446 if err != nil {
@@ -57,7 +59,7 @@ func init() {
5759 Region = viper .GetString ("Region" )
5860 }
5961
60- // HttpClient 注意client 本身是连接池,不要每次请求时创建client
62+ // 初始化全局 HTTP 客户端,避免频繁创建
6163 dialer := & net.Dialer {
6264 Resolver : & net.Resolver {
6365 PreferGo : true ,
@@ -82,58 +84,70 @@ func init() {
8284 }
8385}
8486
87+ // 主命令定义,支持批量文件/URL上传
8588var rootCmd = & cobra.Command {
86- Short : "TYPORA UPLOAD IAMGE TO AWS" ,
87- Long : "优雅的使用 TYPORA 上传图片到 AWS 存储桶" ,
89+ Short : "Typora 上传图片到 AWS" ,
90+ Long : "优雅地使用 Typora 上传图片到 AWS 存储桶" ,
8891 Version : versionData ,
8992
9093 Run : func (cmd * cobra.Command , args []string ) {
94+ // 如果没有图片路径参数,则用 -f 指定的文件
9195 if args == nil || len (args ) == 0 {
9296 args = append (args , file )
9397 }
94- // log.Infof ("args %v", args)
95- // log.Infof("update {%v} file {%v} name {%v}", update , file, name)
98+ log .Debugf ("args: %v" , args )
99+ log .Debugf ( " file: %v, name: %v" , file , name )
96100 for _ , v := range args {
97101 var data []byte
102+ log .Debugf ("处理文件/URL: %s" , v )
98103 getImgName (v )
104+ log .Debugf ("最终上传文件名: %s" , fileName )
99105 imageType = checkImg (v )
100- // 判断文件是否存在
106+ log .Debugf ("文件类型判断: %v (true=本地文件, false=URL)" , imageType )
107+ // 判断是本地文件还是URL,分别处理
101108 if ! imageType {
109+ log .Debugf ("尝试下载图片: %s" , v )
102110 data , err = getImageUrl (v )
103111 if err != nil {
104112 log .Fatalln (err )
105113 continue
106114 }
107115 } else {
116+ log .Debugf ("尝试读取本地图片: %s" , v )
108117 data , err = getImageFile (v )
109118 if err != nil {
110119 log .Fatalln (err )
111120 continue
112121 }
113122 }
114123
124+ log .Debugf ("开始上传到 S3: %s" , fileName )
115125 _ , err := UploadObject (data )
116126 if err != nil {
117127 log .Fatalln (err )
118128 continue
119129 }
130+ log .Debugf ("上传成功: %s" , fileName )
120131
121132 if imageType {
133+ // 上传图片后删除原文件
122134 if err := wastebasket .Trash (v ); err != nil {
123135 log .Errorf ("删除文件失败: %v" , err )
124136 return
125137 }
138+ log .Debugf ("移动图片到垃圾篓成功: %s" , fileName )
126139 }
127140 fmt .Printf ("https://%v.%v%v%v?fmt=webp&q=48&w=800\n " , viper .GetString ("BucketName" ), Endpoint , viper .GetString ("Path" ), fileName )
128141 }
129142 },
130143 Example : ` - bitiful /Users/xxx/xxx.png
131144 - bitiful "/example/example.png" "/example/example2.png"
132- - bitiful -u -f /Users/xxx/xxx.png -nTest .png
133- - bitiful -u -f /Users/xxx /xxx.png -n Test .png
145+ - bitiful -n Test.png /Users/xxx/xxx.png
146+ - bitiful -n Test.png https://example.com /xxx.png
134147` ,
135148}
136149
150+ // 创建 S3 会话
137151func CreateS3Session () {
138152 SVC = s3 .New (session .Must (session .NewSession (
139153 & aws.Config {
@@ -150,21 +164,26 @@ func CreateS3Session() {
150164 )))
151165}
152166
167+ // 生成最终上传文件名:有 -n 用 -n,否则用时间戳
153168func getImgName (image string ) {
154- //filetype := http.DetectContentType(data)
155- fileNameAll := path .Base (image ) // 文件全名
156- fileSuffix := path .Ext (image ) // 文件类型
157- fileName = fileNameAll
169+ fileSuffix := path .Ext (image ) // 文件类型
158170 if fileSuffix == "" {
159171 fileSuffix = ".png"
160172 }
161173
162- // 检测是否覆盖
163- if ! update {
164- fileName = strings .Replace (time .Now ().Format ("20060102150405.00000" ), "." , "" , - 1 ) + fileSuffix
174+ // 有 -n 就用 -n,否则一律生成新名字
175+ if name != "" {
176+ fileName = name
177+ if ! strings .HasSuffix (fileName , fileSuffix ) {
178+ fileName += fileSuffix
179+ }
180+ return
165181 }
182+
183+ fileName = strings .Replace (time .Now ().Format ("20060102150405.00000" ), "." , "" , - 1 ) + fileSuffix
166184}
167185
186+ // 判断文件是否为本地文件
168187func checkImg (file string ) bool {
169188 if _ , err := os .Stat (file ); err != nil {
170189 if os .IsNotExist (err ) {
@@ -176,6 +195,7 @@ func checkImg(file string) bool {
176195 return false
177196}
178197
198+ // 下载图片(URL)
179199func getImageUrl (imgUrl string ) ([]byte , error ) {
180200 resp , err := HttpClient .Get (imgUrl )
181201 if err != nil {
@@ -188,18 +208,19 @@ func getImageUrl(imgUrl string) ([]byte, error) {
188208 }
189209 }(resp .Body )
190210
191- // Check Status
211+ // 检查HTTP状态码
192212 if resp .StatusCode != 200 {
193213 return nil , errors .New (fmt .Sprintf ("下载图片的状态码异常: %v" , resp .Status ))
194214 }
195- // Read the data
215+ // 读取图片数据
196216 data , err := io .ReadAll (resp .Body )
197217 if err != nil {
198218 return nil , errors .New (fmt .Sprintf ("读取图片失败: %v" , err ))
199219 }
200220 return data , nil
201221}
202222
223+ // 读取本地图片文件
203224func getImageFile (imgPath string ) ([]byte , error ) {
204225 tempFile , err := os .Open (imgPath )
205226 if err != nil {
@@ -217,8 +238,8 @@ func getImageFile(imgPath string) ([]byte, error) {
217238 return data , nil
218239}
219240
241+ // 上传图片到 S3
220242func UploadObject (raw []byte ) (output * s3.PutObjectOutput , err error ) {
221- // Upload to s3
222243 output , err = SVC .PutObjectWithContext (context .TODO (), & s3.PutObjectInput {
223244 Bucket : aws .String (viper .GetString ("BucketName" )),
224245 Key : aws .String (viper .GetString ("Path" ) + fileName ),
@@ -234,12 +255,25 @@ func UploadObject(raw []byte) (output *s3.PutObjectOutput, err error) {
234255 return output , nil
235256}
236257
258+ // 程序入口
237259func main () {
238- // upload img/png/jpeg/webp to aws
260+ // 初始化 S3 会话
239261 CreateS3Session ()
240- rootCmd . Flags (). BoolVarP ( & update , "update" , "u" , false , "更新您的图片." )
262+ // 注册命令行参数
241263 rootCmd .Flags ().StringVarP (& file , "file" , "f" , "" , "图片 路径|URL ." )
242264 rootCmd .Flags ().StringVarP (& name , "name" , "n" , "" , "被覆盖的图片名称." )
265+ rootCmd .Flags ().BoolVarP (& verbose , "verbose" , "v" , false , "显示详细日志" )
266+
267+ // 日志级别初始化
268+ cobra .OnInitialize (func () {
269+ if verbose {
270+ log .SetLevel (log .DebugLevel )
271+ log .Debug ("已启用详细日志模式" )
272+ } else {
273+ log .SetLevel (log .InfoLevel )
274+ }
275+ })
276+
243277 if err := rootCmd .Execute (); err != nil {
244278 log .Errorf ("参数错误: %v" , err )
245279 }
0 commit comments