Skip to content

Commit

Permalink
feat: add smms plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyue committed Mar 19, 2024
1 parent 678ad8a commit 679625b
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 66 deletions.
4 changes: 4 additions & 0 deletions libs/Universal-PicGo-Core/src/core/UniversalPicGo.ts
Expand Up @@ -17,6 +17,7 @@ import {
IPicGo,
IPicGoPlugin,
IPicGoPluginInterface,
IPicGoRequest,
IPluginLoader,
IStringKeyMap,
} from "../types"
Expand All @@ -36,6 +37,7 @@ import { I18nManager } from "../i18n"
import { browserPathJoin, getBrowserDirectoryPath } from "../utils/browserUtils"
import { isConfigKeyInBlackList, isInputConfigValid } from "../utils/common"
import { eventBus } from "../utils/eventBus"
import { PicGoRequest } from "../lib/PicGoRequest"

/*
* 通用 PicGO 对象定义
Expand All @@ -56,6 +58,7 @@ class UniversalPicGo extends EventEmitter implements IPicGo {
output: IImgInfo[]
input: any[]
pluginHandler: PluginHandler
request: IPicGoRequest
i18n!: II18nManager
VERSION: string = process.env.PICGO_VERSION ?? "unknown"
private readonly isDev: boolean
Expand Down Expand Up @@ -87,6 +90,7 @@ class UniversalPicGo extends EventEmitter implements IPicGo {
this.initConfigPath()
// this.cmd = new Commander(this)
this.pluginHandler = new PluginHandler(this)
this.request = PicGoRequest
this.initConfig()
this.init()

Expand Down
25 changes: 25 additions & 0 deletions libs/Universal-PicGo-Core/src/lib/PicGoRequest.ts
@@ -0,0 +1,25 @@
/*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* Copyright (C) 2022-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 { AxiosRequestConfig } from "axios"
import { IResponse } from "../types"

// #64 dynamic get proxy value
/**
* PicGo 统一请求封装,基于 axios
*
* @param options
* @constructor
*/
function PicGoRequest<T, U extends AxiosRequestConfig>(options: U): Promise<IResponse<T, U>> {
throw new Error("PicGoRequest is not implemented")
}

export { PicGoRequest }
21 changes: 10 additions & 11 deletions libs/Universal-PicGo-Core/src/plugins/uploader/smms.ts
Expand Up @@ -10,26 +10,25 @@
import { ILocalesKey } from "../../i18n/zh-CN"
import { IPicGo, IPluginConfig, ISmmsConfig } from "../../types"
import { IBuildInEvent } from "../../utils/enums"
import { AxiosRequestConfig } from "axios"

const postOptions = (fileName: string, image: Buffer, apiToken: string, backupDomain = ""): IOldReqOptions => {
const postOptions = (fileName: string, image: Buffer, apiToken: string, backupDomain = ""): AxiosRequestConfig => {
const domain = backupDomain || "sm.ms"

const formData = new FormData()
formData.append("smfile", new Blob([image], { type: "image/png" }), fileName)
formData.append("ssl", "true")

return {
method: "POST",
url: `https://${domain}/api/v2/upload`,
headers: {
contentType: "multipart/form-data",
"Content-Type": "multipart/form-data",
"User-Agent": "PicGo",
Authorization: apiToken,
},
formData: {
smfile: {
value: image,
options: {
filename: fileName,
},
},
ssl: "true",
},
data: formData,
responseType: "json",
}
}

Expand Down
61 changes: 61 additions & 0 deletions libs/Universal-PicGo-Core/src/types/index.d.ts
Expand Up @@ -10,6 +10,7 @@

import { EventEmitter, Buffer } from "../utils/nodePolyfill"
import { ILogger } from "zhi-lib-base"
import {AxiosRequestConfig} from "axios";

export interface IPicGo extends EventEmitter {
/**
Expand Down Expand Up @@ -46,6 +47,10 @@ export interface IPicGo extends EventEmitter {
* install\uninstall\update picgo's plugin via npm
*/
pluginHandler: IPluginHandler
/**
* request based on axios
*/
request: IPicGoRequest
/**
* plugin system core part transformer\uploader\beforeTransformPlugins...
*/
Expand Down Expand Up @@ -454,3 +459,59 @@ export interface IImgSize {
export interface IPathTransformedImgInfo extends IImgInfo {
success: boolean
}

// =====================================================================================================================
// request start

export type IPicGoRequest = <T, U extends AxiosRequestConfig>(config: U) => Promise<IResponse<T, U>>

/**
* for PicGo new request api, the response will be json format
*/
export type IReqOptions<T = any> = AxiosRequestConfig<T> & {
resolveWithFullResponse: true
}

/**
* for PicGo new request api, the response will be Buffer
*/
export type IReqOptionsWithArrayBufferRes<T = any> = IReqOptions<T> & {
responseType: 'arraybuffer'
}

/**
* for PicGo new request api, the response will be just response data. (not statusCode, headers, etc.)
*/
export type IReqOptionsWithBodyResOnly<T = any> = AxiosRequestConfig<T>

export type IFullResponse<T = any, U = any> = AxiosResponse<T, U> & {
statusCode: number
body: T
}

type AxiosResponse<T = any, U = any> = import('axios').AxiosResponse<T, U>

type AxiosRequestConfig<T = any> = import('axios').AxiosRequestConfig<T>

interface IRequestOptionsWithFullResponse {
resolveWithFullResponse: true
}

interface IRequestOptionsWithJSON {
json: true
}

interface IRequestOptionsWithResponseTypeArrayBuffer {
responseType: 'arraybuffer'
}

/**
* T is the response data type
* U is the config type
*/
export type IResponse<T, U> = U extends IRequestOptionsWithFullResponse ? IFullResponse<T, U>
: U extends IRequestOptionsWithJSON ? T
: U extends IRequestOptionsWithResponseTypeArrayBuffer ? Buffer
: U extends IReqOptionsWithBodyResOnly ? T
: string
// request end
114 changes: 59 additions & 55 deletions libs/Universal-PicGo-Core/src/utils/common.ts
Expand Up @@ -50,63 +50,67 @@ export const getFSFile = async (filePath: string): Promise<IPathTransformedImgIn

export const getURLFile = async (url: string, ctx: IPicGo): Promise<IPathTransformedImgInfo> => {
url = handleUrlEncode(url)
const isImage = false
const extname = ""
let isImage = false
let extname = ""
let timeoutId: any

throw new Error("getURLFile is not implemented")
// const requestFn = new Promise<IPathTransformedImgInfo>((resolve, reject) => {
// ;(async () => {
// try {
// const res = await ctx
// .request({
// method: "get",
// url,
// resolveWithFullResponse: true,
// responseType: "arraybuffer",
// })
// .then((resp: any) => {
// const contentType = resp.headers["content-type"]
// if (contentType?.includes("image")) {
// isImage = true
// extname = `.${contentType.split("image/")[1]}`
// }
// return resp.data as Buffer
// })
// clearTimeout(timeoutId)
// if (isImage) {
// const urlPath = new URL(url).pathname
// resolve({
// buffer: res,
// fileName: path.basename(urlPath),
// extname,
// success: true,
// })
// } else {
// resolve({
// success: false,
// reason: `${url} is not image`,
// })
// }
// } catch (error: any) {
// clearTimeout(timeoutId)
// resolve({
// success: false,
// // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
// reason: `request ${url} error, ${error?.message ?? ""}`,
// })
// }
// })().catch(reject)
// })
// const timeoutPromise = new Promise<IPathTransformedImgInfo>((resolve): void => {
// timeoutId = setTimeout(() => {
// resolve({
// success: false,
// reason: `request ${url} timeout`,
// })
// }, 10000)
// })
// return Promise.race([requestFn, timeoutPromise])
const requestFn = new Promise<IPathTransformedImgInfo>((resolve, reject) => {
;(async () => {
try {
const res = await ctx
.request({
method: "get",
url,
resolveWithFullResponse: true,
responseType: "arraybuffer",
})
.then((resp: any) => {
const contentType = resp.headers["content-type"]
if (contentType?.includes("image")) {
isImage = true
extname = `.${contentType.split("image/")[1]}`
}
return resp.data as Buffer
})
clearTimeout(timeoutId)
if (isImage) {
const urlPath = new URL(url).pathname
const fileName = urlPath.split("/").pop()
// if (hasNodeEnv) {
// const path = win.require("path")
// fileName = path.basename(urlPath)
// }
resolve({
buffer: res,
fileName: fileName,
extname,
success: true,
})
} else {
resolve({
success: false,
reason: `${url} is not image`,
})
}
} catch (error: any) {
clearTimeout(timeoutId)
resolve({
success: false,
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
reason: `request ${url} error, ${error?.message ?? ""}`,
})
}
})().catch(reject)
})
const timeoutPromise = new Promise<IPathTransformedImgInfo>((resolve): void => {
timeoutId = setTimeout(() => {
resolve({
success: false,
reason: `request ${url} timeout`,
})
}, 10000)
})
return Promise.race([requestFn, timeoutPromise])
}

/**
Expand Down

0 comments on commit 679625b

Please sign in to comment.