Skip to content

Commit 0d87342

Browse files
committed
✨ Feature: add upload image from URL support
1 parent 7975f73 commit 0d87342

File tree

6 files changed

+114
-16
lines changed

6 files changed

+114
-16
lines changed

logo.png

9.24 KB
Loading

src/plugins/commander/upload.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import PicGo from '../../core/PicGo'
22
import path from 'path'
33
import fs from 'fs-extra'
4+
import { isUrl } from '../../utils/common'
45

56
export default {
67
handle: (ctx: PicGo): void => {
@@ -12,9 +13,11 @@ export default {
1213
.alias('u')
1314
.action(async (input: string[]) => {
1415
const inputList = input
15-
.map((item: string) => path.resolve(item))
16+
.map((item: string) => {
17+
return isUrl(item) ? item : path.resolve(item)
18+
})
1619
.filter((item: string) => {
17-
const exist = fs.existsSync(item)
20+
const exist = fs.existsSync(item) || isUrl(item)
1821
if (!exist) {
1922
ctx.log.warn(`${item} does not exist.`)
2023
}

src/plugins/transformer/path.ts

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,55 @@ import probe from 'probe-image-size'
22
import path from 'path'
33
import fs from 'fs-extra'
44
import PicGo from '../../core/PicGo'
5+
import { getURLFile } from '../../utils/getURLFile'
6+
import { isUrl } from '../../utils/common'
7+
import { IPathTransformedImgInfo, ImgInfo } from '../../utils/interfaces'
58

69
const handle = async (ctx: PicGo): Promise<PicGo> => {
7-
let results = ctx.output
10+
let results: ImgInfo[] = ctx.output
811
await Promise.all(ctx.input.map(async (item: string) => {
9-
let fileName = path.basename(item)
10-
let buffer = await fs.readFile(item)
11-
// let base64Image = Buffer.from(buffer).toString('base64')
12-
let imgSize = probe.sync(buffer)
13-
results.push({
14-
buffer,
15-
// base64Image,
16-
fileName,
17-
width: imgSize.width,
18-
height: imgSize.height,
19-
extname: path.extname(item)
20-
})
12+
let info: IPathTransformedImgInfo
13+
if (isUrl(item)) {
14+
info = await getURLFile(ctx, item)
15+
} else {
16+
info = await getFSFile(item)
17+
}
18+
if (info.success) {
19+
try {
20+
const imgSize = probe.sync(info.buffer)
21+
results.push({
22+
buffer: info.buffer,
23+
fileName: info.fileName,
24+
width: imgSize.width,
25+
height: imgSize.height,
26+
extname: path.extname(item)
27+
})
28+
} catch (e) {
29+
ctx.log.error(e)
30+
}
31+
} else {
32+
ctx.log.error(info.reason)
33+
}
2134
}))
2235
return ctx
2336
}
2437

38+
const getFSFile = async (item: string): Promise<IPathTransformedImgInfo> => {
39+
try {
40+
return {
41+
extname: path.extname(item),
42+
fileName: path.basename(item),
43+
buffer: await fs.readFile(item),
44+
success: true
45+
}
46+
} catch {
47+
return {
48+
reason: `read file ${item} error`,
49+
success: false
50+
}
51+
}
52+
}
53+
2554
export default {
2655
handle
2756
}

src/utils/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const isUrl = (url: string): boolean => (url.startsWith('http://') || url.startsWith('https://'))

src/utils/getURLFile.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import PicGo from '../core/PicGo'
2+
import request from 'request'
3+
import path from 'path'
4+
import { IPathTransformedImgInfo } from './interfaces'
5+
import fs from 'fs'
6+
7+
export const getURLFile = async (ctx: PicGo, url: string): Promise<IPathTransformedImgInfo> => {
8+
const requestOptions = {
9+
method: 'GET',
10+
url,
11+
encoding: null
12+
}
13+
let isImage = false
14+
let extname = ''
15+
let timeoutId
16+
// tslint:disable-next-line: typedef
17+
const requestPromise = new Promise<IPathTransformedImgInfo>(async (resolve): Promise<void> => {
18+
try {
19+
const res = await ctx.Request.request(requestOptions)
20+
.on('response', (response: request.Response): void => {
21+
const contentType = response.headers['content-type']
22+
if (contentType.includes('image')) {
23+
isImage = true
24+
extname = `.${contentType.split('image/')[1]}`
25+
}
26+
})
27+
clearTimeout(timeoutId)
28+
if (isImage) {
29+
fs.writeFileSync('./logo.png', res)
30+
resolve({
31+
buffer: res,
32+
fileName: path.basename(requestOptions.url.split('?')[0]),
33+
extname,
34+
success: true
35+
})
36+
} else {
37+
resolve({
38+
success: false,
39+
reason: `${url} is not image`
40+
})
41+
}
42+
} catch {
43+
clearTimeout(timeoutId)
44+
resolve({
45+
success: false,
46+
reason: `request ${url} error`
47+
})
48+
}
49+
})
50+
// tslint:disable-next-line: typedef
51+
const timeoutPromise = new Promise<IPathTransformedImgInfo>((resolve): void => {
52+
timeoutId = setTimeout(() => {
53+
resolve({
54+
success: false,
55+
reason: `request ${url} timeout`
56+
})
57+
}, 10000)
58+
})
59+
return Promise.race([requestPromise, timeoutPromise])
60+
}

src/utils/interfaces.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ interface ImgInfo {
3636
[propName: string]: any
3737
}
3838

39+
interface IPathTransformedImgInfo extends ImgInfo {
40+
success: boolean
41+
}
42+
3943
/**
4044
* for config options
4145
*/
@@ -105,5 +109,6 @@ export {
105109
ImgSize,
106110
Options,
107111
ClipboardImage,
108-
ProcessEnv
112+
ProcessEnv,
113+
IPathTransformedImgInfo
109114
}

0 commit comments

Comments
 (0)