一、Picog开发介绍
Picgo是(作者博客)使用electron-vue
开发的,借用作者的话,“picgo是个上传的流程系统。因此插件其实就是针对这个流程系统的某个部件或者某些部件的开发”。
Picgo的插件开发主要针对五个部分:
- Transformer
- Uploader
- beforeTransformPlugins
- beforeUploadPlugins
- afterUploadPlugins
这里我们开发的是上传插件,也就是Uploader。
Picgo调用插件通过调用插件向外暴露的handle方法,同时会向handle传入picgo的ctx,既picgo的上下文对象,包含picgo提供的api。
如下,定义一个register方法,利用ctx的注册方法注册一个uploader插件,同时定义handle和name,picgo调用这个插件时就会调用handle方法。
module.exports = (ctx) => {
const register = () => {
ctx.log.success('csdn插件加载成功')
ctx.helper.uploader.register('csdn-uploader', {
handle: handle, //定义插件主方法
config: config,
name: 'csdn'
})
}
return {
register,
uploader: 'csdn-uploader'
}
}
Picgo插件的详细开发过程,参考:
二、下载插件模板
Picgo提供插件开发的模板,方便很多,只需要关注具体功能的开发。
流程:
- 首先,全局安装picgo
npm install picgo -g
- picgo安装成功后,在cmd命令行,使用命令创建插件:
picgo init plugin <your-project-name>
如果你已经创建过一次模板,下次可以使用离线模式:
picgo init plugin <your-project-name> --offline
因为插件模板是从GitHub下载的,众所周知…卡…慢…崩,所以耐心尝试
在下载过程中会提示补充插件的各项信息,如下,这里我选择使用JS开发
[PicGo INFO]: Template files are downloading...
[PicGo SUCCESS]: Template files are downloaded!
# 插件名称
? Plugin name: csdn
# 插件简介
? Plugin description: 测试
# 作者
? author: <你自己>
# 开发模块(上下键移动,enter选择)
? Choose modules you want to develop: uploader
# 是否只是命令行插件
? Your plugin is just used in CLI? NO
# 用 TypeScript 还是 JavaScript
? Use TS or JS? JS
# 有没有快捷方式
? Your plugin has some shortcut for GUI? NO
# 创建成功
[PicGo SUCCESS]:
Generate template files successfully!
Please cd E:\csdn, and then
# 接下来进入文件夹 安装依赖包
npm install
# or
yarn
[PicGo SUCCESS]: Done!
三、注册插件
下载完插件模板后进入src/index.js
发现是这样的:
module.exports = (ctx) => {
const register = () => {
}
return {
register
}
}
我们需要在register方法中注册我们的插件:
module.exports = (ctx) => {
const register = () => {
ctx.log.success('csdn插件加载成功')
ctx.helper.uploader.register('csdn-uploader', {
handle: handle,
config: config,
name: 'csdn'
})
}
return {
register,
uploader: 'csdn-uploader'
}
}
其中handle就是我们插件的主方法,config是用户配置信息。
四、handle主方法
handle是我们插件运行的主方法,在里面我们需要获取用户配置信息、获取图片的缓存(即ctx.out,就是我们将要上传的图片信息)、构造请求上传图片、返回图片上传后的URL。
const handle = async (ctx) => {
let output = ctx.output
let key, policy, OSSAccessKeyId, signature, callback, aliyun_url
for (let i in output) {
// output[i].imgUrl = 'https://zqx.jpg'// 真实地址
// output[i].url = 'https://zzzzzz.jpg'// 显示
var request = preRequestConstruct()//构造第一个请求
var response = await ctx.Request.request(request)
if (response.statusCode === 200 || response.statusCode === 201) {
response = JSON.parse(response.body)
ctx.log.info(JSON.stringify(response))
ctx.log.info('---------------------')
key = response['data']['filePath']
policy = response['data']['policy']
OSSAccessKeyId = response['data']['accessId']
signature = response['data']['signature']
callback = response['data']['callbackUrl']
aliyun_url = response['data']['host']
} else {
throw new Error('Upload failed')
}
//构造第二个请求
var uploadrequest = uploadRequestConstruct(aliyun_url, output[i], key, policy, OSSAccessKeyId, signature, callback)
// ctx.log.info(JSON.stringify(uploadrequest))
var uploadresponse = await ctx.Request.request(uploadrequest)
if (uploadresponse.statusCode === 200 || uploadresponse.statusCode === 201) {
uploadresponse = JSON.parse(uploadresponse.body)//body里面才是响应内容
// ctx.log.info(JSON.stringify(uploadresponse))
var img_url = uploadresponse['data']['imageUrl']
output[i].imgUrl = img_url// 真实地址
output[i].url = img_url// 显示
} else {
throw new Error('Upload failed')
}
}
return ctx
}
因为函数中有网络请求,所以这里我们使用async关键字。
五、用户配置config方法
{
name: 'accessKey',//字段
type: 'input',//类型
default: userConfig.accessKey || '',//默认值
message: 'AccessKey不能为空',//提示语
required: true//是否必要
},
config方法返回了一个数组,包含用户需要配置各项信息,具体参考
const config = (ctx) => {
let userConfig = ctx.getConfig('picBed.csdn-uploader')
if (!userConfig) {
userConfig = {}
}
const config = [
{
name: 'accessKey',
type: 'input',
default: userConfig.accessKey || '',
message: 'AccessKey不能为空',
required: true
},
{
name: 'secretKey',
type: 'input',
default: userConfig.secretKey || '',
message: 'SecretKey不能为空',
required: true
},
{
name: 'bucketName',
type: 'input',
default: userConfig.bucketName || '',
message: 'BucketName不能为空',
required: true
},
{
name: 'region',
type: 'input',
alias: '地区',
default: userConfig.region || '',
message: '例如:bj.bcebos.com',
required: true
},
{
name: 'path',
type: 'input',
alias: '存储路径',
default: userConfig.path || '',
message: '例如:blog/img',
required: false
},
{
name: 'customUrl',
type: 'input',
alias: '自定义域名',
default: userConfig.customUrl || '',
message: '例如:http://bucket.xxx.com',
required: false
}
]
return config
}
客户端的UI界面会根据config返回的数组显示:
当我们在软件界面保存信息后,配置信息会自动保存在C:\Users\用户名\AppData\Roaming\picgo\data.json
文件中
六、构造请求
构造上传图片请求
返回ctx.Request.request方法接受的请求参数
const requestConstruct= (userConfig, fileName, signature, img, dateUTC, dateISO) => {
const bucketName = userConfig.bucketName //我们在软件界面输入的信息
const host = userConfig.region //我们在软件界面输入的信息
const path = (userConfig.path) ? userConfig.path + '/' : '' //我们在软件界面输入的信息
return {
method: 'PUT',
uri: `http://${host}/v1/${bucketName}/${encodeURI(path)}${encodeURI(fileName)}`,
headers: {
Authorization: signature,
Date: dateUTC,
'x-bce-date': dateISO
},
body: img,
resolveWithFullResponse: true
}
}
七、插件安装
将开发好的项目,复制到任意一个文件夹(以后不会移动当前项目),在插件设置
选项中点击向下的箭头
,导入本地插件
八、日志输出调试
ctx.log.success方法会在日志文件中记录信息,可以作为调试的手段之一,可以在C:\Users\用户名\AppData\Roaming\picgo\picgo.log
中查看,AppData
是隐藏文件。