文章首发于:clawhub.club


Go版本的图库依然采用Gin框架作为API网关,zap+lumberjack作为日志框架,用go-ini来读取配置文件。
项目地址:https://github.com/ClawHub/go-figure-bed
目前仍在慢慢完善(抄袭),主要参考(抄袭)项目:https://github.com/aimerforreimu/auxpi
https://www.jianshu.com/p/6ec06f7882e9


简单的分析核心API

1, Upload.cc

https://upload.cc/
image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func UploadToCC(img []byte, imgInfo string, imgType string) (string, string) {
url := "https://upload.cc/image_upload"
name := utils.GetFileNameByMimeType(imgInfo)

file := &utils.FormFile{
Name: name,
Key: "uploaded_file[]",
Value: img,
Type: imgType,
}
var header map[string]string
data := utils.FormPost(file, url, header)
cc := bed.CCResp{}
err := json.Unmarshal([]byte(data), &cc)
if err != nil {
logging.AppLogger.Error("UploadToCC fail ", zap.Error(err))
return "", ""
}
mj, _ := cc.SuccessImage[0].(map[string]interface{})
smj, _ := mj["url"].(string)
del, _ := mj["delete"].(string)

url = "https://upload.cc/" + smj

deleteJson := `[{"path":"` + smj + `",key":"` + del + `"}]`
return url, deleteJson
}

2,sina

新浪图床貌似很稳啊,不过目前也仅仅是从网上得来的结论。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package server

import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/astaxie/beego/cache"
"go-figure-bed/pkg/e/bed"
"go-figure-bed/pkg/logging"
"go-figure-bed/pkg/setting"
"go-figure-bed/pkg/utils"
"go.uber.org/zap"
"hash/crc32"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strings"
"time"
)

//缓存
var memoryCache, _ = cache.NewCache("memory", `{"interval":3600}`)

//新浪图床登录
func Login(name string, pass string) interface{} {
url := "https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)&_=1403138799543"
userInfo := make(map[string]string)
userInfo["UserName"] = utils.Encode(base64.StdEncoding, name)
userInfo["PassWord"] = pass
cookie := getCookies(url, userInfo)
return cookie
}

//获取新浪图床 Cookie
func getCookies(durl string, data map[string]string) interface{} {
//尝试从缓存里面获取 Cookie
if memoryCache.Get("SinaCookies") != nil {
return memoryCache.Get("SinaCookies")
}
postData := make(url.Values)
postData["entry"] = []string{"sso"}
postData["gateway"] = []string{"1"}
postData["from"] = []string{"null"}
postData["savestate"] = []string{"30"}
postData["uAddicket"] = []string{"0"}
postData["pagerefer"] = []string{""}
postData["vsnf"] = []string{"1"}
postData["su"] = []string{data["UserName"]} //UserName
postData["service"] = []string{"sso"}
postData["sp"] = []string{data["PassWord"]} //PassWord
postData["sr"] = []string{"1920*1080"}
postData["encoding"] = []string{"UTF-8"}
postData["cdult"] = []string{"3"}
postData["domain"] = []string{"sina.com.cn"}
postData["prelt"] = []string{"0"}
postData["returntype"] = []string{"TEXT"}
client := &http.Client{}
request, err := http.NewRequest("POST", durl, strings.NewReader(postData.Encode()))
if err != nil {
fmt.Println(err)
}
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(request)
defer resp.Body.Close()
cookie := resp.Cookies()
//缓存 Cookie 缓存一个小时
_ = memoryCache.Put("SinaCookies", cookie, time.Second*3600)
return cookie
}

//上传图片
func UpLoadToSina(img []byte, imgType string) string {
//是否开启新浪图床
if setting.BedSetting.Sina.OpenSinaPicStore == false {
return ""
}
durl := "http://picupload.service.weibo.com/interface/pic_upload.php" +
"?ori=1&mime=image%2Fjpeg&data=base64&url=0&markpos=1&logo=&nick=0&marks=1&app=miniblog"
imgStr := base64.StdEncoding.EncodeToString(img)
//构造 http 请求
postData := make(url.Values)
postData["b64_data"] = []string{imgStr}
client := &http.Client{}
request, err := http.NewRequest("POST", durl, strings.NewReader(postData.Encode()))
if err != nil {
logging.AppLogger.Error("UpLoad To Sina fail", zap.Error(err))
fmt.Println(err)
}
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
//设置 cookie
uncooikes := Login(setting.BedSetting.Sina.UserName, setting.BedSetting.Sina.PassWord)
//需要进行断言转换
cookies, ok := uncooikes.([]*http.Cookie)
if !ok {
panic(ok)
}
for _, value := range cookies {
request.AddCookie(value)
}
resp, err := client.Do(request)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
return getSinaUrl(body, imgType)
}

//获取 Sina 图床 URL
func getSinaUrl(body []byte, imgType string) string {
str := string(body)
//正则获取
pat := "({.*)"
check := "[a-zA-Z0-9]{32}"
res := regexp.MustCompile(pat)
rule := regexp.MustCompile(check)
jsons := res.FindAllStringSubmatch(str, -1)
msg := bed.SinaMsg{}
//解析 json 到 struct
err := json.Unmarshal([]byte(jsons[0][1]), &msg)
if err != nil {
logging.AppLogger.Error("get Sina Url fail", zap.Error(err))
}
//验证 pid 的合法性
pid := msg.Data.Pics.Pic_1.Pid
if rule.MatchString(pid) {
sinaNumber := fmt.Sprint((crc32.ChecksumIEEE([]byte(pid)) & 3) + 1)
//从配置文件中获取
size := setting.BedSetting.Sina.DefultPicSize
n := len(imgType)
rs := []rune(imgType)
suffix := string(rs[6:n])
if suffix != "gif" {
suffix = "jpg"
}
sinaUrl := "https://ws" + sinaNumber + ".sinaimg.cn/" + size + "/" + pid + "." + suffix
return sinaUrl
}
return ""
}

3,sm.ms

https://sm.ms/
image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//上传 SM 图床 返回图片 URL
func UploadToSmms(img []byte, imgInfo string) string {
body := new(bytes.Buffer)
w := multipart.NewWriter(body)
contentType := w.FormDataContentType()
name := utils.GetFileNameByMimeType(imgInfo)
file, _ := w.CreateFormFile("smfile", name)
_, _ = file.Write(img)
_ = w.Close()
req, _ := http.NewRequest("POST", "https://sm.ms/api/upload", body)
req.Header.Set("Content-Type", contentType)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := ioutil.ReadAll(resp.Body)
sm := bed.SmResponse{}
err := json.Unmarshal([]byte(string(data)), &sm)
if err != nil {
logging.AppLogger.Error("Upload To Smms fail", zap.Error(err))
return ""
}
return string(sm.Data.Url)
}

4,sougou

貌似不是很稳定,依然只是听说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//上传到搜狗,免登陆
func UpLoadToSouGou(img []byte) string {
preStr := "LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5R0xmR0IwSGdVTnRwVFQxaw0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJwaWNfcGF0aCI7IGZpbGVuYW1lPSIxMS5wbmciDQpDb250ZW50LVR5cGU6IGltYWdlL3BuZw0KDQo="
sufStr := "DQotLS0tLS1XZWJLaXRGb3JtQm91bmRhcnlHTGZHQjBIZ1VOdHBUVDFrLS0NCg=="
preStr = utils.Decode(base64.StdEncoding, preStr)
sufStr = utils.Decode(base64.StdEncoding, sufStr)
imgStr := string(img)
data := []byte(preStr + string(img) + sufStr)
url := "http://pic.sogou.com/pic/upload_pic.jsp"
client := &http.Client{}
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(data))
req.Header.Set("Content-Type", " multipart/form-data; boundary=----WebKitFormBoundaryGLfGB0HgUNtpTT1k")
req.Header.Add("Content-Length", string(strings.Count(imgStr, "")))
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
respUrl := string(body)
respUrl = strings.Replace(respUrl, "http", "https", -1)
return respUrl
}