9 Commits
1.1.0 ... 1.1.2

Author SHA1 Message Date
Roel van Uden
887b3ed094 Bump the version 2015-03-06 22:22:53 +01:00
Roel van Uden
49e3290f28 Fixing the README while I'm at it 2015-03-06 22:17:45 +01:00
Roel van Uden
5d32d91d7d #5: Enable merging subtitle-less. 2015-03-06 22:12:03 +01:00
Roel van Uden
2f1858cde7 #5: Support subtitle-less videos 2015-03-06 21:58:31 +01:00
Roel van Uden
a98ed223c6 #5: Support drama videos in regex 2015-03-06 21:50:31 +01:00
Roel van Uden
575569bd91 #4: Support spaces in Windows path 2015-03-06 21:41:02 +01:00
Roel van Uden
44a66286cb Major update of README.md 2015-02-28 13:48:02 +01:00
Roel van Uden
eb7de600c1 Update typing dependencies. 2015-02-28 13:28:59 +01:00
Roel van Uden
d2e8a4c02e Update ts.js 2015-02-07 13:29:10 +01:00
8 changed files with 126 additions and 71 deletions

150
README.md
View File

@@ -1,69 +1,121 @@
# CrunchyRoll.js
*CrunchyRoll.js* 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.
*CrunchyRoll.js* 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.
## Motivation
*CrunchyRoll* has been providing an amazing streaming service and offers the
best way to enjoy *anime* in a *convenient* and *legal* way. As a streaming
service, video files cannot be downloaded and watched offline. Understandable
from a business perspective and considering possible contract implications, but
annoying for users. This application enables episodes to be downloaded for
offline convenience. Please do not abuse this application; download episodes for
**personal use** and **delete them** if you do not have an active premium
account. Continue to support *CrunchyRoll*; without our financial backing their
service cannot exist!
*CrunchyRoll* has been providing an amazing streaming service and offers the best way to enjoy *anime* in a *convenient* and *legal* way. As a streaming service, video files cannot be downloaded and watched offline. Understandable from a business perspective and considering possible contract implications, but annoying for users. This application enables episodes to be downloaded for offline convenience. Please do not abuse this application; download episodes for **personal use** and **delete them** if you do not have an active premium account. Continue to support *CrunchyRoll*; without our financial backing their service cannot exist!
## Legal Warning
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.
## Status
### Implemented
* Subtitle decoding.
* Subtitle converter for SRT subtitle output.
* Video streaming.
* Episode page scraping with subtitle saving and video streaming.
* Add ASS support.
* Add muxing (MP4+ASS=MKV).
* Add series API to save an entire series rather than per-episode.
* Add support for incremental saves.
* Add batch-mode to queue a bunch of series.
* Add CLI interface with all the options.
* Support scheduled merging; if it fails now, the video is probably being watched.
* Add authentication to the entire stack to support premium content.
* Binary runner for `npm`
* Windows examples with a .bat for ease of use.
* Publish to `npm` with a fixed package.json.
* Conversion to beautiful TypeScript 1.4 code.
### Pending Implementation
* Documentation.
* Enjoy beautiful anime series from disk when internet is down.
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.
## Configuration
Set defaults in https://www.crunchyroll.com/acct/?action=video. We'll use that.
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.
## Prerequisites
* NodeJS >= 0.12.x (http://nodejs.org/)
* NPM >= 2.5.x (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)
1. Run in *Terminal*: `sudo apt-get install nodejs npm mkvtoolnix rtmpdump`
2. Run in *Terminal*: `sudo ln -s /usr/bin/nodejs /usr/bin/node`
3. Run in *Terminal*: `sudo npm install -g crunchyroll`
### Mac OS X
1. Install *Homebrew* following the instructions at http://brew.sh/
2. Run in *Terminal*: `brew install node mkvtoolnix rtmpdump`
3. Run in *Terminal*: `npm install -g crunchyroll`
### Windows
1. Install *NodeJS* following the instructions at http://nodejs.org/
3. Run in *Command Prompt*: `npm install -g crunchyroll`
## Instructions
Use the applicable instructions for the interface of your choice (currently limited to command-line).
### Command-line Interface (`crunchyroll`)
The [command-line interface](http://en.wikipedia.org/wiki/Command-line_interface) does not have a graphical component and is ideal for automation purposes and headless machines. The interface can run using a sequence of series addresses (the site address containing the episode listing), or with a batch-mode source file. The `crunchyroll --help` command will produce the following output:
Usage: crunchyroll [options]
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)
#### 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.
#### Examples
Download in batch-mode:
crunchyroll
Download *Fairy Tail* to the current work directory:
crunchyroll http://www.crunchyroll.com/fairy-tail
Download *Fairy Tail* to `C:\Anime`:
crunchyroll --output C:\Anime http://www.crunchyroll.com/fairy-tail
#### Switches
##### Authentication
* `-p or --pass <s>` sets the password.
* `-u or --user <s>` sets the e-mail address or username.
##### Disables
* `-c or --cache` disables the cache.
* `-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
* `-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)
## Developers
More information will be added at a later point. For now the recommendations are:
* Visual Studio 2013 Update 4 (Core)
* NodeJS Tools (Debugging)
* TypeScript 1.4 (Language)
* ReSharper 9.0+ (Hints/Formatting)
* Web Essentials (TSLint)
## Work In Progress
Open an issue or e-mail me directly. I'd be happy to answer your questions.
Since this project uses TypeScript, compile with `node ts` or `npm install`.

View File

@@ -11,7 +11,7 @@
"type": "git",
"url": "git://github.com/Deathspike/crunchyroll.js.git"
},
"version": "1.1.0",
"version": "1.1.2",
"bin": {
"crunchyroll": "./bin/crunchyroll"
},
@@ -33,4 +33,4 @@
"test": "node ts --only-test",
"tsd": "./node_modules/.bin/tsd reinstall --overwrite"
}
}
}

View File

@@ -51,7 +51,8 @@ function download(config: typings.IConfig, page: typings.IEpisodePage, player: t
downloadVideo(config, page, player, filePath, err => {
if (err) return done(err);
if (config.merge) return complete('Finished ' + fileName, now, done);
video.merge(config, player.video.file, filePath, err => {
var isSubtited = Boolean(player.subtitle);
video.merge(config, isSubtited, player.video.file, filePath, err => {
if (err) return done(err);
complete('Finished ' + fileName, now, done);
});
@@ -63,8 +64,9 @@ function download(config: typings.IConfig, page: typings.IEpisodePage, player: t
/**
* Saves the subtitles to disk.
*/
function downloadSubtitle(config: typings.IConfig, player: typings.IEpisodePlayer, filePath: string, done: (err: Error) => void) {
function downloadSubtitle(config: typings.IConfig, player: typings.IEpisodePlayer, filePath: string, done: (err?: Error) => void) {
var enc = player.subtitle;
if (!enc) return done();
subtitle.decode(enc.id, enc.iv, enc.data, (err, data) => {
if (err) return done(err);
var formats = subtitle.formats;
@@ -121,7 +123,7 @@ function scrapePage(config: typings.IConfig, address: string, done: (err: Error,
if (err) return done(err);
var $ = cheerio.load(result);
var swf = /^([^?]+)/.exec($('link[rel=video_src]').attr('href'));
var regexp = /Watch\s+(.+?)(?:\s+Season\s+([0-9]+))?\s+Episode\s+([0-9]+)/;
var regexp = /-\s+(?:Watch\s+)?(.+?)(?:\s+Season\s+([0-9]+))?(?:\s+-)?\s+Episode\s+([0-9]+)/;
var data = regexp.exec($('title').text());
if (!swf || !data) return done(new Error('Invalid page.'));
done(null, {
@@ -151,12 +153,13 @@ function scrapePlayer(config: typings.IConfig, address: string, id: number, done
}, (err: Error, player: typings.IEpisodePlayerConfig) => {
if (err) return done(err);
try {
var isSubtitled = Boolean(player['default:preload'].subtitle);
done(null, {
subtitle: {
subtitle: isSubtitled ? {
id: parseInt(player['default:preload'].subtitle.$.id, 10),
iv: player['default:preload'].subtitle.iv,
data: player['default:preload'].subtitle.data
},
} : null,
video: {
file: player['default:preload'].stream_info.file,
host: player['default:preload'].stream_info.host

View File

@@ -33,7 +33,7 @@ export interface IEpisodePage {
}
export interface IEpisodePlayer {
subtitle: {
subtitle?: {
id: number;
iv: string;
data: string;

View File

@@ -10,13 +10,13 @@ import typings = require('../typings');
/**
* Merges the subtitle and video files into a Matroska Multimedia Container.
*/
function main(config: typings.IConfig, rtmpInputPath: string, filePath: string, done: (err: Error) => void) {
function main(config: typings.IConfig, isSubtitled: boolean, rtmpInputPath: string, filePath: string, done: (err: Error) => void) {
var subtitlePath = filePath + '.' + (subtitle.formats[config.format] ? config.format : 'ass');
var videoPath = filePath + path.extname(rtmpInputPath);
childProcess.exec(command() + ' ' +
'-o "' + filePath + '.mkv" ' +
'"' + videoPath + '" ' +
'"' + subtitlePath + '"', {
(isSubtitled ? '"' + subtitlePath + '"' : ''), {
maxBuffer: Infinity
}, err => {
if (err) return done(err);
@@ -32,7 +32,7 @@ function main(config: typings.IConfig, rtmpInputPath: string, filePath: string,
*/
function command(): string {
if (os.platform() !== 'win32') return 'mkvmerge';
return path.join(__dirname, '../../bin/mkvmerge.exe');
return '"' + path.join(__dirname, '../../bin/mkvmerge.exe') + '"';
}
/**

View File

@@ -22,5 +22,5 @@ function main(rtmpUrl: string, rtmpInputPath: string, swfUrl: string, filePath:
*/
function command(): string {
if (os.platform() !== 'win32') return 'rtmpdump';
return path.join(__dirname, '../../bin/rtmpdump.exe');
return '"' + path.join(__dirname, '../../bin/rtmpdump.exe') + '"';
}

4
ts.js
View File

@@ -48,7 +48,7 @@ function clean(filePaths, done) {
* @param {function(Error)} done
*/
function compile(filePaths, done) {
if (isTest) return done(null);
if (isTest) return done(null);
var execPath = path.join(__dirname, 'node_modules/.bin/tsc');
var options = '--declaration --module CommonJS --noImplicitAny --outDir dist';
childProcess.exec([execPath, options].concat(filePaths).join(' '), function(err, stdout) {
@@ -89,4 +89,4 @@ function read(done) {
var filePaths = [];
while ((matches = expression.exec(contents))) filePaths.push(matches[1]);
done(null, filePaths);
}
}

View File

@@ -6,28 +6,28 @@
"bundle": "typings/tsd.d.ts",
"installed": {
"node/node.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
},
"commander/commander.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
},
"xml2js/xml2js.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
},
"cheerio/cheerio.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
},
"mkdirp/mkdirp.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
},
"request/request.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
},
"big-integer/big-integer.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
},
"form-data/form-data.d.ts": {
"commit": "42c8a3b74c05f6887ce21dd63c6234e424f9f8fe"
"commit": "3882d337bb0808cde9fe4c08012508a48c135482"
}
}
}