diff --git a/libs/Universal-PicGo-Core/src/core/UniversalPicGo.ts b/libs/Universal-PicGo-Core/src/core/UniversalPicGo.ts index f868dd6..98c9648 100644 --- a/libs/Universal-PicGo-Core/src/core/UniversalPicGo.ts +++ b/libs/Universal-PicGo-Core/src/core/UniversalPicGo.ts @@ -17,6 +17,7 @@ import { IPicGo, IPicGoPlugin, IPicGoPluginInterface, + IPicGoRequest, IPluginLoader, IStringKeyMap, } from "../types" @@ -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 对象定义 @@ -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 @@ -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() diff --git a/libs/Universal-PicGo-Core/src/lib/PicGoRequest.ts b/libs/Universal-PicGo-Core/src/lib/PicGoRequest.ts new file mode 100644 index 0000000..e118cc2 --- /dev/null +++ b/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. + * 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(options: U): Promise> { + throw new Error("PicGoRequest is not implemented") +} + +export { PicGoRequest } diff --git a/libs/Universal-PicGo-Core/src/plugins/uploader/smms.ts b/libs/Universal-PicGo-Core/src/plugins/uploader/smms.ts index 5fb2e42..83c1bc9 100644 --- a/libs/Universal-PicGo-Core/src/plugins/uploader/smms.ts +++ b/libs/Universal-PicGo-Core/src/plugins/uploader/smms.ts @@ -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", } } diff --git a/libs/Universal-PicGo-Core/src/types/index.d.ts b/libs/Universal-PicGo-Core/src/types/index.d.ts index 7c8bd0b..fd71452 100644 --- a/libs/Universal-PicGo-Core/src/types/index.d.ts +++ b/libs/Universal-PicGo-Core/src/types/index.d.ts @@ -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 { /** @@ -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... */ @@ -454,3 +459,59 @@ export interface IImgSize { export interface IPathTransformedImgInfo extends IImgInfo { success: boolean } + +// ===================================================================================================================== +// request start + +export type IPicGoRequest = (config: U) => Promise> + +/** + * for PicGo new request api, the response will be json format + */ +export type IReqOptions = AxiosRequestConfig & { + resolveWithFullResponse: true +} + +/** + * for PicGo new request api, the response will be Buffer + */ +export type IReqOptionsWithArrayBufferRes = IReqOptions & { + responseType: 'arraybuffer' +} + +/** + * for PicGo new request api, the response will be just response data. (not statusCode, headers, etc.) + */ +export type IReqOptionsWithBodyResOnly = AxiosRequestConfig + +export type IFullResponse = AxiosResponse & { + statusCode: number + body: T +} + +type AxiosResponse = import('axios').AxiosResponse + +type AxiosRequestConfig = import('axios').AxiosRequestConfig + +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 = U extends IRequestOptionsWithFullResponse ? IFullResponse + : U extends IRequestOptionsWithJSON ? T + : U extends IRequestOptionsWithResponseTypeArrayBuffer ? Buffer + : U extends IReqOptionsWithBodyResOnly ? T + : string +// request end \ No newline at end of file diff --git a/libs/Universal-PicGo-Core/src/utils/common.ts b/libs/Universal-PicGo-Core/src/utils/common.ts index f6f569a..2722b48 100644 --- a/libs/Universal-PicGo-Core/src/utils/common.ts +++ b/libs/Universal-PicGo-Core/src/utils/common.ts @@ -50,63 +50,67 @@ export const getFSFile = async (filePath: string): Promise => { 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((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((resolve): void => { - // timeoutId = setTimeout(() => { - // resolve({ - // success: false, - // reason: `request ${url} timeout`, - // }) - // }, 10000) - // }) - // return Promise.race([requestFn, timeoutPromise]) + const requestFn = new Promise((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((resolve): void => { + timeoutId = setTimeout(() => { + resolve({ + success: false, + reason: `request ${url} timeout`, + }) + }, 10000) + }) + return Promise.race([requestFn, timeoutPromise]) } /**