Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0124e38a89 | ||
|
|
6765b517ec | ||
|
|
8c1e0f2e0c | ||
|
|
817843c40c | ||
|
|
04b22fdce5 | ||
|
|
eb15d7d854 | ||
|
|
66670547b9 | ||
|
|
987e424324 | ||
|
|
523c780b18 | ||
|
|
6c2100fbff | ||
|
|
f10bead0dc | ||
|
|
6448f4ec97 | ||
|
|
829bb080ee | ||
|
|
5edd7cf05a | ||
|
|
8cf70e57cf | ||
|
|
2545c36241 | ||
|
|
e2a4ba738f | ||
|
|
e4e0fc3ea7 | ||
|
|
c56998312c | ||
|
|
3ac1f4ee9e | ||
|
|
c2e9449630 | ||
|
|
fb14020a7f | ||
|
|
5a51d888b8 | ||
|
|
301fa1c860 | ||
|
|
7e32028195 | ||
|
|
dea2c38dc4 | ||
|
|
cdf7f223db | ||
|
|
bb70161652 | ||
|
|
7f2f983f55 | ||
|
|
8dab83b3ef | ||
|
|
cbafa5bc90 | ||
|
|
67735fb52a | ||
|
|
7d6f762f59 | ||
|
|
f3a0d0129d | ||
|
|
65c9032839 | ||
|
|
978a3282a4 | ||
|
|
9f0195bebc | ||
|
|
ea20108222 | ||
|
|
4ee814864c | ||
|
|
4cbfd691c3 | ||
|
|
7c04fb7282 | ||
|
|
849c7612aa | ||
|
|
6ad4cbed0a | ||
|
|
9e2f5401d0 | ||
|
|
b064b97f2d | ||
|
|
b248405437 | ||
|
|
bf941819a8 | ||
|
|
fcae53baae | ||
|
|
05ead50c0d | ||
|
|
0a80f80f91 | ||
|
|
3bf5fea735 |
0
.github/CONTRIBUTING.md
vendored
Normal file
0
.github/CONTRIBUTING.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Please fill theses informations:**
|
||||
(Add a X between brackets to make them ticked)
|
||||
- OS: [e.g:. Windows 10, Mac OS X 10.13, ...]
|
||||
- [ ] I'm using the latest version of Crunchy
|
||||
- [ ] I have a premium accrount on CR
|
||||
- Serie you get a problem with (and specify which episode if it is specific to one):
|
||||
- The command line you are running Crunchy with:
|
||||
- The message Crunchy is giving you, if any:
|
||||
|
||||
**Please be careful to remove your real account login and password if they appear!**
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
|
||||
_Also don't hesitate to add labels you feel apropriate on your report._
|
||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
*Goal for this pull request*
|
||||
A clear and concise description of pull request
|
||||
|
||||
|
||||
|
||||
### Checklist
|
||||
[ ] I've run `npm run compile` and it produce no error
|
||||
[ ] I've run `npm run test` and it produce no error
|
||||
[ ] I've not pushing more than one feature in that pull request
|
||||
[ ] My branch is updated with the latest from main when I make that pull request
|
||||
[ ] I've tested as much as I can my changes
|
||||
@@ -1,9 +1,6 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
- 8
|
||||
- 9
|
||||
before_install:
|
||||
|
||||
119
README.md
119
README.md
@@ -12,39 +12,48 @@
|
||||
|
||||
This application is not endorsed or affliated with *CrunchyRoll*. The usage of this application enables episodes to be downloaded for offline convenience which may be forbidden by law in your country. Usage of this application may also cause a violation of the agreed *Terms of Service* between you and the stream provider. A tool is not responsible for your actions; please make an informed decision prior to using this application.
|
||||
|
||||
**PLEASE _ONLY_ USE THIS TOOL IF YOU HAVE A _PREMIUM ACCOUNT_**
|
||||
**_ONLY_ USE THIS TOOL IF YOU HAVE A _PREMIUM ACCOUNT_**
|
||||
|
||||
## Configuration
|
||||
|
||||
It is recommended to enable authentication (`-p` and `-u`) so your account permissions and settings are available for use. It is not possible to download non-free material without an account and premium subscription. Furthermore, the default account settings are used when downloading. If you want the highest quality videos, configure these preferences at https://www.crunchyroll.com/acct/?action=video.
|
||||
You need to authentication (`-p` and `-u`) to use Crunchy so you need to have an account on *CrunchyRool*. It is not possible to download non-free material without an account and premium subscription.
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* NodeJS >= 5.x (http://nodejs.org/)
|
||||
* NPM >= 2.5.x (https://www.npmjs.org/)
|
||||
* NodeJS >= 8.1 (http://nodejs.org/)
|
||||
* NPM >= 5.8 (https://www.npmjs.org/)
|
||||
|
||||
## Installation
|
||||
|
||||
Use the applicable instructions to install. Is your operating system not listed? Please ask or contribute!
|
||||
|
||||
### Debian (Mint, Ubuntu, etc)
|
||||
### Linux (Debian, Mint, Ubuntu, etc)
|
||||
|
||||
1. Run in *Terminal*: `sudo apt-get install nodejs npm mkvtoolnix rtmpdump ffmpeg`
|
||||
2. Run in *Terminal*: `sudo ln -s /usr/bin/nodejs /usr/bin/node`
|
||||
3. Run in *Terminal*: `sudo npm install -g crunchy`
|
||||
|
||||
#### Updating:
|
||||
1. Run in *Terminal*: `sudo npm update -g crunchy`
|
||||
|
||||
### Mac OS X
|
||||
|
||||
1. Install *Homebrew* following the instructions at http://brew.sh/
|
||||
2. Run in *Terminal*: `brew install node mkvtoolnix rtmpdump ffmpeg`
|
||||
3. Run in *Terminal*: `npm install -g crunchy`
|
||||
|
||||
#### Updating:
|
||||
1. Run in *Terminal*: `sudo npm update -g crunchy`
|
||||
|
||||
### Windows
|
||||
|
||||
1. Install *NodeJS* following the instructions at http://nodejs.org/
|
||||
3. Run in *Command Prompt*: `npm install -g crunchy`
|
||||
|
||||
#### Updating:
|
||||
1. Run in *Command Prompt*: `npm update -g crunchy`
|
||||
|
||||
## Instructions
|
||||
|
||||
Use the applicable instructions for the interface of your choice (currently limited to command-line).
|
||||
@@ -57,22 +66,27 @@ The [command-line interface](http://en.wikipedia.org/wiki/Command-line_interface
|
||||
|
||||
Options:
|
||||
|
||||
-h, --help output usage information
|
||||
-V, --version output the version number
|
||||
-p, --pass <s> The password.
|
||||
-u, --user <s> The e-mail address or username.
|
||||
-c, --cache Disables the cache.
|
||||
-m, --merge Disables merging subtitles and videos.
|
||||
-e, --episode <i> The episode filter.
|
||||
-v, --volume <i> The volume filter.
|
||||
-f, --format <s> The subtitle format. (Default: ass)
|
||||
-o, --output <s> The output path.
|
||||
-s, --series <s> The series override.
|
||||
-t, --tag <s> The subgroup. (Default: CrunchyRoll)
|
||||
-V, --version output the version number
|
||||
-p, --pass <s> The password.
|
||||
-u, --user <s> The e-mail address or username.
|
||||
-c, --cache Disables the cache.
|
||||
-m, --merge Disables merging subtitles and videos.
|
||||
-e, --episodes <s> Episode list. Read documentation on how to use
|
||||
-f, --format <s> The subtitle format. (Default: ass)
|
||||
-o, --output <s> The output path.
|
||||
-s, --series <s> The series override.
|
||||
-n, --filename <s> The name override.
|
||||
-t, --tag <s> The subgroup. (Default: CrunchyRoll) (default: CrunchyRoll)
|
||||
-r, --resolution <s> The video resolution. (Default: 1080 (360, 480, 720, 1080)) (default: 1080)
|
||||
-g, --rebuildcrp Rebuild the crpersistant file.
|
||||
-b, --batch <s> Batch file (default: CrunchyRoll.txt)
|
||||
--verbose Make tool verbose
|
||||
--retry <i> Number or time to retry fetching an episode. Default: 5 (default: 5)
|
||||
-h, --help output usage information
|
||||
|
||||
#### Batch-mode
|
||||
|
||||
When no sequence of series addresses is provided, the batch-mode source file will be read (which is *CrunchyRoll.txt* in the current work directory. Each line in this file is processed as a seperate command-line statement. This makes it ideal to manage a large sequence of series addresses with variating command-line options or incremental episode updates.
|
||||
When no sequence of series addresses is provided, the batch-mode source file will be read (which is *CrunchyRoll.txt* in the current work directory. Each line in this file is processed contain the URL of a series and can support some of the command line paramter (like *-e*). This makes it ideal to manage a large sequence of series addresses.
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -88,7 +102,30 @@ Download *Fairy Tail* to `C:\Anime`:
|
||||
|
||||
crunchy --output C:\Anime http://www.crunchyroll.com/fairy-tail
|
||||
|
||||
#### Switches
|
||||
Download episode 42 of *Fairy Tail* to `C:\Anime`:
|
||||
|
||||
crunchy --output C:\Anime @http://www.crunchyroll.com/fairy-tail/episode-46-the-silver-labyrinth-662721
|
||||
|
||||
*Notice the '@' in front of the URL, it is there to tell Crunchy that the URL is an episode URL and not a series URL.*
|
||||
|
||||
or
|
||||
crunchy --output C:\Anime http://www.crunchyroll.com/fairy-tail -e 42
|
||||
|
||||
Download episode 10 to 42 (both included) of *Fairy Tail*:
|
||||
|
||||
crunchy http://www.crunchyroll.com/fairy-tail -e 10-42
|
||||
|
||||
Download episode up to 42 (included) of *Fairy Tail*:
|
||||
|
||||
crunchy http://www.crunchyroll.com/fairy-tail -e -42
|
||||
|
||||
Download episodes starting from 42 to the last available of *Fairy Tail*:
|
||||
|
||||
crunchy http://www.crunchyroll.com/fairy-tail -e 42-
|
||||
|
||||
|
||||
|
||||
#### Command line parameters
|
||||
|
||||
##### Authentication
|
||||
|
||||
@@ -99,20 +136,25 @@ Download *Fairy Tail* to `C:\Anime`:
|
||||
|
||||
##### Disables
|
||||
|
||||
* `-c or --cache` disables the cache.
|
||||
* `-c or --cache` disables the cache in batch mode.
|
||||
* `-m or --merge` disables merging subtitles and videos.
|
||||
|
||||
##### Filters
|
||||
|
||||
* `-e or --episode <i>` filters episodes (positive is greater than, negative is smaller than).
|
||||
* `-v or --volume <i>` filters volumes (positive is greater than, negative is smaller than).
|
||||
|
||||
##### Settings
|
||||
|
||||
* `-e or --episodes <s>` set an episode
|
||||
* `-f or --format <s>` sets the subtitle format. (Default: ass)
|
||||
* `-o or --output <s>` sets the output path.
|
||||
* `-s or --series <s>` sets the series override.
|
||||
* `-t or --tag <s>` sets The subgroup. (Default: CrunchyRoll)
|
||||
* `-r or --resolution <s>` sets the resolutoin you want to download (360, 480, 720, 1080)
|
||||
* `--retry <i>` set the number of try Crunchy will use if downloading a serie or episode fail
|
||||
|
||||
##### Others
|
||||
|
||||
* `-b or --batch <s>` specify the batch file to use. Default to "CrunchyRoll.txt"
|
||||
* `--verbose` make Crunchy really verbose. You should use it only for bug reporting or to try to see why it does not work
|
||||
* `-g or --rebuildcrp` use that parameter only if the .crpersistent file has been corrupted and Crunchy try to redownload everything. It will try to rebuild the cache file from the file if find. If you renamed of move any file they will be ignored and not added to the cache file.
|
||||
|
||||
|
||||
## When things goes wrong
|
||||
|
||||
@@ -122,27 +164,14 @@ Second thing to check, you have to give your credentials (-u and -p parameters)
|
||||
|
||||
Third, is it a recently released episode? If yes, sometimes CR have issues were the requested format is not available, and Crunchy is not able to get it. When in doubt, try to watch CR website, if it does not work there, Crunchy will not either. This is valid in all cases even on non recently released.
|
||||
|
||||
Fourth, sometimes, CR website does weird things, and there are some transient errors, wait a couple of minutes (or hours) and try again. It often solved the issue on my side (yes I know that's not really a way of fixing, but if the error is on CR side, Crunchy can't do anything)
|
||||
Fourth, sometimes, CR website does weird things, and there are some transient errors, wait a couple of minutes (or hours) and try again. It has really often solved lots of weird issue on my side (yes I know that's not really a way of fixing, but if the error is on CR side, Crunchy can't do anything)
|
||||
|
||||
If really nothing works or you find a problem with Crunchy, then you can go and fill an Issue, first read the already open and closed one to make sure you are not reporting an existing problem. If your problem has been already reported, what you can do is to either:
|
||||
- Add a comment saying you also have the same issue
|
||||
- Add a Thumbs Up reaction to the original entry in the issue, they will are used as a metric to know how many people are annoyed by that issue
|
||||
If you find one which correspond and is close, don't hesitate to add a comment, the issue may have not be fully solved.
|
||||
- Add a Thumbs Up reaction to the original entry in the issue, I use them as a metric to know how many people are annoyed by that issue
|
||||
If you find one which correspond and it is close, don't hesitate to add a comment, the issue may have not be fully solved.
|
||||
|
||||
If there is no comparable opened or close issue, you can create a new one.
|
||||
|
||||
### What to put in a bug report
|
||||
It is really important for me to know:
|
||||
- on which Operating System you are running Crunchy,
|
||||
- which anime you want to fetch if it is related to a specific one,
|
||||
- The command line you use to run Crunchy
|
||||
- What message Crunchy is giving you if any
|
||||
|
||||
**Please be careful to remove your real account login and password if they appear!**
|
||||
|
||||
Also don't hesitate to add labels you feel apropriate on your report.
|
||||
|
||||
_Note: You can also use a bug report for a feature requests._
|
||||
If there is no comparable opened or close issue, you are welcome to create a new one.
|
||||
|
||||
## Developers
|
||||
|
||||
@@ -150,9 +179,5 @@ More information will be added at a later point. For now the recommendations are
|
||||
|
||||
* Atom with `atom-typescript` and `linter-tslint` (and dependencies).
|
||||
|
||||
Since this project uses TypeScript, compile with `node ts` or `npm install`.
|
||||
Since this project uses TypeScript, compile with `node run compile` to build the tool and `npm run test` to run the linter.
|
||||
|
||||
#### A note about pull requests:
|
||||
If you want to help working on this project, Pull request are welcome, but please explain the goal of your changes, and do a pull request per change: you want to add support for _X_, _Y_ and _Z_, make a pull request for X, one for Y and one for Z. I'm not saying a pull request per commit that would be idiotic.
|
||||
The idea is if your pull request changes lots of thing at the same time, if just a single part can't be accepted, if will delay the acceptation of the whole pull request where some of the feature could be integrated quicker is they were requested alone.
|
||||
Also if for example the change _Y_ depends on _X_, you can wait for _X_ to be accepted before requesting for _Y_, if they are independant you can send a pull request for each at the same time.
|
||||
|
||||
10
bin/crunchy.sh
Executable file
10
bin/crunchy.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
PARAMS=$*
|
||||
for i in {1..20}; do
|
||||
crunchy ${PARAMS}
|
||||
if [ $? == 0 ]; then
|
||||
break
|
||||
fi
|
||||
echo "Going to retry..."
|
||||
sleep 3
|
||||
done
|
||||
563
package-lock.json
generated
563
package-lock.json
generated
@@ -1,9 +1,15 @@
|
||||
{
|
||||
"name": "crunchy",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.5",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/bluebird": {
|
||||
"version": "3.5.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.20.tgz",
|
||||
"integrity": "sha512-Wk41MVdF+cHBfVXj/ufUHJeO3BlIQr1McbHZANErMykaCWeDSZbH5erGjNBw2/3UlRdSxZbLfSuQTzFmPOYFsA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/caseless": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz",
|
||||
@@ -16,13 +22,28 @@
|
||||
"integrity": "sha512-+T9qBbqe/jXtTjzVddArZExahoPPmt8eq3O1ZuCKZXjBVxf/ciUYNXrIDZJEVgYvpELnv6VlPRCfLzufRxpAag==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
|
||||
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/form-data": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
|
||||
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "8.5.2"
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/fs-extra": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.3.tgz",
|
||||
"integrity": "sha512-m2QKoRrJnei1s10e1ZfMIa7QcABBVLdQhVUv5+bMRaHhPzxO/IWMmREiags59AqFbI+piWPq/PupTahNS/0kyA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/mkdirp": {
|
||||
@@ -31,40 +52,50 @@
|
||||
"integrity": "sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "8.5.2"
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "8.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.2.tgz",
|
||||
"integrity": "sha512-KA4GKOpgXnrqEH2eCVhiv2CsxgXGQJgV1X0vsGlh+WCnxbeAE1GT44ZsTU1IN5dEeV/gDupKa7gWo08V5IxWVQ==",
|
||||
"dev": true
|
||||
"version": "10.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.3.tgz",
|
||||
"integrity": "sha512-/gwCgiI2e9RzzZTKbl+am3vgNqOt7a9fJ/uxv4SqYKxenoEDNVU3KZEadlpusWhQI0A0dOrZ0T68JYKVjzmgdQ=="
|
||||
},
|
||||
"@types/request": {
|
||||
"version": "2.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.47.0.tgz",
|
||||
"integrity": "sha512-/KXM5oev+nNCLIgBjkwbk8VqxmzI56woD4VUxn95O+YeQ8hJzcSmIZ1IN3WexiqBb6srzDo2bdMbsXxgXNkz5Q==",
|
||||
"version": "2.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.47.1.tgz",
|
||||
"integrity": "sha512-TV3XLvDjQbIeVxJ1Z3oCTDk/KuYwwcNKVwz2YaT0F5u86Prgc4syDAp6P96rkTQQ4bIdh+VswQIC9zS6NjY7/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/caseless": "0.12.1",
|
||||
"@types/form-data": "2.2.1",
|
||||
"@types/node": "8.5.2",
|
||||
"@types/tough-cookie": "2.3.2"
|
||||
"@types/caseless": "*",
|
||||
"@types/form-data": "*",
|
||||
"@types/node": "*",
|
||||
"@types/tough-cookie": "*"
|
||||
}
|
||||
},
|
||||
"@types/request-promise": {
|
||||
"version": "4.1.41",
|
||||
"resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.41.tgz",
|
||||
"integrity": "sha512-qlx6COxSTdSFHY9oX9v2zL1I05hgz5lwqYiXa2SFL2nDxAiG5KK8rnllLBH7k6OqzS3Ck0bWbxlGVdrZhS6oNw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/bluebird": "*",
|
||||
"@types/request": "*"
|
||||
}
|
||||
},
|
||||
"@types/tough-cookie": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.2.tgz",
|
||||
"integrity": "sha512-vOVmaruQG5EatOU/jM6yU2uCp3Lz6mK1P5Ztu4iJjfM4SVHU9XYktPUQtKlIXuahqXHdEyUarMrBEwg5Cwu+bA==",
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.3.tgz",
|
||||
"integrity": "sha512-MDQLxNFRLasqS4UlkWMSACMKeSm1x4Q3TxzUC7KQUsh6RK1ZrQ0VEyE3yzXcBu+K8ejVj4wuX32eUG02yNp+YQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/xml2js": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.2.tgz",
|
||||
"integrity": "sha512-8aKUBSj3oGcnuiBmDLm3BIk09RYg01mz9HlQ2u4aS17oJ25DxjQrEUVGFSBVNOfM45pQW4OjcBPplq6r/exJdA==",
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.3.tgz",
|
||||
"integrity": "sha512-Pv2HGRE4gWLs31In7nsyXEH4uVVsd0HNV9i2dyASvtDIlOtSTr1eczPLDpdEuyv5LWH5LT20GIXwPjkshKWI1g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "8.5.2"
|
||||
"@types/events": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
@@ -72,10 +103,10 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||
"requires": {
|
||||
"co": "4.6.0",
|
||||
"fast-deep-equal": "1.1.0",
|
||||
"fast-json-stable-stringify": "2.0.0",
|
||||
"json-schema-traverse": "0.3.1"
|
||||
"co": "^4.6.0",
|
||||
"fast-deep-equal": "^1.0.0",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
@@ -96,7 +127,7 @@
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "1.0.3"
|
||||
"sprintf-js": "~1.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"sprintf-js": {
|
||||
@@ -128,9 +159,9 @@
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
|
||||
"integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w=="
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
@@ -138,9 +169,9 @@
|
||||
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "1.1.3",
|
||||
"esutils": "2.0.2",
|
||||
"js-tokens": "3.0.2"
|
||||
"chalk": "^1.1.3",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
@@ -149,11 +180,11 @@
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "2.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"has-ansi": "2.0.0",
|
||||
"strip-ansi": "3.0.1",
|
||||
"supports-color": "2.0.0"
|
||||
"ansi-styles": "^2.2.1",
|
||||
"escape-string-regexp": "^1.0.2",
|
||||
"has-ansi": "^2.0.0",
|
||||
"strip-ansi": "^3.0.0",
|
||||
"supports-color": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,34 +201,31 @@
|
||||
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"tweetnacl": "0.14.5"
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"big-integer": {
|
||||
"version": "1.6.27",
|
||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.27.tgz",
|
||||
"integrity": "sha512-NzUKMYW4SWme+H5K+mfEmBxEF/V04PhlzoxxXwSnDig78y2t7HLBVotfDBMUhRPRA3WWID3GmJB/OJSWPhVXtg=="
|
||||
"version": "1.6.31",
|
||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.31.tgz",
|
||||
"integrity": "sha512-lDbZNHHwxDKnjP7LWg2leO+tjs4SyVs2Z83dsR1Idbe2urRnxZAUdeQ8YBhHaGaWK/4WM3mz+RlbZsgqck17CA=="
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
|
||||
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
|
||||
},
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||
},
|
||||
"boom": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
||||
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
|
||||
"requires": {
|
||||
"hoek": "4.2.1"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
|
||||
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "1.0.0",
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
@@ -213,14 +241,14 @@
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
|
||||
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
|
||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"supports-color": "5.3.0"
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
@@ -229,16 +257,16 @@
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.1"
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz",
|
||||
"integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==",
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "3.0.0"
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,22 +276,22 @@
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
|
||||
"integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=",
|
||||
"requires": {
|
||||
"css-select": "1.2.0",
|
||||
"dom-serializer": "0.1.0",
|
||||
"entities": "1.1.1",
|
||||
"htmlparser2": "3.9.2",
|
||||
"lodash.assignin": "4.2.0",
|
||||
"lodash.bind": "4.2.1",
|
||||
"lodash.defaults": "4.2.0",
|
||||
"lodash.filter": "4.6.0",
|
||||
"lodash.flatten": "4.4.0",
|
||||
"lodash.foreach": "4.5.0",
|
||||
"lodash.map": "4.6.0",
|
||||
"lodash.merge": "4.6.0",
|
||||
"lodash.pick": "4.4.0",
|
||||
"lodash.reduce": "4.6.0",
|
||||
"lodash.reject": "4.6.0",
|
||||
"lodash.some": "4.6.0"
|
||||
"css-select": "~1.2.0",
|
||||
"dom-serializer": "~0.1.0",
|
||||
"entities": "~1.1.1",
|
||||
"htmlparser2": "^3.9.1",
|
||||
"lodash.assignin": "^4.0.9",
|
||||
"lodash.bind": "^4.1.4",
|
||||
"lodash.defaults": "^4.0.1",
|
||||
"lodash.filter": "^4.4.0",
|
||||
"lodash.flatten": "^4.2.0",
|
||||
"lodash.foreach": "^4.3.0",
|
||||
"lodash.map": "^4.4.0",
|
||||
"lodash.merge": "^4.4.0",
|
||||
"lodash.pick": "^4.2.1",
|
||||
"lodash.reduce": "^4.4.0",
|
||||
"lodash.reject": "^4.4.0",
|
||||
"lodash.some": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"cloudscraper": {
|
||||
@@ -271,7 +299,7 @@
|
||||
"resolved": "https://registry.npmjs.org/cloudscraper/-/cloudscraper-1.5.0.tgz",
|
||||
"integrity": "sha512-bZagLhj59+N6Z6lD9zRksYu87GthLwXdKARULi4RZ6UVpotH39ruSFN3UQmw3uuqoj00iDxkGrapAvxeurmlQA==",
|
||||
"requires": {
|
||||
"request": "2.85.0"
|
||||
"request": "^2.49.0"
|
||||
}
|
||||
},
|
||||
"co": {
|
||||
@@ -285,7 +313,7 @@
|
||||
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
"color-name": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
@@ -305,7 +333,7 @@
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
|
||||
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
|
||||
"requires": {
|
||||
"delayed-stream": "1.0.0"
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
@@ -324,33 +352,15 @@
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
|
||||
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
|
||||
"requires": {
|
||||
"boom": "5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"boom": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
|
||||
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
|
||||
"requires": {
|
||||
"hoek": "4.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
|
||||
"requires": {
|
||||
"boolbase": "1.0.0",
|
||||
"css-what": "2.1.0",
|
||||
"boolbase": "~1.0.0",
|
||||
"css-what": "2.1",
|
||||
"domutils": "1.5.1",
|
||||
"nth-check": "1.0.1"
|
||||
"nth-check": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
@@ -363,7 +373,7 @@
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
@@ -382,8 +392,8 @@
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
|
||||
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
|
||||
"requires": {
|
||||
"domelementtype": "1.1.3",
|
||||
"entities": "1.1.1"
|
||||
"domelementtype": "~1.1.1",
|
||||
"entities": "~1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": {
|
||||
@@ -403,7 +413,7 @@
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",
|
||||
"integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=",
|
||||
"requires": {
|
||||
"domelementtype": "1.3.0"
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
@@ -411,8 +421,8 @@
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
|
||||
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
|
||||
"requires": {
|
||||
"dom-serializer": "0.1.0",
|
||||
"domelementtype": "1.3.0"
|
||||
"dom-serializer": "0",
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
@@ -421,7 +431,7 @@
|
||||
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"jsbn": "0.1.1"
|
||||
"jsbn": "~0.1.0"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
@@ -479,7 +489,7 @@
|
||||
"integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "5.0.15"
|
||||
"glob": "~5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
@@ -488,11 +498,11 @@
|
||||
"integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inflight": "1.0.6",
|
||||
"inherits": "2.0.3",
|
||||
"minimatch": "3.0.4",
|
||||
"once": "1.4.0",
|
||||
"path-is-absolute": "1.0.1"
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "2 || 3",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -507,19 +517,19 @@
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
|
||||
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
|
||||
"requires": {
|
||||
"asynckit": "0.4.0",
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "1.0.6",
|
||||
"mime-types": "2.1.18"
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
|
||||
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
|
||||
"integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
"jsonfile": "4.0.0",
|
||||
"universalify": "0.1.1"
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
@@ -533,7 +543,7 @@
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
@@ -542,12 +552,12 @@
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
"inflight": "1.0.6",
|
||||
"inherits": "2.0.3",
|
||||
"minimatch": "3.0.4",
|
||||
"once": "1.4.0",
|
||||
"path-is-absolute": "1.0.1"
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
@@ -565,8 +575,8 @@
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
|
||||
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
|
||||
"requires": {
|
||||
"ajv": "5.5.2",
|
||||
"har-schema": "2.0.0"
|
||||
"ajv": "^5.1.0",
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"has-ansi": {
|
||||
@@ -575,7 +585,7 @@
|
||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
@@ -584,33 +594,17 @@
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"hawk": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
|
||||
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
|
||||
"requires": {
|
||||
"boom": "4.3.1",
|
||||
"cryptiles": "3.1.2",
|
||||
"hoek": "4.2.1",
|
||||
"sntp": "2.1.0"
|
||||
}
|
||||
},
|
||||
"hoek": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
|
||||
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
|
||||
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
|
||||
"requires": {
|
||||
"domelementtype": "1.3.0",
|
||||
"domhandler": "2.4.1",
|
||||
"domutils": "1.5.1",
|
||||
"entities": "1.1.1",
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.3"
|
||||
"domelementtype": "^1.3.0",
|
||||
"domhandler": "^2.3.0",
|
||||
"domutils": "^1.5.1",
|
||||
"entities": "^1.1.1",
|
||||
"inherits": "^2.0.1",
|
||||
"readable-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
@@ -618,9 +612,9 @@
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"jsprim": "1.4.1",
|
||||
"sshpk": "1.14.1"
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
"sshpk": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
@@ -629,8 +623,8 @@
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "1.4.0",
|
||||
"wrappy": "1.0.2"
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
@@ -660,13 +654,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz",
|
||||
"integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==",
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
||||
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "1.0.10",
|
||||
"esprima": "4.0.0"
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"jsbn": {
|
||||
@@ -695,7 +689,7 @@
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11"
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"jsprim": {
|
||||
@@ -709,6 +703,11 @@
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.10",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
|
||||
},
|
||||
"lodash.assignin": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
|
||||
@@ -779,7 +778,7 @@
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
|
||||
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
|
||||
"requires": {
|
||||
"mime-db": "1.33.0"
|
||||
"mime-db": "~1.33.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
@@ -788,7 +787,7 @@
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "1.1.8"
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
@@ -817,7 +816,7 @@
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
|
||||
"integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
|
||||
"requires": {
|
||||
"boolbase": "1.0.0"
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"oauth-sign": {
|
||||
@@ -831,7 +830,7 @@
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1.0.2"
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"optimist": {
|
||||
@@ -840,8 +839,8 @@
|
||||
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.10",
|
||||
"wordwrap": "0.0.3"
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"path-is-absolute": {
|
||||
@@ -861,6 +860,11 @@
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"pjson": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/pjson/-/pjson-1.0.9.tgz",
|
||||
"integrity": "sha512-4hRJH3YzkUpOlShRzhyxAmThSNnAaIlWZCAb27hd0pVUAXNUAHAO7XZbsPPvsCYwBFEScTmCCL6DGE8NyZ8BdQ=="
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
||||
@@ -872,51 +876,68 @@
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
|
||||
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
||||
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
"isarray": "1.0.0",
|
||||
"process-nextick-args": "1.0.7",
|
||||
"safe-buffer": "5.1.1",
|
||||
"string_decoder": "1.0.3",
|
||||
"util-deprecate": "1.0.2"
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~1.0.6",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.0.3",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"request": {
|
||||
"version": "2.85.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz",
|
||||
"integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==",
|
||||
"version": "2.87.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
|
||||
"integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
|
||||
"requires": {
|
||||
"aws-sign2": "0.7.0",
|
||||
"aws4": "1.6.0",
|
||||
"caseless": "0.12.0",
|
||||
"combined-stream": "1.0.6",
|
||||
"extend": "3.0.1",
|
||||
"forever-agent": "0.6.1",
|
||||
"form-data": "2.3.2",
|
||||
"har-validator": "5.0.3",
|
||||
"hawk": "6.0.2",
|
||||
"http-signature": "1.2.0",
|
||||
"is-typedarray": "1.0.0",
|
||||
"isstream": "0.1.2",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"mime-types": "2.1.18",
|
||||
"oauth-sign": "0.8.2",
|
||||
"performance-now": "2.1.0",
|
||||
"qs": "6.5.1",
|
||||
"safe-buffer": "5.1.1",
|
||||
"stringstream": "0.0.5",
|
||||
"tough-cookie": "2.3.4",
|
||||
"tunnel-agent": "0.6.0",
|
||||
"uuid": "3.2.1"
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.6.0",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.5",
|
||||
"extend": "~3.0.1",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.3.1",
|
||||
"har-validator": "~5.0.3",
|
||||
"http-signature": "~1.2.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.17",
|
||||
"oauth-sign": "~0.8.2",
|
||||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.5.1",
|
||||
"safe-buffer": "^5.1.1",
|
||||
"tough-cookie": "~2.3.3",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"request-promise": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
|
||||
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
|
||||
"requires": {
|
||||
"bluebird": "^3.5.0",
|
||||
"request-promise-core": "1.1.1",
|
||||
"stealthy-require": "^1.1.0",
|
||||
"tough-cookie": ">=2.3.3"
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
|
||||
"integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
|
||||
"requires": {
|
||||
"lodash": "^4.13.1"
|
||||
}
|
||||
},
|
||||
"resolve": {
|
||||
@@ -925,7 +946,7 @@
|
||||
"integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "1.0.5"
|
||||
"path-parse": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
@@ -944,14 +965,6 @@
|
||||
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
|
||||
"dev": true
|
||||
},
|
||||
"sntp": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
|
||||
"integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
|
||||
"requires": {
|
||||
"hoek": "4.2.1"
|
||||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
|
||||
@@ -963,14 +976,14 @@
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz",
|
||||
"integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=",
|
||||
"requires": {
|
||||
"asn1": "0.2.3",
|
||||
"assert-plus": "1.0.0",
|
||||
"bcrypt-pbkdf": "1.0.1",
|
||||
"dashdash": "1.14.1",
|
||||
"ecc-jsbn": "0.1.1",
|
||||
"getpass": "0.1.7",
|
||||
"jsbn": "0.1.1",
|
||||
"tweetnacl": "0.14.5"
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
"bcrypt-pbkdf": "^1.0.0",
|
||||
"dashdash": "^1.12.0",
|
||||
"ecc-jsbn": "~0.1.1",
|
||||
"getpass": "^0.1.1",
|
||||
"jsbn": "~0.1.0",
|
||||
"tweetnacl": "~0.14.0"
|
||||
}
|
||||
},
|
||||
"stable": {
|
||||
@@ -979,26 +992,26 @@
|
||||
"integrity": "sha1-kQ9dKu17Ugxud3SZwfMuE5/eyxA=",
|
||||
"dev": true
|
||||
},
|
||||
"stealthy-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"stringstream": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
||||
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
@@ -1012,7 +1025,7 @@
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
|
||||
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
|
||||
"requires": {
|
||||
"punycode": "1.4.1"
|
||||
"punycode": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"tsconfig-lint": {
|
||||
@@ -1021,11 +1034,11 @@
|
||||
"integrity": "sha1-rVKxNGEjnRaYA56TrR3TS93WzUs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"exit": "0.1.2",
|
||||
"glob": "7.1.2",
|
||||
"resolve": "1.4.0",
|
||||
"stable": "0.1.6",
|
||||
"tslint": "3.15.1"
|
||||
"exit": "^0.1.2",
|
||||
"glob": "^7.0.3",
|
||||
"resolve": "^1.1.7",
|
||||
"stable": "^0.1.5",
|
||||
"tslint": "^3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslint": {
|
||||
@@ -1034,41 +1047,41 @@
|
||||
"integrity": "sha1-2hZcqT2P3CwIa1EWXuG6y0jJjqU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"colors": "1.1.2",
|
||||
"diff": "2.2.3",
|
||||
"findup-sync": "0.3.0",
|
||||
"glob": "7.1.2",
|
||||
"optimist": "0.6.1",
|
||||
"resolve": "1.4.0",
|
||||
"underscore.string": "3.3.4"
|
||||
"colors": "^1.1.2",
|
||||
"diff": "^2.2.1",
|
||||
"findup-sync": "~0.3.0",
|
||||
"glob": "^7.0.3",
|
||||
"optimist": "~0.6.0",
|
||||
"resolve": "^1.1.7",
|
||||
"underscore.string": "^3.3.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
|
||||
"integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==",
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz",
|
||||
"integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw==",
|
||||
"dev": true
|
||||
},
|
||||
"tslint": {
|
||||
"version": "5.9.1",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz",
|
||||
"integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=",
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.10.0.tgz",
|
||||
"integrity": "sha1-EeJrzLiK+gLdDZlWyuPUVAtfVMM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-code-frame": "6.26.0",
|
||||
"builtin-modules": "1.1.1",
|
||||
"chalk": "2.3.2",
|
||||
"commander": "2.15.1",
|
||||
"diff": "3.5.0",
|
||||
"glob": "7.1.2",
|
||||
"js-yaml": "3.11.0",
|
||||
"minimatch": "3.0.4",
|
||||
"resolve": "1.4.0",
|
||||
"semver": "5.5.0",
|
||||
"tslib": "1.9.0",
|
||||
"tsutils": "2.25.0"
|
||||
"babel-code-frame": "^6.22.0",
|
||||
"builtin-modules": "^1.1.1",
|
||||
"chalk": "^2.3.0",
|
||||
"commander": "^2.12.1",
|
||||
"diff": "^3.2.0",
|
||||
"glob": "^7.1.1",
|
||||
"js-yaml": "^3.7.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.3.0",
|
||||
"tslib": "^1.8.0",
|
||||
"tsutils": "^2.12.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"diff": {
|
||||
@@ -1080,12 +1093,12 @@
|
||||
}
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "2.25.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.25.0.tgz",
|
||||
"integrity": "sha512-SPgUlOAUAe6fCyPi0QR4U0jRuDsHHKvzIR6/hHd0YR0bb8MzeLJgCagkPSmZeJjWImnpJ0xq6XHa9goTvMBBCQ==",
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz",
|
||||
"integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "1.9.0"
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
@@ -1093,7 +1106,7 @@
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"tweetnacl": {
|
||||
@@ -1103,9 +1116,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.1.tgz",
|
||||
"integrity": "sha512-Ao/f6d/4EPLq0YwzsQz8iXflezpTkQzqAyenTiw4kCUGr1uPiFLC3+fZ+gMZz6eeI/qdRUqvC+HxIJzUAzEFdg==",
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
|
||||
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
|
||||
"dev": true
|
||||
},
|
||||
"underscore.string": {
|
||||
@@ -1114,8 +1127,8 @@
|
||||
"integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "1.1.1",
|
||||
"util-deprecate": "1.0.2"
|
||||
"sprintf-js": "^1.0.3",
|
||||
"util-deprecate": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
@@ -1138,9 +1151,9 @@
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "1.3.0"
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"wordwrap": {
|
||||
@@ -1160,8 +1173,8 @@
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||
"requires": {
|
||||
"sax": "1.2.4",
|
||||
"xmlbuilder": "9.0.4"
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~9.0.1"
|
||||
}
|
||||
},
|
||||
"xmlbuilder": {
|
||||
|
||||
29
package.json
29
package.json
@@ -15,33 +15,42 @@
|
||||
"engines": {
|
||||
"node": ">=5.0"
|
||||
},
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.5",
|
||||
"bin": {
|
||||
"crunchy": "./bin/crunchy"
|
||||
"crunchy": "./bin/crunchy",
|
||||
"crunchy.sh": "./bin/crunchy.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.27",
|
||||
"@types/node": "^10.3.3",
|
||||
"big-integer": "^1.6.31",
|
||||
"bluebird": "^3.5.1",
|
||||
"cheerio": "^0.22.0",
|
||||
"cloudscraper": "^1.5.0",
|
||||
"commander": "^2.15.1",
|
||||
"fs-extra": "^5.0.0",
|
||||
"fs-extra": "^6.0.1",
|
||||
"mkdirp": "^0.5.0",
|
||||
"request": "^2.85.0",
|
||||
"pjson": "^1.0.9",
|
||||
"request": "^2.87.0",
|
||||
"request-promise": "^4.2.2",
|
||||
"xml2js": "^0.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bluebird": "^3.5.20",
|
||||
"@types/cheerio": "^0.22.7",
|
||||
"@types/fs-extra": "^5.0.3",
|
||||
"@types/mkdirp": "^0.5.2",
|
||||
"@types/request": "^2.47.0",
|
||||
"@types/xml2js": "^0.4.2",
|
||||
"@types/request": "^2.47.1",
|
||||
"@types/request-promise": "^4.1.41",
|
||||
"@types/xml2js": "^0.4.3",
|
||||
"tsconfig-lint": "^0.12.0",
|
||||
"tslint": "^5.9.1",
|
||||
"typescript": "^2.8.1"
|
||||
"tslint": "^5.10.0",
|
||||
"typescript": "^2.9.2"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run build",
|
||||
"compile": "tsc",
|
||||
"build": "tsc",
|
||||
"test": "tslint -c ./tslint.json --project ./tsconfig.json ./src/**/*.ts",
|
||||
"test": "tslint --project .",
|
||||
"start": "node ./bin/crunchy"
|
||||
},
|
||||
"bugs": {
|
||||
|
||||
154
src/batch.ts
154
src/batch.ts
@@ -2,15 +2,16 @@
|
||||
import commander = require('commander');
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
import series from './series';
|
||||
import log = require('./log');
|
||||
import series from './series';
|
||||
|
||||
/* correspondances between resolution and value CR excpect */
|
||||
let resol_table: { [id: string]: IResolData; } = {
|
||||
'360': {quality:'60', format:'106'},
|
||||
'480': {quality:'61', format:'106'},
|
||||
'720': {quality:'62', format:'106'},
|
||||
'1080': {quality:'80', format:'108'},
|
||||
const resol_table: { [id: string]: IResolData; } =
|
||||
{
|
||||
360: {quality: '60', format: '106'},
|
||||
480: {quality: '61', format: '106'},
|
||||
720: {quality: '62', format: '106'},
|
||||
1080: {quality: '80', format: '108'},
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -19,53 +20,95 @@ let resol_table: { [id: string]: IResolData; } = {
|
||||
export default function(args: string[], done: (err?: Error) => void)
|
||||
{
|
||||
const config = parse(args);
|
||||
const batchPath = path.join(config.output || process.cwd(), 'CrunchyRoll.txt');
|
||||
const batchPath = path.join(config.output || process.cwd(), config.batch);
|
||||
|
||||
// set resolution
|
||||
if (config.resolution)
|
||||
{
|
||||
try
|
||||
{
|
||||
config.video_format = resol_table[config.resolution]['format'];
|
||||
config.video_quality = resol_table[config.resolution]['quality'];
|
||||
config.video_format = resol_table[config.resolution].format;
|
||||
config.video_quality = resol_table[config.resolution].quality;
|
||||
}
|
||||
catch(e)
|
||||
catch (e)
|
||||
{
|
||||
log.warn("Invalid resolution " + config.resolution + "p. Setting to 1080p")
|
||||
config.video_format = resol_table['1080']['format'];
|
||||
config.video_quality = resol_table['1080']['quality'];
|
||||
log.warn('Invalid resolution ' + config.resolution + 'p. Setting to 1080p');
|
||||
config.video_format = resol_table['1080'].format;
|
||||
config.video_quality = resol_table['1080'].quality;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 1080 by default */
|
||||
config.video_format = resol_table['1080']['format'];
|
||||
config.video_quality = resol_table['1080']['quality'];
|
||||
config.video_format = resol_table['1080'].format;
|
||||
config.video_quality = resol_table['1080'].quality;
|
||||
}
|
||||
|
||||
tasks(config, batchPath, (err, tasks) =>
|
||||
if (config.debug)
|
||||
{
|
||||
/* Ugly but meh */
|
||||
const tmp = JSON.parse(JSON.stringify(config));
|
||||
tmp.pass = 'obfuscated';
|
||||
tmp.user = 'obfustated';
|
||||
tmp.rawArgs = undefined;
|
||||
tmp.options = undefined;
|
||||
log.dumpToDebug('Config', JSON.stringify(tmp), true);
|
||||
}
|
||||
|
||||
tasks(config, batchPath, (err, tasksArr) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
return done(err);
|
||||
return done(err);
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
|
||||
(function next()
|
||||
{
|
||||
if (i >= tasks.length)
|
||||
if (i >= tasksArr.length)
|
||||
{
|
||||
return done();
|
||||
}
|
||||
|
||||
series(tasks[i].config, tasks[i].address, (errin) =>
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('Task ' + i, JSON.stringify(tasksArr[i]));
|
||||
}
|
||||
|
||||
series(config, tasksArr[i], (errin) =>
|
||||
{
|
||||
if (errin)
|
||||
{
|
||||
return done(errin);
|
||||
if (tasksArr[i].retry <= 0)
|
||||
{
|
||||
log.error(errin.stack || errin);
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('BatchGiveUp', errin.stack || errin);
|
||||
}
|
||||
log.error('Cannot get episodes from "' + tasksArr[i].address + '", please rerun later');
|
||||
/* Go to the next on the list */
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (config.verbose)
|
||||
{
|
||||
log.error(errin);
|
||||
}
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('BatchRetry', errin.stack || errin);
|
||||
}
|
||||
log.warn('Retrying to fetch episodes list from' + tasksArr[i].retry + ' / ' + config.retry);
|
||||
tasksArr[i].retry -= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i += 1;
|
||||
}
|
||||
i += 1;
|
||||
next();
|
||||
});
|
||||
})();
|
||||
@@ -106,6 +149,52 @@ function split(value: string): string[]
|
||||
return pieces;
|
||||
}
|
||||
|
||||
function get_min_filter(filter: string): number
|
||||
{
|
||||
if (filter !== undefined)
|
||||
{
|
||||
const tok = filter.split('-');
|
||||
|
||||
if (tok.length > 2)
|
||||
{
|
||||
log.error('Invalid episode filter \'' + filter + '\'');
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
if (tok[0] !== '')
|
||||
{
|
||||
return parseInt(tok[0], 10);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function get_max_filter(filter: string): number
|
||||
{
|
||||
if (filter !== undefined)
|
||||
{
|
||||
const tok = filter.split('-');
|
||||
|
||||
if (tok.length > 2)
|
||||
{
|
||||
log.error('Invalid episode filter \'' + filter + '\'');
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
if ((tok.length > 1) && (tok[1] !== ''))
|
||||
{
|
||||
/* We have a max value */
|
||||
return parseInt(tok[1], 10);
|
||||
}
|
||||
else if ((tok.length === 1) && (tok[0] !== ''))
|
||||
{
|
||||
/* A single episode has been requested */
|
||||
return parseInt(tok[0], 10);
|
||||
}
|
||||
}
|
||||
return +Infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the configuration or reads the batch-mode file for tasks.
|
||||
*/
|
||||
@@ -113,11 +202,10 @@ function tasks(config: IConfigLine, batchPath: string, done: (err: Error, tasks?
|
||||
{
|
||||
if (config.args.length)
|
||||
{
|
||||
const configIn = config;
|
||||
|
||||
return done(null, config.args.map((addressIn) =>
|
||||
{
|
||||
return {address: addressIn, config: configIn};
|
||||
return {address: addressIn, retry: config.retry,
|
||||
episode_min: get_min_filter(config.episodes), episode_max: get_max_filter(config.episodes)};
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -153,7 +241,8 @@ function tasks(config: IConfigLine, batchPath: string, done: (err: Error, tasks?
|
||||
return;
|
||||
}
|
||||
|
||||
map.push({address: addressIn, config: lineConfig});
|
||||
map.push({address: addressIn, retry: lineConfig.retry,
|
||||
episode_min: get_min_filter(lineConfig.episodes), episode_max: get_max_filter(lineConfig.episodes)});
|
||||
});
|
||||
});
|
||||
done(null, map);
|
||||
@@ -173,15 +262,20 @@ function parse(args: string[]): IConfigLine
|
||||
// Disables
|
||||
.option('-c, --cache', 'Disables the cache.')
|
||||
.option('-m, --merge', 'Disables merging subtitles and videos.')
|
||||
// Filters
|
||||
.option('-e, --episode <i>', 'The episode filter.')
|
||||
.option('-v, --volume <i>', 'The volume filter.')
|
||||
// Episode filter
|
||||
.option('-e, --episodes <s>', 'Episode list. Read documentation on how to use')
|
||||
// Settings
|
||||
.option('-f, --format <s>', 'The subtitle format. (Default: ass)')
|
||||
.option('-o, --output <s>', 'The output path.')
|
||||
.option('-s, --series <s>', 'The series override.')
|
||||
.option('-n, --filename <s>', 'The name override.')
|
||||
.option('-t, --tag <s>', 'The subgroup. (Default: CrunchyRoll)')
|
||||
.option('-r, --resolution <s>', 'The video resolution. (Default: 1080 (360, 480, 720, 1080))')
|
||||
.option('-t, --tag <s>', 'The subgroup. (Default: CrunchyRoll)', 'CrunchyRoll')
|
||||
.option('-r, --resolution <s>', 'The video resolution. (Default: 1080 (360, 480, 720, 1080))',
|
||||
'1080')
|
||||
.option('-g, --rebuildcrp', 'Rebuild the crpersistant file.')
|
||||
.option('-b, --batch <s>', 'Batch file', 'CrunchyRoll.txt')
|
||||
.option('--verbose', 'Make tool verbose')
|
||||
.option('--debug', 'Create a debug file. Use only if requested!')
|
||||
.option('--retry <i>', 'Number or time to retry fetching an episode. Default: 5', 5)
|
||||
.parse(args);
|
||||
}
|
||||
|
||||
33
src/cli.ts
33
src/cli.ts
@@ -1,10 +1,41 @@
|
||||
'use strict';
|
||||
import batch from './batch';
|
||||
import request = require('request');
|
||||
import log = require('./log');
|
||||
import pjson = require('pjson');
|
||||
|
||||
const current_version = pjson.version;
|
||||
|
||||
/* Check if the current version is the latest */
|
||||
log.info('Crunchy version ' + current_version);
|
||||
request.get({ uri: 'https://raw.githubusercontent.com/Godzil/Crunchy/master/package.json' },
|
||||
(error: Error, response: any, body: any) =>
|
||||
{
|
||||
const onlinepkg = JSON.parse(body);
|
||||
let tmp = current_version.split('.');
|
||||
const cur = (Number(tmp[0]) * 10000) + (Number(tmp[1]) * 100) + Number(tmp[2]);
|
||||
tmp = onlinepkg.version.split('.');
|
||||
const dist = (Number(tmp[0]) * 10000) + (Number(tmp[1]) * 100) + Number(tmp[2]);
|
||||
if (dist > cur)
|
||||
{
|
||||
log.warn('There is a newer version of crunchy (v' + onlinepkg.version + '), you should update!');
|
||||
}
|
||||
});
|
||||
|
||||
batch(process.argv, (err: any) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
console.error(err.stack || err);
|
||||
if (err.stack)
|
||||
{
|
||||
console.error(err.stack || err);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.error(err);
|
||||
}
|
||||
process.exit(-1);
|
||||
}
|
||||
console.info('Done!');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
@@ -57,7 +57,8 @@ function fileExist(path: string)
|
||||
{
|
||||
fs.statSync(path);
|
||||
return true;
|
||||
} catch (e)
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -82,6 +83,13 @@ function download(config: IConfig, page: IEpisodePage, player: IEpisodePlayer, d
|
||||
if (fileExist(filePath + '.mkv'))
|
||||
{
|
||||
let count = 0;
|
||||
|
||||
if (config.rebuildcrp)
|
||||
{
|
||||
log.warn('Adding \'' + fileName + '\' to the DB...');
|
||||
return done(null, false);
|
||||
}
|
||||
|
||||
log.warn('File \'' + fileName + '\' already exist...');
|
||||
|
||||
do
|
||||
@@ -92,6 +100,14 @@ function download(config: IConfig, page: IEpisodePage, player: IEpisodePlayer, d
|
||||
} while (fileExist(filePath + '.mkv'));
|
||||
|
||||
log.warn('Renaming to \'' + fileName + '\'...');
|
||||
|
||||
page.filename = fileName;
|
||||
}
|
||||
|
||||
if (config.rebuildcrp)
|
||||
{
|
||||
log.warn('Ignoring \'' + fileName + '\' as it does not exist...');
|
||||
return done(null, true);
|
||||
}
|
||||
|
||||
mkdirp(path.dirname(filePath), (errM: Error) =>
|
||||
@@ -128,7 +144,7 @@ function download(config: IConfig, page: IEpisodePage, player: IEpisodePlayer, d
|
||||
const isSubtited = Boolean(player.subtitle);
|
||||
|
||||
log.dispEpisode(fileName, 'Merging...', false);
|
||||
video.merge(config, isSubtited, player.video.file, filePath, player.video.mode, (errVM) =>
|
||||
video.merge(config, isSubtited, player.video.file, filePath, player.video.mode, config.verbose, (errVM) =>
|
||||
{
|
||||
if (errVM)
|
||||
{
|
||||
@@ -170,7 +186,7 @@ function downloadSubtitle(config: IConfig, player: IEpisodePlayer, filePath: str
|
||||
const formats = subtitle.formats;
|
||||
const format = formats[config.format] ? config.format : 'ass';
|
||||
|
||||
formats[format](data, (errF: Error, decodedSubtitle: string) =>
|
||||
formats[format](config, data, (errF: Error, decodedSubtitle: string) =>
|
||||
{
|
||||
if (errF)
|
||||
{
|
||||
@@ -185,11 +201,11 @@ function downloadSubtitle(config: IConfig, player: IEpisodePlayer, filePath: str
|
||||
/**
|
||||
* Streams the video to disk.
|
||||
*/
|
||||
function downloadVideo(ignored/*config*/: IConfig, page: IEpisodePage, player: IEpisodePlayer,
|
||||
function downloadVideo(config: IConfig, page: IEpisodePage, player: IEpisodePlayer,
|
||||
filePath: string, done: (err: Error) => void)
|
||||
{
|
||||
video.stream(player.video.host, player.video.file, page.swf, filePath,
|
||||
path.extname(player.video.file), player.video.mode, done);
|
||||
path.extname(player.video.file), player.video.mode, config.verbose, done);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,11 +219,11 @@ function name(config: IConfig, page: IEpisodePage, series: string, extra: string
|
||||
const volume = (volumeNum < 10 ? '0' : '') + page.volume;
|
||||
const tag = config.tag || 'CrunchyRoll';
|
||||
|
||||
if (!config.filename) {
|
||||
if (!page.filename) {
|
||||
return page.series + ' - s' + volume + 'e' + episode + ' - [' + tag + ']' + extra;
|
||||
}
|
||||
|
||||
return config.filename
|
||||
return page.filename
|
||||
.replace(/{EPISODE_ID}/g, page.id.toString())
|
||||
.replace(/{EPISODE_NUMBER}/g, episode)
|
||||
.replace(/{SEASON_NUMBER}/g, volume)
|
||||
@@ -258,13 +274,24 @@ function scrapePage(config: IConfig, address: string, done: (err: Error, page?:
|
||||
const regexp = /\s*([^\n\r\t\f]+)\n?\s*[^0-9]*([0-9][\-0-9.]*)?,?\n?\s\s*[^0-9]*((PV )?[S0-9][P0-9.]*[a-fA-F]?)/;
|
||||
const look = $('#showmedia_about_media').text();
|
||||
const seasonTitle = $('span[itemprop="title"]').text();
|
||||
let episodeTitle = $('#showmedia_about_name').text().replace(/[“”]/g, '');
|
||||
const episodeTitle = $('#showmedia_about_name').text().replace(/[“”]/g, '');
|
||||
const data = regexp.exec(look);
|
||||
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('episode page', $.html());
|
||||
}
|
||||
|
||||
if (!swf || !data)
|
||||
{
|
||||
log.warn('Somethig unexpected in the page at ' + address + ' (data are: ' + look + ')');
|
||||
log.warn('Setting Season to ’0’ and episode to ’0’...');
|
||||
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('episode unexpected', look);
|
||||
}
|
||||
|
||||
done(null, {
|
||||
episode: '0',
|
||||
id: epId,
|
||||
@@ -273,6 +300,7 @@ function scrapePage(config: IConfig, address: string, done: (err: Error, page?:
|
||||
title: episodeTitle,
|
||||
swf: swf[1],
|
||||
volume: '0',
|
||||
filename: '',
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -285,6 +313,7 @@ function scrapePage(config: IConfig, address: string, done: (err: Error, page?:
|
||||
title: episodeTitle,
|
||||
swf: swf[1],
|
||||
volume: data[2] || '1',
|
||||
filename: '',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -351,6 +380,11 @@ function scrapePlayer(config: IConfig, address: string, id: number, done: (err:
|
||||
});
|
||||
} catch (parseError)
|
||||
{
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('player scrape', parseError);
|
||||
}
|
||||
|
||||
done(parseError);
|
||||
}
|
||||
});
|
||||
|
||||
9
src/interface/IConfig.d.ts
vendored
9
src/interface/IConfig.d.ts
vendored
@@ -5,9 +5,7 @@ interface IConfig {
|
||||
// Disables
|
||||
cache?: boolean;
|
||||
merge?: boolean;
|
||||
// Filters
|
||||
episode?: number;
|
||||
volume?: number;
|
||||
episodes?: string;
|
||||
// Settings
|
||||
format?: string;
|
||||
output?: string;
|
||||
@@ -17,4 +15,9 @@ interface IConfig {
|
||||
resolution?: string;
|
||||
video_format?: string;
|
||||
video_quality?: string;
|
||||
rebuildcrp?: boolean;
|
||||
batch?: string;
|
||||
verbose?: boolean;
|
||||
debug?: boolean;
|
||||
retry?: number;
|
||||
}
|
||||
|
||||
4
src/interface/IConfigTask.d.ts
vendored
4
src/interface/IConfigTask.d.ts
vendored
@@ -1,4 +1,6 @@
|
||||
interface IConfigTask {
|
||||
address: string;
|
||||
config: IConfigLine;
|
||||
retry: number;
|
||||
episode_min: number;
|
||||
episode_max: number;
|
||||
}
|
||||
|
||||
1
src/interface/IEpisodePage.d.ts
vendored
1
src/interface/IEpisodePage.d.ts
vendored
@@ -6,4 +6,5 @@ interface IEpisodePage {
|
||||
season: string;
|
||||
title: string;
|
||||
swf: string;
|
||||
filename: string;
|
||||
}
|
||||
|
||||
2
src/interface/IFormatterTable.d.ts
vendored
2
src/interface/IFormatterTable.d.ts
vendored
@@ -1,3 +1,3 @@
|
||||
interface IFormatterTable {
|
||||
[key: string]: (input: string|Buffer, done: (err: Error, subtitle?: string) => void) => void;
|
||||
[key: string]: (config: IConfig, input: string|Buffer, done: (err: Error, subtitle?: string) => void) => void;
|
||||
}
|
||||
|
||||
1
src/interface/ISeriesEpisode.d.ts
vendored
1
src/interface/ISeriesEpisode.d.ts
vendored
@@ -2,4 +2,5 @@ interface ISeriesEpisode {
|
||||
address: string;
|
||||
episode: string;
|
||||
volume: number;
|
||||
retry: number;
|
||||
}
|
||||
|
||||
20
src/log.ts
20
src/log.ts
@@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
import os = require('os');
|
||||
import fs = require('fs-extra');
|
||||
|
||||
export function error(str: string)
|
||||
export function error(str: string|Error)
|
||||
{
|
||||
/* Do fancy output */
|
||||
console.error(' \x1B[1;31m* ERROR\x1B[0m: ' + str);
|
||||
@@ -35,3 +36,20 @@ export function dispEpisode(name: string, status: string, addNL: boolean)
|
||||
console.log('');
|
||||
}
|
||||
}
|
||||
|
||||
export function dumpToDebug(what: string, data: any, create = false)
|
||||
{
|
||||
if (create)
|
||||
{
|
||||
fs.writeFile('debug.txt', '>>>>>>>> ' + what + ':\n' + data + '\n<<<<<<<<\n', (err) =>
|
||||
{
|
||||
if (err) throw err;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fs.appendFile('debug.txt', '>>>>>>>> ' + what + ':\n' + data + '\n<<<<<<<<\n', (err) =>
|
||||
{
|
||||
if (err) throw err;
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
'use strict';
|
||||
import request = require('request');
|
||||
import cheerio = require('cheerio');
|
||||
import request = require('request');
|
||||
import rp = require('request-promise');
|
||||
import Promise = require('bluebird');
|
||||
import log = require('./log');
|
||||
import { RequestPromise } from 'request-promise';
|
||||
import { Response } from 'request';
|
||||
|
||||
// tslint:disable-next-line:no-var-requires
|
||||
const cloudscraper = require('cloudscraper');
|
||||
|
||||
let isAuthenticated = false;
|
||||
@@ -10,30 +16,84 @@ let isPremium = false;
|
||||
const defaultHeaders: request.Headers =
|
||||
{
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
|
||||
// Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
|
||||
'Connection': 'keep-alive',
|
||||
'Referer': 'https://www.crunchyroll.com/login'
|
||||
'Referer': 'https://www.crunchyroll.com/login',
|
||||
};
|
||||
|
||||
function generateDeviceId(): string
|
||||
{
|
||||
let id = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
||||
for (let i = 0; i < 32; i++)
|
||||
{
|
||||
id += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
function startSession(): Promise<string>
|
||||
{
|
||||
return rp(
|
||||
{
|
||||
method: 'GET',
|
||||
url: 'CR_SESSION_URL',
|
||||
qs:
|
||||
{
|
||||
device_id: generateDeviceId(),
|
||||
device_type: 'CR_DEVICE_TYPE',
|
||||
access_token: 'CR_SESSION_KEY',
|
||||
version: 'CR_API_VERSION',
|
||||
locale: 'CR_LOCALE',
|
||||
},
|
||||
json: true,
|
||||
})
|
||||
.then((response: any) =>
|
||||
{
|
||||
return response.data.session_id;
|
||||
});
|
||||
}
|
||||
|
||||
function login(sessionId: string, user: string, pass: string): Promise<any>
|
||||
{
|
||||
return rp(
|
||||
{
|
||||
method: 'POST',
|
||||
url: 'CR_LOGIN_URL',
|
||||
form:
|
||||
{
|
||||
account: user,
|
||||
password: pass,
|
||||
session_id: sessionId,
|
||||
version: 'CR_API_VERSION',
|
||||
},
|
||||
json: true,
|
||||
})
|
||||
.then((response) =>
|
||||
{
|
||||
if (response.error) throw new Error('Login failed: ' + response.message);
|
||||
return response.data;
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: logout
|
||||
|
||||
/**
|
||||
* Performs a GET request for the resource.
|
||||
*/
|
||||
export function get(config: IConfig, options: string|request.Options, done: (err: Error, result?: string) => void)
|
||||
{
|
||||
authenticate(config, err =>
|
||||
authenticate(config, (err) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
return done(err);
|
||||
return done(err);
|
||||
}
|
||||
|
||||
cloudscraper.request(modify(options, 'GET'), (err: Error, response: any, body: any) =>
|
||||
cloudscraper.request(modify(options, 'GET'), (error: Error, response: any, body: any) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
return done(err);
|
||||
}
|
||||
|
||||
if (error) return done(error);
|
||||
done(null, typeof body === 'string' ? body : String(body));
|
||||
});
|
||||
});
|
||||
@@ -44,20 +104,19 @@ export function get(config: IConfig, options: string|request.Options, done: (err
|
||||
*/
|
||||
export function post(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void)
|
||||
{
|
||||
authenticate(config, err =>
|
||||
authenticate(config, (err) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
return done(err);
|
||||
}
|
||||
|
||||
cloudscraper.request(modify(options, 'POST'), (err: Error, response: any, body: any) =>
|
||||
cloudscraper.request(modify(options, 'POST'), (error: Error, response: any, body: any) =>
|
||||
{
|
||||
if (err)
|
||||
if (error)
|
||||
{
|
||||
return done(err);
|
||||
return done(error);
|
||||
}
|
||||
|
||||
done(null, typeof body === 'string' ? body : String(body));
|
||||
});
|
||||
});
|
||||
@@ -68,112 +127,82 @@ export function post(config: IConfig, options: request.Options, done: (err: Erro
|
||||
*/
|
||||
function authenticate(config: IConfig, done: (err: Error) => void)
|
||||
{
|
||||
if (isAuthenticated || !config.pass || !config.user)
|
||||
if (isAuthenticated)
|
||||
{
|
||||
return done(null);
|
||||
return done(null);
|
||||
}
|
||||
|
||||
/* Bypass the login page and send a login request directly */
|
||||
let options =
|
||||
if (!config.pass || !config.user)
|
||||
{
|
||||
headers: defaultHeaders,
|
||||
jar: true,
|
||||
gzip: false,
|
||||
method: 'GET',
|
||||
url: 'https://www.crunchyroll.com/login'
|
||||
};
|
||||
log.error('You need to give login/password to use Crunchy');
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
cloudscraper.request(options, (err: Error, rep: string, body: string) =>
|
||||
startSession()
|
||||
.then((sessionId: string) =>
|
||||
{
|
||||
if (err) return done(err);
|
||||
|
||||
const $ = cheerio.load(body);
|
||||
|
||||
/* Get the token from the login page */
|
||||
const token = $('input[name="login_form[_token]"]').attr('value');
|
||||
if (token === '')
|
||||
{
|
||||
return done(new Error('Can`t find token!'));
|
||||
}
|
||||
|
||||
let options =
|
||||
defaultHeaders.Cookie = `sess_id=${sessionId}; c_locale=enUS`;
|
||||
return login(sessionId, config.user, config.pass);
|
||||
})
|
||||
.then((userData) =>
|
||||
{
|
||||
/**
|
||||
* The page return with a meta based redirection, as we wan't to check that everything is fine, reload
|
||||
* the main page. A bit convoluted, but more sure.
|
||||
*/
|
||||
const options =
|
||||
{
|
||||
headers: defaultHeaders,
|
||||
form:
|
||||
{
|
||||
'login_form[name]': config.user,
|
||||
'login_form[password]': config.pass,
|
||||
'login_form[redirect_url]': '/',
|
||||
'login_form[_token]': token
|
||||
},
|
||||
jar: true,
|
||||
gzip: false,
|
||||
method: 'POST',
|
||||
url: 'https://www.crunchyroll.com/login'
|
||||
url: 'http://www.crunchyroll.com/',
|
||||
method: 'GET',
|
||||
};
|
||||
|
||||
cloudscraper.request(options, (err: Error, rep: string, body: string) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
return done(err);
|
||||
return done(err);
|
||||
}
|
||||
|
||||
/* The page return with a meta based redirection, as we wan't to check that everything is fine, reload
|
||||
* the main page. A bit convoluted, but more sure.
|
||||
*/
|
||||
let options =
|
||||
const $ = cheerio.load(body);
|
||||
|
||||
/* Check if auth worked */
|
||||
const regexps = /ga\('set', 'dimension[5-8]', '([^']*)'\);/g;
|
||||
const dims = regexps.exec($('script').text());
|
||||
|
||||
for (let i = 1; i < 5; i++)
|
||||
{
|
||||
headers: defaultHeaders,
|
||||
jar: true,
|
||||
url: 'http://www.crunchyroll.com/',
|
||||
method: 'GET'
|
||||
};
|
||||
if ((dims[i] !== undefined) && (dims[i] !== '') && (dims[i] !== 'not-registered'))
|
||||
{
|
||||
isAuthenticated = true;
|
||||
}
|
||||
|
||||
cloudscraper.request(options, (err: Error, rep: string, body: string) =>
|
||||
if ((dims[i] === 'premium') || (dims[i] === 'premiumplus'))
|
||||
{
|
||||
isPremium = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAuthenticated === false)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
return done(err);
|
||||
}
|
||||
const error = $('ul.message, li.error').text();
|
||||
log.error('Authentication failed: ' + error);
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
let $ = cheerio.load(body);
|
||||
|
||||
/* Check if auth worked */
|
||||
const regexps = /ga\('set', 'dimension[5-8]', '([^']*)'\);/g;
|
||||
const dims = regexps.exec($('script').text());
|
||||
|
||||
for (let i = 1; i < 5; i++)
|
||||
{
|
||||
if ((dims[i] !== undefined) && (dims[i] !== '') && (dims[i] !== 'not-registered'))
|
||||
{
|
||||
isAuthenticated = true;
|
||||
}
|
||||
|
||||
if ((dims[i] === 'premium') || (dims[i] === 'premiumplus'))
|
||||
{
|
||||
isPremium = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAuthenticated === false)
|
||||
{
|
||||
const error = $('ul.message, li.error').text();
|
||||
return done(new Error('Authentication failed: ' + error));
|
||||
}
|
||||
|
||||
if (isPremium === false)
|
||||
{
|
||||
log.warn('Do not use this app without a premium account.');
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info('You have a premium account! Good!');
|
||||
}
|
||||
done(null);
|
||||
});
|
||||
if (isPremium === false)
|
||||
{
|
||||
log.warn('Do not use this app without a premium account.');
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info('You have a premium account! Good!');
|
||||
}
|
||||
done(null);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(done);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,5 +217,10 @@ function modify(options: string|request.Options, reqMethod: string): request.Opt
|
||||
options.method = reqMethod;
|
||||
return options;
|
||||
}
|
||||
return { jar: true, headers: defaultHeaders, url: options.toString(), method: reqMethod };
|
||||
}
|
||||
return {
|
||||
jar: true,
|
||||
headers: defaultHeaders,
|
||||
url: options.toString(),
|
||||
method: reqMethod
|
||||
};
|
||||
}
|
||||
137
src/series.ts
137
src/series.ts
@@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
import cheerio = require('cheerio');
|
||||
import episode from './episode';
|
||||
import fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
// import fs = require('fs');
|
||||
import fs = require('fs-extra');
|
||||
import my_request = require('./my_request');
|
||||
import path = require('path');
|
||||
import url = require('url');
|
||||
@@ -27,21 +27,21 @@ function fileExist(path: string)
|
||||
/**
|
||||
* Streams the series to disk.
|
||||
*/
|
||||
export default function(config: IConfig, address: string, done: (err: Error) => void)
|
||||
export default function(config: IConfig, task: IConfigTask, done: (err: Error) => void)
|
||||
{
|
||||
const persistentPath = path.join(config.output || process.cwd(), persistent);
|
||||
|
||||
/* Make a backup of the persistent file in case of */
|
||||
if (fileExist(persistentPath))
|
||||
{
|
||||
fse.copySync(persistentPath, persistentPath + '.backup');
|
||||
fs.copySync(persistentPath, persistentPath + '.backup');
|
||||
}
|
||||
|
||||
fs.readFile(persistentPath, 'utf8', (err: Error, contents: string) =>
|
||||
{
|
||||
const cache = config.cache ? {} : JSON.parse(contents || '{}');
|
||||
|
||||
page(config, address, (errP, page) =>
|
||||
pageScrape(config, task, (errP, page) =>
|
||||
{
|
||||
if (errP)
|
||||
{
|
||||
@@ -51,32 +51,65 @@ export default function(config: IConfig, address: string, done: (err: Error) =>
|
||||
let i = 0;
|
||||
(function next()
|
||||
{
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('Episode ' + i, JSON.stringify(page.episodes[i]));
|
||||
}
|
||||
|
||||
if (i >= page.episodes.length) return done(null);
|
||||
download(cache, config, address, page.episodes[i], (errD, ignored) =>
|
||||
download(cache, config, task, page.episodes[i], (errD, ignored) =>
|
||||
{
|
||||
if (errD)
|
||||
{
|
||||
return done(errD);
|
||||
}
|
||||
|
||||
if ((ignored === false) || (ignored === undefined))
|
||||
{
|
||||
const newCache = JSON.stringify(cache, null, ' ');
|
||||
fs.writeFile(persistentPath, newCache, (errW: Error) =>
|
||||
if (page.episodes[i].retry <= 0)
|
||||
{
|
||||
if (errW)
|
||||
{
|
||||
return done(errW);
|
||||
}
|
||||
|
||||
log.dispEpisode(config.filename, 'Error...', true);
|
||||
log.error(errD);
|
||||
log.error('Cannot fetch episode "s' + page.episodes[i].volume + 'e' + page.episodes[i].episode +
|
||||
'", please rerun later');
|
||||
/* Go to the next on the list */
|
||||
i += 1;
|
||||
next();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
log.dispEpisode(config.filename, 'Error...', true);
|
||||
if ((config.verbose) || (config.debug))
|
||||
{
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('series address', task.address);
|
||||
log.dumpToDebug('series error', errD.stack || errD);
|
||||
log.dumpToDebug('series data', JSON.stringify(page));
|
||||
}
|
||||
log.error(errD);
|
||||
}
|
||||
log.warn('Retrying to fetch episode "s' + page.episodes[i].volume + 'e' + page.episodes[i].episode +
|
||||
'" - Retry ' + page.episodes[i].retry + ' / ' + config.retry);
|
||||
page.episodes[i].retry -= 1;
|
||||
}
|
||||
next();
|
||||
}
|
||||
else
|
||||
{
|
||||
i += 1;
|
||||
next();
|
||||
if ((ignored === false) || (ignored === undefined))
|
||||
{
|
||||
const newCache = JSON.stringify(cache, null, ' ');
|
||||
fs.writeFile(persistentPath, newCache, (errW: Error) =>
|
||||
{
|
||||
if (errW)
|
||||
{
|
||||
return done(errW);
|
||||
}
|
||||
|
||||
i += 1;
|
||||
next();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
i += 1;
|
||||
next();
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -88,15 +121,18 @@ export default function(config: IConfig, address: string, done: (err: Error) =>
|
||||
* Downloads the episode.
|
||||
*/
|
||||
function download(cache: {[address: string]: number}, config: IConfig,
|
||||
baseAddress: string, item: ISeriesEpisode,
|
||||
task: IConfigTask, item: ISeriesEpisode,
|
||||
done: (err: Error, ign: boolean) => void)
|
||||
{
|
||||
if (!filter(config, item))
|
||||
const episodeNumber = parseInt(item.episode, 10);
|
||||
|
||||
if ( (episodeNumber < task.episode_min) ||
|
||||
(episodeNumber > task.episode_max) )
|
||||
{
|
||||
return done(null, false);
|
||||
}
|
||||
|
||||
const address = url.resolve(baseAddress, item.address);
|
||||
const address = url.resolve(task.address, item.address);
|
||||
|
||||
if (cache[address])
|
||||
{
|
||||
@@ -115,50 +151,27 @@ function download(cache: {[address: string]: number}, config: IConfig,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the item based on the configuration.
|
||||
*/
|
||||
function filter(config: IConfig, item: ISeriesEpisode)
|
||||
{
|
||||
// Filter on chapter.
|
||||
const episodeFilter = config.episode;
|
||||
// Filter on volume.
|
||||
const volumeFilter = config.volume;
|
||||
|
||||
const currentEpisode = parseInt(item.episode, 10);
|
||||
const currentVolume = item.volume;
|
||||
|
||||
if ( ( (episodeFilter > 0) && (currentEpisode <= episodeFilter) ) ||
|
||||
( (episodeFilter < 0) && (currentEpisode >= -episodeFilter) ) ||
|
||||
( (volumeFilter > 0) && (currentVolume <= volumeFilter ) ) ||
|
||||
( (volumeFilter < 0) && (currentVolume >= -volumeFilter ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the page and scrapes the episodes and series.
|
||||
*/
|
||||
function page(config: IConfig, address: string, done: (err: Error, result?: ISeries) => void)
|
||||
function pageScrape(config: IConfig, task: IConfigTask, done: (err: Error, result?: ISeries) => void)
|
||||
{
|
||||
if (address[0] === '@')
|
||||
if (task.address[0] === '@')
|
||||
{
|
||||
log.info('Trying to fetch from ' + address.substr(1));
|
||||
log.info('Trying to fetch from ' + task.address.substr(1));
|
||||
const episodes: ISeriesEpisode[] = [];
|
||||
episodes.push({
|
||||
address: address.substr(1),
|
||||
address: task.address.substr(1),
|
||||
episode: '',
|
||||
volume: 0,
|
||||
retry: config.retry,
|
||||
});
|
||||
done(null, {episodes: episodes.reverse(), series: ""});
|
||||
done(null, {episodes: episodes.reverse(), series: ''});
|
||||
}
|
||||
else
|
||||
{
|
||||
let episodeCount = 0;
|
||||
my_request.get(config, address, (err, result) => {
|
||||
my_request.get(config, task.address, (err, result) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
@@ -166,8 +179,17 @@ function page(config: IConfig, address: string, done: (err: Error, result?: ISer
|
||||
const $ = cheerio.load(result);
|
||||
const title = $('span[itemprop=name]').text();
|
||||
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('serie page', $.html());
|
||||
}
|
||||
|
||||
if (!title) {
|
||||
return done(new Error('Invalid page.(' + address + ')'));
|
||||
if (config.debug)
|
||||
{
|
||||
log.dumpToDebug('missing title', task.address);
|
||||
}
|
||||
return done(new Error('Invalid page.(' + task.address + ')'));
|
||||
}
|
||||
|
||||
log.info('Checking availability for ' + title);
|
||||
@@ -191,11 +213,12 @@ function page(config: IConfig, address: string, done: (err: Error, result?: ISer
|
||||
address: url,
|
||||
episode: episode[1],
|
||||
volume: volume ? parseInt(volume[0], 10) : 1,
|
||||
retry: config.retry,
|
||||
});
|
||||
});
|
||||
if (episodeCount === 0)
|
||||
{
|
||||
log.warn("No episodes found for " + title + ". Could it be a movie?");
|
||||
log.warn('No episodes found for ' + title + '. Could it be a movie?');
|
||||
}
|
||||
done(null, {episodes: episodes.reverse(), series: title});
|
||||
});
|
||||
|
||||
@@ -24,8 +24,8 @@ export default function(id: number, iv: Buffer|string, data: Buffer|string,
|
||||
*/
|
||||
function decrypt(id: number, iv: Buffer|string, data: Buffer|string)
|
||||
{
|
||||
const ivBuffer = typeof iv === 'string' ? new Buffer(iv, 'base64') : iv;
|
||||
const dataBuffer = typeof data === 'string' ? new Buffer(data, 'base64') : data;
|
||||
const ivBuffer = typeof iv === 'string' ? Buffer.from(iv, 'base64') : iv;
|
||||
const dataBuffer = typeof data === 'string' ? Buffer.from(data, 'base64') : data;
|
||||
const decipher = crypto.createDecipheriv('aes-256-cbc', key(id), ivBuffer);
|
||||
|
||||
decipher.setAutoPadding(false);
|
||||
@@ -53,7 +53,7 @@ function decompress(data: Buffer, done: (err: Error, result?: Buffer) => void)
|
||||
function key(subtitleId: number): Buffer
|
||||
{
|
||||
const hash = secret(20, 97, 1, 2) + magic(subtitleId);
|
||||
const result = new Buffer(32);
|
||||
const result = Buffer.allocUnsafe(32);
|
||||
|
||||
result.fill(0);
|
||||
crypto.createHash('sha1').update(hash).digest().copy(result);
|
||||
|
||||
@@ -4,7 +4,7 @@ import xml2js = require('xml2js');
|
||||
/**
|
||||
* Converts an input buffer to a SubStation Alpha subtitle.
|
||||
*/
|
||||
export default function(input: string|Buffer, done: (err: Error, subtitle?: string) => void)
|
||||
export default function(config: IConfig, input: string|Buffer, done: (err: Error, subtitle?: string) => void)
|
||||
{
|
||||
xml2js.parseString(input.toString(), {
|
||||
explicitArray: false,
|
||||
@@ -18,9 +18,9 @@ export default function(input: string|Buffer, done: (err: Error, subtitle?: stri
|
||||
|
||||
try
|
||||
{
|
||||
done(null, script(xml) + '\n' +
|
||||
done(null, script(config, xml) + '\n' +
|
||||
style(xml.styles) + '\n' +
|
||||
event(xml.events));
|
||||
event(config, xml.events));
|
||||
} catch (err)
|
||||
{
|
||||
done(err);
|
||||
@@ -31,12 +31,12 @@ export default function(input: string|Buffer, done: (err: Error, subtitle?: stri
|
||||
/**
|
||||
* Converts the event block.
|
||||
*/
|
||||
function event(block: ISubtitleEvent): string
|
||||
function event(config: IConfig, block: ISubtitleEvent): string
|
||||
{
|
||||
var format = 'Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text';
|
||||
const format = 'Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text';
|
||||
|
||||
return '[Events]\n' +
|
||||
'Format: ' + format + '\n' + [].concat(block.event).map(style => ('Dialogue: 0,' +
|
||||
'Format: ' + format + '\n' + [].concat(block.event).map((style) => ('Dialogue: 0,' +
|
||||
style.$.start + ',' +
|
||||
style.$.end + ',' +
|
||||
style.$.style + ',' +
|
||||
@@ -51,10 +51,11 @@ function event(block: ISubtitleEvent): string
|
||||
/**
|
||||
* Converts the script block.
|
||||
*/
|
||||
function script(block: ISubtitle): string
|
||||
function script(config: IConfig, block: ISubtitle): string
|
||||
{
|
||||
|
||||
return '[Script Info]\n' +
|
||||
'Origin: Downloaded from Crunchyroll.com by ' + config.user + '\n' +
|
||||
'Title: ' + block.$.title + '\n' +
|
||||
'ScriptType: v4.00+\n' +
|
||||
'WrapStyle: ' + block.$.wrap_style + '\n' +
|
||||
@@ -70,13 +71,13 @@ function script(block: ISubtitle): string
|
||||
*/
|
||||
function style(block: ISubtitleStyle): string
|
||||
{
|
||||
var format = 'Name,Fontname,Fontsize,PrimaryColour,SecondaryColour,' +
|
||||
const format = 'Name,Fontname,Fontsize,PrimaryColour,SecondaryColour,' +
|
||||
'OutlineColour,BackColour,Bold,Italic,Underline,StrikeOut,ScaleX,' +
|
||||
'ScaleY,Spacing,Angle,BorderStyle,Outline,Shadow,Alignment,' +
|
||||
'MarginL,MarginR,MarginV,Encoding';
|
||||
|
||||
return '[V4+ Styles]\n' +
|
||||
'Format: ' + format + '\n' + [].concat(block.style).map(style => 'Style: ' +
|
||||
'Format: ' + format + '\n' + [].concat(block.style).map((style) => 'Style: ' +
|
||||
style.$.name + ',' +
|
||||
style.$.font_name + ',' +
|
||||
style.$.font_size + ',' +
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import ass from './ass';
|
||||
import srt from './srt';
|
||||
|
||||
export default <IFormatterTable> {
|
||||
ass: ass,
|
||||
srt: srt
|
||||
};
|
||||
export default {
|
||||
ass,
|
||||
srt
|
||||
} as IFormatterTable;
|
||||
|
||||
@@ -4,7 +4,7 @@ import xml2js = require('xml2js');
|
||||
/**
|
||||
* Converts an input buffer to a SubRip subtitle.
|
||||
*/
|
||||
export default function(input: Buffer|string, done: (err: Error, subtitle?: string) => void)
|
||||
export default function(config: IConfig, input: Buffer|string, done: (err: Error, subtitle?: string) => void)
|
||||
{
|
||||
const options = {explicitArray: false, explicitRoot: false};
|
||||
|
||||
|
||||
@@ -10,21 +10,22 @@ import subtitle from '../subtitle/index';
|
||||
* Merges the subtitle and video files into a Matroska Multimedia Container.
|
||||
*/
|
||||
export default function(config: IConfig, isSubtitled: boolean, rtmpInputPath: string, filePath: string,
|
||||
streamMode: string, done: (err: Error) => void)
|
||||
streamMode: string, verbose: boolean, done: (err: Error) => void)
|
||||
{
|
||||
const subtitlePath = filePath + '.' + (subtitle.formats[config.format] ? config.format : 'ass');
|
||||
let videoPath = filePath;
|
||||
let cp;
|
||||
|
||||
if (streamMode === 'RTMP')
|
||||
{
|
||||
videoPath += path.extname(rtmpInputPath);
|
||||
videoPath += path.extname(rtmpInputPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
videoPath += '.mp4';
|
||||
}
|
||||
|
||||
childProcess.exec(command() + ' ' +
|
||||
cp = childProcess.exec(command() + ' ' +
|
||||
'-o "' + filePath + '.mkv" ' +
|
||||
'"' + videoPath + '" ' +
|
||||
(isSubtitled ? '"' + subtitlePath + '"' : ''), {
|
||||
@@ -46,6 +47,13 @@ export default function(config: IConfig, isSubtitled: boolean, rtmpInputPath: st
|
||||
done(null);
|
||||
});
|
||||
});
|
||||
|
||||
if (verbose === true)
|
||||
{
|
||||
cp.stdin.pipe(process.stdin);
|
||||
cp.stdout.pipe(process.stdout);
|
||||
cp.stderr.pipe(process.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,32 +9,42 @@ import log = require('../log');
|
||||
* Streams the video to disk.
|
||||
*/
|
||||
export default function(rtmpUrl: string, rtmpInputPath: string, swfUrl: string, filePath: string,
|
||||
fileExt: string, mode: string, done: (err: Error) => void)
|
||||
fileExt: string, mode: string, verbose: boolean, done: (err: Error) => void)
|
||||
{
|
||||
if (mode === 'RTMP')
|
||||
{
|
||||
childProcess.exec(command('rtmpdump') + ' ' +
|
||||
'-r "' + rtmpUrl + '" ' +
|
||||
'-y "' + rtmpInputPath + '" ' +
|
||||
'-W "' + swfUrl + '" ' +
|
||||
'-o "' + filePath + fileExt + '"', {
|
||||
maxBuffer: Infinity,
|
||||
}, done);
|
||||
}
|
||||
else if (mode === 'HLS')
|
||||
{
|
||||
const cmd = command('ffmpeg') + ' ' +
|
||||
'-i "' + rtmpInputPath + '" ' +
|
||||
'-c copy -bsf:a aac_adtstoasc ' +
|
||||
'"' + filePath + '.mp4"';
|
||||
childProcess.exec(cmd, {
|
||||
maxBuffer: Infinity,
|
||||
}, done);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error('No such mode: ' + mode);
|
||||
}
|
||||
let cp;
|
||||
let cmd;
|
||||
if (mode === 'RTMP')
|
||||
{
|
||||
cmd = command('rtmpdump') + ' ' +
|
||||
'-r "' + rtmpUrl + '" ' +
|
||||
'-y "' + rtmpInputPath + '" ' +
|
||||
'-W "' + swfUrl + '" ' +
|
||||
'-o "' + filePath + fileExt + '"';
|
||||
}
|
||||
else if (mode === 'HLS')
|
||||
{
|
||||
cmd = command('ffmpeg') + ' ' +
|
||||
'-y -xerror ' +
|
||||
'-i "' + rtmpInputPath + '" ' +
|
||||
'-c copy -bsf:a aac_adtstoasc ' +
|
||||
'"' + filePath + '.mp4"';
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error('No such mode: ' + mode);
|
||||
}
|
||||
|
||||
cp = childProcess.exec(cmd,
|
||||
{
|
||||
maxBuffer: Infinity,
|
||||
}, done);
|
||||
|
||||
if (verbose === true)
|
||||
{
|
||||
cp.stdin.pipe(process.stdin);
|
||||
cp.stdout.pipe(process.stdout);
|
||||
cp.stderr.pipe(process.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +54,7 @@ function command(exe: string): string
|
||||
{
|
||||
if (os.platform() !== 'win32')
|
||||
{
|
||||
return exe;
|
||||
return exe;
|
||||
}
|
||||
|
||||
return '"' + path.join(__dirname, '../../bin/' + exe + '.exe') + '"';
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
{
|
||||
"target": "es6",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"noImplicitAny": true,
|
||||
"removeComments": false,
|
||||
"module": "commonjs",
|
||||
"outDir": "dist",
|
||||
"sourceMap": true
|
||||
"sourceMap": true,
|
||||
"lib": [
|
||||
"es2015"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
18
tslint.json
18
tslint.json
@@ -9,23 +9,22 @@
|
||||
"curly": false,
|
||||
"eofline": false,
|
||||
"forin": true,
|
||||
"indent": [true, 2],
|
||||
"indent": [true, "spaces", 2],
|
||||
"interface-name": true,
|
||||
"jsdoc-format": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [true, 140],
|
||||
"member-ordering": [true,
|
||||
"public-before-private",
|
||||
"static-before-instance",
|
||||
"variables-before-functions"
|
||||
],
|
||||
"member-ordering": false,
|
||||
"no-shadowed-variable": false,
|
||||
"array-type": [true, "array"],
|
||||
"trailing-comma": false,
|
||||
"no-any": false,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"space-within-parens": false,
|
||||
"no-object-literal-type-assertion": false,
|
||||
"no-console": [true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
@@ -42,7 +41,6 @@
|
||||
"no-use-before-declare": false,
|
||||
"no-var-requires": true,
|
||||
"one-line": [true,
|
||||
"check-catch",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [true, "single"],
|
||||
@@ -67,6 +65,8 @@
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
],
|
||||
"object-literal-sort-keys": false,
|
||||
"ordered-imports": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user