Skip to content

Commit

Permalink
feat: Add duplex streams (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipjscott committed May 11, 2019
1 parent 3427bdf commit bbe0076
Show file tree
Hide file tree
Showing 7 changed files with 14,529 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules/
test/out/
test/write.png
test/duplex.jpg
.nyc_output/
*.swo
*.swp
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ $ npm install simple-thumbnail --save
## Usage

```js
const fs = require('fs')
const genThumbnail = require('simple-thumbnail')

// promise
Expand All @@ -41,6 +42,11 @@ app.get('/some/endpoint', (req, res) => {
.then(() => console.log('done!'))
.catch(err => console.error(err))
})

// duplex streams
fs.createReadStream('path/to/image')
.pipe(genThumbnail(null, null, '250x?'))
.pipe(fs.createWriteStream('output/file/path.jpg'))
```

## Getting FFmpeg
Expand All @@ -66,13 +72,13 @@ download()

#### genThumbnail(input, output, size, [config])

Returns of a `Promise` which resolves on thumbnail creation.
Returns of a `Promise` which resolves on thumbnail creation, or a `stream.Duplex` (see below).

#### input

Type: `String | stream.Readable`
Type: `String | stream.Readable | Null`

The URL, file path, or read-stream of an image or video.
The URL, file path, or read-stream of an image or video. If both the input and output are null, then `genThumbnail` will return a `stream.Duplex`.

#### output

Expand Down
43 changes: 42 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const { spawn } = require('child_process')
const { Duplex } = require('stream')

/**
* Parse a size string (eg. '240x?')
Expand Down Expand Up @@ -124,6 +125,42 @@ function ffmpegStreamExecute (path, args, rstream) {
return Promise.resolve(ffmpeg.stdout)
}

class DuplexFfmpeg extends Duplex {
constructor (ffmpeg) {
super()
this.ffmpeg = ffmpeg
}

_read (size) {
this.ffmpeg.stdout.on('data', data => {
this.push(data)
})
}

_write (...args) {
this.ffmpeg.on('close', () => {
this.end()
})
this.ffmpeg.stdin._write(...args)
}

_final () {}
}

/**
* Return a duplex stream
* @func ffmpegDuplexExecute
* @param {String} path The path of the ffmpeg binary
* @param {Array<string>} args An array of arguments for ffmpeg
* the standard input of ffmpeg
* @returns {stream.Duplex} A duplex stream :)
*/
function ffmpegDuplexExecute (path, args) {
const ffmpeg = spawn(path, args, { shell: true })

return new DuplexFfmpeg(ffmpeg)
}

/**
* Generates a thumbnail from the first frame of a video file
* @func genThumbnail
Expand All @@ -133,7 +170,7 @@ function ffmpegStreamExecute (path, args, rstream) {
* @param {Object} [config={}] A configuration object
* @param {String} [config.path='ffmpeg'] Path of the ffmpeg binary
* @param {String} [config.seek='00:00:00'] Time to seek for videos
* @returns {Promise} Resolves on completion, or rejects on error
* @returns {Promise|stream.Duplex} Resolves on completion, or rejects on error
*/
function genThumbnail (input, output, size, config = {}) {
const ffmpegPath = config.path || process.env.FFMPEG_PATH || 'ffmpeg'
Expand All @@ -149,6 +186,10 @@ function genThumbnail (input, output, size, config = {}) {
seek
)

if (input === null && output === null) {
console.log(args)
return ffmpegDuplexExecute(ffmpegPath, args)
}
if (output === null) {
return ffmpegStreamExecute(ffmpegPath, args, rstream)
}
Expand Down
Loading

0 comments on commit bbe0076

Please sign in to comment.