diff --git a/rollup.config.js b/rollup.config.js index 547abe3..d160ba6 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,6 +7,7 @@ import { string } from 'rollup-plugin-string' import json from '@rollup/plugin-json' import builtins from 'builtins' import replace from '@rollup/plugin-replace' + const version = process.env.VERSION || pkg.version const sourcemap = 'inline' const banner = `/* diff --git a/src/core/Lifecycle.ts b/src/core/Lifecycle.ts index 771125f..3a41bf7 100644 --- a/src/core/Lifecycle.ts +++ b/src/core/Lifecycle.ts @@ -32,6 +32,7 @@ import { createContext } from '../utils/createContext' const watermarkMsg = 'Add watermark to image' const compressMsg = 'Compress or convert image' + export class Lifecycle extends EventEmitter { private readonly ctx: IPicGo private readonly ttfLink: string = 'https://release.piclist.cn/simhei.ttf' diff --git a/src/core/PicGo.ts b/src/core/PicGo.ts index 1ae32d2..e78b6f1 100644 --- a/src/core/PicGo.ts +++ b/src/core/PicGo.ts @@ -13,8 +13,8 @@ import { Request } from '../lib/Request' import { Lifecycle } from './Lifecycle' -import uploaders from '../plugins/uploader' -import transformers from '../plugins/transformer' +import buildInUploaders from '../plugins/uploader' +import buildInTransformers from '../plugins/transformer' import getClipboardImage from '../utils/getClipboardImage' @@ -112,8 +112,8 @@ export class PicGo extends EventEmitter implements IPicGo { this._pluginLoader = new PluginLoader(this) // load self plugins setCurrentPluginName('picgo') - uploaders(this).register(this) - transformers(this).register(this) + buildInUploaders().register(this) + buildInTransformers().register(this) setCurrentPluginName('') // load third-party plugins this._pluginLoader.load() @@ -212,7 +212,7 @@ export class PicGo extends EventEmitter implements IPicGo { this.log.error('No config file found, please check your config file path') return [] } - // upload from clipboard + if (input === undefined || input.length === 0) { try { const { imgPath, shouldKeepAfterUploading } = await getClipboardImage(this) @@ -236,7 +236,6 @@ export class PicGo extends EventEmitter implements IPicGo { throw e } } else { - // upload from path const { output } = await this.lifecycle.start(input) return output } diff --git a/src/i18n/en.ts b/src/i18n/en.ts index a7afd6b..bdf30e4 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -12,6 +12,7 @@ export const EN: ILocales = { // smms PICBED_SMMS: 'SM.MS', PICBED_SMMS_TOKEN: 'Set Token', + PICBED_SMMS_MESSAGE_TOKEN: 'Please enter the token', PICBED_SMMS_BACKUP_DOMAIN: 'Set Backup Upload Domain', PICBED_SMMS_MESSAGE_BACKUP_DOMAIN: 'Ex. smms.app', @@ -234,9 +235,11 @@ export const EN: ILocales = { PICBED_AWSS3PLIST_MESSAGE_ACL: 'Ex. public-read', PICBED_AWSS3PLIST_MESSAGE_DISABLEBUCKETPREFIXTOURL: 'Enable when `pathStyleAccess` is enabled', + BUILDIN_RENAME: 'Rename Settings', BUILDIN_RENAME_FORMAT: 'Set rename format', BUILDIN_RENAME_ENABLE: 'Enable rename', + BUILDIN_WATERMARK: 'Watermark Settings', BUILDIN_WATERMARK_ISADDWATERMARK: 'Whether to add watermark', BUILDIN_WATERMARK_MESSAGE_ISADDWATERMARK: 'Enable when watermark is required', BUILDIN_WATERMARK_WATERMARKTYPE: 'Set watermark type', @@ -258,6 +261,7 @@ export const EN: ILocales = { BUILDIN_WATERMARK_WATERMARKPOSITION: 'Set watermark position', BUILDIN_WATERMARK_MESSAGE_WATERMARKPOSITION: 'Please select watermark position', + BUILDIN_COMPRESS: 'Processing Settings', BUILDIN_COMPRESS_QUALITY: 'Set image quality', BUILDIN_COMPRESS_MESSAGE_QUALITY: 'Please enter an integer between 0-100', BUILDIN_COMPRESS_ISCONVERT: 'Whether to perform format conversion', diff --git a/src/i18n/zh-CN.ts b/src/i18n/zh-CN.ts index 769351d..9aa2958 100644 --- a/src/i18n/zh-CN.ts +++ b/src/i18n/zh-CN.ts @@ -10,6 +10,7 @@ export const ZH_CN = { // smms PICBED_SMMS: 'SM.MS', PICBED_SMMS_TOKEN: '设定Token', + PICBED_SMMS_MESSAGE_TOKEN: '请填写Token', PICBED_SMMS_BACKUP_DOMAIN: '备用上传域名', PICBED_SMMS_MESSAGE_BACKUP_DOMAIN: '例如 smms.app', @@ -188,7 +189,7 @@ export const ZH_CN = { PICBED_PICLIST_KEY: '设定鉴权Key', // Lsky Pro - PICBED_LSKY_PLIST: 'Lsky', + PICBED_LSKY_PLIST: '兰空图床', PICBED_LSKY_VERSION: '设定版本', PICBED_LSKY_MESSAGE_VERSION: '例如V1', PICBED_LSKY_HOST: '设定主机', @@ -229,6 +230,7 @@ export const ZH_CN = { PICBED_AWSS3PLIST_MESSAGE_ACL: '例如:public-read', PICBED_AWSS3PLIST_MESSAGE_DISABLEBUCKETPREFIXTOURL: '需要时启用', + BUILDIN_WATERMARK: '水印设置', BUILDIN_WATERMARK_ISADDWATERMARK: '是否添加水印', BUILDIN_WATERMARK_MESSAGE_ISADDWATERMARK: '需要添加水印时启用', BUILDIN_WATERMARK_WATERMARKTYPE: '设定水印类型', @@ -250,9 +252,11 @@ export const ZH_CN = { BUILDIN_WATERMARK_WATERMARKPOSITION: '设定水印位置', BUILDIN_WATERMARK_MESSAGE_WATERMARKPOSITION: '请选择水印位置', + BUILDIN_RENAME: '重命名设置', BUILDIN_RENAME_FORMAT: '设定重命名格式', BUILDIN_RENAME_ENABLE: '是否启用重命名', + BUILDIN_COMPRESS: '图片处理', BUILDIN_COMPRESS_QUALITY: '设定图片质量', BUILDIN_COMPRESS_MESSAGE_QUALITY: '请输入0-100的整数', BUILDIN_COMPRESS_ISCONVERT: '是否进行格式转换', diff --git a/src/i18n/zh-TW.ts b/src/i18n/zh-TW.ts index dd4335b..f57c250 100644 --- a/src/i18n/zh-TW.ts +++ b/src/i18n/zh-TW.ts @@ -12,6 +12,7 @@ export const ZH_TW: ILocales = { // smms PICBED_SMMS: 'SM.MS', PICBED_SMMS_TOKEN: '設定Token', + PICBED_SMMS_MESSAGE_TOKEN: '請輸入Token', PICBED_SMMS_BACKUP_DOMAIN: '備用上傳網址', PICBED_SMMS_MESSAGE_BACKUP_DOMAIN: '例如 smms.app', @@ -190,7 +191,7 @@ export const ZH_TW: ILocales = { PICBED_PICLIST_KEY: '設定鑒權Key', // Lsky Pro - PICBED_LSKY_PLIST: 'Lsky', + PICBED_LSKY_PLIST: '蘭空圖床', PICBED_LSKY_VERSION: '設定版本', PICBED_LSKY_MESSAGE_VERSION: '請選擇版本', PICBED_LSKY_HOST: '設定主機', @@ -231,6 +232,7 @@ export const ZH_TW: ILocales = { PICBED_AWSS3PLIST_MESSAGE_ACL: '例如:public-read', PICBED_AWSS3PLIST_MESSAGE_DISABLEBUCKETPREFIXTOURL: '需要時啟用', + BUILDIN_WATERMARK: '水印設定', BUILDIN_WATERMARK_ISADDWATERMARK: '是否添加水印', BUILDIN_WATERMARK_MESSAGE_ISADDWATERMARK: '需要添加水印時啟用', BUILDIN_WATERMARK_WATERMARKTYPE: '設定水印類型', @@ -252,9 +254,11 @@ export const ZH_TW: ILocales = { BUILDIN_WATERMARK_WATERMARKPOSITION: '設定水印位置', BUILDIN_WATERMARK_MESSAGE_WATERMARKPOSITION: '請選擇水印位置', + BUILDIN_RENAME: '重命名設定', BUILDIN_RENAME_FORMAT: '設定重命名格式', BUILDIN_RENAME_ENABLE: '是否啟用重命名', + BUILDIN_COMPRESS: '圖片處理設定', BUILDIN_COMPRESS_QUALITY: '設定圖片質量', BUILDIN_COMPRESS_MESSAGE_QUALITY: '請輸入0-100的整數', BUILDIN_COMPRESS_ISCONVERT: '是否進行格式轉換', diff --git a/src/lib/LifecyclePlugins.ts b/src/lib/LifecyclePlugins.ts index e4d5709..d2d9f5e 100644 --- a/src/lib/LifecyclePlugins.ts +++ b/src/lib/LifecyclePlugins.ts @@ -2,9 +2,19 @@ import { IPlugin, ILifecyclePlugins } from '../types' export class LifecyclePlugins implements ILifecyclePlugins { static currentPlugin: string | null + + /** + * The name of the plugin + */ + private readonly name: string + /** + * The list of plugins + */ private readonly list: Map + /** + * The map of plugin id + */ private readonly pluginIdMap: Map - private readonly name: string constructor(name: string) { this.name = name @@ -16,7 +26,9 @@ export class LifecyclePlugins implements ILifecyclePlugins { if (!id) throw new TypeError('id is required!') if (typeof plugin.handle !== 'function') throw new TypeError('plugin.handle must be a function!') if (this.list.has(id)) throw new TypeError(`${this.name} duplicate id: ${id}!`) + this.list.set(id, plugin) + if (LifecyclePlugins.currentPlugin) { if (this.pluginIdMap.has(LifecyclePlugins.currentPlugin)) { this.pluginIdMap.get(LifecyclePlugins.currentPlugin)?.push(id) diff --git a/src/lib/PluginLoader.ts b/src/lib/PluginLoader.ts index 75fb8c8..157e181 100644 --- a/src/lib/PluginLoader.ts +++ b/src/lib/PluginLoader.ts @@ -42,12 +42,12 @@ export class PluginLoader implements IPluginLoader { // load all third party plugin load(): boolean { - const packagePath = path.join(this.ctx.baseDir, 'package.json') const pluginDir = path.join(this.ctx.baseDir, 'node_modules/') // Thanks to hexo -> https://github.com/hexojs/hexo/blob/master/lib/hexo/load_plugins.js if (!fs.existsSync(pluginDir)) { return false } + const packagePath = path.join(this.ctx.baseDir, 'package.json') const json = readJSONSync(packagePath) const deps = Object.keys(json.dependencies || {}) const devDeps = Object.keys(json.devDependencies || {}) diff --git a/src/lib/Request.ts b/src/lib/Request.ts index 905e471..b9c0a35 100644 --- a/src/lib/Request.ts +++ b/src/lib/Request.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/explicit-function-return-type */ -/* eslint-disable @typescript-eslint/promise-function-async */ import axios from 'axios' import type { AxiosRequestConfig, AxiosResponse } from 'axios' import FormData from 'form-data' diff --git a/src/plugins/commander/setting.ts b/src/plugins/commander/setting.ts index 8faa2c1..0fa5232 100644 --- a/src/plugins/commander/setting.ts +++ b/src/plugins/commander/setting.ts @@ -1,7 +1,9 @@ +import { ILocalesKey } from '../../i18n/zh-CN' import { IPicGo, IPluginConfig, IStringKeyMap } from '../../types' import compress from '../beforetransformer/compress' import watermark from '../beforetransformer/watermark' import rename from '../beforeupload/buildInRename' +import { uploaderTranslators } from './utils' // handle modules config -> save to picgo config file const handleConfig = async (ctx: IPicGo, prompts: IPluginConfig[], module: string, name: string): Promise => { @@ -56,7 +58,11 @@ const setting = { { type: 'list', name: 'buildin', - choices: ['compress', 'watermark', 'rename'], + choices: [ + { name: ctx.i18n.translate('BUILDIN_COMPRESS'), value: 'compress' }, + { name: ctx.i18n.translate('BUILDIN_WATERMARK'), value: 'watermark' }, + { name: ctx.i18n.translate('BUILDIN_RENAME'), value: 'rename' } + ], message: 'Choose a buildin module' } ] @@ -86,7 +92,12 @@ const setting = { { type: 'list', name: `${module}`, - choices: ctx.helper[module].getIdList(), + choices: ctx.helper[module].getIdList().map((item: string) => { + return { + name: uploaderTranslators(ctx)[item] || item, + value: item + } + }), message: `Choose a(n) ${module}` // default: ctx.getConfig('picBed.uploader') || ctx.getConfig('picBed.current') } diff --git a/src/plugins/commander/use.ts b/src/plugins/commander/use.ts index 25f11df..1f62ec7 100644 --- a/src/plugins/commander/use.ts +++ b/src/plugins/commander/use.ts @@ -1,4 +1,5 @@ import { IPicGo, IPlugin, Undefinable, ICLIConfigs, IStringKeyMap } from '../../types' +import { uploaderTranslators } from './utils' const use: IPlugin = { handle: async (ctx: IPicGo) => { @@ -16,7 +17,12 @@ const use: IPlugin = { type: 'list', name: 'uploader', message: 'Use an uploader', - choices: ctx.helper.uploader.getIdList(), + choices: ctx.helper.uploader.getIdList().map((item: string) => { + return { + name: uploaderTranslators(ctx)[item] || item, + value: item + } + }), default: ctx.getConfig('picBed.uploader') || ctx.getConfig('picBed.current') || 'smms' }, transformer: { diff --git a/src/plugins/commander/utils.ts b/src/plugins/commander/utils.ts new file mode 100644 index 0000000..1e16eb1 --- /dev/null +++ b/src/plugins/commander/utils.ts @@ -0,0 +1,22 @@ +import { ILocalesKey } from '../../i18n/zh-CN' +import { IPicGo, IStringKeyMap } from '../../types' + +export const uploaderTranslators = (ctx: IPicGo) => { + return { + alistplist: ctx.i18n.translate('PICBED_ALIST_PLIST'), + aliyun: ctx.i18n.translate('PICBED_ALICLOUD'), + 'aws-s3-plist': ctx.i18n.translate('PICBED_AWSS3PLIST'), + github: ctx.i18n.translate('PICBED_GITHUB'), + imgur: ctx.i18n.translate('PICBED_IMGUR'), + local: ctx.i18n.translate('PICBED_LOCAL'), + lskyplist: ctx.i18n.translate('PICBED_LSKY_PLIST'), + piclist: ctx.i18n.translate('PICBED_PICLIST'), + qiniu: ctx.i18n.translate('PICBED_QINIU'), + sftpplist: ctx.i18n.translate('PICBED_SFTPPLIST'), + smms: ctx.i18n.translate('PICBED_SMMS'), + tcyun: ctx.i18n.translate('PICBED_TENCENTCLOUD'), + telegraphplist: ctx.i18n.translate('PICBED_TELEGRAPH'), + upyun: ctx.i18n.translate('PICBED_UPYUN'), + webdavplist: ctx.i18n.translate('PICBED_WEBDAVPLIST') + } as IStringKeyMap +} diff --git a/src/plugins/transformer/index.ts b/src/plugins/transformer/index.ts index 9dc6f82..92e4d23 100644 --- a/src/plugins/transformer/index.ts +++ b/src/plugins/transformer/index.ts @@ -1,8 +1,8 @@ -import { IPicGo, IPicGoPlugin } from '../../types' +import { IPicGo } from '../../types' import ImgFromPath from './path' import ImgFromBase64 from './base64' -const buildInTransformers: IPicGoPlugin = () => { +const buildInTransformers = () => { return { register(ctx: IPicGo) { ctx.helper.transformer.register('path', ImgFromPath) diff --git a/src/plugins/uploader/alist.ts b/src/plugins/uploader/alist.ts index d60a03f..eda0bf2 100644 --- a/src/plugins/uploader/alist.ts +++ b/src/plugins/uploader/alist.ts @@ -93,12 +93,14 @@ const extractConfig = (config: IAlistConfig) => { const handle = async (ctx: IPicGo): Promise => { const alistConfig = ctx.getConfig('picBed.alistplist') if (!alistConfig) throw new Error('Can not find alist config!') + const { url, username, password, uploadPath, webPath, customUrl } = extractConfig(alistConfig) let { token } = extractConfig(alistConfig) if (!token) { token = await getAlistToken(ctx, url, username, password) } if (!url || !(token || (username && password))) throw new Error('Please check your alist config!') + const imgList = ctx.output for (const img of imgList) { if (img.fileName && img.buffer) { @@ -108,55 +110,50 @@ const handle = async (ctx: IPicGo): Promise => { } const fullUploadPath = `${uploadPath}${img.fileName}` const postConfig = postOptions(url, token, img.fileName, fullUploadPath, image) - try { - const uploadRes = (await ctx.request(postConfig)) as unknown as IFullResponse - handleResError(ctx, uploadRes) - const refreshUrl = `${url}/api/fs/list` - const getInfoUrl = `${url}/api/fs/get` - const refreshRes = (await ctx.request({ - method: 'POST', - url: refreshUrl, - headers: { - Authorization: token, - 'Content-Type': 'application/json' - }, - body: { - password: '', - page: 1, - per_page: 1, - refresh: true, - path: path.dirname(fullUploadPath) - }, - resolveWithFullResponse: true - })) as unknown as IFullResponse - handleResError(ctx, refreshRes) - const getInfoRes = (await ctx.request({ - method: 'POST', - url: getInfoUrl, - headers: { - Authorization: token, - 'Content-Type': 'application/json' - }, - body: { - password: '', - path: fullUploadPath, - page: 1, - per_page: 1, - refresh: true - }, - resolveWithFullResponse: true - })) as unknown as IFullResponse - handleResError(ctx, getInfoRes) - const sign = getInfoRes.body.data.sign - const encodedPath = encodePath(`${webPath || uploadPath}${img.fileName}`) - img.imgUrl = `${customUrl || url}/d${encodedPath}` - img.imgUrl += sign ? `?sign=${sign}` : '' - delete img.base64Image - delete img.buffer - } catch (e: any) { - ctx.log.error(e) - throw e - } + const uploadRes = (await ctx.request(postConfig)) as unknown as IFullResponse + handleResError(ctx, uploadRes) + const refreshUrl = `${url}/api/fs/list` + const getInfoUrl = `${url}/api/fs/get` + const refreshRes = (await ctx.request({ + method: 'POST', + url: refreshUrl, + headers: { + Authorization: token, + 'Content-Type': 'application/json' + }, + body: { + password: '', + page: 1, + per_page: 1, + refresh: true, + path: path.dirname(fullUploadPath) + }, + resolveWithFullResponse: true + })) as unknown as IFullResponse + handleResError(ctx, refreshRes) + const getInfoRes = (await ctx.request({ + method: 'POST', + url: getInfoUrl, + headers: { + Authorization: token, + 'Content-Type': 'application/json' + }, + body: { + password: '', + path: fullUploadPath, + page: 1, + per_page: 1, + refresh: true + }, + resolveWithFullResponse: true + })) as unknown as IFullResponse + handleResError(ctx, getInfoRes) + const sign = getInfoRes.body.data.sign + const encodedPath = encodePath(`${webPath || uploadPath}${img.fileName}`) + img.imgUrl = `${customUrl || url}/d${encodedPath}` + img.imgUrl += sign ? `?sign=${sign}` : '' + delete img.base64Image + delete img.buffer } } return ctx diff --git a/src/plugins/uploader/aliyun.ts b/src/plugins/uploader/aliyun.ts index e4d02a3..5d7250a 100644 --- a/src/plugins/uploader/aliyun.ts +++ b/src/plugins/uploader/aliyun.ts @@ -38,9 +38,7 @@ const postOptions = ( const handle = async (ctx: IPicGo): Promise => { const aliYunOptions = ctx.getConfig('picBed.aliyun') - if (!aliYunOptions) { - throw new Error("Can't find aliYun OSS config") - } + if (!aliYunOptions) throw new Error("Can't find aliYun OSS config") aliYunOptions.path = formatPathHelper({ path: aliYunOptions.path }) try { const imgList = ctx.output @@ -70,7 +68,7 @@ const handle = async (ctx: IPicGo): Promise => { } } return ctx - } catch (err) { + } catch (err: any) { ctx.emit(IBuildInEvent.NOTIFICATION, { title: ctx.i18n.translate('UPLOAD_FAILED'), body: ctx.i18n.translate('CHECK_SETTINGS') diff --git a/src/plugins/uploader/awss3plist.ts b/src/plugins/uploader/awss3plist.ts index 5da71b2..d88341b 100644 --- a/src/plugins/uploader/awss3plist.ts +++ b/src/plugins/uploader/awss3plist.ts @@ -3,6 +3,7 @@ import uploader, { IUploadResult } from './s3/uploader' import { formatPath } from './s3/utils' import { IAwsS3PListUserConfig, IPicGo, IPluginConfig } from '../../types' import { ILocalesKey } from '../../i18n/zh-CN' +import { IBuildInEvent } from '../../utils/enum' function formatDisableBucketPrefixToURL(disableBucketPrefixToURL: string | boolean | undefined): boolean { if (typeof disableBucketPrefixToURL === 'string') { @@ -13,9 +14,8 @@ function formatDisableBucketPrefixToURL(disableBucketPrefixToURL: string | boole const handle = async (ctx: IPicGo): Promise => { const userConfig: IAwsS3PListUserConfig = ctx.getConfig('picBed.aws-s3-plist') - if (!userConfig) { - throw new Error("Can't find amazon s3 uploader config") - } + if (!userConfig) throw new Error("Can't find aws s3 uploader config") + const disableBucketPrefixToURL = formatDisableBucketPrefixToURL(userConfig.disableBucketPrefixToURL) let urlPrefix = userConfig.urlPrefix if (urlPrefix) { @@ -46,8 +46,7 @@ const handle = async (ctx: IPicGo): Promise => { results = await Promise.all(tasks) } catch (err: any) { ctx.log.error('上传到 S3 存储发生错误,请检查网络连接和配置是否正确') - ctx.log.error(err) - ctx.emit('notification', { + ctx.emit(IBuildInEvent.NOTIFICATION, { title: 'S3 存储上传错误', body: '请检查配置是否正确', text: '' diff --git a/src/plugins/uploader/github.ts b/src/plugins/uploader/github.ts index fe3d2e3..182ab23 100644 --- a/src/plugins/uploader/github.ts +++ b/src/plugins/uploader/github.ts @@ -40,9 +40,8 @@ const getOptions = (fileName: string, options: IGithubConfig): IOldReqOptionsWit const handle = async (ctx: IPicGo): Promise => { const githubOptions = ctx.getConfig('picBed.github') - if (!githubOptions) { - throw new Error("Can't find github config") - } + if (!githubOptions) throw new Error("Can't find github config") + const uploadPath = formatPathHelper({ path: githubOptions.path }) githubOptions.path = uploadPath githubOptions.customUrl = (githubOptions.customUrl || '').replace(/\/$/, '') @@ -76,18 +75,15 @@ const handle = async (ctx: IPicGo): Promise => { throw new Error('Server error, please try again') } } catch (err: any) { - if (err.statusCode === 422) { - delete img.base64Image - delete img.buffer - const res = (await ctx.request(getOptions(img.fileName, githubOptions))) as any - if (Object.keys(res).length) { - img.hash = res.sha - img.imgUrl = githubOptions.customUrl - ? `${githubOptions.customUrl}/${encodePath(`${uploadPath}${img.fileName}`)}` - : res.download_url - } else { - throw err - } + if (err.statusCode !== 422) throw err + delete img.base64Image + delete img.buffer + const res = (await ctx.request(getOptions(img.fileName, githubOptions))) as any + if (Object.keys(res).length) { + img.hash = res.sha + img.imgUrl = githubOptions.customUrl + ? `${githubOptions.customUrl}/${encodePath(`${uploadPath}${img.fileName}`)}` + : res.download_url } else { throw err } @@ -95,7 +91,7 @@ const handle = async (ctx: IPicGo): Promise => { } } return ctx - } catch (err) { + } catch (err: any) { ctx.emit(IBuildInEvent.NOTIFICATION, { title: ctx.i18n.translate('UPLOAD_FAILED'), body: ctx.i18n.translate('CHECK_SETTINGS_AND_NETWORK') diff --git a/src/plugins/uploader/imgur.ts b/src/plugins/uploader/imgur.ts index c3d1d6c..869e566 100644 --- a/src/plugins/uploader/imgur.ts +++ b/src/plugins/uploader/imgur.ts @@ -82,9 +82,7 @@ const postOptions = async ( const handle = async (ctx: IPicGo): Promise => { const imgurOptions = ctx.getConfig('picBed.imgur') - if (!imgurOptions) { - throw new Error("Can't find imgur config") - } + if (!imgurOptions) throw new Error("Can't find imgur config") try { const imgList = ctx.output for (const img of imgList) { @@ -104,13 +102,12 @@ const handle = async (ctx: IPicGo): Promise => { } } return ctx - } catch (err) { + } catch (err: any) { ctx.emit(IBuildInEvent.NOTIFICATION, { title: ctx.i18n.translate('UPLOAD_FAILED'), body: ctx.i18n.translate('CHECK_SETTINGS_AND_NETWORK'), text: 'http://docs.imgur.com/api/errno/' }) - // @ts-expect-error string | IError throw err?.response?.data || err } } diff --git a/src/plugins/uploader/index.ts b/src/plugins/uploader/index.ts index ee13c92..6bf775b 100644 --- a/src/plugins/uploader/index.ts +++ b/src/plugins/uploader/index.ts @@ -1,21 +1,21 @@ -import { IPicGo, IPicGoPlugin } from '../../types' -import smmsUploader from './smms' -import tcYunUploader from './tcyun' +import { IPicGo } from '../../types' +import alistUploader from './alist' +import aliYunUploader from './aliyun' +import awss3plistUploader from './awss3plist' import githubUploader from './github' -import qiniuUploader from './qiniu' import imgurUploader from './imgur' -import aliYunUploader from './aliyun' -import upYunUploader from './upyun' -import webdavplistUploader from './webdav' import localUploader from './local' +import lskyUploader from './lsky' +import piclistUploader from './piclist' +import qiniuUploader from './qiniu' import sftpUploader from './sftp' +import smmsUploader from './smms' +import tcYunUploader from './tcyun' import telegraphUploader from './telegraph' -import piclistUploader from './piclist' -import lskyUploader from './lsky' -import awss3plistUploader from './awss3plist' -import alistUploader from './alist' +import upYunUploader from './upyun' +import webdavplistUploader from './webdav' -const buildInUploaders: IPicGoPlugin = () => { +const buildInUploaders = () => { return { register(ctx: IPicGo) { alistUploader(ctx) diff --git a/src/plugins/uploader/local.ts b/src/plugins/uploader/local.ts index 314e7ba..7c93919 100644 --- a/src/plugins/uploader/local.ts +++ b/src/plugins/uploader/local.ts @@ -9,9 +9,8 @@ import { encodePath, formatPathHelper } from './utils' const handle = async (ctx: IPicGo): Promise => { const localConfig = ctx.getConfig('picBed.local') - if (!localConfig) { - throw new Error('Can not find local config!') - } + if (!localConfig) throw new Error('Can not find local config!') + const uploadPath = localConfig.path || '' const customUrl = (localConfig.customUrl || '').replace(/\/$/, '') const webPath = formatPathHelper({ @@ -25,33 +24,28 @@ const handle = async (ctx: IPicGo): Promise => { image = Buffer.from(img.base64Image, 'base64') } try { - try { - const imgTempPath = path.join(ctx.baseDir, 'imgTemp', 'local') - const fileImgTempPath = path.join(imgTempPath, img.fileName) - const fileUploadPath = path.join(uploadPath, img.fileName) - ensureDirSync(path.dirname(fileUploadPath)) - ensureDirSync(path.dirname(fileImgTempPath)) - fs.writeFileSync(fileUploadPath, image) - fs.copyFileSync(fileUploadPath, fileImgTempPath) - delete img.base64Image - delete img.buffer - if (customUrl) { - img.imgUrl = `${customUrl}/${encodePath(`${webPath}${img.fileName}`)}` - } else { - img.imgUrl = path.join(uploadPath, img.fileName) - } - img.hash = path.join(uploadPath, img.fileName) - img.galleryPath = `http://localhost:36699/local/${encodeURIComponent(img.fileName)}` - } catch (e: any) { - ctx.emit(IBuildInEvent.NOTIFICATION, { - title: ctx.i18n.translate('UPLOAD_FAILED'), - body: 'failed to upload image' - }) - throw new Error('failed to upload image') + const imgTempPath = path.join(ctx.baseDir, 'imgTemp', 'local') + const fileImgTempPath = path.join(imgTempPath, img.fileName) + const fileUploadPath = path.join(uploadPath, img.fileName) + ensureDirSync(path.dirname(fileUploadPath)) + ensureDirSync(path.dirname(fileImgTempPath)) + fs.writeFileSync(fileUploadPath, image) + fs.copyFileSync(fileUploadPath, fileImgTempPath) + delete img.base64Image + delete img.buffer + if (customUrl) { + img.imgUrl = `${customUrl}/${encodePath(`${webPath}${img.fileName}`)}` + } else { + img.imgUrl = path.join(uploadPath, img.fileName) } + img.hash = path.join(uploadPath, img.fileName) + img.galleryPath = `http://localhost:36699/local/${encodePath(img.fileName).replace(/^\//, '')}` } catch (e: any) { - ctx.log.error(e) - throw e + ctx.emit(IBuildInEvent.NOTIFICATION, { + title: ctx.i18n.translate('UPLOAD_FAILED'), + body: 'failed to upload image' + }) + throw new Error('failed to upload image') } } } diff --git a/src/plugins/uploader/lsky.ts b/src/plugins/uploader/lsky.ts index 605a8dd..5186f65 100644 --- a/src/plugins/uploader/lsky.ts +++ b/src/plugins/uploader/lsky.ts @@ -97,44 +97,35 @@ const postOptions = (options: ILskyConfig, fileName: string | undefined, image: const handle = async (ctx: IPicGo): Promise => { const lskyOptions = ctx.getConfig('picBed.lskyplist') - if (!lskyOptions) { - throw new Error("Can't find lsky uploader config") - } - try { - const imgList = ctx.output - for (const img of imgList) { - let image = img.buffer! - if (!image && img.base64Image) { - image = Buffer.from(img.base64Image, 'base64') - } - const postConfig = postOptions(lskyOptions, img.fileName, image) - let body = (await ctx.Request.request(postConfig)) as any - body = typeof body === 'string' ? JSON.parse(body) : body - const isV2 = lskyOptions.version === 'V2' - const condition = isV2 ? body.status === true : body.code === 200 - if (condition) { - delete img.base64Image - delete img.buffer - img.imgUrl = isV2 ? body.data.links.url : body.data.url - if (isV2) { - img.hash = body.data.key - } - } else { - ctx.emit('notification', { - title: 'upload failed', - body: body.message - }) - throw new Error(body.message) + if (!lskyOptions) throw new Error("Can't find lsky uploader config") + + const imgList = ctx.output + for (const img of imgList) { + let image = img.buffer! + if (!image && img.base64Image) { + image = Buffer.from(img.base64Image, 'base64') + } + const postConfig = postOptions(lskyOptions, img.fileName, image) + let body = (await ctx.request(postConfig)) as any + body = typeof body === 'string' ? JSON.parse(body) : body + const isV2 = lskyOptions.version === 'V2' + const condition = isV2 ? body.status === true : body.code === 200 + if (condition) { + delete img.base64Image + delete img.buffer + img.imgUrl = isV2 ? body.data.links.url : body.data.url + if (isV2) { + img.hash = body.data.key } + } else { + ctx.emit(IBuildInEvent.NOTIFICATION, { + title: 'upload failed', + body: body.message + }) + throw new Error(body.message) } - return ctx - } catch (err) { - ctx.emit(IBuildInEvent.NOTIFICATION, { - title: ctx.i18n.translate('UPLOAD_FAILED'), - body: ctx.i18n.translate('CHECK_SETTINGS') - }) - throw err } + return ctx } const config = (ctx: IPicGo): IPluginConfig[] => { diff --git a/src/plugins/uploader/smms.ts b/src/plugins/uploader/smms.ts index 5335873..4aea85c 100644 --- a/src/plugins/uploader/smms.ts +++ b/src/plugins/uploader/smms.ts @@ -28,9 +28,8 @@ const postOptions = (fileName: string, image: Buffer, apiToken: string, backupDo const handle = async (ctx: IPicGo): Promise => { const smmsConfig = ctx.getConfig('picBed.smms') - if (!smmsConfig) { - throw new Error('Can not find smms config!') - } + if (!smmsConfig) throw new Error('Can not find smms config!') + const imgList = ctx.output for (const img of imgList) { if (img.fileName && img.buffer) { @@ -39,43 +38,39 @@ const handle = async (ctx: IPicGo): Promise => { image = Buffer.from(img.base64Image, 'base64') } const postConfig = postOptions(img.fileName, image, smmsConfig?.token, smmsConfig?.backupDomain) - try { - const res: string = await ctx.request(postConfig) - const body = JSON.parse(res) - if (body.code === 'success') { - delete img.base64Image - delete img.buffer - img.imgUrl = body.data.url - img.hash = body.data.hash - } else if (body.code === 'image_repeated' && typeof body.images === 'string') { - // do extra check since this error return is not documented at https://doc.sm.ms/#api-Image-Upload - delete img.base64Image - delete img.buffer - img.imgUrl = body.images - const uploadHistory = await axios.get('https://sm.ms/api/v2/upload_history', { - headers: { - Authorization: smmsConfig.token - } - }) - if (uploadHistory.data.code === 'success') { - const images = uploadHistory.data.data - for (const image of images) { - if (image.url === body.images) { - img.hash = image.hash - break - } + + const res: string = await ctx.request(postConfig) + const body = JSON.parse(res) + if (body.code === 'success') { + delete img.base64Image + delete img.buffer + img.imgUrl = body.data.url + img.hash = body.data.hash + } else if (body.code === 'image_repeated' && typeof body.images === 'string') { + // do extra check since this error return is not documented at https://doc.sm.ms/#api-Image-Upload + delete img.base64Image + delete img.buffer + img.imgUrl = body.images + const uploadHistory = await axios.get('https://sm.ms/api/v2/upload_history', { + headers: { + Authorization: smmsConfig.token + } + }) + if (uploadHistory.data.code === 'success') { + const images = uploadHistory.data.data + for (const image of images) { + if (image.url === body.images) { + img.hash = image.hash + break } } - } else { - ctx.emit(IBuildInEvent.NOTIFICATION, { - title: ctx.i18n.translate('UPLOAD_FAILED'), - body: body.message - }) - throw new Error(body.message) } - } catch (e: any) { - ctx.log.error(e) - throw e + } else { + ctx.emit(IBuildInEvent.NOTIFICATION, { + title: ctx.i18n.translate('UPLOAD_FAILED'), + body: body.message + }) + throw new Error(body.message) } } } @@ -87,7 +82,6 @@ const config = (ctx: IPicGo): IPluginConfig[] => { const config: IPluginConfig[] = [ { name: 'token', - message: 'api token', type: 'input', get prefix() { return ctx.i18n.translate('PICBED_SMMS_TOKEN') @@ -95,6 +89,9 @@ const config = (ctx: IPicGo): IPluginConfig[] => { get alias() { return ctx.i18n.translate('PICBED_SMMS_TOKEN') }, + get message() { + return ctx.i18n.translate('PICBED_SMMS_MESSAGE_TOKEN') + }, default: userConfig.token || '', required: true }, @@ -104,12 +101,12 @@ const config = (ctx: IPicGo): IPluginConfig[] => { get prefix() { return ctx.i18n.translate('PICBED_SMMS_BACKUP_DOMAIN') }, - get message() { - return ctx.i18n.translate('PICBED_SMMS_MESSAGE_BACKUP_DOMAIN') - }, get alias() { return ctx.i18n.translate('PICBED_SMMS_BACKUP_DOMAIN') }, + get message() { + return ctx.i18n.translate('PICBED_SMMS_MESSAGE_BACKUP_DOMAIN') + }, default: userConfig.backupDomain || '', required: false } diff --git a/src/plugins/uploader/tcyun.ts b/src/plugins/uploader/tcyun.ts index 2692b7a..8190bd0 100644 --- a/src/plugins/uploader/tcyun.ts +++ b/src/plugins/uploader/tcyun.ts @@ -95,9 +95,7 @@ const postOptions = ( const handle = async (ctx: IPicGo): Promise => { const tcYunOptions = ctx.getConfig('picBed.tcyun') - if (!tcYunOptions) { - throw new Error("Can't find tencent COS config") - } + if (!tcYunOptions) throw new Error("Can't find tencent COS config") try { const imgList = ctx.output const customUrl = (tcYunOptions.customUrl || '').replace(/\/$/, '') diff --git a/src/plugins/uploader/telegraph.ts b/src/plugins/uploader/telegraph.ts index e9566c8..28324bf 100644 --- a/src/plugins/uploader/telegraph.ts +++ b/src/plugins/uploader/telegraph.ts @@ -54,13 +54,12 @@ const handle = async (ctx: IPicGo): Promise => { } } return ctx - } catch (err) { + } catch (err: any) { ctx.emit(IBuildInEvent.NOTIFICATION, { title: ctx.i18n.translate('UPLOAD_FAILED'), body: ctx.i18n.translate('CHECK_SETTINGS_AND_NETWORK'), text: '' }) - // @ts-expect-error string | IError throw err?.response?.data || err } } diff --git a/src/plugins/uploader/upyun.ts b/src/plugins/uploader/upyun.ts index 6900d88..67e8372 100644 --- a/src/plugins/uploader/upyun.ts +++ b/src/plugins/uploader/upyun.ts @@ -66,9 +66,7 @@ const getAntiLeechParam = ( const handle = async (ctx: IPicGo): Promise => { const upyunOptions = ctx.getConfig('picBed.upyun') - if (!upyunOptions) { - throw new Error("Can't find upYun config") - } + if (!upyunOptions) throw new Error("Can't find upYun config") try { const imgList = ctx.output const path = formatPathHelper({ path: upyunOptions.path }) diff --git a/src/plugins/uploader/webdav.ts b/src/plugins/uploader/webdav.ts index 025d0e2..2b1ca46 100644 --- a/src/plugins/uploader/webdav.ts +++ b/src/plugins/uploader/webdav.ts @@ -9,9 +9,7 @@ import { encodePath, formatPathHelper } from './utils' const handle = async (ctx: IPicGo): Promise => { const webdavplistOptions = ctx.getConfig('picBed.webdavplist') - if (!webdavplistOptions) { - throw new Error("Can't find webdavplist config") - } + if (!webdavplistOptions) throw new Error("Can't find webdavplist config") webdavplistOptions.host = webdavplistOptions.host.replace(/^https?:\/\/|\/+$/g, '') webdavplistOptions.host = (webdavplistOptions.sslEnabled ? 'https://' : 'http://') + webdavplistOptions.host webdavplistOptions.path = formatPathHelper({