Skip to content

Commit f6cb69b

Browse files
committed
feat(图床): 新增GitHub图床和又拍云图床
1 parent 06db055 commit f6cb69b

File tree

8 files changed

+196
-8
lines changed

8 files changed

+196
-8
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"rimraf": "^2.6.2",
4646
"superagent": "^7.0.2",
4747
"update-check": "^1.5.3",
48+
"upyun": "^3.4.6",
4849
"urllib": "^2.29.1"
4950
},
5051
"devDependencies": {

util/imageBeds/cos.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// 腾讯云图床
44
const COS = require('cos-nodejs-sdk-v5');
55
const out = require('../../lib/out');
6+
const { transformRes } = require('../index');
67

78
const secretId = process.env.SECRET_ID;
89
const secretKey = process.env.SECRET_KEY;
@@ -37,8 +38,9 @@ class CosClient {
3738
Region: this.config.region, // 存储桶所在地域,必须字段
3839
Key: `${this.config.prefixKey}/${fileName}`, // 文件名 必须
3940
});
40-
return `https://${this.config.bucket}.cos.${this.config.region}.myqcloud.com/${this.config.prefixKey}/${fileName}`;
41+
return `https://${this.config.bucket}.cos.${this.config.region}.myqcloud.com/c`;
4142
} catch (e) {
43+
out.warn(`检查图片信息时出错: ${transformRes(e)}`);
4244
return '';
4345
}
4446
}
@@ -61,7 +63,7 @@ class CosClient {
6163
});
6264
return `https://${res.Location}`;
6365
} catch (e) {
64-
out.error(`上传图片失败,请检查: ${e}`);
66+
out.error(`上传图片失败,请检查: ${transformRes(e)}`);
6567
process.exit(-1);
6668
}
6769
}

util/imageBeds/github.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
'use strict';
2+
3+
// Github图床
4+
const urllib = require('urllib');
5+
const out = require('../../lib/out');
6+
const { transformRes } = require('../index');
7+
8+
const secretId = process.env.SECRET_ID;
9+
const secretKey = process.env.SECRET_KEY;
10+
11+
12+
class GithubClient {
13+
constructor(config) {
14+
this.config = config;
15+
}
16+
17+
static getInstance(config) {
18+
if (!this.instance) {
19+
this.instance = new GithubClient(config);
20+
}
21+
return this.instance;
22+
}
23+
24+
async _fetch(method, fileName, base64File) {
25+
const path = `https://api.github.com/repos/${secretId}/${this.config.bucket}/contents/${this.config.prefixKey}/${fileName}`;
26+
const data = method === 'PUT' ? {
27+
message: 'yuque-hexo upload images',
28+
content: base64File,
29+
} : null;
30+
try {
31+
const result = await urllib.request(path, {
32+
dataType: 'json',
33+
method,
34+
data,
35+
timeout: 60000,
36+
headers: {
37+
'Content-Type': 'application/json',
38+
'User-Agent': 'yuque-hexo',
39+
Authorization: `token ${secretKey}`,
40+
},
41+
});
42+
if (result.status === 200) {
43+
return result.data.download_url;
44+
}
45+
out.warn(`请求图片失败,请检查: ${transformRes(result)}`);
46+
return '';
47+
} catch (error) {
48+
out.warn(`请求图片失败,请检查: ${transformRes(error)}`);
49+
return '';
50+
}
51+
}
52+
53+
54+
/**
55+
* 检查图床是否已经存在图片,存在则返回url,不存在返回空
56+
*
57+
* @param {string} fileName 文件名
58+
* @return {Promise<string>} 图片url
59+
*/
60+
async hasImage(fileName) {
61+
try {
62+
return await this._fetch('GET', fileName);
63+
} catch (e) {
64+
out.warn(`检查图片信息时出错: ${transformRes(e)}`);
65+
return '';
66+
}
67+
}
68+
69+
/**
70+
* 上传图片到图床
71+
*
72+
* @param {Buffer} imgBuffer 文件buffer
73+
* @param {string} fileName 文件名
74+
* @return {Promise<string>} 图床的图片url
75+
*/
76+
async uploadImg(imgBuffer, fileName) {
77+
try {
78+
const base64File = imgBuffer.toString('base64');
79+
const imgUrl = await this._fetch('PUT', fileName, base64File);
80+
if (imgUrl) return imgUrl;
81+
process.exit(-1);
82+
} catch (e) {
83+
out.error(`上传图片失败,请检查: ${transformRes(e)}`);
84+
process.exit(-1);
85+
}
86+
}
87+
}
88+
89+
module.exports = GithubClient;

util/imageBeds/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
const CosClient = require('./cos');
44
const OssClient = require('./oss');
55
const QiniuClient = require('./qiniu');
6+
const UPClient = require('./upyun');
7+
const GithubClient = require('./github');
68
const out = require('../../lib/out');
79

810
// 目前已适配图床列表
9-
const imageBedList = [ 'qiniu', 'cos', 'oss' ];
11+
const imageBedList = [ 'qiniu', 'cos', 'oss', 'upyun', 'github' ];
1012

1113
class ImageBeds {
1214
constructor(config) {
@@ -39,6 +41,10 @@ class ImageBeds {
3941
return OssClient.getInstance(this.config);
4042
case 'qiniu':
4143
return QiniuClient.getInstance(this.config);
44+
case 'upyun':
45+
return UPClient.getInstance(this.config);
46+
case 'github':
47+
return GithubClient.getInstance(this.config);
4248
default:
4349
return QiniuClient.getInstance(this.config);
4450
}

util/imageBeds/oss.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// 阿里云图床
44
const OSS = require('ali-oss');
55
const out = require('../../lib/out');
6+
const { transformRes } = require('../index');
67

78
const secretId = process.env.SECRET_ID;
89
const secretKey = process.env.SECRET_KEY;
@@ -39,6 +40,7 @@ class OssClient {
3940
await this.imageBedInstance.head(`${this.config.prefixKey}/${fileName}`);
4041
return `https://${this.config.bucket}.${this.config.region}.aliyuncs.com/${this.config.prefixKey}/${fileName}`;
4142
} catch (e) {
43+
out.warn(`检查图片信息时出错: ${transformRes(e)}`);
4244
return '';
4345
}
4446
}
@@ -55,7 +57,7 @@ class OssClient {
5557
const res = await this.imageBedInstance.put(`${this.config.prefixKey}/${fileName}`, imgBuffer);
5658
return res.url;
5759
} catch (e) {
58-
out.error(`上传图片失败,请检查: ${e}`);
60+
out.error(`上传图片失败,请检查: ${transformRes(e)}`);
5961
process.exit(-1);
6062
}
6163
}

util/imageBeds/qiniu.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// 七牛云图床
44
const qiniu = require('qiniu');
55
const out = require('../../lib/out');
6+
const { transformRes } = require('../index');
67

78
const secretId = process.env.SECRET_ID;
89
const secretKey = process.env.SECRET_KEY;
@@ -46,8 +47,7 @@ class QiniuClient {
4647
return await new Promise(resolve => {
4748
this.bucketManager.stat(this.config.bucket, `${this.config.prefixKey}/${fileName}`, (err, respBody, respInfo) => {
4849
if (err) {
49-
out.error(`上传图片失败,请检查: ${err}`);
50-
process.exit(-1);
50+
out.warn(`检查图片信息时出错: ${transformRes(err)}`);
5151
} else {
5252
if (respInfo.statusCode === 200) {
5353
resolve(`${this.config.host}/${this.config.prefixKey}/${fileName}`);
@@ -71,13 +71,13 @@ class QiniuClient {
7171
this.formUploader.put(this.uploadToken, `${this.config.prefixKey}/${fileName}`, imgBuffer, this.putExtra, (respErr,
7272
respBody, respInfo) => {
7373
if (respErr) {
74-
out.error(`上传图片失败,请检查: ${respErr}`);
74+
out.error(`上传图片失败,请检查: ${transformRes(respErr)}`);
7575
process.exit(-1);
7676
}
7777
if (respInfo.statusCode === 200) {
7878
resolve(`${this.config.host}/${this.config.prefixKey}/${fileName}`);
7979
} else {
80-
out.error(`上传图片失败,请检查: ${respInfo}`);
80+
out.error(`上传图片失败,请检查: ${transformRes(respInfo)}`);
8181
process.exit(-1);
8282
}
8383
});

util/imageBeds/upyun.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
'use strict';
2+
3+
// 又拍云图床
4+
const upyun = require('upyun');
5+
const out = require('../../lib/out');
6+
const { transformRes } = require('../index');
7+
8+
const secretId = process.env.SECRET_ID;
9+
const secretKey = process.env.SECRET_KEY;
10+
11+
class UPClient {
12+
constructor(config) {
13+
this.config = config;
14+
this.init();
15+
}
16+
init() {
17+
if (!this.config.host) {
18+
out.warn(`未指定域名host,将使用测试域名:http://${this.config.bucket}.test.upcdn.net`);
19+
this.config.host = `http://${this.config.bucket}.test.upcdn.net`;
20+
}
21+
// 如果不指定协议,默认使用http
22+
if (!this.config.host.startsWith('http')) {
23+
this.config.host = `http://${this.config.bucket}`;
24+
}
25+
this.imageBedInstance = new upyun.Client(new upyun.Service(this.config.bucket, secretId, secretKey));
26+
}
27+
28+
static getInstance(config) {
29+
if (!this.instance) {
30+
this.instance = new UPClient(config);
31+
}
32+
return this.instance;
33+
}
34+
35+
/**
36+
* 检查图床是否已经存在图片,存在则返回url,不存在返回空
37+
*
38+
* @param {string} fileName 文件名
39+
* @return {Promise<string>} 图片url
40+
*/
41+
async hasImage(fileName) {
42+
try {
43+
const res = await this.imageBedInstance.headFile(`${this.config.prefixKey}/${fileName}`);
44+
if (res) {
45+
return `${this.config.host}/${this.config.prefixKey}/${fileName}`;
46+
}
47+
return '';
48+
} catch (e) {
49+
out.error(`上传图片失败,请检查: ${transformRes(e)}`);
50+
return '';
51+
}
52+
}
53+
54+
/**
55+
* 上传图片到图床
56+
*
57+
* @param {Buffer} imgBuffer 文件buffer
58+
* @param {string} fileName 文件名
59+
* @return {Promise<string>} 图床的图片url
60+
*/
61+
async uploadImg(imgBuffer, fileName) {
62+
try {
63+
const res = await this.imageBedInstance.putFile(`${this.config.prefixKey}/${fileName}`, imgBuffer);
64+
if (res) {
65+
return `${this.config.host}/${this.config.prefixKey}/${fileName}`;
66+
}
67+
out.error('上传图片失败,请检查又拍云配置');
68+
process.exit(-1);
69+
} catch (e) {
70+
out.error(`上传图片失败,请检查: ${transformRes(e)}`);
71+
process.exit(-1);
72+
}
73+
}
74+
}
75+
76+
module.exports = UPClient;
77+

util/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,14 @@ function formatDate(date) {
9595
}
9696

9797
exports.formatDate = formatDate;
98+
99+
function transformRes(res) {
100+
try {
101+
if (lodash.isString(res)) return res;
102+
return JSON.stringify(res);
103+
} catch (e) {
104+
return res;
105+
}
106+
}
107+
108+
exports.transformRes = transformRes;

0 commit comments

Comments
 (0)