FFmpegDownloader.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { dirname, basename, resolve } from 'path';
  2. import * as request from 'request';
  3. import * as ProgressBar from 'progress';
  4. const debug = require('debug')('build:ffmpegDownloader');
  5. const progress = require('request-progress');
  6. import { Event, DownloaderBase } from './common';
  7. import { mergeOptions, extractGeneric } from './util';
  8. export interface IRequestProgress {
  9. percent: number;
  10. speed: number;
  11. size: {
  12. total: number,
  13. transferred: number,
  14. };
  15. time: {
  16. elapsed: number,
  17. remaining: number,
  18. };
  19. }
  20. export interface IFFmpegDownloaderOptions {
  21. platform?: string;
  22. arch?: string;
  23. version?: string;
  24. mirror?: string;
  25. useCaches?: boolean;
  26. showProgress?: boolean;
  27. forceCaches?: boolean;
  28. destination?: string;
  29. }
  30. export class FFmpegDownloader extends DownloaderBase {
  31. public static DEFAULT_OPTIONS: IFFmpegDownloaderOptions = {
  32. platform: process.platform,
  33. arch: process.arch,
  34. version: '0.14.7',
  35. mirror: 'https://github.com/iteufel/nwjs-ffmpeg-prebuilt/releases/download/',
  36. useCaches: true,
  37. showProgress: true,
  38. forceCaches: false,
  39. destination: DownloaderBase.DEFAULT_DESTINATION,
  40. };
  41. public options: IFFmpegDownloaderOptions;
  42. constructor(options: IFFmpegDownloaderOptions) {
  43. super();
  44. this.options = mergeOptions(FFmpegDownloader.DEFAULT_OPTIONS, options);
  45. if(this.options.destination !== this.destination) {
  46. this.setDestination(this.options.destination);
  47. }
  48. debug('in constructor', 'options', options);
  49. }
  50. public async fetch() {
  51. const { mirror, version, platform, arch, showProgress } = this.options;
  52. const partVersion = await this.handleVersion(version);
  53. const partPlatform = this.handlePlatform(platform);
  54. const partArch = this.handleArch(arch);
  55. const url = `${ mirror }/${ partVersion }/${ partVersion }-${ partPlatform }-${ partArch }.zip`;
  56. const filename = `ffmpeg-${ basename(url) }`;
  57. const path = resolve(this.destination, filename);
  58. debug('in fetch', 'url', url);
  59. debug('in fetch', 'filename', filename);
  60. debug('in fetch', 'path', path);
  61. if (this.options.forceCaches && await this.isFileExists(path)) {
  62. return path;
  63. }
  64. try {
  65. if(await this.isFileExists(path) && await this.isFileSynced(url, path)) {
  66. return path;
  67. }
  68. }
  69. catch(err) {
  70. debug('in fetch', 'err', err);
  71. if(err.code === 'ENOTFOUND' && this.options.useCaches) {
  72. console.info('DNS lookup fails, use local caches at this time.');
  73. return path;
  74. }
  75. else if(err.code === 'EAI_AGAIN' && this.options.useCaches) {
  76. console.info('DNS lookup timeout, use local caches at this time.');
  77. return path;
  78. }
  79. else {
  80. throw err;
  81. }
  82. }
  83. await this.download(url, filename, path, showProgress);
  84. return path;
  85. }
  86. protected async handleVersion(version: string) {
  87. switch(version) {
  88. case 'lts':
  89. case 'stable':
  90. case 'latest':
  91. throw new Error('ERROR_VERSION_UNSUPPORTED');
  92. default:
  93. return version[0] == 'v' ? version.slice(1) : version;
  94. }
  95. }
  96. }