index.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. 'use strict';
  2. const fs = require('fs');
  3. const path = require('path');
  4. const {URL} = require('url');
  5. const contentDisposition = require('content-disposition');
  6. const archiveType = require('archive-type');
  7. const decompress = require('decompress');
  8. const filenamify = require('filenamify');
  9. const getStream = require('get-stream');
  10. const got = require('got');
  11. const makeDir = require('make-dir');
  12. const pify = require('pify');
  13. const pEvent = require('p-event');
  14. const fileType = require('file-type');
  15. const extName = require('ext-name');
  16. const fsP = pify(fs);
  17. const filenameFromPath = res => path.basename(new URL(res.requestUrl).pathname);
  18. const getExtFromMime = res => {
  19. const header = res.headers['content-type'];
  20. if (!header) {
  21. return null;
  22. }
  23. const exts = extName.mime(header);
  24. if (exts.length !== 1) {
  25. return null;
  26. }
  27. return exts[0].ext;
  28. };
  29. const getFilename = (res, data) => {
  30. const header = res.headers['content-disposition'];
  31. if (header) {
  32. const parsed = contentDisposition.parse(header);
  33. if (parsed.parameters && parsed.parameters.filename) {
  34. return parsed.parameters.filename;
  35. }
  36. }
  37. let filename = filenameFromPath(res);
  38. if (!path.extname(filename)) {
  39. const ext = (fileType(data) || {}).ext || getExtFromMime(res);
  40. if (ext) {
  41. filename = `${filename}.${ext}`;
  42. }
  43. }
  44. return filename;
  45. };
  46. module.exports = (uri, output, opts) => {
  47. if (typeof output === 'object') {
  48. opts = output;
  49. output = null;
  50. }
  51. opts = Object.assign({
  52. encoding: null,
  53. rejectUnauthorized: process.env.npm_config_strict_ssl !== 'false'
  54. }, opts);
  55. const stream = got.stream(uri, opts);
  56. const promise = pEvent(stream, 'response').then(res => {
  57. const encoding = opts.encoding === null ? 'buffer' : opts.encoding;
  58. return Promise.all([getStream(stream, {encoding}), res]);
  59. }).then(result => {
  60. const [data, res] = result;
  61. if (!output) {
  62. return opts.extract && archiveType(data) ? decompress(data, opts) : data;
  63. }
  64. const filename = opts.filename || filenamify(getFilename(res, data));
  65. const outputFilepath = path.join(output, filename);
  66. if (opts.extract && archiveType(data)) {
  67. return decompress(data, path.dirname(outputFilepath), opts);
  68. }
  69. return makeDir(path.dirname(outputFilepath))
  70. .then(() => fsP.writeFile(outputFilepath, data))
  71. .then(() => data);
  72. });
  73. stream.then = promise.then.bind(promise);
  74. stream.catch = promise.catch.bind(promise);
  75. return stream;
  76. };