Add authentication.
This commit is contained in:
parent
17b5c8414c
commit
fd9ef59145
10
README.md
10
README.md
@ -40,12 +40,20 @@ prior to using this application.
|
||||
* 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.
|
||||
|
||||
### Pending Implementation
|
||||
|
||||
* Add authentication to the entire stack to support premium content.
|
||||
* Binary runner for `npm`
|
||||
* Windows examples with a .bat for ease of use.
|
||||
* Documentation.
|
||||
* Publish to `npm` with a fixed package.json.
|
||||
* Enjoy beautiful anime series from disk when internet is down.
|
||||
|
||||
## Configuration
|
||||
|
||||
Set defaults in https://www.crunchyroll.com/acct/?action=video. We'll use that.
|
||||
|
||||
## Work In Progress
|
||||
|
||||
Open an issue or e-mail me directly. I'd be happy to answer your questions.
|
||||
|
||||
@ -91,6 +91,9 @@ function _parse(args) {
|
||||
.option('-m, --merge', 'Disables merging subtitles and videos.')
|
||||
// Filters
|
||||
.option('-e, --episode <i>', 'The episode filter.')
|
||||
// Authentication
|
||||
.option('-p, --pass <s>', 'The password.')
|
||||
.option('-u, --user <s>', 'The e-mail address or username.')
|
||||
// Settings
|
||||
.option('-f, --format <s>', 'The subtitle format. (Default: ass)')
|
||||
.option('-o, --output <s>', 'The output path.')
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
var cheerio = require('cheerio');
|
||||
var fs = require('fs');
|
||||
var mkdirp = require('mkdirp');
|
||||
var request = require('request');
|
||||
var request = require('./request');
|
||||
var path = require('path');
|
||||
var subtitle = require('./subtitle');
|
||||
var video = require('./video');
|
||||
@ -15,9 +15,9 @@ var xml2js = require('xml2js');
|
||||
* @param {function(Error)} done
|
||||
*/
|
||||
module.exports = function (config, address, done) {
|
||||
_page(address, function(err, page) {
|
||||
_page(config, address, function(err, page) {
|
||||
if (err) return done(err);
|
||||
_player(address, page.id, function(err, player) {
|
||||
_player(config, address, page.id, function(err, player) {
|
||||
if (err) return done(err);
|
||||
_download(config, page, player, done);
|
||||
});
|
||||
@ -87,13 +87,14 @@ function _name(config, page, series, tag) {
|
||||
/**
|
||||
* Requests the page data and scrapes the id, episode, series and swf.
|
||||
* @private
|
||||
* @param {Object} config
|
||||
* @param {string} address
|
||||
* @param {function(Error, Object=)} done
|
||||
*/
|
||||
function _page(address, done) {
|
||||
function _page(config, address, done) {
|
||||
var id = parseInt((address.match(/[0-9]+$/) || [0])[0], 10);
|
||||
if (!id) return done(new Error('Invalid address.'));
|
||||
request.get(address, function(err, res, body) {
|
||||
request.get(config, address, function(err, res, body) {
|
||||
if (err) return done(err);
|
||||
var $ = cheerio.load(body);
|
||||
var swf = /^([^?]+)/.exec($('link[rel=video_src]').attr('href'));
|
||||
@ -124,14 +125,15 @@ function _prefix(value, length) {
|
||||
/**
|
||||
* Requests the player data and scrapes the subtitle and video data.
|
||||
* @private
|
||||
* @param {Object} config
|
||||
* @param {string} address
|
||||
* @param {number} id
|
||||
* @param {function(Error, Object=)} done
|
||||
*/
|
||||
function _player(address, id, done) {
|
||||
function _player(config, address, id, done) {
|
||||
var url = address.match(/^(https?:\/\/[^\/]+)/);
|
||||
if (!url) return done(new Error('Invalid address.'));
|
||||
request.post({
|
||||
request.post(config, {
|
||||
form: {current_page: address},
|
||||
url: url[1] + '/xml/?req=RpcApiVideoPlayer_GetStandardConfig&media_id=' + id
|
||||
}, function(err, res, xml) {
|
||||
|
||||
63
src/request.js
Normal file
63
src/request.js
Normal file
@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
var isAuthenticated = false;
|
||||
var request = require('request');
|
||||
|
||||
/**
|
||||
* Performs a GET request for the resource.
|
||||
* @param {Object} config
|
||||
* @param {(string|Object)} options
|
||||
* @param {function(Error, Object, string)} done
|
||||
*/
|
||||
module.exports.get = function(config, options, done) {
|
||||
_authenticate(config, function(err) {
|
||||
if (err) return done(err);
|
||||
request.get(_modify(options), done);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a POST request for the resource.
|
||||
* @param {Object} config
|
||||
* @param {(string|Object)} options
|
||||
* @param {function(Error, Object, string)} done
|
||||
*/
|
||||
module.exports.post = function(config, options, done) {
|
||||
_authenticate(config, function(err) {
|
||||
if (err) return done(err);
|
||||
request.post(_modify(options), done);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Authenticates using the configured pass and user.
|
||||
* @param {Object} config
|
||||
* @param {function(Error)} done
|
||||
*/
|
||||
function _authenticate(config, done) {
|
||||
if (isAuthenticated || !config.pass || !config.user) return done();
|
||||
request.post({
|
||||
form: {
|
||||
formname: 'RpcApiUser_Login',
|
||||
fail_url: 'https://www.crunchyroll.com/login',
|
||||
name: config.user,
|
||||
password: config.pass
|
||||
},
|
||||
jar: true,
|
||||
url: 'https://www.crunchyroll.com/?a=formhandler'
|
||||
}, function(err) {
|
||||
if (err) return done(err);
|
||||
isAuthenticated = true;
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the options to use the authenticated cookie jar.
|
||||
* @param {(string|Object)} options
|
||||
* @returns {Object}
|
||||
*/
|
||||
function _modify(options) {
|
||||
if (typeof options === 'string') options = {url: options};
|
||||
options.jar = true;
|
||||
return options;
|
||||
}
|
||||
@ -3,7 +3,7 @@ var cheerio = require('cheerio');
|
||||
var episode = require('./episode');
|
||||
var persistent = '.crpersistent';
|
||||
var fs = require('fs');
|
||||
var request = require('request');
|
||||
var request = require('./request');
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
|
||||
@ -13,11 +13,11 @@ var url = require('url');
|
||||
* @param {string} address
|
||||
* @param {function(Error)} done
|
||||
*/
|
||||
module.exports = function (config, address, done) {
|
||||
module.exports = function(config, address, done) {
|
||||
var persistentPath = path.join(config.output || process.cwd(), persistent);
|
||||
fs.readFile(persistentPath, 'utf8', function(err, data) {
|
||||
var cache = config.cache ? {} : JSON.parse(data || '{}');
|
||||
_page(address, function(err, page) {
|
||||
_page(config, address, function(err, page) {
|
||||
if (err) return done(err);
|
||||
var i = 0;
|
||||
(function next() {
|
||||
@ -62,11 +62,12 @@ function _download(cache, config, baseAddress, data, done) {
|
||||
/**
|
||||
* Requests the page data and scrapes the episodes and series.
|
||||
* @private
|
||||
* @param {Object} config
|
||||
* @param {string} address
|
||||
* @param {function(Error, Object=)} done
|
||||
*/
|
||||
function _page(address, done) {
|
||||
request.get(address, function(err, res, body) {
|
||||
function _page(config, address, done) {
|
||||
request.get(config, address, function(err, res, body) {
|
||||
if (err) return done(err);
|
||||
var $ = cheerio.load(body);
|
||||
var title = $('.season-dropdown').text() || $('span[itemprop=name]').text();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user