起因
之前使用picgo
+telegraph代理
+Obsidian插件image Auto Upload Plugin
实现图片自动上传到telegraph图床,效果完美,但是需要nodejs
运行环境,还要装一堆依赖,虽然我主力机因为搭建了各种开发环境本来就有nodejs
环境,但是我的另一台轻薄本我是不想装这么多乱七八糟的东西了,于是就想着找一个解决方案
过程记录
我的要求:
- 配合
image Auto Upload Plugin
实现图片上传 - 不依赖外部运行环境,至少windows和linux通用
go语言恰好符合平台通用性要求,这里使用go语言实现,这里先来看看image Auto Upload Plugin
如何运作,以下是操作picgo-core
上传的核心逻辑代码
export class PicGoCoreUploader {
async uploadFiles(fileList: Array<String>): Promise<any> {
let command = `${cli} upload ${fileList
.map(item => `"${item}"`)
.join(" ")}`;
const res = await this.exec(command);
const splitList = res.split("\n");
const splitListLength = splitList.length;
const data = splitList.splice(splitListLength - 1 - length, length);
if (res.includes("PicGo ERROR")) {
} else {
return {
success: true,
result: data,
};
}
}
}
// PicGo-Core 上传处理
async uploadFileByClipboard() {
const res = await this.uploadByClip();
const splitList = res.split("\n");
const lastImage = getLastImage(splitList);
if (lastImage) {
return {
code: 0,
msg: "success",
data: lastImage,
};
} else {
//错误处理
}
}
// PicGo-Core的剪切上传反馈
async uploadByClip() {
let command;
if (this.settings.picgoCorePath) {
command = `${this.settings.picgoCorePath} upload`;
} else {
command = `picgo upload`;
}
const res = await this.exec(command);
return res;
}
}
export function getLastImage(list: string[]) {
const reversedList = list.reverse();
let lastImage;
reversedList.forEach(item => {
if (item && item.startsWith("http")) {
lastImage = item;
return item;
}
});
return lastImage;
}
大概的逻辑就是:从剪切板粘贴就使用child_process
执行picgo upload
,其他的就执行picgo upload xxx1.jpg xxx2.jpg
,然后从控制台输出读取上传之后图片的网址,每行一个,从最后一行读取跟参数数量一样的行数作为图片网址,如果是剪切板上传就读取最后一个http开头的字符串
理解逻辑之后就可以开始写了:
package main
import (
"bytes"
"fmt"
"image/png"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"strings"
"golang.design/x/clipboard"
)
func uploadImage(file bytes.Buffer) {
buf := new(bytes.Buffer)
wr := multipart.NewWriter(buf)
fw, err := wr.CreateFormFile("uploadfile", "image.png")
if err != nil {
panic(err)
}
io.Copy(fw, &file)
wr.Close()
req, err := http.NewRequest("POST", "https://telegra.ph/upload", buf)
req.Header.Set("Content-Type", wr.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
body, _ := ioutil.ReadAll(resp.Body)
str := string(body)
str = strings.TrimPrefix(str, `[{"src":"\/file\/`)
str = strings.TrimSuffix(str, `"}]`)
fmt.Println("https://telegra.ph/file/" + str)
}
func main() {
if len(os.Args) == 2 && os.Args[1] == "upload" {
var file bytes.Buffer
img := clipboard.Read(clipboard.FmtImage)
if img != nil {
img, err := png.Decode(bytes.NewReader(img))
if err != nil {
panic(err)
}
png.Encode(&file, img)
}
uploadImage(file)
} else if len(os.Args) > 2 && os.Args[1] == "upload" {
for _, filePath := range os.Args[2:] {
var file bytes.Buffer
f, err := os.Open(filePath)
if err != nil {
panic(err)
}
defer f.Close()
io.Copy(&file, f)
uploadImage(file)
}
} else {
fmt.Println("Usage: go run main.go upload [image1] [image2] ...")
}
}
写完了,把编译出来的程序改名成picgo.exe
或者linux下改成picgo
放在path
里,或者在image Auto Upload Plugin
里面设置路径,粘贴和拖入图片自动上传功能使用正常
有需要的可以自己拿去编译一下用,如果你的网络访问telegraph有障碍,可以参考picgo+自建telegraph代理图床实现无限图片存储搭建自己的代理,再把程序中的域名换成你自己的,之后可能更完善些支持其他图床,暂时就不扔github了,也许未来某天会继续完善,但是目前已经够我用了,如果有你有自己的需求可以在这上面改改拿着用