PicGo 是一个用于快速上传图片并获取图片预览链接的工具,可以作为 Typora 在编辑 MarkDown 文档时插件处理图片保存的问题。
官方文档地址:picgo.github.io/PicGo-Core-…
PicGo 上传流程
可供开发的部分包括:两个模块(Transformer、Uploader)、三个生命周期函数(beforeTransformPlugins、beforeUploadPlugins、afterUploadPlugins)
module.exports = (ctx) => {
const register = () => {
// 注册钩子函数
ctx.helper.uploader.register('wlyd', { handle: handleUploader, config })
ctx.helper.beforeTransformPlugins.register('wlyd', handleBeforeTransform)
}
return {
register, // 注册函数
uploader: 'wlyd' // 声明注册的uploader的id
}
}
注册模块(Transformer、Uploader):handle 执行函数;config 界面配置
ctx.helper.uploader.register('wlyd', { handle, config })
执行函数
const handle = (ctx) => {
// todo...
}
ctx 常用属性如下
- output:Array 上传文件列表
- getConfig、setConfig、saveConfig、unsetConfig、removeConfig 操作配置文件
- Request.request 发起请求(v1.5.0后废弃,可以使用 request 方法)
界面配置
const config = (ctx) => {
// todo...
return [...]
}
配置对象
{
name: 'upload_guid', // 字段名称,读取时使用
type: 'input', // 展示类型
default: '', // 默认值
required: true, // 是否必须
alias: '上传GUID' // 字段别名,界面展示使用
choices: [ // 下拉框选项
{ name: '', value: '' }
]
}
type值
-
input:输入框
-
password
-
list:下拉框,必须包含 choices 属性
-
checkbox:多选下拉框,必须包含 choices 属性
-
confirm:开关
注意事项
上传完成后必要操作:
delete ctx.output[index].base64Image
delete ctx.output[index].buffer
// 更新图片链接,否则无法正常预览
ctx.output[index].imgUrl = link
完整demo
const fs = require('fs')
const path = require('path')
/** 获取上传后图片的预览链接 */
const getPreviewLink = () => {
return ''
}
/** 获取上传链接 */
const getUploadLink = async () => {
return ''
}
/** 获取上传配置 */
const getUploadConfig = (uploadLink, fileName, file) => {
return {
method: 'POST',
url: uploadLink,
headers: {
contentType: 'multipart/form-data'
},
formData: {/** 上传参数 */}
}
}
const getImageBuffer = (image) => {
let buffer = image.buffer
if (!buffer && image.base64Image) {
buffer = Buffer.from(image.base64Image, 'base64')
}
return new Uint8Array(buffer)
}
const getFilePath = (fileName) => {
return path.join(__dirname, fileName)
}
/** 获取上传文件:先保存本地目录,然后再读取,最后删除本地文件 */
const getFile = async (image) => {
const filePath = getFilePath(image.fileName)
await fs.writeFileSync(filePath, getImageBuffer(image))
const stream = fs.createReadStream(filePath)
setTimeout(() => fs.unlink(getFilePath(image.fileName), () => {}), 100)
return stream
}
/** 判断是否上传成功 */
const isUploadSuccess = (data) => {
return true
}
/** 上传文件 */
const uploadFile = (ctx, config) => {
return async image => {
try {
const uploadLink = getUploadLink()
const file = await getFile(image)
const uploadConfig = getUploadConfig(uploadLink, image.fileName, file)
return await ctx.Request.request(uploadConfig)
} catch (error) {
ctx.emit('notification', { title: '上传失败', error })
throw new Error(JSON.stringify(error))
}
}
}
/** 图片重命名方式 */
const UPDATE_FILE_NAME_ACTION = {
time: (file) => {
const date = new Date()
const hour = `${date.getHours()}`.padStart(2, '0')
const minute = `${date.getMinutes()}`.padStart(2, '0')
const second = `${date.getSeconds()}`.padStart(2, '0')
return `${hour}${minute}${second}${date.getMilliseconds()}${file.extname}`
},
guid: (file) => {
let d = new Date().getTime()
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = (d + Math.random() * 16) % 16 | 0
d = Math.floor(d / 16)
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
}) + file.extname
}
}
/** 图片重命名 */
const updateFileName = (type, file) => {
return type in UPDATE_FILE_NAME_ACTION
? UPDATE_FILE_NAME_ACTION[type](file)
: file.fileName
}
/** 主函数 */
const handle = async (ctx) => {
// 获取 data.json 配置
const config = ctx.getConfig('picBed.wlyd')
const upload = uploadFile(ctx, config)
for (const key in ctx.output) {
const image = ctx.output[key]
image.fileName = updateFileName(config.rename_type, image)
const body = await upload(image)
if (isUploadSuccess(body)) {
delete ctx.output[key].base64Image
delete ctx.output[key].buffer
// 更新图片链接,否则 typora 无法正常预览
ctx.output[key].imgUrl = getPreviewLink(image.fileName, config.preview_guid)
}
}
}
/** 界面配置 */
const config = (ctx) => {
return [
{
name: 'upload_guid',
type: 'input',
default: '',
required: true,
alias: '上传GUID'
},
{
name: 'rename_type',
type: 'list',
default: 'time',
alias: '文件重命名',
choices: [
{ name: '关闭', value: 'close' },
{ name: '时间戳', value: 'time' },
{ name: 'GUID', value: 'guid' }
]
}
]
}
module.exports = (ctx) => {
const register = () => {
ctx.helper.uploader.register('wlyd', { handle, config })
}
return { uploader: 'wlyd', register }
}
原文链接: # PicGo图床插件