28 Commits

Author SHA1 Message Date
Godzil
cdf7f223db 1.3.1 2018-07-30 22:47:33 +01:00
Godzil
bb70161652 Add a really simple and stupid way to check if you are running the latest version. 2018-07-30 22:47:33 +01:00
Godzil
7f2f983f55 using log instead of console is nicer 2018-07-30 22:47:33 +01:00
Godzil
8dab83b3ef Add log when not adding an episode when rebuilding the .crpresistent. 2018-07-30 22:47:33 +01:00
Godzil
cbafa5bc90 Now that retrying is there; force ffmpeg to fail in case or error (should now avoid to silently download a corrupted video file) 2018-07-30 22:47:33 +01:00
Godzil
67735fb52a Add a similar mechanism for episodes downloads.
If it can't fetch it after a couple of retry (5 by default, can be changed on the command line) it will just ignore it and go to the next episode.
2018-07-30 22:47:33 +01:00
Godzil
7d6f762f59 Add retry mechanism in case of episodes list retrieve failure instead of just failing.
If it can't after a couple of retry (5 by default, can be changed on the command line) it will just ignore it and go to the next anime.
2018-07-30 22:47:33 +01:00
Godzil
f3a0d0129d Correct a bug with ffmpeg where it will wait forever for the user to answer a question when trying to overwrite a file.
Fix #68
2018-07-30 22:47:33 +01:00
Godzil
65c9032839 Add an option to make ffmpeg, mkvmerge and rtmpdump running verbosely. 2018-07-30 22:47:33 +01:00
Godzil
978a3282a4 1.3.0 2018-07-30 22:47:33 +01:00
Manoël Trapier
9f0195bebc Update README.md 2018-07-30 22:47:33 +01:00
Manoël Trapier
ea20108222 Update README.md 2018-07-30 22:47:33 +01:00
Godzil
4ee814864c Add support for changing the batchfile on the command line 2018-07-30 22:47:33 +01:00
Godzil
4cbfd691c3 add missing package 2018-07-30 22:47:32 +01:00
Godzil
7c04fb7282 Make tslint happy! 2018-07-30 22:47:29 +01:00
Godzil
849c7612aa A bit of code reformating and add an option to regenerate the .crpersistant file in case it become corrupted and Crunchy try to redownload everything. 2018-07-30 22:46:29 +01:00
Roei Elisha
6ad4cbed0a make login work 2018-07-30 22:45:28 +01:00
Godzil
9e2f5401d0 Update tslint.json 2018-07-30 22:44:18 +01:00
Roei Elisha
b064b97f2d fix linter problems 2018-05-22 23:55:10 +03:00
Godzil
b248405437 1.2.2 2018-05-09 22:33:45 +01:00
Godzil
bf941819a8 remove unwwanted parameter 2018-05-09 22:31:50 +01:00
Godzil
fcae53baae Node 5, 6 and 7 seems to not like something. Delete them from Travis build 2018-05-08 21:50:58 +01:00
Godzil
05ead50c0d Let's try to make travis happy with older node version 2018-05-08 21:49:11 +01:00
Godzil
0a80f80f91 1.2.1 2018-05-08 21:37:43 +01:00
Godzil
3bf5fea735 Make Crunchy to properly return a return code when running fine or failing 2018-05-08 21:37:34 +01:00
Godzil
3a95994cc2 1.2.0 2018-03-29 22:33:15 +01:00
Godzil
a29870691b Update deps 2018-03-29 22:33:06 +01:00
Godzil
547fdc4aa0 Add a way to select the resolution. Use 1080p by default
Fix #58
2018-03-29 22:29:13 +01:00
20 changed files with 621 additions and 363 deletions

View File

@@ -1,9 +1,6 @@
language: node_js
sudo: false
node_js:
- 5
- 6
- 7
- 8
- 9
before_install:

View File

@@ -21,30 +21,39 @@ It is recommended to enable authentication (`-p` and `-u`) so your account permi
## 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).

10
bin/crunchy.sh Executable file
View 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

377
package-lock.json generated
View File

@@ -1,13 +1,25 @@
{
"name": "crunchy",
"version": "1.1.22",
"version": "1.3.1",
"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",
"integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A==",
"dev": true
},
"@types/cheerio": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.6.tgz",
"integrity": "sha512-Nyk3Gut4CMFZOebvutYAk/Nis7d6u9b7VX4OcG4zUX5gnKnXMiq+8EPdcX7FVakeL4+t770iy8E46W8ZSSXeFA==",
"version": "0.22.7",
"resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.7.tgz",
"integrity": "sha512-+T9qBbqe/jXtTjzVddArZExahoPPmt8eq3O1ZuCKZXjBVxf/ciUYNXrIDZJEVgYvpELnv6VlPRCfLzufRxpAag==",
"dev": true
},
"@types/form-data": {
@@ -19,6 +31,15 @@
"@types/node": "8.5.2"
}
},
"@types/fs-extra": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.2.tgz",
"integrity": "sha512-Q3FWsbdmkQd1ib11A4XNWQvRD//5KpPoGawA8aB2DR7pWKoW9XQv3+dGxD/Z1eVFze23Okdo27ZQytVFlweKvQ==",
"dev": true,
"requires": {
"@types/node": "8.5.2"
}
},
"@types/mkdirp": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz",
@@ -35,19 +56,37 @@
"dev": true
},
"@types/request": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.0.9.tgz",
"integrity": "sha512-IWq4Uhm7dShxPdnfbGtIv9ImhGFJ3HugoIfugUd+jt40Oxe6ZfWIEaHFvp4QmRNZVDj0G6dZfa+u0U0PF3bYpg==",
"version": "2.47.0",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.47.0.tgz",
"integrity": "sha512-/KXM5oev+nNCLIgBjkwbk8VqxmzI56woD4VUxn95O+YeQ8hJzcSmIZ1IN3WexiqBb6srzDo2bdMbsXxgXNkz5Q==",
"dev": true,
"requires": {
"@types/caseless": "0.12.1",
"@types/form-data": "2.2.1",
"@types/node": "8.5.2"
"@types/node": "8.5.2",
"@types/tough-cookie": "2.3.2"
}
},
"@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": "3.5.20",
"@types/request": "2.47.0"
}
},
"@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==",
"dev": true
},
"@types/xml2js": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.2.tgz",
"integrity": "sha512-8aKUBSj3oGcnuiBmDLm3BIk09RYg01mz9HlQ2u4aS17oJ25DxjQrEUVGFSBVNOfM45pQW4OjcBPplq6r/exJdA==",
"integrity": "sha1-pLhLOHn/1HEJU/2Syr/emopOhFY=",
"dev": true,
"requires": {
"@types/node": "8.5.2"
@@ -59,7 +98,7 @@
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"requires": {
"co": "4.6.0",
"fast-deep-equal": "1.0.0",
"fast-deep-equal": "1.1.0",
"fast-json-stable-stringify": "2.0.0",
"json-schema-traverse": "0.3.1"
}
@@ -76,6 +115,23 @@
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"requires": {
"sprintf-js": "1.0.3"
},
"dependencies": {
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
}
}
},
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
@@ -97,9 +153,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",
@@ -143,23 +199,20 @@
}
},
"big-integer": {
"version": "1.6.26",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.26.tgz",
"integrity": "sha1-OvFnL6Ytry1eyvrPblqg0l4Cwcg="
"version": "1.6.30",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.30.tgz",
"integrity": "sha512-LGDF7k/8yjS+GTbfFRGiSdcPnIwcjM6kQ0lmbja3tKJzVMmqHmUFnTuUOm/Lt2KVQ3mAZVupf9KNcsew0QV8Kw=="
},
"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.0"
}
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
@@ -182,32 +235,32 @@
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"chalk": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
"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.0",
"ansi-styles": "3.2.1",
"escape-string-regexp": "1.0.5",
"supports-color": "4.5.0"
"supports-color": "5.4.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "1.9.1"
}
},
"supports-color": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
"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": "2.0.0"
"has-flag": "3.0.0"
}
}
}
@@ -240,7 +293,7 @@
"resolved": "https://registry.npmjs.org/cloudscraper/-/cloudscraper-1.5.0.tgz",
"integrity": "sha512-bZagLhj59+N6Z6lD9zRksYu87GthLwXdKARULi4RZ6UVpotH39ruSFN3UQmw3uuqoj00iDxkGrapAvxeurmlQA==",
"requires": {
"request": "2.83.0"
"request": "2.87.0"
}
},
"co": {
@@ -270,17 +323,17 @@
"dev": true
},
"combined-stream": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"requires": {
"delayed-stream": "1.0.0"
}
},
"commander": {
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA=="
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
},
"concat-map": {
"version": "0.0.1",
@@ -293,24 +346,6 @@
"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.0"
}
}
}
},
"css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
@@ -404,6 +439,12 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"esprima": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
"dev": true
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
@@ -427,9 +468,9 @@
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"fast-deep-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
},
"fast-json-stable-stringify": {
"version": "2.0.0",
@@ -466,19 +507,19 @@
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
"integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
"requires": {
"asynckit": "0.4.0",
"combined-stream": "1.0.5",
"mime-types": "2.1.17"
"combined-stream": "1.0.6",
"mime-types": "2.1.18"
}
},
"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",
@@ -542,27 +583,11 @@
}
},
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"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.0",
"sntp": "2.1.0"
}
},
"hoek": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
},
"htmlparser2": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
@@ -583,7 +608,7 @@
"requires": {
"assert-plus": "1.0.0",
"jsprim": "1.4.1",
"sshpk": "1.13.1"
"sshpk": "1.14.1"
}
},
"inflight": {
@@ -622,6 +647,16 @@
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
"dev": true
},
"js-yaml": {
"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"
}
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
@@ -662,6 +697,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",
@@ -723,16 +763,16 @@
"integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0="
},
"mime-db": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
},
"mime-types": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
"version": "2.1.18",
"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.30.0"
"mime-db": "1.33.0"
}
},
"minimatch": {
@@ -814,6 +854,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",
@@ -825,9 +870,9 @@
"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",
@@ -844,32 +889,49 @@
}
},
"request": {
"version": "2.83.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
"integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
"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",
"aws4": "1.7.0",
"caseless": "0.12.0",
"combined-stream": "1.0.5",
"combined-stream": "1.0.6",
"extend": "3.0.1",
"forever-agent": "0.6.1",
"form-data": "2.3.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.17",
"mime-types": "2.1.18",
"oauth-sign": "0.8.2",
"performance-now": "2.1.0",
"qs": "6.5.1",
"qs": "6.5.2",
"safe-buffer": "5.1.1",
"stringstream": "0.0.5",
"tough-cookie": "2.3.3",
"tough-cookie": "2.3.4",
"tunnel-agent": "0.6.0",
"uuid": "3.1.0"
"uuid": "3.2.1"
}
},
"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.1",
"request-promise-core": "1.1.1",
"stealthy-require": "1.1.1",
"tough-cookie": "2.3.4"
}
},
"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.17.10"
}
},
"resolve": {
@@ -892,19 +954,11 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"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.0"
}
},
"sprintf-js": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
@@ -912,9 +966,9 @@
"dev": true
},
"sshpk": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
"version": "1.14.1",
"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",
@@ -932,6 +986,11 @@
"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",
@@ -940,11 +999,6 @@
"safe-buffer": "5.1.1"
}
},
"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",
@@ -961,9 +1015,9 @@
"dev": true
},
"tough-cookie": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
"requires": {
"punycode": "1.4.1"
}
@@ -999,45 +1053,46 @@
}
},
"tslib": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.1.tgz",
"integrity": "sha1-aUavLR1lGnsYY7Ux1uWvpBqkTqw=",
"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.8.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz",
"integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=",
"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.0",
"commander": "2.12.2",
"diff": "3.4.0",
"chalk": "2.4.1",
"commander": "2.15.1",
"diff": "3.5.0",
"glob": "7.1.2",
"js-yaml": "3.12.0",
"minimatch": "3.0.4",
"resolve": "1.4.0",
"semver": "5.4.1",
"tslib": "1.8.1",
"tsutils": "2.14.0"
"semver": "5.5.0",
"tslib": "1.9.2",
"tsutils": "2.27.1"
},
"dependencies": {
"diff": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz",
"integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==",
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
}
}
},
"tsutils": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.14.0.tgz",
"integrity": "sha512-f6axSMV0RoUufiKiRQgmRlN1c+Ag+mDaZjcd6bHdvplT/zyhuMCGqw3pJS8s3+0x4EVkdoQajs9PchdDZlguvw==",
"version": "2.27.1",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz",
"integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==",
"dev": true,
"requires": {
"tslib": "1.8.1"
"tslib": "1.9.2"
}
},
"tunnel-agent": {
@@ -1055,9 +1110,9 @@
"optional": true
},
"typescript": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz",
"integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=",
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.1.tgz",
"integrity": "sha512-h6pM2f/GDchCFlldnriOhs1QHuwbnmj6/v7499eMHqPeW4V2G0elua2eIc2nu8v2NdHV0Gm+tzX83Hr6nUFjQA==",
"dev": true
},
"underscore.string": {
@@ -1081,9 +1136,9 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA=="
},
"verror": {
"version": "1.10.0",

View File

@@ -15,33 +15,41 @@
"engines": {
"node": ">=5.0"
},
"version": "1.1.22",
"version": "1.3.1",
"bin": {
"crunchy": "./bin/crunchy"
"crunchy": "./bin/crunchy",
"crunchy.sh": "./bin/crunchy.sh"
},
"dependencies": {
"big-integer": "^1.4.4",
"big-integer": "^1.6.30",
"bluebird": "^3.5.1",
"cheerio": "^0.22.0",
"cloudscraper": "^1.5.0",
"commander": "^2.12.2",
"fs-extra": "^5.0.0",
"commander": "^2.15.1",
"fs-extra": "^6.0.1",
"mkdirp": "^0.5.0",
"request": "^2.74.0",
"pjson": "^1.0.9",
"request": "^2.87.0",
"request-promise": "^4.2.2",
"xml2js": "^0.4.5"
},
"devDependencies": {
"@types/cheerio": "^0.22.6",
"@types/bluebird": "^3.5.20",
"@types/cheerio": "^0.22.7",
"@types/fs-extra": "^5.0.2",
"@types/mkdirp": "^0.5.2",
"@types/request": "^2.0.9",
"@types/request": "^2.47.0",
"@types/request-promise": "^4.1.41",
"@types/xml2js": "^0.4.2",
"tsconfig-lint": "^0.12.0",
"tslint": "^5.8.0",
"typescript": "^2.6.2"
"tslint": "^5.10.0",
"typescript": "^2.9.1"
},
"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": {

View File

@@ -2,39 +2,87 @@
import commander = require('commander');
import fs = require('fs');
import path = require('path');
import log = require('./log');
import series from './series';
/* correspondances between resolution and value CR excpect */
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'},
};
/**
* Streams the batch of series to disk.
*/
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);
tasks(config, batchPath, (err, tasks) =>
// set resolution
if (config.resolution)
{
try
{
config.video_format = resol_table[config.resolution].format;
config.video_quality = resol_table[config.resolution].quality;
}
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;
}
}
else
{
/* 1080 by default */
config.video_format = resol_table['1080'].format;
config.video_quality = resol_table['1080'].quality;
}
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) =>
series(tasksArr[i].config, tasksArr[i].address, (errin) =>
{
if (errin)
{
return done(errin);
if (tasksArr[i].retry <= 0)
{
console.error(err.stack || err);
log.error('Cannot get episodes from "' + tasksArr[i].address + '", please rerun later');
}
else
{
if (config.verbose)
{
console.error(err.stack || err);
}
log.warn('Retrying to fetch episodes ' + tasksArr[i].retry + ' / ' + config.retry);
tasksArr[i].retry -= 1;
}
}
else
{
i += 1;
}
i += 1;
next();
});
})();
@@ -86,7 +134,7 @@ function tasks(config: IConfigLine, batchPath: string, done: (err: Error, tasks?
return done(null, config.args.map((addressIn) =>
{
return {address: addressIn, config: configIn};
return {address: addressIn, config: configIn, retry: config.retry};
}));
}
@@ -122,7 +170,7 @@ function tasks(config: IConfigLine, batchPath: string, done: (err: Error, tasks?
return;
}
map.push({address: addressIn, config: lineConfig});
map.push({address: addressIn, config: lineConfig, retry: config.retry});
});
});
done(null, map);
@@ -150,6 +198,12 @@ function parse(args: string[]): IConfigLine
.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('-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('--retry <i>', 'Number or time to retry fetching an episode. Default: 5', 5)
.parse(args);
}

View File

@@ -1,10 +1,34 @@
'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);
process.exit(-1);
}
console.info('Done!');
process.exit(0);
});

View File

@@ -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
@@ -94,6 +102,12 @@ function download(config: IConfig, page: IEpisodePage, player: IEpisodePlayer, d
log.warn('Renaming to \'' + fileName + '\'...');
}
if (config.rebuildcrp)
{
log.warn('Ignoring \'' + fileName + '\' as it does not exist...');
return done(null, true);
}
mkdirp(path.dirname(filePath), (errM: Error) =>
{
if (errM)
@@ -128,7 +142,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)
{
@@ -185,11 +199,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);
}
/**
@@ -258,7 +272,7 @@ 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 (!swf || !data)
@@ -303,7 +317,12 @@ function scrapePlayer(config: IConfig, address: string, id: number, done: (err:
}
my_request.post(config, {
form: {current_page: address},
form: {
current_page: address,
video_format: config.video_format,
video_quality: config.video_quality,
media_id: id
},
url: url[1] + '/xml/?req=RpcApiVideoPlayer_GetStandardConfig&media_id=' + id,
}, (err, result) =>
{
@@ -328,9 +347,9 @@ function scrapePlayer(config: IConfig, address: string, id: number, done: (err:
let streamMode = 'RTMP';
if (player['default:preload'].stream_info.host === '')
{
streamMode = 'HLS';
}
{
streamMode = 'HLS';
}
done(null, {
subtitle: isSubtitled ? {

View File

@@ -14,4 +14,11 @@ interface IConfig {
series?: string;
filename?: string;
tag?: string;
resolution?: string;
video_format?: string;
video_quality?: string;
rebuildcrp?: boolean;
batch?: string;
verbose?: boolean;
retry?: number;
}

View File

@@ -1,4 +1,5 @@
interface IConfigTask {
address: string;
config: IConfigLine;
retry: number;
}

4
src/interface/IResolData.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
interface IResolData {
quality: string;
format: string;
}

View File

@@ -2,4 +2,5 @@ interface ISeriesEpisode {
address: string;
episode: string;
volume: number;
retry: number;
}

View File

@@ -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));
});
});
@@ -73,107 +132,70 @@ function authenticate(config: IConfig, done: (err: Error) => void)
return done(null);
}
/* Bypass the login page and send a login request directly */
let options =
startSession()
.then((sessionId: string) =>
{
headers: defaultHeaders,
jar: true,
gzip: false,
method: 'GET',
url: 'https://www.crunchyroll.com/login'
};
cloudscraper.request(options, (err: Error, rep: string, body: string) =>
defaultHeaders.Cookie = `sess_id=${sessionId}; c_locale=enUS`;
return login(sessionId, config.user, config.pass);
})
.then((userData) =>
{
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 =
/**
* 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();
return done(new Error('Authentication failed: ' + error));
}
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 +210,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
};
}

View File

@@ -2,7 +2,7 @@
import cheerio = require('cheerio');
import episode from './episode';
import fs = require('fs');
const fse = require('fs-extra');
import fse = require('fs-extra');
import my_request = require('./my_request');
import path = require('path');
import url = require('url');
@@ -56,27 +56,45 @@ export default function(config: IConfig, address: string, done: (err: Error) =>
{
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)
console.error(err.stack || err);
log.error('Cannot fetch episode "s' + page.episodes[i].volume + 'e' + page.episodes[i].episode +
'", please rerun later');
}
else
{
if (config.verbose)
{
return done(errW);
console.error(errD.stack || errD);
}
i += 1;
next();
});
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();
}
}
});
})();
@@ -152,8 +170,9 @@ function page(config: IConfig, address: string, done: (err: Error, result?: ISer
address: address.substr(1),
episode: '',
volume: 0,
retry: config.retry,
});
done(null, {episodes: episodes.reverse(), series: ""});
done(null, {episodes: episodes.reverse(), series: ''});
}
else
{
@@ -191,11 +210,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});
});

View File

@@ -33,10 +33,10 @@ export default function(input: string|Buffer, done: (err: Error, subtitle?: stri
*/
function event(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 + ',' +
@@ -70,13 +70,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 + ',' +

View File

@@ -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;

View File

@@ -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);
}
}
/**

View File

@@ -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') + '"';

View File

@@ -1,10 +1,14 @@
{
"target": "es6",
"compilerOptions": {
"declaration": true,
"noImplicitAny": true,
"removeComments": false,
"module": "commonjs",
"outDir": "dist",
"sourceMap": true
"sourceMap": true,
"lib": [
"es2015"
]
}
}

View File

@@ -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
}
}