From 0d873424bc57d2ca4446e2b4f5376c34660506df Mon Sep 17 00:00:00 2001 From: Molunerfinn Date: Sun, 23 Feb 2020 14:55:04 +0800 Subject: [PATCH] :sparkles: Feature: add upload image from URL support --- logo.png | Bin 0 -> 9464 bytes src/plugins/commander/upload.ts | 7 ++-- src/plugins/transformer/path.ts | 55 ++++++++++++++++++++++------- src/utils/common.ts | 1 + src/utils/getURLFile.ts | 60 ++++++++++++++++++++++++++++++++ src/utils/interfaces.ts | 7 +++- 6 files changed, 114 insertions(+), 16 deletions(-) create mode 100644 logo.png create mode 100644 src/utils/common.ts create mode 100644 src/utils/getURLFile.ts diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5c5eefbb262d03c175c2d184470210e6c27fd99f GIT binary patch literal 9464 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 literal 0 HcmV?d00001 diff --git a/src/plugins/commander/upload.ts b/src/plugins/commander/upload.ts index 846f65f..7d41b10 100644 --- a/src/plugins/commander/upload.ts +++ b/src/plugins/commander/upload.ts @@ -1,6 +1,7 @@ import PicGo from '../../core/PicGo' import path from 'path' import fs from 'fs-extra' +import { isUrl } from '../../utils/common' export default { handle: (ctx: PicGo): void => { @@ -12,9 +13,11 @@ export default { .alias('u') .action(async (input: string[]) => { const inputList = input - .map((item: string) => path.resolve(item)) + .map((item: string) => { + return isUrl(item) ? item : path.resolve(item) + }) .filter((item: string) => { - const exist = fs.existsSync(item) + const exist = fs.existsSync(item) || isUrl(item) if (!exist) { ctx.log.warn(`${item} does not exist.`) } diff --git a/src/plugins/transformer/path.ts b/src/plugins/transformer/path.ts index 27def9f..df47860 100644 --- a/src/plugins/transformer/path.ts +++ b/src/plugins/transformer/path.ts @@ -2,26 +2,55 @@ import probe from 'probe-image-size' import path from 'path' import fs from 'fs-extra' import PicGo from '../../core/PicGo' +import { getURLFile } from '../../utils/getURLFile' +import { isUrl } from '../../utils/common' +import { IPathTransformedImgInfo, ImgInfo } from '../../utils/interfaces' const handle = async (ctx: PicGo): Promise => { - let results = ctx.output + let results: ImgInfo[] = ctx.output await Promise.all(ctx.input.map(async (item: string) => { - let fileName = path.basename(item) - let buffer = await fs.readFile(item) - // let base64Image = Buffer.from(buffer).toString('base64') - let imgSize = probe.sync(buffer) - results.push({ - buffer, - // base64Image, - fileName, - width: imgSize.width, - height: imgSize.height, - extname: path.extname(item) - }) + let info: IPathTransformedImgInfo + if (isUrl(item)) { + info = await getURLFile(ctx, item) + } else { + info = await getFSFile(item) + } + if (info.success) { + try { + const imgSize = probe.sync(info.buffer) + results.push({ + buffer: info.buffer, + fileName: info.fileName, + width: imgSize.width, + height: imgSize.height, + extname: path.extname(item) + }) + } catch (e) { + ctx.log.error(e) + } + } else { + ctx.log.error(info.reason) + } })) return ctx } +const getFSFile = async (item: string): Promise => { + try { + return { + extname: path.extname(item), + fileName: path.basename(item), + buffer: await fs.readFile(item), + success: true + } + } catch { + return { + reason: `read file ${item} error`, + success: false + } + } +} + export default { handle } diff --git a/src/utils/common.ts b/src/utils/common.ts new file mode 100644 index 0000000..36762c4 --- /dev/null +++ b/src/utils/common.ts @@ -0,0 +1 @@ +export const isUrl = (url: string): boolean => (url.startsWith('http://') || url.startsWith('https://')) diff --git a/src/utils/getURLFile.ts b/src/utils/getURLFile.ts new file mode 100644 index 0000000..3e3fcfd --- /dev/null +++ b/src/utils/getURLFile.ts @@ -0,0 +1,60 @@ +import PicGo from '../core/PicGo' +import request from 'request' +import path from 'path' +import { IPathTransformedImgInfo } from './interfaces' +import fs from 'fs' + +export const getURLFile = async (ctx: PicGo, url: string): Promise => { + const requestOptions = { + method: 'GET', + url, + encoding: null + } + let isImage = false + let extname = '' + let timeoutId + // tslint:disable-next-line: typedef + const requestPromise = new Promise(async (resolve): Promise => { + try { + const res = await ctx.Request.request(requestOptions) + .on('response', (response: request.Response): void => { + const contentType = response.headers['content-type'] + if (contentType.includes('image')) { + isImage = true + extname = `.${contentType.split('image/')[1]}` + } + }) + clearTimeout(timeoutId) + if (isImage) { + fs.writeFileSync('./logo.png', res) + resolve({ + buffer: res, + fileName: path.basename(requestOptions.url.split('?')[0]), + extname, + success: true + }) + } else { + resolve({ + success: false, + reason: `${url} is not image` + }) + } + } catch { + clearTimeout(timeoutId) + resolve({ + success: false, + reason: `request ${url} error` + }) + } + }) + // tslint:disable-next-line: typedef + const timeoutPromise = new Promise((resolve): void => { + timeoutId = setTimeout(() => { + resolve({ + success: false, + reason: `request ${url} timeout` + }) + }, 10000) + }) + return Promise.race([requestPromise, timeoutPromise]) +} diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index db4a5fa..964883c 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -36,6 +36,10 @@ interface ImgInfo { [propName: string]: any } +interface IPathTransformedImgInfo extends ImgInfo { + success: boolean +} + /** * for config options */ @@ -105,5 +109,6 @@ export { ImgSize, Options, ClipboardImage, - ProcessEnv + ProcessEnv, + IPathTransformedImgInfo }