Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a80f80f91 | ||
|
|
3bf5fea735 | ||
|
|
3a95994cc2 | ||
|
|
a29870691b | ||
|
|
547fdc4aa0 | ||
|
|
c78552795f | ||
|
|
090c7e4789 | ||
|
|
bf8e1fe80f | ||
|
|
7344ce3d61 | ||
|
|
c642e76cce | ||
|
|
8ef27066f6 | ||
|
|
621df26b58 | ||
|
|
8060b1b73b | ||
|
|
11f6b3feff | ||
|
|
537639f2a8 | ||
|
|
813f8a997d |
@@ -3,9 +3,11 @@ sudo: false
|
||||
node_js:
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
- 8
|
||||
- 9
|
||||
before_install:
|
||||
- npm install --only=dev
|
||||
script:
|
||||
- npm run types
|
||||
- npm run compile
|
||||
- npm run build
|
||||
- npm test
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Crunchy: a fork of Deathspike/CrunchyRoll.js
|
||||
|
||||
[](http://issuestats.com/github/Godzil/Crunchy) [](https://travis-ci.org/Godzil/Crunchy)
|
||||
[](http://issuestats.com/github/Godzil/Crunchy) [](https://travis-ci.org/Godzil/Crunchy) [](https://codeclimate.com/github/Godzil/Crunchy/maintainability)
|
||||
|
||||
*Crunchy* is capable of downloading *anime* episodes from the popular *CrunchyRoll* streaming service. An episode is stored in the original video format (often H.264 in a MP4 container) and the configured subtitle format (ASS or SRT).The two output files are then merged into a single MKV file.
|
||||
|
||||
|
||||
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 -u ${PARAMS}
|
||||
if [ $? == 0 ]; then
|
||||
break
|
||||
fi
|
||||
echo "Going to retry..."
|
||||
sleep 3
|
||||
done
|
||||
1812
package-lock.json
generated
1812
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@@ -15,31 +15,34 @@
|
||||
"engines": {
|
||||
"node": ">=5.0"
|
||||
},
|
||||
"version": "1.1.20",
|
||||
"version": "1.2.1",
|
||||
"bin": {
|
||||
"crunchy": "./bin/crunchy"
|
||||
"crunchy": "./bin/crunchy",
|
||||
"crunchy.sh": "./bin/crunchy.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"big-integer": "^1.4.4",
|
||||
"big-integer": "^1.6.27",
|
||||
"cheerio": "^0.22.0",
|
||||
"cloudscraper": "^1.4.1",
|
||||
"commander": "^2.6.0",
|
||||
"fs-extra": "^2.0.0",
|
||||
"cloudscraper": "^1.5.0",
|
||||
"commander": "^2.15.1",
|
||||
"fs-extra": "^5.0.0",
|
||||
"mkdirp": "^0.5.0",
|
||||
"request": "^2.74.0",
|
||||
"request": "^2.85.0",
|
||||
"xml2js": "^0.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cheerio": "^0.22.7",
|
||||
"@types/mkdirp": "^0.5.2",
|
||||
"@types/request": "^2.47.0",
|
||||
"@types/xml2js": "^0.4.2",
|
||||
"tsconfig-lint": "^0.12.0",
|
||||
"tslint": "^4.4.2",
|
||||
"typescript": "^2.2.0",
|
||||
"typings": "^2.1.0"
|
||||
"tslint": "^5.9.1",
|
||||
"typescript": "^2.8.1"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "npm run types && tsc",
|
||||
"compile": "tsc",
|
||||
"prepublishOnly": "npm run build",
|
||||
"build": "tsc",
|
||||
"test": "tslint -c ./tslint.json --project ./tsconfig.json ./src/**/*.ts",
|
||||
"types": "typings install",
|
||||
"start": "node ./bin/crunchy"
|
||||
},
|
||||
"bugs": {
|
||||
|
||||
32
src/batch.ts
32
src/batch.ts
@@ -3,6 +3,15 @@ import commander = require('commander');
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
import series from './series';
|
||||
import log = require('./log');
|
||||
|
||||
/* 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'},
|
||||
};
|
||||
|
||||
/**
|
||||
* Streams the batch of series to disk.
|
||||
@@ -12,6 +21,28 @@ export default function(args: string[], done: (err?: Error) => void)
|
||||
const config = parse(args);
|
||||
const batchPath = path.join(config.output || process.cwd(), 'CrunchyRoll.txt');
|
||||
|
||||
// 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, tasks) =>
|
||||
{
|
||||
if (err)
|
||||
@@ -151,5 +182,6 @@ function parse(args: string[]): IConfigLine
|
||||
.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))')
|
||||
.parse(args);
|
||||
}
|
||||
|
||||
@@ -6,5 +6,8 @@ batch(process.argv, (err: any) =>
|
||||
if (err)
|
||||
{
|
||||
console.error(err.stack || err);
|
||||
process.exit(-1)
|
||||
}
|
||||
console.info("Done!")
|
||||
process.exit(0)
|
||||
});
|
||||
|
||||
@@ -303,7 +303,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 +333,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 ? {
|
||||
|
||||
3
src/interface/IConfig.d.ts
vendored
3
src/interface/IConfig.d.ts
vendored
@@ -14,4 +14,7 @@ interface IConfig {
|
||||
series?: string;
|
||||
filename?: string;
|
||||
tag?: string;
|
||||
resolution?: string;
|
||||
video_format?: string;
|
||||
video_quality?: string;
|
||||
}
|
||||
|
||||
4
src/interface/IResolData.d.ts
vendored
Normal file
4
src/interface/IResolData.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
interface IResolData {
|
||||
quality: string;
|
||||
format: string;
|
||||
}
|
||||
@@ -9,8 +9,10 @@ let isPremium = false;
|
||||
|
||||
const defaultHeaders: request.Headers =
|
||||
{
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
|
||||
'Connection': 'keep-alive'
|
||||
'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'
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -99,9 +101,9 @@ function authenticate(config: IConfig, done: (err: Error) => void)
|
||||
headers: defaultHeaders,
|
||||
form:
|
||||
{
|
||||
'login_form[redirect_url]': '/',
|
||||
'login_form[name]': config.user,
|
||||
'login_form[password]': config.pass,
|
||||
'login_form[redirect_url]': '/',
|
||||
'login_form[_token]': token
|
||||
},
|
||||
jar: true,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/* tslint:disable:no-bitwise false */
|
||||
'use strict';
|
||||
import crypto = require('crypto');
|
||||
import bigInt = require('big-integer');
|
||||
import crypto = require('crypto');
|
||||
import zlib = require('zlib');
|
||||
|
||||
/**
|
||||
* Decodes the data.
|
||||
*/
|
||||
export default function(id: number, iv: Buffer|string, data: Buffer|string,
|
||||
done: (err?: Error, result?: Buffer) => void)
|
||||
export default function(id: number, iv: Buffer|string, data: Buffer|string,
|
||||
done: (err?: Error, result?: Buffer) => void)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
'use strict';
|
||||
import childProcess = require('child_process');
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
import os = require('os');
|
||||
import path = require('path');
|
||||
|
||||
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)
|
||||
export default function(config: IConfig, isSubtitled: boolean, rtmpInputPath: string, filePath: string,
|
||||
streamMode: string, done: (err: Error) => void)
|
||||
{
|
||||
const subtitlePath = filePath + '.' + (subtitle.formats[config.format] ? config.format : 'ass');
|
||||
let videoPath = filePath;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
import childProcess = require('child_process');
|
||||
import path = require('path');
|
||||
import os = require('os');
|
||||
import path = require('path');
|
||||
|
||||
import log = require('../log');
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,46 +1,10 @@
|
||||
{
|
||||
"version": "1.5.1-beta",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"noImplicitAny": true,
|
||||
"removeComments": false,
|
||||
"module": "commonjs",
|
||||
"outDir": "dist",
|
||||
"sourceMap": true,
|
||||
"target": "es5"
|
||||
},
|
||||
"filesGlob": [
|
||||
"src/**/*.ts",
|
||||
"typings/**/*.ts"
|
||||
],
|
||||
"files": [
|
||||
"src/batch.ts",
|
||||
"src/cli.ts",
|
||||
"src/episode.ts",
|
||||
"src/index.ts",
|
||||
"src/log.ts",
|
||||
"src/interface/IConfig.d.ts",
|
||||
"src/interface/IConfigLine.d.ts",
|
||||
"src/interface/IConfigTask.d.ts",
|
||||
"src/interface/IEpisodePage.d.ts",
|
||||
"src/interface/IEpisodePlayer.d.ts",
|
||||
"src/interface/IEpisodePlayerConfig.d.ts",
|
||||
"src/interface/IFormatterTable.d.ts",
|
||||
"src/interface/ISeries.d.ts",
|
||||
"src/interface/ISeriesEpisode.d.ts",
|
||||
"src/interface/ISubtitle.d.ts",
|
||||
"src/interface/ISubtitleEvent.d.ts",
|
||||
"src/interface/ISubtitleStyle.d.ts",
|
||||
"src/my_request.ts",
|
||||
"src/series.ts",
|
||||
"src/subtitle/decode.ts",
|
||||
"src/subtitle/formats/ass.ts",
|
||||
"src/subtitle/formats/index.ts",
|
||||
"src/subtitle/formats/srt.ts",
|
||||
"src/subtitle/index.ts",
|
||||
"src/video/index.ts",
|
||||
"src/video/merge.ts",
|
||||
"src/video/stream.ts",
|
||||
"typings/index.d.ts"
|
||||
]
|
||||
"sourceMap": true
|
||||
}
|
||||
}
|
||||
|
||||
13
typings.json
13
typings.json
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "crunchy",
|
||||
"globalDependencies": {
|
||||
"node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
|
||||
"commander": "github:DefinitelyTyped/DefinitelyTyped/commander/commander.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
|
||||
"xml2js": "github:DefinitelyTyped/DefinitelyTyped/xml2js/xml2js.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
|
||||
"cheerio": "github:DefinitelyTyped/DefinitelyTyped/cheerio/cheerio.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
|
||||
"mkdirp": "github:DefinitelyTyped/DefinitelyTyped/mkdirp/mkdirp.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
|
||||
"request": "github:DefinitelyTyped/DefinitelyTyped/request/request.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
|
||||
"big-integer": "github:DefinitelyTyped/DefinitelyTyped/big-integer/big-integer.d.ts#3882d337bb0808cde9fe4c08012508a48c135482",
|
||||
"form-data": "github:DefinitelyTyped/DefinitelyTyped/form-data/form-data.d.ts#3882d337bb0808cde9fe4c08012508a48c135482"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user