UNPKG

1.95 kBJavaScriptView Raw
1'use strict'
2
3const { spawn } = require('child_process')
4
5function parseSize (sizeStr) {
6 const percentRegex = /(\d+)%/g
7 const sizeRegex = /(\d+|\?)x(\d+|\?)/g
8 let payload
9
10 const percentResult = percentRegex.exec(sizeStr)
11 const sizeResult = sizeRegex.exec(sizeStr)
12
13 if (percentResult) {
14 payload = { percentage: Number.parseInt(percentResult[1]) }
15 } else if (sizeResult) {
16 const sizeValues = sizeResult.map(x => x === '?' ? null : Number.parseInt(x))
17
18 payload = {
19 width: sizeValues[1],
20 height: sizeValues[2]
21 }
22 } else {
23 throw new Error('Invalid size argument')
24 }
25
26 return payload
27}
28
29function buildArgs (input, output, { width, height, percentage }) {
30 const scaleArg = (percentage)
31 ? `-vf scale=iw*${percentage / 100}:ih*${percentage / 100}`
32 : `-vf scale=${width || -1}:${height || -1}`
33
34 return [
35 '-y',
36 `-i ${input}`,
37 '-vframes 1',
38 scaleArg,
39 output
40 ]
41}
42
43function ffmpegExecute (path, args, stream = null) {
44 const ffmpeg = spawn(path, args, { shell: true })
45 let stderr = ''
46
47 return new Promise((resolve, reject) => {
48 if (stream) {
49 stream.pipe(ffmpeg.stdin)
50 }
51
52 ffmpeg.stderr.on('data', (data) => {
53 stderr += data.toString()
54 })
55 // use sinon?
56 ffmpeg.stderr.on('error', (err) => {
57 reject(err)
58 })
59
60 ffmpeg.on('close', resolve)
61 ffmpeg.on('exit', (code, signal) => {
62 if (code !== 0) {
63 const err = new Error(`ffmpeg exited ${code}\nffmpeg stderr:\n\n${stderr}`)
64
65 reject(err)
66 }
67 })
68 })
69}
70
71function genThumbnail (input, output, size, config = {}) {
72 const ffmpegPath = config.path || 'ffmpeg'
73
74 const parsedSize = parseSize(size)
75 const args = buildArgs(
76 typeof input === 'string' ? input : 'pipe:0',
77 output,
78 parsedSize
79 )
80
81 return typeof input === 'string'
82 ? ffmpegExecute(ffmpegPath, args)
83 : ffmpegExecute(ffmpegPath, args, input)
84}
85
86module.exports = genThumbnail