Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb15d7d854 | ||
|
|
66670547b9 | ||
|
|
987e424324 | ||
|
|
523c780b18 | ||
|
|
6c2100fbff | ||
|
|
f10bead0dc | ||
|
|
6448f4ec97 | ||
|
|
829bb080ee | ||
|
|
5edd7cf05a |
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -17,6 +17,7 @@ If applicable, add screenshots to help explain your problem.
|
|||||||
(Add a X between brackets to make them ticked)
|
(Add a X between brackets to make them ticked)
|
||||||
- OS: [e.g:. Windows 10, Mac OS X 10.13, ...]
|
- OS: [e.g:. Windows 10, Mac OS X 10.13, ...]
|
||||||
- [ ] I'm using the latest version of Crunchy
|
- [ ] I'm using the latest version of Crunchy
|
||||||
|
- [ ] I have a premium accrount on CR
|
||||||
- Serie you get a problem with (and specify which episode if it is specific to one):
|
- Serie you get a problem with (and specify which episode if it is specific to one):
|
||||||
- The command line you are running Crunchy with:
|
- The command line you are running Crunchy with:
|
||||||
- The message Crunchy is giving you, if any:
|
- The message Crunchy is giving you, if any:
|
||||||
|
|||||||
@@ -71,8 +71,6 @@ The [command-line interface](http://en.wikipedia.org/wiki/Command-line_interface
|
|||||||
-u, --user <s> The e-mail address or username.
|
-u, --user <s> The e-mail address or username.
|
||||||
-c, --cache Disables the cache.
|
-c, --cache Disables the cache.
|
||||||
-m, --merge Disables merging subtitles and videos.
|
-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)
|
-f, --format <s> The subtitle format. (Default: ass)
|
||||||
-o, --output <s> The output path.
|
-o, --output <s> The output path.
|
||||||
-s, --series <s> The series override.
|
-s, --series <s> The series override.
|
||||||
@@ -117,13 +115,6 @@ Download *Fairy Tail* to `C:\Anime`:
|
|||||||
* `-c or --cache` disables the cache in batch mode.
|
* `-c or --cache` disables the cache in batch mode.
|
||||||
* `-m or --merge` disables merging subtitles and videos.
|
* `-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).
|
|
||||||
|
|
||||||
_These parameters are probably extremely buggy at the moment..._
|
|
||||||
|
|
||||||
##### Settings
|
##### Settings
|
||||||
|
|
||||||
* `-f or --format <s>` sets the subtitle format. (Default: ass)
|
* `-f or --format <s>` sets the subtitle format. (Default: ass)
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "crunchy",
|
"name": "crunchy",
|
||||||
"version": "1.3.2",
|
"version": "1.3.4",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=5.0"
|
"node": ">=5.0"
|
||||||
},
|
},
|
||||||
"version": "1.3.2",
|
"version": "1.3.4",
|
||||||
"bin": {
|
"bin": {
|
||||||
"crunchy": "./bin/crunchy",
|
"crunchy": "./bin/crunchy",
|
||||||
"crunchy.sh": "./bin/crunchy.sh"
|
"crunchy.sh": "./bin/crunchy.sh"
|
||||||
|
|||||||
23
src/batch.ts
23
src/batch.ts
@@ -44,6 +44,17 @@ export default function(args: string[], done: (err?: Error) => void)
|
|||||||
config.video_quality = resol_table['1080'].quality;
|
config.video_quality = resol_table['1080'].quality;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.debug)
|
||||||
|
{
|
||||||
|
/* Ugly but meh */
|
||||||
|
const tmp = JSON.parse(JSON.stringify(config));
|
||||||
|
tmp.pass = 'obfuscated';
|
||||||
|
tmp.user = 'obfustated';
|
||||||
|
tmp.rawArgs = undefined;
|
||||||
|
tmp.options = undefined;
|
||||||
|
log.dumpToDebug('Config', JSON.stringify(tmp), true);
|
||||||
|
}
|
||||||
|
|
||||||
tasks(config, batchPath, (err, tasksArr) =>
|
tasks(config, batchPath, (err, tasksArr) =>
|
||||||
{
|
{
|
||||||
if (err)
|
if (err)
|
||||||
@@ -66,16 +77,18 @@ export default function(args: string[], done: (err?: Error) => void)
|
|||||||
{
|
{
|
||||||
if (tasksArr[i].retry <= 0)
|
if (tasksArr[i].retry <= 0)
|
||||||
{
|
{
|
||||||
console.error(err);
|
console.error(errin);
|
||||||
log.error('Cannot get episodes from "' + tasksArr[i].address + '", please rerun later');
|
log.error('Cannot get episodes from "' + tasksArr[i].address + '", please rerun later');
|
||||||
|
/* Go to the next on the list */
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (config.verbose)
|
if (config.verbose)
|
||||||
{
|
{
|
||||||
console.error(err);
|
console.error(errin);
|
||||||
}
|
}
|
||||||
log.warn('Retrying to fetch episodes ' + tasksArr[i].retry + ' / ' + config.retry);
|
log.warn('Retrying to fetch episodes list from' + tasksArr[i].retry + ' / ' + config.retry);
|
||||||
tasksArr[i].retry -= 1;
|
tasksArr[i].retry -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,9 +203,6 @@ function parse(args: string[]): IConfigLine
|
|||||||
// Disables
|
// Disables
|
||||||
.option('-c, --cache', 'Disables the cache.')
|
.option('-c, --cache', 'Disables the cache.')
|
||||||
.option('-m, --merge', 'Disables merging subtitles and videos.')
|
.option('-m, --merge', 'Disables merging subtitles and videos.')
|
||||||
// Filters
|
|
||||||
.option('-e, --episode <i>', 'The episode filter.')
|
|
||||||
.option('-v, --volume <i>', 'The volume filter.')
|
|
||||||
// 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.')
|
||||||
@@ -204,6 +214,7 @@ function parse(args: string[]): IConfigLine
|
|||||||
.option('-g, --rebuildcrp', 'Rebuild the crpersistant file.')
|
.option('-g, --rebuildcrp', 'Rebuild the crpersistant file.')
|
||||||
.option('-b, --batch <s>', 'Batch file', 'CrunchyRoll.txt')
|
.option('-b, --batch <s>', 'Batch file', 'CrunchyRoll.txt')
|
||||||
.option('--verbose', 'Make tool verbose')
|
.option('--verbose', 'Make tool verbose')
|
||||||
|
.option('--debug', 'Create a debug file. Use only if requested!')
|
||||||
.option('--retry <i>', 'Number or time to retry fetching an episode. Default: 5', 5)
|
.option('--retry <i>', 'Number or time to retry fetching an episode. Default: 5', 5)
|
||||||
.parse(args);
|
.parse(args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ function downloadSubtitle(config: IConfig, player: IEpisodePlayer, filePath: str
|
|||||||
const formats = subtitle.formats;
|
const formats = subtitle.formats;
|
||||||
const format = formats[config.format] ? config.format : 'ass';
|
const format = formats[config.format] ? config.format : 'ass';
|
||||||
|
|
||||||
formats[format](data, (errF: Error, decodedSubtitle: string) =>
|
formats[format](config, data, (errF: Error, decodedSubtitle: string) =>
|
||||||
{
|
{
|
||||||
if (errF)
|
if (errF)
|
||||||
{
|
{
|
||||||
|
|||||||
4
src/interface/IConfig.d.ts
vendored
4
src/interface/IConfig.d.ts
vendored
@@ -5,9 +5,6 @@ interface IConfig {
|
|||||||
// Disables
|
// Disables
|
||||||
cache?: boolean;
|
cache?: boolean;
|
||||||
merge?: boolean;
|
merge?: boolean;
|
||||||
// Filters
|
|
||||||
episode?: number;
|
|
||||||
volume?: number;
|
|
||||||
// Settings
|
// Settings
|
||||||
format?: string;
|
format?: string;
|
||||||
output?: string;
|
output?: string;
|
||||||
@@ -20,5 +17,6 @@ interface IConfig {
|
|||||||
rebuildcrp?: boolean;
|
rebuildcrp?: boolean;
|
||||||
batch?: string;
|
batch?: string;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
debug?: boolean;
|
||||||
retry?: number;
|
retry?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/interface/IFormatterTable.d.ts
vendored
2
src/interface/IFormatterTable.d.ts
vendored
@@ -1,3 +1,3 @@
|
|||||||
interface IFormatterTable {
|
interface IFormatterTable {
|
||||||
[key: string]: (input: string|Buffer, done: (err: Error, subtitle?: string) => void) => void;
|
[key: string]: (config: IConfig, input: string|Buffer, done: (err: Error, subtitle?: string) => void) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/log.ts
20
src/log.ts
@@ -1,7 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import os = require('os');
|
import os = require('os');
|
||||||
|
import fs = require('fs-extra');
|
||||||
|
|
||||||
export function error(str: string)
|
export function error(str: string|Error)
|
||||||
{
|
{
|
||||||
/* Do fancy output */
|
/* Do fancy output */
|
||||||
console.error(' \x1B[1;31m* ERROR\x1B[0m: ' + str);
|
console.error(' \x1B[1;31m* ERROR\x1B[0m: ' + str);
|
||||||
@@ -35,3 +36,20 @@ export function dispEpisode(name: string, status: string, addNL: boolean)
|
|||||||
console.log('');
|
console.log('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function dumpToDebug(what: string, data: any, create = false)
|
||||||
|
{
|
||||||
|
if (create)
|
||||||
|
{
|
||||||
|
fs.writeFile('debug.txt', '>>>>>>>> ' + what + ':\n' + data + '\n<<<<<<<<\n', (err) =>
|
||||||
|
{
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.appendFile('debug.txt', '>>>>>>>> ' + what + ':\n' + data + '\n<<<<<<<<\n', (err) =>
|
||||||
|
{
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -127,9 +127,15 @@ export function post(config: IConfig, options: request.Options, done: (err: Erro
|
|||||||
*/
|
*/
|
||||||
function authenticate(config: IConfig, done: (err: Error) => void)
|
function authenticate(config: IConfig, done: (err: Error) => void)
|
||||||
{
|
{
|
||||||
if (isAuthenticated || !config.pass || !config.user)
|
if (isAuthenticated)
|
||||||
{
|
{
|
||||||
return done(null);
|
return done(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.pass || !config.user)
|
||||||
|
{
|
||||||
|
log.error('You need to give login/password to use Crunchy');
|
||||||
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
startSession()
|
startSession()
|
||||||
@@ -181,7 +187,8 @@ function authenticate(config: IConfig, done: (err: Error) => void)
|
|||||||
if (isAuthenticated === false)
|
if (isAuthenticated === false)
|
||||||
{
|
{
|
||||||
const error = $('ul.message, li.error').text();
|
const error = $('ul.message, li.error').text();
|
||||||
return done(new Error('Authentication failed: ' + error));
|
log.error('Authentication failed: ' + error);
|
||||||
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPremium === false)
|
if (isPremium === false)
|
||||||
@@ -190,7 +197,7 @@ function authenticate(config: IConfig, done: (err: Error) => void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.info('You have a premium account! Good!');
|
log.info('You have a premium account! Good!');
|
||||||
}
|
}
|
||||||
done(null);
|
done(null);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -59,16 +59,24 @@ export default function(config: IConfig, address: string, done: (err: Error) =>
|
|||||||
if (page.episodes[i].retry <= 0)
|
if (page.episodes[i].retry <= 0)
|
||||||
{
|
{
|
||||||
log.dispEpisode(config.filename, 'Error...', true);
|
log.dispEpisode(config.filename, 'Error...', true);
|
||||||
console.error(err);
|
log.error(errD);
|
||||||
log.error('Cannot fetch episode "s' + page.episodes[i].volume + 'e' + page.episodes[i].episode +
|
log.error('Cannot fetch episode "s' + page.episodes[i].volume + 'e' + page.episodes[i].episode +
|
||||||
'", please rerun later');
|
'", please rerun later');
|
||||||
|
/* Go to the next on the list */
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.dispEpisode(config.filename, 'Error...', true);
|
log.dispEpisode(config.filename, 'Error...', true);
|
||||||
if (config.verbose)
|
if ((config.verbose) || (config.debug))
|
||||||
{
|
{
|
||||||
console.error(errD);
|
if (config.debug)
|
||||||
|
{
|
||||||
|
log.dumpToDebug('series address', address);
|
||||||
|
log.dumpToDebug('series error', errD.stack || errD);
|
||||||
|
log.dumpToDebug('series data', JSON.stringify(page));
|
||||||
|
}
|
||||||
|
log.error(errD);
|
||||||
}
|
}
|
||||||
log.warn('Retrying to fetch episode "s' + page.episodes[i].volume + 'e' + page.episodes[i].episode +
|
log.warn('Retrying to fetch episode "s' + page.episodes[i].volume + 'e' + page.episodes[i].episode +
|
||||||
'" - Retry ' + page.episodes[i].retry + ' / ' + config.retry);
|
'" - Retry ' + page.episodes[i].retry + ' / ' + config.retry);
|
||||||
@@ -111,11 +119,6 @@ function download(cache: {[address: string]: number}, config: IConfig,
|
|||||||
baseAddress: string, item: ISeriesEpisode,
|
baseAddress: string, item: ISeriesEpisode,
|
||||||
done: (err: Error, ign: boolean) => void)
|
done: (err: Error, ign: boolean) => void)
|
||||||
{
|
{
|
||||||
if (!filter(config, item))
|
|
||||||
{
|
|
||||||
return done(null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const address = url.resolve(baseAddress, item.address);
|
const address = url.resolve(baseAddress, item.address);
|
||||||
|
|
||||||
if (cache[address])
|
if (cache[address])
|
||||||
@@ -135,30 +138,6 @@ function download(cache: {[address: string]: number}, config: IConfig,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters the item based on the configuration.
|
|
||||||
*/
|
|
||||||
function filter(config: IConfig, item: ISeriesEpisode)
|
|
||||||
{
|
|
||||||
// Filter on chapter.
|
|
||||||
const episodeFilter = config.episode;
|
|
||||||
// Filter on volume.
|
|
||||||
const volumeFilter = config.volume;
|
|
||||||
|
|
||||||
const currentEpisode = parseInt(item.episode, 10);
|
|
||||||
const currentVolume = item.volume;
|
|
||||||
|
|
||||||
if ( ( (episodeFilter > 0) && (currentEpisode <= episodeFilter) ) ||
|
|
||||||
( (episodeFilter < 0) && (currentEpisode >= -episodeFilter) ) ||
|
|
||||||
( (volumeFilter > 0) && (currentVolume <= volumeFilter ) ) ||
|
|
||||||
( (volumeFilter < 0) && (currentVolume >= -volumeFilter ) ) )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests the page and scrapes the episodes and series.
|
* Requests the page and scrapes the episodes and series.
|
||||||
*/
|
*/
|
||||||
@@ -188,6 +167,11 @@ function page(config: IConfig, address: string, done: (err: Error, result?: ISer
|
|||||||
const title = $('span[itemprop=name]').text();
|
const title = $('span[itemprop=name]').text();
|
||||||
|
|
||||||
if (!title) {
|
if (!title) {
|
||||||
|
if (config.debug)
|
||||||
|
{
|
||||||
|
log.dumpToDebug('inval page addr', address);
|
||||||
|
log.dumpToDebug('inval page data', $);
|
||||||
|
}
|
||||||
return done(new Error('Invalid page.(' + address + ')'));
|
return done(new Error('Invalid page.(' + address + ')'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import xml2js = require('xml2js');
|
|||||||
/**
|
/**
|
||||||
* Converts an input buffer to a SubStation Alpha subtitle.
|
* Converts an input buffer to a SubStation Alpha subtitle.
|
||||||
*/
|
*/
|
||||||
export default function(input: string|Buffer, done: (err: Error, subtitle?: string) => void)
|
export default function(config: IConfig, input: string|Buffer, done: (err: Error, subtitle?: string) => void)
|
||||||
{
|
{
|
||||||
xml2js.parseString(input.toString(), {
|
xml2js.parseString(input.toString(), {
|
||||||
explicitArray: false,
|
explicitArray: false,
|
||||||
@@ -18,9 +18,9 @@ export default function(input: string|Buffer, done: (err: Error, subtitle?: stri
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
done(null, script(xml) + '\n' +
|
done(null, script(config, xml) + '\n' +
|
||||||
style(xml.styles) + '\n' +
|
style(xml.styles) + '\n' +
|
||||||
event(xml.events));
|
event(config, xml.events));
|
||||||
} catch (err)
|
} catch (err)
|
||||||
{
|
{
|
||||||
done(err);
|
done(err);
|
||||||
@@ -31,7 +31,7 @@ export default function(input: string|Buffer, done: (err: Error, subtitle?: stri
|
|||||||
/**
|
/**
|
||||||
* Converts the event block.
|
* Converts the event block.
|
||||||
*/
|
*/
|
||||||
function event(block: ISubtitleEvent): string
|
function event(config: IConfig, block: ISubtitleEvent): string
|
||||||
{
|
{
|
||||||
const format = 'Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text';
|
const format = 'Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text';
|
||||||
|
|
||||||
@@ -51,10 +51,11 @@ function event(block: ISubtitleEvent): string
|
|||||||
/**
|
/**
|
||||||
* Converts the script block.
|
* Converts the script block.
|
||||||
*/
|
*/
|
||||||
function script(block: ISubtitle): string
|
function script(config: IConfig, block: ISubtitle): string
|
||||||
{
|
{
|
||||||
|
|
||||||
return '[Script Info]\n' +
|
return '[Script Info]\n' +
|
||||||
|
'Origin: Downloaded from Crunchyroll.com by ' + config.user + '\n' +
|
||||||
'Title: ' + block.$.title + '\n' +
|
'Title: ' + block.$.title + '\n' +
|
||||||
'ScriptType: v4.00+\n' +
|
'ScriptType: v4.00+\n' +
|
||||||
'WrapStyle: ' + block.$.wrap_style + '\n' +
|
'WrapStyle: ' + block.$.wrap_style + '\n' +
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import xml2js = require('xml2js');
|
|||||||
/**
|
/**
|
||||||
* Converts an input buffer to a SubRip subtitle.
|
* Converts an input buffer to a SubRip subtitle.
|
||||||
*/
|
*/
|
||||||
export default function(input: Buffer|string, done: (err: Error, subtitle?: string) => void)
|
export default function(config: IConfig, input: Buffer|string, done: (err: Error, subtitle?: string) => void)
|
||||||
{
|
{
|
||||||
const options = {explicitArray: false, explicitRoot: false};
|
const options = {explicitArray: false, explicitRoot: false};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user