first commit
This commit is contained in:
21
node_modules/node-downloader-helper/LICENSE
generated
vendored
Normal file
21
node_modules/node-downloader-helper/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Jose De Gouveia
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
265
node_modules/node-downloader-helper/README.md
generated
vendored
Normal file
265
node_modules/node-downloader-helper/README.md
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
# node-downloader-helper
|
||||
|
||||
[](https://www.npmjs.com/package/node-downloader-helper)
|
||||

|
||||

|
||||
[](https://ci.appveyor.com/project/hgouveia/node-downloader-helper) [](https://gitter.im/node-downloader-helper/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fhgouveia%2Fnode-downloader-helper?ref=badge_shield)
|
||||
|
||||
|
||||
A simple http file downloader for node.js
|
||||
|
||||
Features:
|
||||
- No thirdparty dependecies
|
||||
- Pause/Resume
|
||||
- Retry on fail
|
||||
- Supports http/https
|
||||
- Supports http redirects
|
||||
- Supports pipes
|
||||
- Custom native http request options
|
||||
- Usable on vanilla nodejs, electron, nwjs
|
||||
- Progress stats
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install --save node-downloader-helper
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
For a more complete example check [example](example/) folder
|
||||
|
||||
```javascript
|
||||
const { DownloaderHelper } = require('node-downloader-helper');
|
||||
const dl = new DownloaderHelper('https://proof.ovh.net/files/1Gb.dat', __dirname);
|
||||
|
||||
dl.on('end', () => console.log('Download Completed'));
|
||||
dl.on('error', (err) => console.log('Download Failed', err));
|
||||
dl.start().catch(err => console.error(err));
|
||||
```
|
||||
|
||||
**IMPORTANT NOTE:** I highly recommend to use both `.on('error')` and `.start().catch`, although they do the same thing, if `on('error')` is not defined, an error will be thrown when the `error` event is emitted and not listing, this is because EventEmitter is designed to throw an `unhandled error event` error if not been listened and is too late to change it now.
|
||||
|
||||
### CLI
|
||||
|
||||
This can be used as standalone CLI downloader
|
||||
|
||||
Install `npm i -g node-downloader-helper`
|
||||
|
||||
Usage: `ndh [folder] [url]`
|
||||
|
||||
```bash
|
||||
$ ndh ./folder http://url
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
Download Helper constructor also allow a 3rd parameter to set some options `constructor(url, destinationFolder, options)`,
|
||||
these are the default values
|
||||
|
||||
```javascript
|
||||
{
|
||||
body: null, // Request body, can be any, string, object, etc.
|
||||
method: 'GET', // Request Method Verb
|
||||
headers: {}, // Custom HTTP Header ex: Authorization, User-Agent
|
||||
timeout: -1, // Request timeout in milliseconds (-1 use default), is the equivalent of 'httpRequestOptions: { timeout: value }' (also applied to https)
|
||||
metadata: {}, // custom metadata for the user retrieve later (default:null)
|
||||
resumeOnIncomplete: true, // Resume download if the file is incomplete (set false if using any pipe that modifies the file)
|
||||
resumeOnIncompleteMaxRetry: 5, // Max retry when resumeOnIncomplete is true
|
||||
resumeIfFileExists: false, // it will resume if a file already exists and is not completed, you might want to set removeOnStop and removeOnFail to false. If you used pipe for compression it will produce corrupted files
|
||||
fileName: string|cb(fileName, filePath, contentType)|{name, ext}, // Custom filename when saved
|
||||
retry: false, // { maxRetries: number, delay: number in ms } or false to disable (default)
|
||||
forceResume: false, // If the server does not return the "accept-ranges" header, can be force if it does support it
|
||||
removeOnStop: true, // remove the file when is stopped (default:true)
|
||||
removeOnFail: true, // remove the file when fail (default:true)
|
||||
progressThrottle: 1000, // interval time of the 'progress.throttled' event will be emitted
|
||||
override: boolean|{skip, skipSmaller}, // Behavior when local file already exists
|
||||
httpRequestOptions: {}, // Override the http request options
|
||||
httpsRequestOptions: {}, // Override the https request options, ex: to add SSL Certs
|
||||
}
|
||||
```
|
||||
for `body` you can provide any parameter accepted by http.request write function `req.write(body)` https://nodejs.org/api/http.html, when using this, you might need to add the `content-length` and `content-type` header in addition with the http method `POST` or `PUT`
|
||||
|
||||
ex:
|
||||
```javascript
|
||||
const data = JSON.stringify({
|
||||
todo: 'Buy the milk'
|
||||
});
|
||||
const dl = new DownloaderHelper('my_url', __dirname, {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': data.length
|
||||
} } );
|
||||
```
|
||||
|
||||
for `fileName` you can provide 3 types of parameter
|
||||
- **string**: will use the full string as the filename including extension
|
||||
- **callback(fileName, filePath, contentType)**: must return an string, only sync function are supported ex: `(fileName) => 'PREFIX_' + fileName;`, **contentType** will be provided if available
|
||||
- **object**: this object must contain a `name` attribute and an optional `ext` attribute, the `ext` attribute can be an string without dot(`.`) or a boolean where `true` use the `name` as full file name (same as just giving an string to the `fileName` parameter) or false *(default)* will only replace the name and keep the original extension, for example if the original name is `myfile.zip` and the option is `{name: 'somename'}` the output will be `somename.zip`
|
||||
|
||||
for `override` you can provide 2 types of parameter
|
||||
- **boolean**: `true` to override existing local file, `false` to append '(number)' to new file name
|
||||
- **object**: object with properties `skip` (boolean): whether to skip download if file exists, and `skipSmaller` (boolean): whether to skip download if file exists but is smaller. Both default to `false`, for the equivalent of `override: true`.
|
||||
|
||||
for `httpRequestOptions` the available options are detailed in here https://nodejs.org/api/http.html#http_http_request_options_callback
|
||||
|
||||
for `httpsRequestOptions` the available options are detailed in here https://nodejs.org/api/https.html#https_https_request_options_callback
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
| Name | Description |
|
||||
|---------- |--------------------------------------------------------------------------- |
|
||||
| start | starts the downloading |
|
||||
| pause | pause the downloading |
|
||||
| resume | resume the downloading if supported, if not it will start from the beginning |
|
||||
| stop | stop the downloading and remove the file |
|
||||
| pipe | `readable.pipe(stream.Readable, options) : stream.Readable` |
|
||||
| unpipe | `(stream)` if not stream is not specified, then all pipes are detached. |
|
||||
| updateOptions | `(options, url)` updates the options, can be use on pause/resume events |
|
||||
| getStats | returns `stats` from the current download, these are the same `stats` sent via progress event |
|
||||
| getTotalSize | gets the total file size from the server |
|
||||
| getDownloadPath | gets the full path where the file will be downloaded (available after the start phase) |
|
||||
| isResumable | return true/false if the download can be resumable (available after the start phase) |
|
||||
| getResumeState | Get the state required to resume the download after restart. This state can be passed back to `resumeFromFile()` to resume a download |
|
||||
| resumeFromFile | `resumeFromFile(filePath?: string, state?: IResumeState)` Resume the download from a previous file path, if the state is not provided it will try to fetch from the information the headers and filePath, @see `resumeIfFileExists` option |
|
||||
|
||||
usage of `resumeFromFile`
|
||||
|
||||
```javascript
|
||||
const downloadDir = 'D:/TEMP';
|
||||
const { DownloaderHelper } = require('node-downloader-helper');
|
||||
const dl = new DownloaderHelper('https://proof.ovh.net/files/1Gb.dat', downloadDir);
|
||||
dl.on('end', () => console.log('Download Completed'));
|
||||
dl.on('error', (err) => console.log('Download Failed', err));
|
||||
|
||||
// option 1
|
||||
const prevFilePath = `${downloadDir}/1Gb.dat`;
|
||||
dl.resumeFromFile(prevFilePath).catch(err => console.error(err));
|
||||
|
||||
// option 2
|
||||
const prevState = dl.getResumeState(); // this should be stored in a file, localStorage, db, etc in a previous process for example on 'stop'
|
||||
dl.resumeFromFile(prevState.filePath, prevState).catch(err => console.error(err));
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
| Name | Description |
|
||||
|-------------- |----------------------------------------------------------------------------------- |
|
||||
| start | Emitted when the .start method is called |
|
||||
| skip | Emitted when the download is skipped because the file already exists |
|
||||
| download | Emitted when the download starts `callback(downloadInfo)` |
|
||||
| progress | Emitted every time gets data from the server `callback(stats)` |
|
||||
| progress.throttled| The same as `progress` but emits every 1 second while is downloading `callback(stats)` |
|
||||
| retry | Emitted when the download fails and retry is enabled `callback(attempt, retryOpts, err)` |
|
||||
| end | Emitted when the downloading has finished `callback(downloadInfo)` |
|
||||
| error | Emitted when there is any error `callback(error)` |
|
||||
| timeout | Emitted when the underlying socket times out from inactivity. |
|
||||
| pause | Emitted when the .pause method is called |
|
||||
| stop | Emitted when the .stop method is called |
|
||||
| resume | Emitted when the .resume method is called `callback(isResume)` |
|
||||
| renamed | Emitted when '(number)' is appended to the end of file, this requires `override:false` opt, `callback(filePaths)` |
|
||||
| redirected | Emitted when an url redirect happened `callback(newUrl, oldUrl)` NOTE: this will be triggered during getTotalSize() as well |
|
||||
| stateChanged | Emitted when the state changes `callback(state)` |
|
||||
| warning | Emitted when an error occurs that was not thrown intentionally `callback(err: Error)` |
|
||||
|
||||
event **skip** `skipInfo` object
|
||||
```javascript
|
||||
{
|
||||
totalSize:, // total file size got from the server (will be set as 'null' if content-length header is not available)
|
||||
fileName:, // original file name
|
||||
filePath:, // original path name
|
||||
downloadedSize:, // the downloaded amount
|
||||
}
|
||||
```
|
||||
|
||||
event **download** `downloadInfo` object
|
||||
```javascript
|
||||
{
|
||||
totalSize:, // total file size got from the server (will be set as 'null' if content-length header is not available)
|
||||
fileName:, // assigned name
|
||||
filePath:, // download path
|
||||
isResumed:, // if the download is a resume,
|
||||
downloadedSize:, // the downloaded amount (only if is resumed otherwise always 0)
|
||||
}
|
||||
```
|
||||
|
||||
event **progress** or **progress.throttled** `stats` object
|
||||
```javascript
|
||||
{
|
||||
name:, // file name
|
||||
total:, // total size that needs to be downloaded in bytes, (will be set as 'null' if content-length header is not available)
|
||||
downloaded:, // downloaded size in bytes
|
||||
progress:, // progress porcentage 0-100%, (will be set as 0 if total is null)
|
||||
speed: // download speed in bytes
|
||||
}
|
||||
```
|
||||
|
||||
event **end** `downloadInfo` object
|
||||
```javascript
|
||||
{
|
||||
fileName:,
|
||||
filePath:,
|
||||
totalSize:, // total file size got from the server, (will be set as 'null' if content-length header is not available)
|
||||
incomplete:, // true/false if the download endend but still incomplete, set as 'false' if totalSize is null
|
||||
onDiskSize, // total size of file on the disk
|
||||
downloadedSize:, // the total size downloaded
|
||||
}
|
||||
```
|
||||
|
||||
event **renamed** `filePaths` object
|
||||
```javascript
|
||||
{
|
||||
path:, // modified path name
|
||||
fileName:, // modified file name
|
||||
prevPath:, // original path name
|
||||
prevFileName:, // original file name
|
||||
}
|
||||
```
|
||||
|
||||
event **error** `error` object
|
||||
```javascript
|
||||
{
|
||||
message:, // Error message
|
||||
status:, // Http status response if available
|
||||
body:, // Http body response if available
|
||||
}
|
||||
```
|
||||
|
||||
## States
|
||||
|
||||
| Name | Value |
|
||||
|-------------- |---------------------------------- |
|
||||
| IDLE | 'IDLE' |
|
||||
| SKIPPED | 'SKIPPED' |
|
||||
| STARTED | 'STARTED' |
|
||||
| DOWNLOADING | 'DOWNLOADING' |
|
||||
| PAUSED | 'PAUSED' |
|
||||
| RESUMED | 'RESUMED' |
|
||||
| STOPPED | 'STOPPED' |
|
||||
| FINISHED | 'FINISHED' |
|
||||
| FAILED | 'FAILED' |
|
||||
| RETRY | 'RETRY' |
|
||||
|
||||
## Test
|
||||
|
||||
```
|
||||
$ npm test
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Read [License](LICENSE) for more licensing information.
|
||||
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fhgouveia%2Fnode-downloader-helper?ref=badge_large)
|
||||
|
||||
## Contributing
|
||||
|
||||
Read [here](CONTRIBUTING.md) for more information.
|
||||
|
||||
## TODO
|
||||
- Better code testing
|
50
node_modules/node-downloader-helper/bin/helpers.js
generated
vendored
Normal file
50
node_modules/node-downloader-helper/bin/helpers.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/*eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
|
||||
const { URL } = require('url');
|
||||
const { existsSync } = require('fs');
|
||||
|
||||
// Console colors
|
||||
module.exports.COLOR_NC = '\x1b[0m'; // No Color \e
|
||||
module.exports.COLOR_RED = '\x1b[0;31m';
|
||||
module.exports.COLOR_GREEN = '\x1b[0;32m';
|
||||
module.exports.COLOR_YELLOW = '\x1b[0;33m';
|
||||
module.exports.COLOR_BLUE = '\x1b[0;34m';
|
||||
module.exports.COLOR_MAGENTA = '\x1b[0;35m';
|
||||
module.exports.COLOR_CYAN = '\x1b[0;36m';
|
||||
|
||||
// https://gist.github.com/thomseddon/3511330
|
||||
module.exports.byteHelper = function (value) {
|
||||
if (value === 0) {
|
||||
return '0 b';
|
||||
}
|
||||
const units = ['b', 'kB', 'MB', 'GB', 'TB'];
|
||||
const number = Math.floor(Math.log(value) / Math.log(1024));
|
||||
return (value / Math.pow(1024, Math.floor(number))).toFixed(1) + ' ' +
|
||||
units[number];
|
||||
};
|
||||
|
||||
module.exports.color = function (color, text) {
|
||||
return `${color}${text}${module.exports.COLOR_NC}`;
|
||||
};
|
||||
|
||||
module.exports.inlineLog = function (msg) {
|
||||
process.stdout.clearLine();
|
||||
process.stdout.cursorTo(0);
|
||||
process.stdout.write(msg);
|
||||
};
|
||||
|
||||
module.exports.isValidUrl = function (url) {
|
||||
try {
|
||||
new URL(url);
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.isValidPath = function (path) {
|
||||
try {
|
||||
return existsSync(path);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
};
|
68
node_modules/node-downloader-helper/bin/ndh
generated
vendored
Executable file
68
node_modules/node-downloader-helper/bin/ndh
generated
vendored
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env node
|
||||
/*eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
|
||||
const args = process.argv.slice(2);
|
||||
const { DownloaderHelper } = require('../dist');
|
||||
const { byteHelper, color, COLOR_RED, COLOR_GREEN,
|
||||
COLOR_YELLOW, COLOR_CYAN, COLOR_MAGENTA,
|
||||
isValidPath, isValidUrl, inlineLog
|
||||
} = require('./helpers');
|
||||
const pkg = require('../package.json');
|
||||
|
||||
// Arguments
|
||||
if (!args.length || args.length < 2) {
|
||||
return console.log('USAGE: ndh [destination] [url]');
|
||||
}
|
||||
|
||||
const dest = args[0];
|
||||
const url = args[1];
|
||||
|
||||
if (!isValidPath(dest)) {
|
||||
return console.error(color(COLOR_RED, 'Please use an existing folder or valid path'));
|
||||
}
|
||||
|
||||
if (!isValidUrl(url)) {
|
||||
return console.error(color(COLOR_RED, 'Please use a valid URL'));
|
||||
}
|
||||
|
||||
let progressLog = '';
|
||||
const dl = new DownloaderHelper(url, dest, {
|
||||
headers: {
|
||||
'user-agent': pkg.name + '@' + pkg.version
|
||||
},
|
||||
});
|
||||
|
||||
dl
|
||||
.on('end', _ =>
|
||||
inlineLog(progressLog + ' - ' + color(COLOR_GREEN, 'Download Completed'))
|
||||
)
|
||||
.on('retry', (attempt, opts) => {
|
||||
let count = Math.floor(opts.delay / 1000);
|
||||
const retryLog = () => {
|
||||
inlineLog(color(COLOR_YELLOW, `Retry Attempt: ${attempt}/${opts.maxRetries} | Starts on: ${count} secs`));
|
||||
if (count > 0) {
|
||||
setTimeout(() => retryLog(), 1000);
|
||||
}
|
||||
count--;
|
||||
};
|
||||
retryLog();
|
||||
})
|
||||
.on('resume', isResumed => {
|
||||
if (!isResumed) {
|
||||
console.warn(color(COLOR_YELLOW, "\nThis URL doesn't support resume, it will start from the beginning"));
|
||||
}
|
||||
})
|
||||
.on('progress.throttled', stats => {
|
||||
const progress = stats.progress.toFixed(1);
|
||||
const speed = byteHelper(stats.speed);
|
||||
const downloaded = byteHelper(stats.downloaded);
|
||||
const total = byteHelper(stats.total);
|
||||
|
||||
const cName = color(COLOR_YELLOW, stats.name);
|
||||
const cSpeed = color(COLOR_MAGENTA, speed + '/s');
|
||||
const cProgress = color(COLOR_MAGENTA, progress + '%');
|
||||
const cSize = color(COLOR_CYAN, `[${downloaded}/${total}]`);
|
||||
progressLog = `${cName}: ${cSpeed} - ${cProgress} ${cSize}`;
|
||||
inlineLog(progressLog);
|
||||
});
|
||||
|
||||
dl.start().catch(err => console.error(color(COLOR_RED, 'Something happend'), err));
|
1
node_modules/node-downloader-helper/dist/index.js
generated
vendored
Normal file
1
node_modules/node-downloader-helper/dist/index.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
55
node_modules/node-downloader-helper/package.json
generated
vendored
Normal file
55
node_modules/node-downloader-helper/package.json
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "node-downloader-helper",
|
||||
"version": "2.1.9",
|
||||
"description": "A simple http/s file downloader for node.js",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./types/index.d.ts",
|
||||
"scripts": {
|
||||
"start": "npm run build && node ./example/index.js",
|
||||
"lint": "npx eslint src",
|
||||
"build": "npx babel --presets minify -d ./dist ./src",
|
||||
"watch": "npx babel --watch ./src/index.js -o ./dist/index.js",
|
||||
"test": "npm run lint && jest"
|
||||
},
|
||||
"pre-commit": [
|
||||
"test"
|
||||
],
|
||||
"keywords": [
|
||||
"nwjs",
|
||||
"node",
|
||||
"nodejs",
|
||||
"node.js",
|
||||
"electron",
|
||||
"download",
|
||||
"resumable",
|
||||
"resume",
|
||||
"http"
|
||||
],
|
||||
"author": "Jose De Gouveia",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hgouveia/node-downloader-helper"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/hgouveia/node-downloader-helper/issues"
|
||||
},
|
||||
"homepage": "https://github.com/hgouveia/node-downloader-helper",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"ndh": "bin/ndh"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.14.31",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-jest": "^23.6.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-minify": "^0.5.0",
|
||||
"chai": "^4.1.2",
|
||||
"eslint": "^4.19.1",
|
||||
"jest": "^24.9.0",
|
||||
"pre-commit": "^1.2.2"
|
||||
}
|
||||
}
|
292
node_modules/node-downloader-helper/types/index.d.ts
generated
vendored
Normal file
292
node_modules/node-downloader-helper/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import stream from 'stream';
|
||||
|
||||
type Stats = {
|
||||
total: number;
|
||||
name: string;
|
||||
downloaded: number;
|
||||
progress: number;
|
||||
speed: number;
|
||||
}
|
||||
|
||||
export enum DH_STATES {
|
||||
IDLE = 'IDLE',
|
||||
SKIPPED = 'SKIPPED',
|
||||
STARTED = 'STARTED',
|
||||
DOWNLOADING = 'DOWNLOADING',
|
||||
RETRY = 'RETRY',
|
||||
PAUSED = 'PAUSED',
|
||||
RESUMED = 'RESUMED',
|
||||
STOPPED = 'STOPPED',
|
||||
FINISHED = 'FINISHED',
|
||||
FAILED = 'FAILED',
|
||||
}
|
||||
|
||||
interface BaseStats {
|
||||
/** total file size got from the server */
|
||||
totalSize: number | null;
|
||||
/** original file name */
|
||||
fileName: string;
|
||||
/** original path name */
|
||||
filePath: string;
|
||||
/** the downloaded amount */
|
||||
downloadedSize: number;
|
||||
}
|
||||
|
||||
interface DownloadInfoStats extends BaseStats {
|
||||
/** if the download is a resume */
|
||||
isResumed: boolean;
|
||||
}
|
||||
|
||||
interface DownloadEndedStats extends BaseStats {
|
||||
/** total size of file on the disk */
|
||||
onDiskSize: number;
|
||||
/** true/false if the download endend but still incomplete */
|
||||
incomplete: boolean;
|
||||
}
|
||||
|
||||
interface FileRenamedStats {
|
||||
/** modified path name */
|
||||
path: string;
|
||||
/** modified file name */
|
||||
fileName: string;
|
||||
/** original path name */
|
||||
prevPath: string;
|
||||
/** original file name */
|
||||
prevFileName: string;
|
||||
}
|
||||
|
||||
interface IResumeState {
|
||||
downloaded?: number;
|
||||
filePath?: string;
|
||||
fileName?: string;
|
||||
total?: number;
|
||||
}
|
||||
|
||||
interface ErrorStats {
|
||||
/** Error message */
|
||||
message: string;
|
||||
/** Http status response if available */
|
||||
status?: number;
|
||||
/** Http body response if available */
|
||||
body?: string;
|
||||
}
|
||||
interface DownloadEvents {
|
||||
/** Emitted when the .start method is called */
|
||||
start: () => any;
|
||||
/** Emitted when the download is skipped because the file already exists */
|
||||
skip: (stats: BaseStats) => any;
|
||||
/** Emitted when the download starts */
|
||||
download: (stats: DownloadInfoStats) => any;
|
||||
/** Emitted every time gets data from the server */
|
||||
progress: (stats: Stats) => any;
|
||||
/** The same as progress but emits every 1 second while is downloading */
|
||||
"progress.throttled": (stats: Stats) => any;
|
||||
/** Emitted when the download fails and retry is enabled */
|
||||
retry: (attempt: any, retryOptions: RetryOptions, error: Error | null) => any;
|
||||
/** Emitted when the downloading has finished */
|
||||
end: (stats: DownloadEndedStats) => any;
|
||||
/** Emitted when there is any error */
|
||||
error: (stats: ErrorStats) => any;
|
||||
/** Emitted when the underlying socket times out from inactivity. */
|
||||
timeout: () => any;
|
||||
/** Emitted when the .pause method is called */
|
||||
pause: () => any;
|
||||
/** Emitted when the .resume method is called */
|
||||
resume: (isResume: boolean) => any;
|
||||
/** Emitted when the .stop method is called */
|
||||
stop: () => any;
|
||||
/** Emitted when '(number)' is appended to the end of file, this requires override:false opt, callback(filePaths) */
|
||||
renamed: (stats: FileRenamedStats) => any;
|
||||
/** Emitted when an url redirect happened `callback(newUrl, oldUrl)` NOTE: this will be triggered during getTotalSize() as well */
|
||||
redirected: (newUrl: string, oldUrl: string) => any;
|
||||
/** Emitted when the state changes */
|
||||
stateChanged: (state: DH_STATES) => any;
|
||||
/** Emitted when an error occurs that was not thrown intentionally */
|
||||
warning: (error: Error) => any;
|
||||
}
|
||||
type FilenameCallback = (fileName: string, filePath: string) => string;
|
||||
interface FilenameDefinition {
|
||||
name: string;
|
||||
/** The extension of the file. It may be a boolean: `true` will use the `name` property as the full file name (including the extension),
|
||||
`false` will keep the extension of the downloaded file.
|
||||
|
||||
(default:false) */
|
||||
ext?: string | boolean;
|
||||
}
|
||||
interface RetryOptions {
|
||||
maxRetries: number;
|
||||
/** in milliseconds */
|
||||
delay: number;
|
||||
}
|
||||
interface OverrideOptions {
|
||||
skip?: boolean;
|
||||
skipSmaller?: boolean;
|
||||
}
|
||||
interface DownloaderHelperOptions {
|
||||
/** parameter accepted by http.request write function req.write(body) (default(null)) */
|
||||
body?: any;
|
||||
/** Request Method Verb */
|
||||
method?: "GET" | "PUT" | "POST" | "DELETE" | "OPTIONS",
|
||||
/** Custom HTTP Header ex: Authorization, User-Agent */
|
||||
headers?: object;
|
||||
/** Custom filename when saved */
|
||||
fileName?: string | FilenameCallback | FilenameDefinition;
|
||||
retry?: boolean | RetryOptions;
|
||||
/* Request timeout in milliseconds (-1 use default), is the equivalent of 'httpRequestOptions: { timeout: value }' (also applied to https) */
|
||||
timeout?: number;
|
||||
/* custom metadata for the user retrieve later */
|
||||
metadata?: object | null;
|
||||
/** it will resume if a file already exists and is not completed, you might want to set removeOnStop and removeOnFail to false. If you used pipe for compression it will produce corrupted files */
|
||||
resumeIfFileExists?: boolean;
|
||||
/** If the server does not return the "accept-ranges" header, can be force if it does support it */
|
||||
forceResume?: boolean;
|
||||
/** remove the file when is stopped (default:true) */
|
||||
removeOnStop?: boolean;
|
||||
/** remove the file when fail (default:true) */
|
||||
removeOnFail?: boolean;
|
||||
/** Behavior when local file already exists (default:false)*/
|
||||
override?: boolean | OverrideOptions;
|
||||
/** interval time of the 'progress.throttled' event will be emitted (default:1000) */
|
||||
progressThrottle?: number;
|
||||
/** Override the http request options */
|
||||
httpRequestOptions?: object;
|
||||
/** Override the https request options, ex: to add SSL Certs */
|
||||
httpsRequestOptions?: object;
|
||||
/** Resume download if the file is incomplete */
|
||||
resumeOnIncomplete?: boolean;
|
||||
/** Max retry when resumeOnIncomplete is true */
|
||||
resumeOnIncompleteMaxRetry?: number;
|
||||
}
|
||||
export class DownloaderHelper extends EventEmitter {
|
||||
/**
|
||||
* Creates an instance of DownloaderHelper.
|
||||
* @param {String} url
|
||||
* @param {String} destFolder
|
||||
* @param {Object} [options={}]
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
constructor(url: string, destFolder: string, options?: DownloaderHelperOptions);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns {Promise<boolean>}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
start(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns {Promise<boolean>}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
pause(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns {Promise<boolean>}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
resume(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns {Promise<boolean>}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
stop(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Add pipes to the pipe list that will be applied later when the download starts
|
||||
* @url https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
|
||||
* @param {stream.Readable} stream https://nodejs.org/api/stream.html#stream_class_stream_readable
|
||||
* @param {Object} [options=null]
|
||||
* @returns {stream.Readable}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
pipe(stream: stream.Readable, options?: object): stream.Readable;
|
||||
|
||||
/**
|
||||
* Unpipe an stream , if a stream is not specified, then all pipes are detached.
|
||||
*
|
||||
* @url https://nodejs.org/api/stream.html#stream_readable_unpipe_destination
|
||||
* @param {stream.Readable} [stream=null]
|
||||
* @returns
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
unpipe(stream?: stream.Readable): void;
|
||||
|
||||
/**
|
||||
* Where the download will be saved
|
||||
*
|
||||
* @returns {String}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
getDownloadPath(): string;
|
||||
|
||||
/**
|
||||
* Indicates if the download can be resumable (available after the start phase)
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
isResumable(): boolean;
|
||||
|
||||
/**
|
||||
* Updates the options, can be use on pause/resume events
|
||||
*
|
||||
* @param {Object} [options={}]
|
||||
* @param {String} [url='']
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
updateOptions(options?: object, url?: string): void;
|
||||
|
||||
getOptions(): object;
|
||||
getMetadata(): object | null;
|
||||
|
||||
/**
|
||||
* Current download progress stats
|
||||
*
|
||||
* @returns {Stats}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
getStats(): Stats;
|
||||
|
||||
/**
|
||||
* Gets the total file size from the server
|
||||
*
|
||||
* @returns {Promise<{name:string, total:number|null}>}
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
getTotalSize(): Promise<{ name: string; total: number | null }>;
|
||||
|
||||
/**
|
||||
* Subscribes to events
|
||||
*
|
||||
* @memberof EventEmitter
|
||||
*/
|
||||
on<E extends keyof DownloadEvents>(event: E, callback: DownloadEvents[E]): any;
|
||||
|
||||
/**
|
||||
* Get the state required to resume the download after restart. This state
|
||||
* can be passed back to `resumeFromFile()` to resume a download
|
||||
*
|
||||
* @returns {IResumeState} Returns the state required to resume
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
getResumeState(): IResumeState;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} filePath - The path to the file to resume from ex: C:\Users\{user}\Downloads\file.txt
|
||||
* @param {IResumeState} state - (optionl) resume download state, if not provided it will try to fetch from the headers and filePath
|
||||
*
|
||||
* @returns {Promise<boolean>} - Returns the same result as `start()`
|
||||
* @memberof DownloaderHelper
|
||||
*/
|
||||
resumeFromFile(filePath: string, state?: IResumeState): Promise<boolean>;
|
||||
}
|
Reference in New Issue
Block a user