diff --git a/package.json b/package.json index 8ce375d..f33e49c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ ], "name": "crunchyroll", "repository": "git://github.com/Deathspike/crunchyroll.js.git", - "version": "1.0.3", + "version": "1.0.4", "bin": { "crunchyroll": "./bin/crunchyroll" }, diff --git a/src/batch.js b/src/batch.js index 9a5a2ba..5187fbc 100644 --- a/src/batch.js +++ b/src/batch.js @@ -88,19 +88,19 @@ function _tasks(config, batchPath, done) { */ function _parse(args) { return new Command().version(require('../package').version) + // Authentication + .option('-p, --pass ', 'The password.') + .option('-u, --user ', 'The e-mail address or username.') // Disables .option('-c, --cache', 'Disables the cache.') .option('-m, --merge', 'Disables merging subtitles and videos.') // Filters .option('-e, --episode ', 'The episode filter.') - // Authentication - .option('-p, --pass ', 'The password.') - .option('-u, --user ', 'The e-mail address or username.') + .option('-v, --volume ', 'The volume filter.') // Settings .option('-f, --format ', 'The subtitle format. (Default: ass)') .option('-o, --output ', 'The output path.') .option('-s, --series ', 'The series override.') .option('-t, --tag ', 'The subgroup. (Default: CrunchyRoll)') - .option('-v, --volume ', 'The volume.') .parse(args); } diff --git a/src/episode.js b/src/episode.js index 694be5a..14c147a 100644 --- a/src/episode.js +++ b/src/episode.js @@ -49,9 +49,8 @@ function _complete(message, begin, done) { * @param {function(Error)} done */ function _download(config, page, player, done) { - var tag = config.tag || 'CrunchyRoll'; var series = config.series || page.series; - var fileName = _name(config, page, series, tag); + var fileName = _name(config, page, series); var filePath = path.join(config.output || process.cwd(), series, fileName); mkdirp(path.dirname(filePath), function(err) { if (err) return done(err); @@ -77,13 +76,13 @@ function _download(config, page, player, done) { * @param {Object} config * @param {Object} page * @param {string} series - * @param {string} tag * @returns {string} */ -function _name(config, page, series, tag) { - var v = config.volume ? (config.volume < 10 ? '0' : '') + config.volume : ''; - var e = (page.episode < 10 ? '0' : '') + page.episode; - return series + ' ' + (v ? v + 'x' : '') + e + ' [' + tag + ']'; +function _name(config, page, series) { + var episode = (page.episode < 10 ? '0' : '') + page.episode; + var volume = (page.volume < 10 ? '0' : '') + page.volume; + var tag = config.tag || 'CrunchyRoll'; + return series + ' ' + volume + 'x' + episode + ' [' + tag + ']'; } /** @@ -100,13 +99,15 @@ function _page(config, address, done) { if (err) return done(err); var $ = cheerio.load(body); var swf = /^([^?]+)/.exec($('link[rel=video_src]').attr('href')); - var title = /Watch ([\w\W]+) Episode ([0-9]+)/.exec($('title').text()); - if (!swf || !title) return done(new Error('Invalid page.')); + var regexp = /Watch\s+(.+?)(?:\s+Season\s+([0-9]+))?\s+Episode\s+([0-9]+)/; + var data = regexp.exec($('title').text()); + if (!swf || !data) return done(new Error('Invalid page.')); done(undefined, { id: id, - episode: parseInt(title[2], 10), - series: title[1], - swf: swf[1] + episode: parseInt(data[3], 10), + series: data[1], + swf: swf[1], + volume: parseInt(data[2], 10) || 1 }); }); } diff --git a/src/series.js b/src/series.js index b5db841..0a6a75c 100644 --- a/src/series.js +++ b/src/series.js @@ -15,8 +15,8 @@ var url = require('url'); */ 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 || '{}'); + fs.readFile(persistentPath, 'utf8', function(err, contents) { + var cache = config.cache ? {} : JSON.parse(contents || '{}'); _page(config, address, function(err, page) { if (err) return done(err); var i = 0; @@ -42,16 +42,12 @@ module.exports = function(config, address, done) { * @param {Object.} cache * @param {Object} config * @param {string} baseAddress - * @param {Object} data + * @param {Object} item * @param {function(Error)} done */ -function _download(cache, config, baseAddress, data, done) { - if (typeof config.episode !== 'undefined') { - var filter = parseInt(config.episode, 10); - if (filter > 0 && data.number <= filter) return done(); - if (filter < 0 && data.number >= Math.abs(filter)) return done(); - } - var address = url.resolve(baseAddress, data.address); +function _download(cache, config, baseAddress, item, done) { + if (!_filter(config, item)) return done(); + var address = url.resolve(baseAddress, item.address); if (cache[address]) return done(); episode(config, address, function(err) { if (err) return done(err); @@ -61,7 +57,26 @@ function _download(cache, config, baseAddress, data, done) { } /** - * Requests the page data and scrapes the episodes and series. +* Filters the item based on the configuration. +* @param {Object} config +* @param {Object} item +* @returns {boolean} +*/ +function _filter(config, item) { + // Filter on chapter. + var episodeFilter = parseInt(config.episode, 10); + if (episodeFilter > 0 && item.episode <= episodeFilter) return false; + if (episodeFilter < 0 && item.episode >= -episodeFilter) return false; + + // Filter on volume. + var volumeFilter = parseInt(config.volume, 10); + if (volumeFilter > 0 && item.volume <= volumeFilter) return false; + if (volumeFilter < 0 && item.volume >= -volumeFilter) return false; + return true; +} + +/** + * Requests the page and scrapes the episodes and series. * @private * @param {Object} config * @param {string} address @@ -77,10 +92,14 @@ function _page(config, address, done) { $('.episode').each(function(i, el) { if ($(el).children('img[src*=coming_soon]').length) return; var address = $(el).attr('href'); - var title = ($(el).children('.series-title').text() || '').trim(); - var match = /([0-9]+)$/.exec(title); - if (!address || !match) return; - episodes.push({address: address, number: parseInt(match[0], 10)}); + var episode = /([0-9]+)\s*$/.exec($(el).children('.series-title').text()); + var volume = /([0-9]+)\s*$/.exec($(el).closest('ul').prev('a').text()); + if (!address || !episode) return; + episodes.push({ + address: address, + episode: parseInt(episode[0], 10), + volume: volume ? parseInt(volume[0], 10) : 1 + }); }); done(undefined, {episodes: episodes.reverse(), series: title}); });