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 batch-mode to queue a bunch of series.
|
||||||
* Add CLI interface with all the options.
|
* Add CLI interface with all the options.
|
||||||
* Support scheduled merging; if it fails now, the video is probably being watched.
|
* 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
|
### 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.
|
* 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
|
## Work In Progress
|
||||||
|
|
||||||
Open an issue or e-mail me directly. I'd be happy to answer your questions.
|
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.')
|
.option('-m, --merge', 'Disables merging subtitles and videos.')
|
||||||
// Filters
|
// Filters
|
||||||
.option('-e, --episode <i>', 'The episode filter.')
|
.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
|
// Settings
|
||||||
.option('-f, --format <s>', 'The subtitle format. (Default: ass)')
|
.option('-f, --format <s>', 'The subtitle format. (Default: ass)')
|
||||||
.option('-o, --output <s>', 'The output path.')
|
.option('-o, --output <s>', 'The output path.')
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
var cheerio = require('cheerio');
|
var cheerio = require('cheerio');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var mkdirp = require('mkdirp');
|
var mkdirp = require('mkdirp');
|
||||||
var request = require('request');
|
var request = require('./request');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var subtitle = require('./subtitle');
|
var subtitle = require('./subtitle');
|
||||||
var video = require('./video');
|
var video = require('./video');
|
||||||
@ -15,9 +15,9 @@ var xml2js = require('xml2js');
|
|||||||
* @param {function(Error)} done
|
* @param {function(Error)} done
|
||||||
*/
|
*/
|
||||||
module.exports = function (config, address, done) {
|
module.exports = function (config, address, done) {
|
||||||
_page(address, function(err, page) {
|
_page(config, address, function(err, page) {
|
||||||
if (err) return done(err);
|
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);
|
if (err) return done(err);
|
||||||
_download(config, page, player, done);
|
_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.
|
* Requests the page data and scrapes the id, episode, series and swf.
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Object} config
|
||||||
* @param {string} address
|
* @param {string} address
|
||||||
* @param {function(Error, Object=)} done
|
* @param {function(Error, Object=)} done
|
||||||
*/
|
*/
|
||||||
function _page(address, done) {
|
function _page(config, address, done) {
|
||||||
var id = parseInt((address.match(/[0-9]+$/) || [0])[0], 10);
|
var id = parseInt((address.match(/[0-9]+$/) || [0])[0], 10);
|
||||||
if (!id) return done(new Error('Invalid address.'));
|
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);
|
if (err) return done(err);
|
||||||
var $ = cheerio.load(body);
|
var $ = cheerio.load(body);
|
||||||
var swf = /^([^?]+)/.exec($('link[rel=video_src]').attr('href'));
|
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.
|
* Requests the player data and scrapes the subtitle and video data.
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Object} config
|
||||||
* @param {string} address
|
* @param {string} address
|
||||||
* @param {number} id
|
* @param {number} id
|
||||||
* @param {function(Error, Object=)} done
|
* @param {function(Error, Object=)} done
|
||||||
*/
|
*/
|
||||||
function _player(address, id, done) {
|
function _player(config, address, id, done) {
|
||||||
var url = address.match(/^(https?:\/\/[^\/]+)/);
|
var url = address.match(/^(https?:\/\/[^\/]+)/);
|
||||||
if (!url) return done(new Error('Invalid address.'));
|
if (!url) return done(new Error('Invalid address.'));
|
||||||
request.post({
|
request.post(config, {
|
||||||
form: {current_page: address},
|
form: {current_page: address},
|
||||||
url: url[1] + '/xml/?req=RpcApiVideoPlayer_GetStandardConfig&media_id=' + id
|
url: url[1] + '/xml/?req=RpcApiVideoPlayer_GetStandardConfig&media_id=' + id
|
||||||
}, function(err, res, xml) {
|
}, 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 episode = require('./episode');
|
||||||
var persistent = '.crpersistent';
|
var persistent = '.crpersistent';
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var request = require('request');
|
var request = require('./request');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ module.exports = function (config, address, done) {
|
|||||||
var persistentPath = path.join(config.output || process.cwd(), persistent);
|
var persistentPath = path.join(config.output || process.cwd(), persistent);
|
||||||
fs.readFile(persistentPath, 'utf8', function(err, data) {
|
fs.readFile(persistentPath, 'utf8', function(err, data) {
|
||||||
var cache = config.cache ? {} : JSON.parse(data || '{}');
|
var cache = config.cache ? {} : JSON.parse(data || '{}');
|
||||||
_page(address, function(err, page) {
|
_page(config, address, function(err, page) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
var i = 0;
|
var i = 0;
|
||||||
(function next() {
|
(function next() {
|
||||||
@ -62,11 +62,12 @@ function _download(cache, config, baseAddress, data, done) {
|
|||||||
/**
|
/**
|
||||||
* Requests the page data and scrapes the episodes and series.
|
* Requests the page data and scrapes the episodes and series.
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Object} config
|
||||||
* @param {string} address
|
* @param {string} address
|
||||||
* @param {function(Error, Object=)} done
|
* @param {function(Error, Object=)} done
|
||||||
*/
|
*/
|
||||||
function _page(address, done) {
|
function _page(config, address, done) {
|
||||||
request.get(address, function(err, res, body) {
|
request.get(config, address, function(err, res, body) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
var $ = cheerio.load(body);
|
var $ = cheerio.load(body);
|
||||||
var title = $('.season-dropdown').text() || $('span[itemprop=name]').text();
|
var title = $('.season-dropdown').text() || $('span[itemprop=name]').text();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user