GUI插件开发
概述
GUI插件指的是运行在electron版本的PicGo (opens new window)里的插件。它支持绝大多数在普通插件里能实现的功能,还增加了额外的guiApi
和其他的GUI特有的事件,让你的插件在PicGo里更加强大。
PicGo在2.0版本之后支持的插件系统其实就是以PicGo-Core为底层核心实现的。在PicGo上传图片的过程中,你书写的插件(包括Uploader、Transformer等等)都会进入PicGo-Core的上传流程中,所以如果你写了一个CLI版本的插件,基本都能无缝运行在PicGo里。
不过有的时候我们还需要一些额外的功能,比如:
- 相册里图片删除之后,对应的云端也删除图片
- 通过url地址上传图片
- 通过PicGo提供的上传接口,将某些MarkDown里的图片地址进行图床迁移
等等。这些操作或多或少需要额外的信息输入与交互,而不仅仅是依赖PicGo本身的上传区域来进行上传。所以针对GUI插件,PicGo提供了一些特殊的API来支持这些独立于常规上传流程之外的功能。
警告
确保你已经阅读过非GUI版本的插件开发,之前提到的概念在GUI版本的插件概述里将不会重复。
guiMenu
guiMenu是PicGo提给给插件的自主控制权的主入口。它的作用是在PicGo的插件页面给予每个插件自主的菜单项,如下图:
guiMenu是一个function,PicGo会传入ctx
(picgo本身)方便开发者使用picgo自带的一些方法,最后应该返回一个 数组。
每个menuItem只有两个属性,
- 一个是
label
,用于显示菜单文本。 - 一个是
handle
,用于点击之后执行相应的操作。其中handle
是一个function
,推荐写成async function
,方便控制流程。handle
里会传入ctx
和guiApi
,ctx
就是picgo本身,而guiApi
后文会详细介绍。
代码示例:
const guiMenu = ctx => {
return [
{
label: '打开InputBox',
async handle (ctx, guiApi) {
// do something...
}
},
{
label: '打开FileExplorer',
async handle (ctx, guiApi) {
// do something...
}
},
// ...
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
guiMenu应该在插件的module.exports
里暴露出去。例如你已经写了一个普通的picgo插件如下:
const handle = ctx => {
const input = ctx.input
let output
// do something
ctx.output = output
return ctx
}
module.exports = ctx => {
const register = () => {
ctx.helper.transformer.register('test', { handle })
}
return {
register,
transformer: 'test'
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
那么加入guiMenu
应该是这样:
const handle = ctx => {
const input = ctx.input
let output
// do something
ctx.output = output
return ctx
}
const guiMenu = ctx => {
return [
{
label: '打开InputBox',
async handle (ctx, guiApi) {
// do something...
}
},
{
label: '打开FileExplorer',
async handle (ctx, guiApi) {
// do something...
}
},
// ...
]
}
module.exports = ctx => {
const register = () => {
ctx.helper.transformer.register('test', { handle })
}
return {
register,
guiMenu, // <-- 在这里注册
transformer: 'test'
}
}
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
默认菜单项
根据插件开发-配置项处理一章的描述,如果你的插件提供了 Plugin
或 Uploader
或 Transformer
维度的配置,会在插件的右键菜单生成对应默认的配置菜单:
点击之后,PicGo会根据提供的配置项,转换生成可视化的配置表单:
如果觉得菜单项都是英文不好理解(默认取的是 name
值),你可以通过配置每个菜单项的 alias
字段,来让表单显示成 alias
的文字。
例子:
const conf = [
{
alias: '仓库名',
name: 'repo',
type: 'input',
default: userConfig.repo || '',
required: true
},
// ...
]
2
3
4
5
6
7
8
9
10
当用户点击确定之后,PicGo会根据配置项维度的不同,自动根据规则写入配置文件。
guiApi
注意
本章节的api版本是跟随PicGo的Electron版本 (opens new window),而不是PicGo-Core的版本,请务必注意
上文介绍了每个菜单项都应该对应一个handle
方法,用于执行点击菜单后的操作。其中传入的第一个参数为ctx
,第二个参数为guiApi
。
guiApi目前提供了如下的api:
guiApi.showInputBox
用于打开一个输入框guiApi.showFileExplorer
用于打开文件浏览器guiApi.upload
用于调用PicGo内部的上传方法上传guiApi.showNotification
用于调用系统级别的通知 2.0.1+guiApi.showMessageBox
用于调用系统级别的对话框 2.1.0+guiApi.galleryDB
用于操作相册数据 2.3.0+
后续会逐渐增加。
showInputBox([option])
调用之后打开一个输入弹窗,可以用于接受用户输入。
- option: Object ||
undefined
- return: 返回一个Promise对象,resolve的值是用户输入的结果。所以推荐用
async await
的方式获取。
其中option是可选值,可以传入一个{title, placeholder}
的对象,用于弹窗的标题和输入框的placeholder
显示。
示例:
const guiMenu = ctx => {
return [
{
label: '打开InputBox',
async handle (ctx, guiApi) {
const value = await guiApi.showInputBox({
title: '打开对话框',
placeholder: '请输入文件地址'
})
console.log(value)
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
showFileExplorer([option])
调用之后打开一个文件浏览器,可以得到用户选择的文件(夹)路径。
- option: Object ||
undefined
- return: 返回一个Promise对象,resolve的值是用户选择的文件路径数组。所以推荐用
async await
的方式获取。
其中option是可选值,可以传入一个合法的electron的dialog的options对象 (opens new window),用于指定是否可多选,用于选择文件还是文件夹等等。
示例:
const guiMenu = ctx => {
return [
{
label: '打开文件浏览器',
async handle (ctx, guiApi) {
const files = await guiApi.showFileExplorer({
properties: ['openFile', 'multiSelections']
})
console.log(files)
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
upload([file])
调用之后使用PicGo底层来上传,可以实现自动更新相册图片、上传成功后自动将URL写入剪贴板。
- file: Array ||
undefined
- return: 返回一个Promise对象,resolve的值是PicGo上传成功后的output值,是一个数组。所以推荐用
async await
获取。
提示
实际上如果通过上面的showInputBox
获得输入项,或者showFileExplorer
选中文件,再通过upload
上传的话,也可以很好的达到上传的目的。
推荐还是书写Uploader或者Transformer等插件,来实现接管PicGo的上传流程。
示例:
const guiMenu = ctx => {
return [
{
label: '独立上传',
async handle (ctx, guiApi) {
const files = await guiApi.showFileExplorer({
properties: ['openFile', 'multiSelections'
})
guiApi.upload(files)
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
2.0.1+
showNotification(option)调用之后弹出系统通知窗口。
- option: Object ||
undefined
- return: undefined(无返回值)
其中option是必选值,需要提供{title, body}
用于通知窗口的显示。
示例:
const guiMenu = ctx => {
return [
{
label: '显示通知',
async handle (ctx, guiApi) {
guiApi.showNotification({
title: '提示',
body: '本提示来自插件'
})
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
2.1.0+
showMessageBox([option])调用之后弹出系统的对话框窗口。
- option: Object ||
{title: '', message: '', type: 'info', buttons: ['Yes', 'No']}
- return: Object ->
{result, checkboxChecked}
其中,option的完整参数可以参考Electron的dialog.showMessageBox (opens new window)。返回的值里,result
为你指定的buttons的index值。比如上图如果我点了是(Y)
,那么我会收到如下返回值:
{
result: 0,
checkboxChecked: false // 如果你在options里指定了checkboxLabel则会出现一个checkbox,如果不提供,默认返回false
}
2
3
4
示例:
const guiMenu = ctx => {
return [
{
label: '显示MessageBox',
async handle (ctx, guiApi) {
const result = await guiApi.showMessageBox({
title: '这是title',
message: '这是message',
type: 'info',
buttons: ['Yes', 'No']
})
console.log(result) // { result: 0, checkboxChecked: false }
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2.3.0+
galleryDB2.3.0版本开始,提供了专门的相册数据操作api。包括了获取、更新、删除、插入等操作。详细说明可以参考 api-guiApi-galleryDB。
2.3.1+
i18n 国际化目前 PicGo 支持了如下几种语言:
- zh-CN (默认)
- zh-TW
- en
如果你的插件希望添加多语言支持,可以参考 cli-i18n 一节。
如果你希望给 PicGo-GUI 添加一种默认的新语言支持,参考文档 (opens new window)。
2.2.0+
快捷键系统从PicGo的2.2.0版本开始,插件支持注册全局快捷键了,可以注册快捷键来让实现一些便捷功能。
要注册插件需要暴露一个 commands
function,并返回一个 快捷键数组。每个 commandItem
有如下几个属性:
- key: string - 预设的快捷键
- name: string - 快捷键的唯一标识(用于和其他快捷键区分)
- label: string - 快捷键对用户展示的作用名称
- handle: async (ctx, guiApi) => {} - 快捷键的处理函数
代码示例:
const commands = (ctx) => {
const config = ctx.getConfig('xxx')
return [{
label: '快捷截图',
name: 'quickCapture',
key: 'Ctrl+Shift+0',
async handle (ctx, guiApi) {
// ...在这里实现你的快捷键要做的操作
}
}]
}
2
3
4
5
6
7
8
9
10
11
跟guiMenu相同,commands应该在插件的module.exports
里暴露出去。例如:
// ...
const commands = ctx => {}
module.exports = ctx => {
const register = () => {}
return {
register,
commands // <- 在这里注册
}
}
2
3
4
5
6
7
8
9
当安装了插件之后,可以在「PicGo设置-快捷键设置」打开快捷键设置界面,就可以看到注册的快捷键。
PicGo会根据插件的名字以及快捷键Item的name值,给快捷键分配不同的配置作用域,从而生成配置文件,生成的配置文件的key名的规则为 ${pluginName}:${commandItem.name}
(开发者无需关注):
"shortKey": {
"picgo:upload": {
"enable": false,
"key": "Ctrl+Shift+U",
"name": "upload",
"label": "快捷上传"
},
"picgo-plugin-test:test": {
"enable": true,
"name": "test",
"label": "快捷截图",
"key": "Ctrl+Shift+0"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
可以参考插件picgo-plugin-quick-capture (opens new window)的写法。
事件
PicGo在一些情况下会触发一些事件,这些事件可以被插件监听从而实现一些额外的功能。你可以在你的插件的register
里监听这些事件。
remove
当用户在相册里点击删除,并且确定的时候,将会触发remove
事件:
remove
事件会发送删除的图片列表(哪怕只有一张也是以数组格式传递),格式大概如下:
[
{
"fileName": "20190112165042.png",
"width": 1660,
"height": 932,
"extname": ".png",
"imgUrl": "https://yyyy/xxxx.png",
"type": "tcyun",
"id": "564b4cb8-3f1c-4af3-88b0-e9ba7f970468"
},
{
"fileName": "new.jpg",
"width": 1648,
"height": 936,
"extname": ".gif",
"imgUrl": "https://i.loli.net/2019/01/12/xxxx.jpg",
"type": "smms",
"id": "8532567a-a307-426e-8d10-c54aecc2100d"
}
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
你可以从中获取type
值(上传的图床类型),文件名、URL、后缀等等信息。
从 GUI VERSION 2.3.0 开始,你可以在第二个参数拿到 guiApi。
示例:
module.exports = ctx => {
const register = () => {
ctx.on('remove', (files, guiApi) => {
console.log(files, guiApi)
})
}
return {
register
}
}
2
3
4
5
6
7
8
9
10
其他
Uploader的名字
如果你写了一个Uploader
的插件,PicGo将会自动将其显示到图床列表里。你可以自定义一下这个图床要显示的名字,通过name
选项来实现。如果你不提供这个name
选项,那么PicGo将会显示Uploader注册的时候的id
值。
const handle = ctx => {
// ...
}
module.exports = ctx => {
const register = () => {
ctx.helper.uploader.register('test', {
handle,
name: '微博图床Plus'
})
}
return {
register,
uploader: 'test' // Uploader的id
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如果你的Uploader
提供了config
配置,那么在PicGo上也会相应显示出来。