Skip to content

Commit 9f746d0

Browse files
committed
优化图片覆盖逻辑,新增日志详细模式
1 parent d737a21 commit 9f746d0

8 files changed

Lines changed: 137 additions & 51 deletions

File tree

.idea/.gitignore

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/bitiful-typora-upload-cli.iml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bitiful.go

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,22 @@ import (
2525
"time"
2626
)
2727

28+
// S3 配置及全局变量
2829
var (
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客户端
4244
func 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上传
8588
var 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 会话
137151
func CreateS3Session() {
138152
SVC = s3.New(session.Must(session.NewSession(
139153
&aws.Config{
@@ -150,21 +164,26 @@ func CreateS3Session() {
150164
)))
151165
}
152166

167+
// 生成最终上传文件名:有 -n 用 -n,否则用时间戳
153168
func 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+
// 判断文件是否为本地文件
168187
func 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)
179199
func 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+
// 读取本地图片文件
203224
func 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
220242
func 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+
// 程序入口
237259
func 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
}

docs/README.md

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
1-
## Bitiful Typora Upload CLI
1+
## Bitiful Typora 图片上传 命令行工具
22

33
![show1](https://xrsec.s3.bitiful.net/IMG/2023011808315652353.gif?fmt=webp&q=48)
44

55
![show2](https://xrsec.s3.bitiful.net/IMG/2023011808320175950.gif?fmt=webp&q=48)
66

7-
## Install & Use
7+
## 安装与使用
88

9-
1. [Release Download](https://github.com/XRSec/bitiful-typora-upload-cli/releases)
9+
1. [发布版下载](https://github.com/XRSec/bitiful-typora-upload-cli/releases)
1010

1111
```bash
12-
bitiful # require config file
12+
bitiful # 需要配置文件
1313
bitiful "/example/example.png"
1414
bitiful "https://example.com/example.png"
15+
bitiful /path/to/1.png /path/to/2.jpg # 支持多文件批量上传
1516
```
1617

17-
or dev build
18+
2. 开发构建
1819

1920
```bash
2021
git clone https://github.com/XRSec/bitiful-typora-upload-cli.git
2122
cd bitiful-typora-upload-cli
22-
# Edit bitifulUrl in bitiful-typora-upload-cli.go
23+
# 编辑 bitifulUrl 变量
2324
CGO_ENABLED=0 go build -o bitiful
2425
# mv bitiful /usr/local/bin
2526
# cd .. && rm -rf bitiful-typora-upload-cli
2627
```
2728

28-
2. Open Typora and set `cli` -> `Preference` -> `Image` -> `Upload Image` -> `Custom Command` -> `/home/xxx/bitiful`
29+
3. 打开 Typora`偏好设置` -> `图片` -> `上传图片` -> `自定义命令` -> `/home/xxx/bitiful`
2930

30-
## Config
31+
## 配置文件
32+
33+
配置文件路径:`~/Library/Application\ Support/bitiful.yml`
34+
35+
### 配置文件示例
3136

3237
```yaml
3338
Endpoint: s3.bitiful.net
@@ -38,14 +43,36 @@ BucketName: "xxxxxxxxxx"
3843
Path: "/xxxxxxxx/"
3944
```
4045
41-
### Cover image
46+
### 指定文件名(覆盖上传)
47+
48+
如需自定义上传后的文件名(如封面图),可用 `-n` 参数:
4249

4350
```bash
44-
bitiful -u -n "20220903" -f https://example.com/20220903.jpg
45-
bitiful -u -f/Users/xxx/xxx.png -nTest.png
51+
bitiful -n "20220903.jpg" https://example.com/20220903.jpg
52+
bitiful -n Test.png /Users/xxx/xxx.png
4653
```
47-
## Doing
4854

49-
- [x] file
50-
- [x] url
55+
- 仅当指定 `-n` 时,才会用该名字覆盖同名文件。
56+
- 未指定 `-n` 时,自动生成唯一文件名,绝不覆盖。
57+
58+
### 多文件批量上传
59+
60+
直接在命令行追加多个文件或URL即可:
61+
62+
```bash
63+
bitiful /path/to/1.png /path/to/2.jpg
64+
```
65+
66+
### 日志与调试
67+
68+
加 `-v` 参数可显示详细日志,便于排查问题:
69+
70+
```bash
71+
bitiful -v /path/to/1.png
72+
```
73+
74+
## 功能进度
75+
76+
- [x] 本地文件上传
77+
- [x] URL 上传
5178
- [?] ftp/smb/afs

go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ go 1.18
55
require (
66
github.com/Bios-Marcel/wastebasket v0.0.2
77
github.com/aws/aws-sdk-go v1.44.180
8-
github.com/shamsher31/goimgtype v1.0.0
98
github.com/sirupsen/logrus v1.9.0
109
github.com/spf13/cobra v1.6.1
1110
github.com/spf13/viper v1.14.0
@@ -20,7 +19,6 @@ require (
2019
github.com/mitchellh/mapstructure v1.5.0 // indirect
2120
github.com/pelletier/go-toml v1.9.5 // indirect
2221
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
23-
github.com/shamsher31/goimgext v1.0.0 // indirect
2422
github.com/spf13/afero v1.9.2 // indirect
2523
github.com/spf13/cast v1.5.0 // indirect
2624
github.com/spf13/jwalterweatherman v1.1.0 // indirect

go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,6 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
158158
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
159159
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
160160
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
161-
github.com/shamsher31/goimgext v1.0.0 h1:wFKf9GeeE0Xr6UQtliaPgYYgTju2izobM7XpCEgUCC8=
162-
github.com/shamsher31/goimgext v1.0.0/go.mod h1:rYLKgXuTGBIaH49z+jUVSWz7gUWIZmqvYUsdvJbNNOc=
163-
github.com/shamsher31/goimgtype v1.0.0 h1:7nmPz5GEb01sjFUojCbZJcBI68A8tmLXoCFbb5I34u4=
164-
github.com/shamsher31/goimgtype v1.0.0/go.mod h1:OZm3NZQDbK0ezlk9IV5oq3cWQwjF1oVSxKNx19bkf64=
165161
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
166162
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
167163
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=

0 commit comments

Comments
 (0)