Skip to content

Commit

Permalink
feat: support qiniu
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Mar 26, 2024
1 parent 80df23e commit 3cb223a
Show file tree
Hide file tree
Showing 10 changed files with 422 additions and 31 deletions.
@@ -1,8 +1,17 @@
import { IAliyunConfig, IPicGo, IPluginConfig } from "../../types"
import { ILocalesKey } from "../../i18n/zh-CN"
/*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* Copyright (C) 2024 Terwer, Inc. <https://terwer.space/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/

import { IAliyunConfig, IPicGo, IPluginConfig } from "../../../types"
import { ILocalesKey } from "../../../i18n/zh-CN"
import { hasNodeEnv } from "universal-picgo-store"
import { handleNode } from "./aliyun-node"
import { handleWeb } from "./aliyun-web"
import { handleNode } from "./node"
import { handleWeb } from "./web"

const handle = async (ctx: IPicGo): Promise<IPicGo> => {
if (hasNodeEnv) {
Expand All @@ -21,7 +30,7 @@ const config = (ctx: IPicGo): IPluginConfig[] => {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD_ACCESSKEYID")
},
default: userConfig.accessKeyId || "",
required: true
required: true,
},
{
name: "accessKeySecret",
Expand All @@ -30,7 +39,7 @@ const config = (ctx: IPicGo): IPluginConfig[] => {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD_ACCESSKEYSECRET")
},
default: userConfig.accessKeySecret || "",
required: true
required: true,
},
{
name: "bucket",
Expand All @@ -39,7 +48,7 @@ const config = (ctx: IPicGo): IPluginConfig[] => {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD_BUCKET")
},
default: userConfig.bucket || "",
required: true
required: true,
},
{
name: "area",
Expand All @@ -54,7 +63,7 @@ const config = (ctx: IPicGo): IPluginConfig[] => {
get message() {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD_MESSAGE_AREA")
},
required: true
required: true,
},
{
name: "path",
Expand All @@ -69,7 +78,7 @@ const config = (ctx: IPicGo): IPluginConfig[] => {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD_MESSAGE_PATH")
},
default: userConfig.path || "",
required: false
required: false,
},
{
name: "customUrl",
Expand All @@ -84,7 +93,7 @@ const config = (ctx: IPicGo): IPluginConfig[] => {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD_MESSAGE_CUSTOMURL")
},
default: userConfig.customUrl || "",
required: false
required: false,
},
{
name: "options",
Expand All @@ -99,8 +108,8 @@ const config = (ctx: IPicGo): IPluginConfig[] => {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD_MESSAGE_OPTIONS")
},
default: userConfig.options || "",
required: false
}
required: false,
},
]
return config
}
Expand All @@ -111,6 +120,6 @@ export default function register(ctx: IPicGo): void {
return ctx.i18n.translate<ILocalesKey>("PICBED_ALICLOUD")
},
handle,
config
config,
})
}
@@ -1,9 +1,18 @@
/*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* Copyright (C) 2024 Terwer, Inc. <https://terwer.space/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/

// noinspection ES6PreferShortImport

import { IAliyunConfig, IPicGo } from "../../types"
import { IBuildInEvent } from "../../utils/enums"
import { ILocalesKey } from "../../i18n/zh-CN"
import { base64ToBuffer } from "../../utils/common"
import { IAliyunConfig, IPicGo } from "../../../types"
import { IBuildInEvent } from "../../../utils/enums"
import { ILocalesKey } from "../../../i18n/zh-CN"
import { base64ToBuffer } from "../../../utils/common"
import OSS from "ali-oss"

const handleNode = async (ctx: IPicGo): Promise<IPicGo> => {
Expand Down
@@ -1,10 +1,19 @@
import { IAliyunConfig, IPicGo } from "../../types"
/*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* Copyright (C) 2024 Terwer, Inc. <https://terwer.space/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/

import { IAliyunConfig, IPicGo } from "../../../types"
import crypto from "crypto"
import mime from "mime-types"
import { IBuildInEvent } from "../../utils/enums"
import { ILocalesKey } from "../../i18n/zh-CN"
import { IBuildInEvent } from "../../../utils/enums"
import { ILocalesKey } from "../../../i18n/zh-CN"
import { AxiosRequestConfig } from "axios"
import { base64ToBuffer, safeParse } from "../../utils/common"
import { base64ToBuffer, safeParse } from "../../../utils/common"

// generate OSS signature
const generateSignature = (options: IAliyunConfig, fileName: string): string => {
Expand Down
6 changes: 4 additions & 2 deletions libs/Universal-PicGo-Core/src/plugins/uploader/index.ts
Expand Up @@ -8,19 +8,21 @@
*/

import { IPicGo, IPicGoPlugin } from "../../types"
import SMMSUploader from "./smms"
import githubUploader from "./github"
import gitlabUploader from "./gitlab"
import aliYunUploader from "./aliyun"
import qiniuUploader from "./qiniu"
import SMMSUploader from "./smms"
import imgurUploader from "./imgur"

const buildInUploaders: IPicGoPlugin = () => {
return {
register(ctx: IPicGo) {
SMMSUploader(ctx)
githubUploader(ctx)
gitlabUploader(ctx)
aliYunUploader(ctx)
qiniuUploader(ctx)
SMMSUploader(ctx)
imgurUploader(ctx)
},
}
Expand Down
22 changes: 22 additions & 0 deletions libs/Universal-PicGo-Core/src/plugins/uploader/qiniu/digest.ts
@@ -0,0 +1,22 @@
/*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* Copyright (C) 2024 Terwer, Inc. <https://terwer.space/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/

class Mac {
accessKey: string
secretKey: string
options: any

constructor(accessKey: string, secretKey: string, options?: Partial<any>) {
this.accessKey = accessKey
this.secretKey = secretKey
this.options = { ...options }
}
}

export { Mac }
210 changes: 210 additions & 0 deletions libs/Universal-PicGo-Core/src/plugins/uploader/qiniu/index.ts
@@ -0,0 +1,210 @@
/*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* Copyright (C) 2024 Terwer, Inc. <https://terwer.space/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/

import { ILocalesKey } from "../../../i18n/zh-CN"
import { IPicGo, IPluginConfig, IQiniuConfig } from "../../../types"
import { IBuildInEvent } from "../../../utils/enums"
import { bufferToBase64, safeParse } from "../../../utils/common"
import mime from "mime-types"
import { AxiosRequestConfig } from "axios"
import { Mac } from "./digest"
import { PutPolicy } from "./rs"

function postOptions(options: IQiniuConfig, fileName: string, token: string, imgBase64: string): AxiosRequestConfig {
const area = selectArea(options.area || "z0")
const path = options.path || ""
const base64FileName = Buffer.from(path + fileName, "utf-8")
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
return {
method: "POST",
url: `http://upload${area}.qiniup.com/putb64/-1/key/${base64FileName}`,
headers: {
Authorization: `UpToken ${token}`,
"Content-Type": mime.lookup(fileName) || "application/octet-stream",
},
data: imgBase64,
proxy: false,
}
}

function selectArea(area: string): string {
return area === "z0" ? "" : "-" + area
}

function getToken(qiniuOptions: any): string {
const accessKey = qiniuOptions.accessKey
const secretKey = qiniuOptions.secretKey
const mac = new Mac(accessKey, secretKey)
const options = {
scope: qiniuOptions.bucket,
}
const putPolicy = new PutPolicy(options)
return putPolicy.uploadToken(mac)
}

const handle = async (ctx: IPicGo): Promise<IPicGo> => {
const qiniuOptions = ctx.getConfig<IQiniuConfig>("picBed.qiniu")
if (!qiniuOptions) {
throw new Error("Can't find qiniu config")
}

const imgList = ctx.output
for (const img of imgList) {
if (img.fileName && img.buffer) {
try {
let base64Image = img.base64Image
if (!base64Image && img.buffer) {
base64Image = bufferToBase64(img.buffer)
}
if (!base64Image) {
ctx.log.error("Can not find image base64")
throw new Error("Can not find image base64")
}
const options = postOptions(qiniuOptions, img.fileName, getToken(qiniuOptions), base64Image)
const res: any = await ctx.request(options)
const body = safeParse<any>(res)

if (body?.key) {
delete img.base64Image
delete img.buffer
const baseUrl = qiniuOptions.url
const options = qiniuOptions.options
img.imgUrl = `${baseUrl}/${body.key as string}${options}`
} else {
ctx.emit(IBuildInEvent.NOTIFICATION, {
title: ctx.i18n.translate<ILocalesKey>("UPLOAD_FAILED"),
body: body.msg,
})
ctx.log.error("qiniu error", body)
throw new Error("Upload failed")
}
} catch (e: any) {
if (e.message !== "Upload failed") {
// err.response maybe undefined
if (e.error) {
const errMsg = e.error
ctx.emit(IBuildInEvent.NOTIFICATION, {
title: ctx.i18n.translate<ILocalesKey>("UPLOAD_FAILED"),
body: errMsg,
})
throw errMsg
}
}
throw e
}
}
}
return ctx
}

const config = (ctx: IPicGo): IPluginConfig[] => {
const userConfig = ctx.getConfig<IQiniuConfig>("picBed.qiniu") || {}
const config: IPluginConfig[] = [
{
name: "accessKey",
type: "input",
get alias() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_ACCESSKEY")
},
default: userConfig.accessKey || "",
required: true,
},
{
name: "secretKey",
type: "password",
get alias() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_SECRETKEY")
},
default: userConfig.secretKey || "",
required: true,
},
{
name: "bucket",
type: "input",
get alias() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_BUCKET")
},
default: userConfig.bucket || "",
required: true,
},
{
name: "url",
type: "input",
get prefix() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_URL")
},
get alias() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_URL")
},
get message() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_MESSAGE_URL")
},
default: userConfig.url || "",
required: true,
},
{
name: "area",
type: "input",
get prefix() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_AREA")
},
get alias() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_AREA")
},
get message() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_MESSAGE_AREA")
},
default: userConfig.area || "",
required: true,
},
{
name: "options",
type: "input",
get prefix() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_OPTIONS")
},
get alias() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_OPTIONS")
},
get message() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_MESSAGE_OPTIONS")
},
default: userConfig.options || "",
required: false,
},
{
name: "path",
type: "input",
get prefix() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_PATH")
},
get alias() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_PATH")
},
get message() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU_MESSAGE_PATH")
},
default: userConfig.path || "",
required: false,
},
]
return config
}

export default function register(ctx: IPicGo): void {
ctx.helper.uploader.register("qiniu", {
get name() {
return ctx.i18n.translate<ILocalesKey>("PICBED_QINIU")
},
handle,
config,
})
}

0 comments on commit 3cb223a

Please sign in to comment.