深色模式
一键上传图片到七牛云
需求
写博客时,需要在Markdown中插入图片,图片是一个链接。
这里考虑将图片上传到七牛云,得到远程的图片链接,将此链接写入Markdown中,就可以显示图片了。
需求分析
使用Go语言,写一个命令行工具:
- 可以读取1或多个本地的图片路径参数
- 依次上传到七牛云,得到图片链接
- 将远程图片链接写入剪贴板,方便粘贴到Markdown中
编码
七牛云官方,有提供Go语言SDK,可以很方便地实现上传图片。
代码如下:
go
package main
import (
"context"
"encoding/base64"
"errors"
"flag"
"fmt"
"math/rand"
"path"
"strconv"
"time"
"github.com/atotto/clipboard"
"github.com/qiniu/go-sdk/v7/auth/qbox"
"github.com/qiniu/go-sdk/v7/storage"
)
var (
accessKey = "xxx"
secretKey = "xxx"
bucketName = "xxx" // 空间名
keyPrefix = "xxx/" // 指定上传后的文件名前缀
customHost = "https://xxx" // 自定义域名
)
// 接收1个或多个本地图片文件
// 上传到七牛kodo
// 并且对远程文件重命名为随机字符串
// 将上传后的链接写入剪贴板
func main() {
// 读取命令参数
files, err := readCMD()
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
// 上传
fmt.Println("Upload start...")
urls := ""
for _, file := range files {
key, err := uploadDirectly(file)
if err != nil {
fmt.Printf("Upload failed: %s\n", err)
return
}
if len(urls) > 0 {
urls += "\n"
}
urls += fmt.Sprintf("%s/%s", customHost, key)
}
fmt.Printf("Upload succeed!\n%s\n", urls)
// 复制文本到剪贴板
err = clipboard.WriteAll(urls)
if err != nil {
fmt.Printf("Write into clipboard failed: %s\n", err)
return
}
fmt.Println("Urls are already wrote into clipboard.")
}
// 读取命令行参数,返回所有文件路径
func readCMD() ([]string, error) {
// 读取命令行参数
flag.Parse()
files := flag.Args()
if len(files) == 0 {
return nil, errors.New("one or more files are required")
}
return files, nil
}
// 服务端直传方式
func uploadDirectly(localFile string) (string, error) {
putPolicy := storage.PutPolicy{
Scope: bucketName,
}
mac := qbox.NewMac(accessKey, secretKey)
upToken := putPolicy.UploadToken(mac)
cfg := storage.Config{}
// 空间对应的机房
cfg.Zone = &storage.ZoneHuanan
// 是否使用https域名
cfg.UseHTTPS = false
// 上传是否使用CDN上传加速
cfg.UseCdnDomains = false
// 构建表单上传的对象
formUploader := storage.NewFormUploader(&cfg)
ret := storage.PutRet{}
// 可选配置
putExtra := storage.PutExtra{
Params: map[string]string{
// "x:name": "github logo",
},
}
// 保存的名称
key := newRemoteKey(localFile)
err := formUploader.PutFile(context.Background(), &ret, upToken, key, localFile, &putExtra)
if err != nil {
return "", fmt.Errorf("%s", err)
}
return ret.Key, nil
}
// 根据本地文件路径,生成随机的远程路径,此路径即是七牛上传对象的key
func newRemoteKey(localFile string) string {
// 文件后缀,包含了点号"."
ext := path.Ext(localFile)
// 随机数字 转 字符串
rand.Seed(time.Now().UnixNano())
timeStr := strconv.Itoa(rand.Int())
// base64 编码,作为图片名的一部分
name := base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString([]byte(timeStr))
// 拼接
key := fmt.Sprintf("%s%s%s", keyPrefix, name, ext)
return key
}
module upkodo
go 1.23.1
require github.com/qiniu/go-sdk/v7 v7.23.0
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/elastic/go-sysinfo v1.0.2 // indirect
github.com/elastic/go-windows v1.0.0 // indirect
github.com/gammazero/toposort v0.1.1 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect
github.com/pkg/errors v0.8.1 // indirect
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.0.0-20190425145619-16072639606e // indirect
howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect
modernc.org/fileutil v1.3.0 // indirect
)
编译
编译并安装
sh
go install
会在~/go/bin
目录中,生成一个程序:upkodo
。
由于安装Go时,一般会自动把~/go/bin
添加到PATH
中,所以可以直接在命令行中使用upkodo
命令。
仅编译
sh
go build -o upkodo main.go
会在go.mod
的同级目录中,生成一个程序:upkodo
。
如果要调用此程序,要注意路径和权限问题。
使用
sh
upkodo path/to/pic.png
输出:
Upload start...
Upload succeed!
https://xxx.xxx.com/blog/xxx.png
Url(s) are already wrote into clipboard.
此时https://xxx.xxx.comblog/xxx.png
已经写入剪贴板,可以直接⌘+V
粘贴到其它文档中。
如果一次上传多张图片,会得到多行链接输出。