README
Downldr
A simple downloader which prevents writing invalid files:
- Will throw an error in case of non 2xx status code
- Allows file type filtering
Install
npm install downldr
API
downldr(input, [options])
Returns a PassThrough stream
with some extra events.
complete
: When the target or returned stream is fully written.type
: Triggered when the file type is available &filter
function is not passed or returnedtrue
.abort
: When the request is aborted.
input
Type: string
/ object (request options)
You can pass either an URL
or an object that will be passed directly to request.
options (optional)
ignoreStatus
- Iftrue
it will ignore non2xx
status code, defaults tofalse
target
- Takes afunction
or aWritable Stream
. When passed the response will be piped into this stream. If it's afunction
the file will be passed extension if available & must return aWritable Stream
. The function will only be executed once the download is valid:2xx
status code & wasn't filtered by thefilter
function.filter
- which takes afunction
that should returnfalse
value if the download should be aborted.
This function will be triggered with the first chunk, and uses file-type to detect the file type.
function filter(type, chunk, statusCode) {
// - type.mime may be null if `file-type` fails to detect the type
// - type.contentType will always contain the response Conten-Type header
// but the Content-Type header is not always
// accurate; A video with png extension
return type.mime === 'image/jpeg'; // Only accepts jpeg
}
If the file type is not in this list type.mime
will be undefined
, but you can do the checks either using type.contentType
or the first chunk
Note: type.mime
may also be undefined
for: docx
/pptx
/xlsx
The exception is detection of
docx
,pptx
, andxlsx
which potentially requires reading the whole file.
const downldr = require('downldr');
downldr('https://example.com/video.mp4')
.on('error', console.error)
.pipe(fs.createWriteStream('/tmp/video.mp4'))
downldr().abort()
This method will abort the current download. It uses request.abort()
const downldr = require('downldr');
const req = downldr('https://example.com/video.mp4')
.on('error', console.error)
.on('abort', () => console.log('Aborted!'));
req.abort();
.promise(input, options)
A convenient Promise
wrapper around downldr
.
options.target
is required, since .pipe
isn't available.
await downldr.promise('https://example.com/image', {
filter: type => type && type.mime.startsWith('image/'),
target: (ext) => fs.createWriteStream(`out.${ext}`)
});
Will resolve
once target
is fully written, and reject
if an error occurs.
Examples
File type filter
const downldr = require('downldr');
downldr('https://example.com/image.jpg', {
filter: (type, chunk, statusCode) => {
// or check the first chunk or the statusCode
return type.mime && type.mime.startsWith('image/');
}
})
.on('error', console.error)
.pipe(fs.createWriteStream('/tmp/image.jpg'))
Create stream on success
When saving the file to disk, a common practice is:
read
.pipe(fs.createWriteStream('/tmp/file.txt');
But if the Readable
stream fails, we end up with an empty file. To avoid that downldr
can take a target
option (function
) which will be executed only when it's time to actually write to the stream.
downldr('https://example.com/image', {
filter: type => type.mime == 'image/png',
target: (ext) => fs.createWriteStream(`out.${ext}`)
})
.on('error', console.error)
.on('complete', () => console.log('done!'));
Set request Content-Type
const downldr = require('downldr');
app.get('/download/:image', (req, res) => {
downldr(`http://example.com/${req.params.image}`, {
filter: ({ mime = '' }) => {
// type.mime may be undefined for some files
// so we default it to = '' to safely use .startsWith
return mime.startsWith('image/');
}
})
// 'type' is only triggered once filter returned true
.on('type', type => res.set('Content-Type', type.mime))
.on('error', err => {
res.status(404)
.send('Image not found')
})
.pipe(res); // Nothing will be piped if 'error' is triggered
});
License
ISC