From ebfe6575938967dfec104b2d9f048b4156ec0a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=8C=E8=90=8C=E5=93=92=E8=B5=AB=E8=90=9D?= Date: Sat, 15 Apr 2023 20:50:16 +0800 Subject: [PATCH] :sparkles: Feature: add auth user upload for imgur --- src/i18n/en.ts | 7 +++ src/i18n/zh-CN.ts | 7 +++ src/i18n/zh-TW.ts | 7 +++ src/plugins/uploader/imgur.ts | 100 ++++++++++++++++++++++++++++++---- src/types/index.ts | 6 ++ yarn.lock | 49 +++++------------ 6 files changed, 131 insertions(+), 45 deletions(-) diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 695cea4..0f3764a 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -75,7 +75,14 @@ export const EN: ILocales = { // imgur PICBED_IMGUR: 'Imgur', PICBED_IMGUR_CLIENTID: 'Set ClientId', + PICBED_IMGUR_USERNAME: 'Set Username', + PICBED_IMGUR_ACCESS_TOKEN: 'Set Access Token', + PICBED_IMGUR_ALBUM: 'Set Album Name', PICBED_IMGUR_PROXY: 'Set Proxy', + PICBED_IMGUR_MESSAGE_CLIENTID: 'Fill in when you need to upload as anonymous', + PICBED_IMGUR_MESSAGE_USERNAME: 'Fill in when you need to upload to the account', + PICBED_IMGUR_MESSAGE_ACCESS_TOKEN: 'Fill in when you need to upload to the account', + PICBED_IMGUR_MESSAGE_ALBUM: '例如:test', PICBED_IMGUR_MESSAGE_PROXY: 'Ex. http://127.0.0.1:1080', // upyun diff --git a/src/i18n/zh-CN.ts b/src/i18n/zh-CN.ts index 96f73d3..20b8aab 100644 --- a/src/i18n/zh-CN.ts +++ b/src/i18n/zh-CN.ts @@ -73,7 +73,14 @@ export const ZH_CN = { // imgur PICBED_IMGUR: 'Imgur', PICBED_IMGUR_CLIENTID: '设定ClientId', + PICBED_IMGUR_USERNAME: '设定用户名', + PICBED_IMGUR_ACCESS_TOKEN: '设定accessToken', + PICBED_IMGUR_ALBUM: '设定相册名', PICBED_IMGUR_PROXY: '设定代理', + PICBED_IMGUR_MESSAGE_CLIENTID: '匿名上传时填写', + PICBED_IMGUR_MESSAGE_USERNAME: '需要上传到账户时填写', + PICBED_IMGUR_MESSAGE_ACCESS_TOKEN: '需要上传到账户时填写', + PICBED_IMGUR_MESSAGE_ALBUM: '例如:test', PICBED_IMGUR_MESSAGE_PROXY: '例如:http://127.0.0.1:1080', // upyun diff --git a/src/i18n/zh-TW.ts b/src/i18n/zh-TW.ts index 18ffb85..cf9054a 100644 --- a/src/i18n/zh-TW.ts +++ b/src/i18n/zh-TW.ts @@ -75,7 +75,14 @@ export const ZH_TW: ILocales = { // imgur PICBED_IMGUR: 'Imgur', PICBED_IMGUR_CLIENTID: '設定ClientId', + PICBED_IMGUR_USERNAME: '設定用戶名', + PICBED_IMGUR_ACCESS_TOKEN: '設定accessToken', + PICBED_IMGUR_ALBUM: '設定相簿名', PICBED_IMGUR_PROXY: '設定PROXY', + PICBED_IMGUR_MESSAGE_CLIENTID: '匿名上傳時填寫', + PICBED_IMGUR_MESSAGE_USERNAME: '需要上傳到賬戶時填寫', + PICBED_IMGUR_MESSAGE_ACCESS_TOKEN: '需要上傳到賬戶時填寫', + PICBED_IMGUR_MESSAGE_ALBUM: '例如:test', PICBED_IMGUR_MESSAGE_PROXY: '例如:http://127.0.0.1:1080', // upyun diff --git a/src/plugins/uploader/imgur.ts b/src/plugins/uploader/imgur.ts index 96a641f..55b5d03 100644 --- a/src/plugins/uploader/imgur.ts +++ b/src/plugins/uploader/imgur.ts @@ -1,28 +1,77 @@ -import { IPicGo, IPluginConfig, IImgurConfig, IOldReqOptions } from '../../types' +import { IPicGo, IPluginConfig, IImgurConfig, IOldReqOptions, IFullResponse } from '../../types' import { IBuildInEvent } from '../../utils/enum' import { ILocalesKey } from '../../i18n/zh-CN' -const postOptions = (options: IImgurConfig, fileName: string, imgBase64: string): IOldReqOptions => { - const clientId = options.clientId - const obj: IOldReqOptions = { +const formatAccessToken = (accessToken: string): string => accessToken ? accessToken.startsWith('Bearer') ? accessToken : `Bearer ${accessToken}` : '' + +const postOptions = async (ctx: IPicGo, options: IImgurConfig, fileName: string, imgBase64: string): Promise => { + const clientId = options.clientId || '' + const username = options.username || '' + const accessToken = formatAccessToken(options.accessToken || '') + const album = options.album || '' + let authorization + if (username && accessToken) { + authorization = accessToken + } else if (clientId) { + authorization = `Client-ID ${clientId}` + } else { + throw new Error('clientId or accessToken is required') + } + const requestOptions: IOldReqOptions = { method: 'POST', url: 'https://api.imgur.com/3/image', headers: { - Authorization: `Client-ID ${clientId}`, + Authorization: authorization, 'content-type': 'multipart/form-data', Host: 'api.imgur.com', - 'User-Agent': 'PicGo' + 'User-Agent': 'PicList' }, formData: { image: imgBase64, type: 'base64', - name: fileName + name: fileName, + description: 'Uploaded with PicList' + } + } + if (username && accessToken && album) { + let initPages = 0 + let res + let albumHash = '' + do { + const getAlbumHashOptions: IOldReqOptions = { + method: 'GET', + url: `https://api.imgur.com/3/account/${username}/albums/${initPages}`, + headers: { + Authorization: authorization + }, + json: true, + resolveWithFullResponse: true, + timeout: 10000 + } + if (options.proxy) { + getAlbumHashOptions.proxy = options.proxy + } + res = await ctx.request(getAlbumHashOptions) as unknown as IFullResponse + if (!(res.statusCode === 200 && res.body.success)) { + throw new Error('Server error, please try again') + } + const albumList = res.body.data + for (const item of albumList) { + if (item.title === album) { + albumHash = item.id + break + } + } + initPages++ + } while (res.body.data.length > 0) + if (albumHash && requestOptions.formData) { + requestOptions.formData.album = albumHash } } if (options.proxy) { - obj.proxy = options.proxy + requestOptions.proxy = options.proxy } - return obj + return requestOptions } const handle = async (ctx: IPicGo): Promise => { @@ -35,7 +84,7 @@ const handle = async (ctx: IPicGo): Promise => { for (const img of imgList) { if (img.fileName && img.buffer) { const base64Image = img.base64Image || Buffer.from(img.buffer).toString('base64') - const options = postOptions(imgurOptions, img.fileName, base64Image) + const options = await postOptions(ctx, imgurOptions, img.fileName, base64Image) const res: string = await ctx.request(options) const body = typeof res === 'string' ? JSON.parse(res) : res if (body.success) { @@ -66,9 +115,38 @@ const config = (ctx: IPicGo): IPluginConfig[] => { { name: 'clientId', type: 'input', + get prefix () { return ctx.i18n.translate('PICBED_IMGUR_CLIENTID') }, get alias () { return ctx.i18n.translate('PICBED_IMGUR_CLIENTID') }, + get message () { return ctx.i18n.translate('PICBED_IMGUR_MESSAGE_CLIENTID') }, default: userConfig.clientId || '', - required: true + required: false + }, + { + name: 'username', + type: 'input', + get prefix () { return ctx.i18n.translate('PICBED_IMGUR_USERNAME') }, + get alias () { return ctx.i18n.translate('PICBED_IMGUR_USERNAME') }, + get message () { return ctx.i18n.translate('PICBED_IMGUR_MESSAGE_USERNAME') }, + default: userConfig.username || '', + required: false + }, + { + name: 'accessToken', + type: 'input', + get prefix () { return ctx.i18n.translate('PICBED_IMGUR_ACCESS_TOKEN') }, + get alias () { return ctx.i18n.translate('PICBED_IMGUR_ACCESS_TOKEN') }, + get message () { return ctx.i18n.translate('PICBED_IMGUR_MESSAGE_ACCESS_TOKEN') }, + default: userConfig.accessToken || '', + required: false + }, + { + name: 'album', + type: 'input', + get prefix () { return ctx.i18n.translate('PICBED_IMGUR_ALBUM') }, + get alias () { return ctx.i18n.translate('PICBED_IMGUR_ALBUM') }, + get message () { return ctx.i18n.translate('PICBED_IMGUR_MESSAGE_ALBUM') }, + default: userConfig.album || '', + required: false }, { name: 'proxy', diff --git a/src/types/index.ts b/src/types/index.ts index 349a2e0..02d6c72 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -365,6 +365,12 @@ export interface IImgurConfig { clientId: string /** 代理地址,仅支持 http 代理 */ proxy: string + /** imgur 用户名 */ + username: string + /** imgur access token */ + accessToken: string + /** imgur album name */ + album: string } /** Webdav 图床配置项 */ export interface IWebdavPlistConfig{ diff --git a/yarn.lock b/yarn.lock index fdde745..a4f3021 100644 --- a/yarn.lock +++ b/yarn.lock @@ -501,12 +501,12 @@ "@types/fs-extra@^8.0.1": version "8.1.2" - resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz#7125cc2e4bdd9bd2fc83005ffdb1d0ba00cca61f" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz" integrity sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg== dependencies: "@types/node" "*" -"@types/glob@*": +"@types/glob@*", "@types/glob@^7.1.1": version "7.1.4" resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz" integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== @@ -514,14 +514,6 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/glob@^7.1.1": - version "7.2.0" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" - integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - "@types/graceful-fs@^4.1.3": version "4.1.5" resolved "https://registry.npmmirror.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz" @@ -608,7 +600,7 @@ "@types/opentype.js@*": version "1.3.4" - resolved "https://registry.npmjs.org/@types/opentype.js/-/opentype.js-1.3.4.tgz#d9ef2e6ed3ba9d2b6822e38febb1834fb037641b" + resolved "https://registry.npmjs.org/@types/opentype.js/-/opentype.js-1.3.4.tgz" integrity sha512-6fbXi67I07ugNM+FExwJnfuui2hD7hraD6nqjr3UnqsbBpxSkrtmO6tBubPdNAjqRT9TVkquVkNS9IkgTtq6/w== "@types/parse-json@^4.0.0": @@ -741,14 +733,14 @@ "@types/sharp@^0.31.1": version "0.31.1" - resolved "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz#db768461455dbcf9ff11d69277fd70564483c4df" + resolved "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz" integrity sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag== dependencies: "@types/node" "*" "@types/text-to-svg@^3.1.1": version "3.1.1" - resolved "https://registry.npmjs.org/@types/text-to-svg/-/text-to-svg-3.1.1.tgz#c9bec66ad69f9c80bf690f01fd799532f1ebdcac" + resolved "https://registry.npmjs.org/@types/text-to-svg/-/text-to-svg-3.1.1.tgz" integrity sha512-7jvQ8p6amiXkuA7VXjgurnlyFGbABHOezWoDjCZu0QWMNugiI4JhJ78vZUYrfhakfHF6GwpZP5UVu7Kd9oXctg== dependencies: "@types/opentype.js" "*" @@ -1023,7 +1015,7 @@ asynckit@^0.4.0: axios@^1.3.4: version "1.3.4" - resolved "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" + resolved "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz" integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ== dependencies: follow-redirects "^1.15.0" @@ -1387,7 +1379,7 @@ color@^4.2.3: colorette@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== combined-stream@^1.0.8: @@ -2498,18 +2490,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.0.3: - version "3.2.12" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-glob@^3.1.1: +fast-glob@^3.0.3, fast-glob@^3.1.1: version "3.2.7" resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz" integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== @@ -2983,7 +2964,7 @@ globals@^13.6.0, globals@^13.9.0: globby@10.0.1: version "10.0.1" - resolved "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz#4782c34cb75dd683351335c5829cc3420e606b22" + resolved "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz" integrity sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A== dependencies: "@types/glob" "^7.1.1" @@ -3444,7 +3425,7 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: is-plain-object@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz" integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== is-reference@^1.2.1: @@ -4235,7 +4216,7 @@ onetime@^5.1.2: opentype.js@0.11.0: version "0.11.0" - resolved "https://registry.npmjs.org/opentype.js/-/opentype.js-0.11.0.tgz#310f3fb85f09ca6cf22ac8cf540df67b418c3351" + resolved "https://registry.npmjs.org/opentype.js/-/opentype.js-0.11.0.tgz" integrity sha512-Z9NkAyQi/iEKQYzCSa7/VJSqVIs33wknw8Z8po+DzuRUAqivJ+hJZ94mveg3xIeKwLreJdWTMyEO7x1K13l41Q== dependencies: string.prototype.codepointat "^0.2.1" @@ -4955,7 +4936,7 @@ rimraf@~2.6.2: rollup-plugin-copy@^3.4.0: version "3.4.0" - resolved "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz#f1228a3ffb66ffad8606e2f3fb7ff23141ed3286" + resolved "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz" integrity sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ== dependencies: "@types/fs-extra" "^8.0.1" @@ -5348,7 +5329,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: string.prototype.codepointat@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc" + resolved "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz" integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg== string.prototype.trimend@^1.0.4: @@ -5557,7 +5538,7 @@ text-table@^0.2.0: text-to-svg@^3.1.5: version "3.1.5" - resolved "https://registry.npmjs.org/text-to-svg/-/text-to-svg-3.1.5.tgz#493913d70eae1b12240b309547d64d787ec11e57" + resolved "https://registry.npmjs.org/text-to-svg/-/text-to-svg-3.1.5.tgz" integrity sha512-mbeGhMz9MAFaGaZGE8n4Mh/iQV/UkVnYJXhXFrv0eWkcNTgflhpHR2a8nr2ci3NU4FekIHJYKh0N0qdc6yUpfA== dependencies: commander "^2.11.0" @@ -5604,7 +5585,7 @@ timed-out@^4.0.1: tiny-inflate@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" + resolved "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz" integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw== tmp@^0.0.33: