Update to TS1.5
This commit is contained in:
parent
5fdee94b38
commit
18375d3d22
@ -11,7 +11,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/Deathspike/crunchyroll.js.git"
|
"url": "git://github.com/Deathspike/crunchyroll.js.git"
|
||||||
},
|
},
|
||||||
"version": "1.1.3",
|
"version": "1.1.4",
|
||||||
"bin": {
|
"bin": {
|
||||||
"crunchyroll": "./bin/crunchyroll"
|
"crunchyroll": "./bin/crunchyroll"
|
||||||
},
|
},
|
||||||
|
|||||||
15
src/batch.ts
15
src/batch.ts
@ -1,15 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
|
||||||
import commander = require('commander');
|
import commander = require('commander');
|
||||||
import fs = require('fs');
|
import fs = require('fs');
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
import series = require('./series');
|
import series from './series';
|
||||||
import typings = require('./typings');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streams the batch of series to disk.
|
* Streams the batch of series to disk.
|
||||||
*/
|
*/
|
||||||
function main(args: string[], done: (err?: Error) => void) {
|
export default function(args: string[], done: (err?: Error) => void) {
|
||||||
var config = parse(args);
|
var config = parse(args);
|
||||||
var batchPath = path.join(config.output || process.cwd(), 'CrunchyRoll.txt');
|
var batchPath = path.join(config.output || process.cwd(), 'CrunchyRoll.txt');
|
||||||
tasks(config, batchPath, (err, tasks) => {
|
tasks(config, batchPath, (err, tasks) => {
|
||||||
@ -41,14 +39,15 @@ function split(value: string): string[] {
|
|||||||
previous = i + 1;
|
previous = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pieces.push(value.substring(previous, i).match(/^"?(.+?)"?$/)[1]);
|
var lastPiece = value.substring(previous, i).match(/^"?(.+?)"?$/);
|
||||||
|
if (lastPiece) pieces.push(lastPiece[1]);
|
||||||
return pieces;
|
return pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the configuration or reads the batch-mode file for tasks.
|
* Parses the configuration or reads the batch-mode file for tasks.
|
||||||
*/
|
*/
|
||||||
function tasks(config: typings.IConfigLine, batchPath: string, done: (err: Error, tasks?: typings.IConfigTask[]) => void) {
|
function tasks(config: IConfigLine, batchPath: string, done: (err: Error, tasks?: IConfigTask[]) => void) {
|
||||||
if (config.args.length) {
|
if (config.args.length) {
|
||||||
return done(null, config.args.map(address => {
|
return done(null, config.args.map(address => {
|
||||||
return {address: address, config: config};
|
return {address: address, config: config};
|
||||||
@ -58,7 +57,7 @@ function tasks(config: typings.IConfigLine, batchPath: string, done: (err: Error
|
|||||||
if (!exists) return done(null, []);
|
if (!exists) return done(null, []);
|
||||||
fs.readFile(batchPath, 'utf8', (err, data) => {
|
fs.readFile(batchPath, 'utf8', (err, data) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
var map: typings.IConfigTask[] = [];
|
var map: IConfigTask[] = [];
|
||||||
data.split(/\r?\n/).forEach(line => {
|
data.split(/\r?\n/).forEach(line => {
|
||||||
if (/^(\/\/|#)/.test(line)) return;
|
if (/^(\/\/|#)/.test(line)) return;
|
||||||
var lineConfig = parse(process.argv.concat(split(line)));
|
var lineConfig = parse(process.argv.concat(split(line)));
|
||||||
@ -75,7 +74,7 @@ function tasks(config: typings.IConfigLine, batchPath: string, done: (err: Error
|
|||||||
/**
|
/**
|
||||||
* Parses the arguments and returns a configuration.
|
* Parses the arguments and returns a configuration.
|
||||||
*/
|
*/
|
||||||
function parse(args: string[]): typings.IConfigLine {
|
function parse(args: string[]): IConfigLine {
|
||||||
return new commander.Command().version(require('../package').version)
|
return new commander.Command().version(require('../package').version)
|
||||||
// Authentication
|
// Authentication
|
||||||
.option('-p, --pass <s>', 'The password.')
|
.option('-p, --pass <s>', 'The password.')
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import batch = require('./batch');
|
import batch from './batch';
|
||||||
|
|
||||||
batch(process.argv, (err: any) => {
|
batch(process.argv, (err: any) => {
|
||||||
if (err) console.error(err.stack || err);
|
if (err) console.error(err.stack || err);
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
|
||||||
import cheerio = require('cheerio');
|
import cheerio = require('cheerio');
|
||||||
import fs = require('fs');
|
import fs = require('fs');
|
||||||
import mkdirp = require('mkdirp');
|
import mkdirp = require('mkdirp');
|
||||||
import request = require('./request');
|
import request = require('./request');
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
import subtitle = require('./subtitle/index');
|
import subtitle from './subtitle/index';
|
||||||
import typings = require('./typings');
|
import video from './video/index';
|
||||||
import video = require('./video/index');
|
|
||||||
import xml2js = require('xml2js');
|
import xml2js = require('xml2js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streams the episode to disk.
|
* Streams the episode to disk.
|
||||||
*/
|
*/
|
||||||
function main(config: typings.IConfig, address: string, done: (err: Error) => void) {
|
export default function(config: IConfig, address: string, done: (err: Error) => void) {
|
||||||
scrapePage(config, address, (err, page) => {
|
scrapePage(config, address, (err, page) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
scrapePlayer(config, address, page.id, (err, player) => {
|
scrapePlayer(config, address, page.id, (err, player) => {
|
||||||
@ -38,7 +36,7 @@ function complete(message: string, begin: number, done: (err: Error) => void) {
|
|||||||
/**
|
/**
|
||||||
* Downloads the subtitle and video.
|
* Downloads the subtitle and video.
|
||||||
*/
|
*/
|
||||||
function download(config: typings.IConfig, page: typings.IEpisodePage, player: typings.IEpisodePlayer, done: (err: Error) => void) {
|
function download(config: IConfig, page: IEpisodePage, player: IEpisodePlayer, done: (err: Error) => void) {
|
||||||
var series = config.series || page.series;
|
var series = config.series || page.series;
|
||||||
var fileName = name(config, page, series);
|
var fileName = name(config, page, series);
|
||||||
var filePath = path.join(config.output || process.cwd(), series, fileName);
|
var filePath = path.join(config.output || process.cwd(), series, fileName);
|
||||||
@ -64,7 +62,7 @@ function download(config: typings.IConfig, page: typings.IEpisodePage, player: t
|
|||||||
/**
|
/**
|
||||||
* Saves the subtitles to disk.
|
* Saves the subtitles to disk.
|
||||||
*/
|
*/
|
||||||
function downloadSubtitle(config: typings.IConfig, player: typings.IEpisodePlayer, filePath: string, done: (err?: Error) => void) {
|
function downloadSubtitle(config: IConfig, player: IEpisodePlayer, filePath: string, done: (err?: Error) => void) {
|
||||||
var enc = player.subtitle;
|
var enc = player.subtitle;
|
||||||
if (!enc) return done();
|
if (!enc) return done();
|
||||||
subtitle.decode(enc.id, enc.iv, enc.data, (err, data) => {
|
subtitle.decode(enc.id, enc.iv, enc.data, (err, data) => {
|
||||||
@ -81,9 +79,9 @@ function downloadSubtitle(config: typings.IConfig, player: typings.IEpisodePlaye
|
|||||||
/**
|
/**
|
||||||
* Streams the video to disk.
|
* Streams the video to disk.
|
||||||
*/
|
*/
|
||||||
function downloadVideo(config: typings.IConfig,
|
function downloadVideo(config: IConfig,
|
||||||
page: typings.IEpisodePage,
|
page: IEpisodePage,
|
||||||
player: typings.IEpisodePlayer,
|
player: IEpisodePlayer,
|
||||||
filePath: string,
|
filePath: string,
|
||||||
done: (err: Error) => void) {
|
done: (err: Error) => void) {
|
||||||
video.stream(
|
video.stream(
|
||||||
@ -97,7 +95,7 @@ function downloadVideo(config: typings.IConfig,
|
|||||||
/**
|
/**
|
||||||
* Names the file based on the config, page, series and tag.
|
* Names the file based on the config, page, series and tag.
|
||||||
*/
|
*/
|
||||||
function name(config: typings.IConfig, page: typings.IEpisodePage, series: string) {
|
function name(config: IConfig, page: IEpisodePage, series: string) {
|
||||||
var episode = (page.episode < 10 ? '0' : '') + page.episode;
|
var episode = (page.episode < 10 ? '0' : '') + page.episode;
|
||||||
var volume = (page.volume < 10 ? '0' : '') + page.volume;
|
var volume = (page.volume < 10 ? '0' : '') + page.volume;
|
||||||
var tag = config.tag || 'CrunchyRoll';
|
var tag = config.tag || 'CrunchyRoll';
|
||||||
@ -116,7 +114,7 @@ function prefix(value: number|string, length: number) {
|
|||||||
/**
|
/**
|
||||||
* Requests the page data and scrapes the id, episode, series and swf.
|
* Requests the page data and scrapes the id, episode, series and swf.
|
||||||
*/
|
*/
|
||||||
function scrapePage(config: typings.IConfig, address: string, done: (err: Error, page?: typings.IEpisodePage) => void) {
|
function scrapePage(config: IConfig, address: string, done: (err: Error, page?: IEpisodePage) => void) {
|
||||||
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(config, address, (err, result) => {
|
request.get(config, address, (err, result) => {
|
||||||
@ -139,7 +137,7 @@ function scrapePage(config: typings.IConfig, address: string, done: (err: Error,
|
|||||||
/**
|
/**
|
||||||
* Requests the player data and scrapes the subtitle and video data.
|
* Requests the player data and scrapes the subtitle and video data.
|
||||||
*/
|
*/
|
||||||
function scrapePlayer(config: typings.IConfig, address: string, id: number, done: (err: Error, player?: typings.IEpisodePlayer) => void) {
|
function scrapePlayer(config: IConfig, address: string, id: number, done: (err: Error, player?: IEpisodePlayer) => void) {
|
||||||
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(config, {
|
request.post(config, {
|
||||||
@ -150,7 +148,7 @@ function scrapePlayer(config: typings.IConfig, address: string, id: number, done
|
|||||||
xml2js.parseString(result, {
|
xml2js.parseString(result, {
|
||||||
explicitArray: false,
|
explicitArray: false,
|
||||||
explicitRoot: false
|
explicitRoot: false
|
||||||
}, (err: Error, player: typings.IEpisodePlayerConfig) => {
|
}, (err: Error, player: IEpisodePlayerConfig) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
try {
|
try {
|
||||||
var isSubtitled = Boolean(player['default:preload'].subtitle);
|
var isSubtitled = Boolean(player['default:preload'].subtitle);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export import batch = require('./batch');
|
import batch from './batch';
|
||||||
export import episode = require('./episode');
|
import episode from './episode';
|
||||||
export import series = require('./series');
|
import series from './series';
|
||||||
|
export {batch, episode, series};
|
||||||
|
|||||||
16
src/interface/IConfig.d.ts
vendored
Normal file
16
src/interface/IConfig.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
interface IConfig {
|
||||||
|
// Authentication
|
||||||
|
pass?: string;
|
||||||
|
user?: string;
|
||||||
|
// Disables
|
||||||
|
cache?: boolean;
|
||||||
|
merge?: boolean;
|
||||||
|
// Filters
|
||||||
|
episode?: number;
|
||||||
|
volume?: number;
|
||||||
|
// Settings
|
||||||
|
format?: string;
|
||||||
|
output?: string;
|
||||||
|
series?: string;
|
||||||
|
tag?: string;
|
||||||
|
}
|
||||||
3
src/interface/IConfigLine.d.ts
vendored
Normal file
3
src/interface/IConfigLine.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
interface IConfigLine extends IConfig {
|
||||||
|
args: string[];
|
||||||
|
}
|
||||||
4
src/interface/IConfigTask.d.ts
vendored
Normal file
4
src/interface/IConfigTask.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface IConfigTask {
|
||||||
|
address: string;
|
||||||
|
config: IConfigLine;
|
||||||
|
}
|
||||||
7
src/interface/IEpisodePage.d.ts
vendored
Normal file
7
src/interface/IEpisodePage.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
interface IEpisodePage {
|
||||||
|
id: number;
|
||||||
|
episode: number;
|
||||||
|
series: string;
|
||||||
|
volume: number;
|
||||||
|
swf: string;
|
||||||
|
}
|
||||||
11
src/interface/IEpisodePlayer.d.ts
vendored
Normal file
11
src/interface/IEpisodePlayer.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
interface IEpisodePlayer {
|
||||||
|
subtitle?: {
|
||||||
|
id: number;
|
||||||
|
iv: string;
|
||||||
|
data: string;
|
||||||
|
};
|
||||||
|
video: {
|
||||||
|
file: string;
|
||||||
|
host: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
15
src/interface/IEpisodePlayerConfig.d.ts
vendored
Normal file
15
src/interface/IEpisodePlayerConfig.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
interface IEpisodePlayerConfig {
|
||||||
|
'default:preload': {
|
||||||
|
subtitle: {
|
||||||
|
$: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
iv: string;
|
||||||
|
data: string;
|
||||||
|
};
|
||||||
|
stream_info: {
|
||||||
|
file: string;
|
||||||
|
host: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
3
src/interface/IFormatterTable.d.ts
vendored
Normal file
3
src/interface/IFormatterTable.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
interface IFormatterTable {
|
||||||
|
[key: string]: (input: string|Buffer, done: (err: Error, subtitle?: string) => void) => void;
|
||||||
|
}
|
||||||
4
src/interface/ISeries.d.ts
vendored
Normal file
4
src/interface/ISeries.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface ISeries {
|
||||||
|
episodes: ISeriesEpisode[];
|
||||||
|
series: string;
|
||||||
|
}
|
||||||
5
src/interface/ISeriesEpisode.d.ts
vendored
Normal file
5
src/interface/ISeriesEpisode.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
interface ISeriesEpisode {
|
||||||
|
address: string;
|
||||||
|
episode: number;
|
||||||
|
volume: number;
|
||||||
|
}
|
||||||
13
src/interface/ISubtitle.d.ts
vendored
Normal file
13
src/interface/ISubtitle.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
interface ISubtitle {
|
||||||
|
$: {
|
||||||
|
title: string;
|
||||||
|
wrap_style: string;
|
||||||
|
play_res_x: string;
|
||||||
|
play_res_y: string;
|
||||||
|
id: string;
|
||||||
|
lang_string: string;
|
||||||
|
created: string;
|
||||||
|
};
|
||||||
|
events: ISubtitleEvent;
|
||||||
|
styles: ISubtitleStyle;
|
||||||
|
}
|
||||||
15
src/interface/ISubtitleEvent.d.ts
vendored
Normal file
15
src/interface/ISubtitleEvent.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
interface ISubtitleEvent {
|
||||||
|
event: {
|
||||||
|
$: {
|
||||||
|
end: string;
|
||||||
|
start: string;
|
||||||
|
style: string;
|
||||||
|
name: string;
|
||||||
|
margin_l: string;
|
||||||
|
margin_r: string;
|
||||||
|
margin_v: string;
|
||||||
|
effect: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
}
|
||||||
29
src/interface/ISubtitleStyle.d.ts
vendored
Normal file
29
src/interface/ISubtitleStyle.d.ts
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
interface ISubtitleStyle {
|
||||||
|
style: {
|
||||||
|
$: {
|
||||||
|
name: string;
|
||||||
|
font_name: string;
|
||||||
|
font_size: string;
|
||||||
|
primary_colour: string;
|
||||||
|
secondary_colour: string;
|
||||||
|
outline_colour: string;
|
||||||
|
back_colour: string;
|
||||||
|
bold: string;
|
||||||
|
italic: string;
|
||||||
|
underline: string;
|
||||||
|
strikeout: string;
|
||||||
|
scale_x: string;
|
||||||
|
scale_y: string;
|
||||||
|
spacing: string;
|
||||||
|
angle: string;
|
||||||
|
border_style: string;
|
||||||
|
outline: string;
|
||||||
|
shadow: string;
|
||||||
|
alignment: string;
|
||||||
|
margin_l: string;
|
||||||
|
margin_r: string;
|
||||||
|
margin_v: string;
|
||||||
|
encoding: string;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
}
|
||||||
@ -1,12 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import request = require('request');
|
import request = require('request');
|
||||||
import typings = require('./typings');
|
|
||||||
var isAuthenticated = false;
|
var isAuthenticated = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a GET request for the resource.
|
* Performs a GET request for the resource.
|
||||||
*/
|
*/
|
||||||
export function get(config: typings.IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
|
export function get(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
|
||||||
authenticate(config, err => {
|
authenticate(config, err => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
request.get(modify(options), (err: Error, response: any, body: any) => {
|
request.get(modify(options), (err: Error, response: any, body: any) => {
|
||||||
@ -19,7 +18,7 @@ export function get(config: typings.IConfig, options: request.Options, done: (er
|
|||||||
/**
|
/**
|
||||||
* Performs a POST request for the resource.
|
* Performs a POST request for the resource.
|
||||||
*/
|
*/
|
||||||
export function post(config: typings.IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
|
export function post(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
|
||||||
authenticate(config, err => {
|
authenticate(config, err => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
request.post(modify(options), (err: Error, response: any, body: any) => {
|
request.post(modify(options), (err: Error, response: any, body: any) => {
|
||||||
@ -32,7 +31,7 @@ export function post(config: typings.IConfig, options: request.Options, done: (e
|
|||||||
/**
|
/**
|
||||||
* Authenticates using the configured pass and user.
|
* Authenticates using the configured pass and user.
|
||||||
*/
|
*/
|
||||||
function authenticate(config: typings.IConfig, done: (err: Error) => void) {
|
function authenticate(config: IConfig, done: (err: Error) => void) {
|
||||||
if (isAuthenticated || !config.pass || !config.user) return done(null);
|
if (isAuthenticated || !config.pass || !config.user) return done(null);
|
||||||
var options = {
|
var options = {
|
||||||
form: {
|
form: {
|
||||||
|
|||||||
@ -1,18 +1,16 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
|
||||||
import cheerio = require('cheerio');
|
import cheerio = require('cheerio');
|
||||||
import episode = require('./episode');
|
import episode from './episode';
|
||||||
import fs = require('fs');
|
import fs = require('fs');
|
||||||
import request = require('./request');
|
import request = require('./request');
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
import typings = require('./typings');
|
|
||||||
import url = require('url');
|
import url = require('url');
|
||||||
var persistent = '.crpersistent';
|
var persistent = '.crpersistent';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streams the series to disk.
|
* Streams the series to disk.
|
||||||
*/
|
*/
|
||||||
function main(config: typings.IConfig, address: string, done: (err: Error) => void) {
|
export default function(config: IConfig, address: string, done: (err: Error) => void) {
|
||||||
var persistentPath = path.join(config.output || process.cwd(), persistent);
|
var persistentPath = path.join(config.output || process.cwd(), persistent);
|
||||||
fs.readFile(persistentPath, 'utf8', (err, contents) => {
|
fs.readFile(persistentPath, 'utf8', (err, contents) => {
|
||||||
var cache = config.cache ? {} : JSON.parse(contents || '{}');
|
var cache = config.cache ? {} : JSON.parse(contents || '{}');
|
||||||
@ -39,9 +37,9 @@ function main(config: typings.IConfig, address: string, done: (err: Error) => vo
|
|||||||
* Downloads the episode.
|
* Downloads the episode.
|
||||||
*/
|
*/
|
||||||
function download(cache: {[address: string]: number},
|
function download(cache: {[address: string]: number},
|
||||||
config: typings.IConfig,
|
config: IConfig,
|
||||||
baseAddress: string,
|
baseAddress: string,
|
||||||
item: typings.ISeriesEpisode,
|
item: ISeriesEpisode,
|
||||||
done: (err: Error) => void) {
|
done: (err: Error) => void) {
|
||||||
if (!filter(config, item)) return done(null);
|
if (!filter(config, item)) return done(null);
|
||||||
var address = url.resolve(baseAddress, item.address);
|
var address = url.resolve(baseAddress, item.address);
|
||||||
@ -56,7 +54,7 @@ function download(cache: {[address: string]: number},
|
|||||||
/**
|
/**
|
||||||
* Filters the item based on the configuration.
|
* Filters the item based on the configuration.
|
||||||
*/
|
*/
|
||||||
function filter(config: typings.IConfig, item: typings.ISeriesEpisode) {
|
function filter(config: IConfig, item: ISeriesEpisode) {
|
||||||
// Filter on chapter.
|
// Filter on chapter.
|
||||||
var episodeFilter = config.episode;
|
var episodeFilter = config.episode;
|
||||||
if (episodeFilter > 0 && item.episode <= episodeFilter) return false;
|
if (episodeFilter > 0 && item.episode <= episodeFilter) return false;
|
||||||
@ -72,13 +70,13 @@ function filter(config: typings.IConfig, item: typings.ISeriesEpisode) {
|
|||||||
/**
|
/**
|
||||||
* Requests the page and scrapes the episodes and series.
|
* Requests the page and scrapes the episodes and series.
|
||||||
*/
|
*/
|
||||||
function page(config: typings.IConfig, address: string, done: (err: Error, result?: typings.ISeries) => void) {
|
function page(config: IConfig, address: string, done: (err: Error, result?: ISeries) => void) {
|
||||||
request.get(config, address, (err, result) => {
|
request.get(config, address, (err, result) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
var $ = cheerio.load(result);
|
var $ = cheerio.load(result);
|
||||||
var title = $('span[itemprop=name]').text();
|
var title = $('span[itemprop=name]').text();
|
||||||
if (!title) return done(new Error('Invalid page.'));
|
if (!title) return done(new Error('Invalid page.'));
|
||||||
var episodes: typings.ISeriesEpisode[] = [];
|
var episodes: ISeriesEpisode[] = [];
|
||||||
$('.episode').each((i, el) => {
|
$('.episode').each((i, el) => {
|
||||||
if ($(el).children('img[src*=coming_soon]').length) return;
|
if ($(el).children('img[src*=coming_soon]').length) return;
|
||||||
var volume = /([0-9]+)\s*$/.exec($(el).closest('ul').prev('a').text());
|
var volume = /([0-9]+)\s*$/.exec($(el).closest('ul').prev('a').text());
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
/* tslint:disable:no-bitwise false */
|
/* tslint:disable:no-bitwise false */
|
||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
|
||||||
import crypto = require('crypto');
|
import crypto = require('crypto');
|
||||||
import bigInt = require('big-integer');
|
import bigInt = require('big-integer');
|
||||||
import zlib = require('zlib');
|
import zlib = require('zlib');
|
||||||
@ -8,7 +7,7 @@ import zlib = require('zlib');
|
|||||||
/**
|
/**
|
||||||
* Decodes the data.
|
* Decodes the data.
|
||||||
*/
|
*/
|
||||||
function main(id: number, iv: Buffer|string, data: Buffer|string, done: (err?: Error, result?: Buffer) => void) {
|
export default function(id: number, iv: Buffer|string, data: Buffer|string, done: (err?: Error, result?: Buffer) => void) {
|
||||||
try {
|
try {
|
||||||
decompress(decrypt(id, iv, data), done);
|
decompress(decrypt(id, iv, data), done);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
|
||||||
import xml2js = require('xml2js');
|
import xml2js = require('xml2js');
|
||||||
import typings = require('../../typings');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an input buffer to a SubStation Alpha subtitle.
|
* Converts an input buffer to a SubStation Alpha subtitle.
|
||||||
*/
|
*/
|
||||||
function main(input: string|Buffer, done: (err: Error, subtitle?: string) => void) {
|
export default function(input: string|Buffer, done: (err: Error, subtitle?: string) => void) {
|
||||||
xml2js.parseString(input.toString(), {
|
xml2js.parseString(input.toString(), {
|
||||||
explicitArray: false,
|
explicitArray: false,
|
||||||
explicitRoot: false
|
explicitRoot: false
|
||||||
}, (err: Error, xml: typings.ISubtitle) => {
|
}, (err: Error, xml: ISubtitle) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
try {
|
try {
|
||||||
done(null, script(xml) + '\n' +
|
done(null, script(xml) + '\n' +
|
||||||
@ -25,7 +23,7 @@ function main(input: string|Buffer, done: (err: Error, subtitle?: string) => voi
|
|||||||
/**
|
/**
|
||||||
* Converts the event block.
|
* Converts the event block.
|
||||||
*/
|
*/
|
||||||
function event(block: typings.ISubtitleEvent): string {
|
function event(block: ISubtitleEvent): string {
|
||||||
var format = 'Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text';
|
var format = 'Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text';
|
||||||
return '[Events]\n' +
|
return '[Events]\n' +
|
||||||
'Format: ' + format + '\n' +
|
'Format: ' + format + '\n' +
|
||||||
@ -44,7 +42,7 @@ function event(block: typings.ISubtitleEvent): string {
|
|||||||
/**
|
/**
|
||||||
* Converts the script block.
|
* Converts the script block.
|
||||||
*/
|
*/
|
||||||
function script(block: typings.ISubtitle): string {
|
function script(block: ISubtitle): string {
|
||||||
return '[Script Info]\n' +
|
return '[Script Info]\n' +
|
||||||
'Title: ' + block.$.title + '\n' +
|
'Title: ' + block.$.title + '\n' +
|
||||||
'ScriptType: v4.00+\n' +
|
'ScriptType: v4.00+\n' +
|
||||||
@ -59,7 +57,7 @@ function script(block: typings.ISubtitle): string {
|
|||||||
/**
|
/**
|
||||||
* Converts the style block.
|
* Converts the style block.
|
||||||
*/
|
*/
|
||||||
function style(block: typings.ISubtitleStyle): string {
|
function style(block: ISubtitleStyle): string {
|
||||||
var format = 'Name,Fontname,Fontsize,PrimaryColour,SecondaryColour,' +
|
var format = 'Name,Fontname,Fontsize,PrimaryColour,SecondaryColour,' +
|
||||||
'OutlineColour,BackColour,Bold,Italic,Underline,StrikeOut,ScaleX,' +
|
'OutlineColour,BackColour,Bold,Italic,Underline,StrikeOut,ScaleX,' +
|
||||||
'ScaleY,Spacing,Angle,BorderStyle,Outline,Shadow,Alignment,' +
|
'ScaleY,Spacing,Angle,BorderStyle,Outline,Shadow,Alignment,' +
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
import ass from './ass';
|
||||||
import ass = require('./ass');
|
import srt from './srt';
|
||||||
import srt = require('./srt');
|
|
||||||
import typings = require('../../typings');
|
|
||||||
|
|
||||||
var main: typings.IFormatterTable = {
|
export default <IFormatterTable> {
|
||||||
ass: ass,
|
ass: ass,
|
||||||
srt: srt
|
srt: srt
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = srt;
|
|
||||||
import xml2js = require('xml2js');
|
import xml2js = require('xml2js');
|
||||||
import typings = require('../../typings');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an input buffer to a SubRip subtitle.
|
* Converts an input buffer to a SubRip subtitle.
|
||||||
*/
|
*/
|
||||||
function srt(input: Buffer|string, done: (err: Error, subtitle?: string) => void) {
|
export default function(input: Buffer|string, done: (err: Error, subtitle?: string) => void) {
|
||||||
var options = {explicitArray: false, explicitRoot: false};
|
var options = {explicitArray: false, explicitRoot: false};
|
||||||
xml2js.parseString(input.toString(), options, (err: Error, xml: typings.ISubtitle) => {
|
xml2js.parseString(input.toString(), options, (err: Error, xml: ISubtitle) => {
|
||||||
try {
|
try {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
done(null, xml.events.event.map((event, index) => {
|
done(null, xml.events.event.map((event, index) => {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export import decode = require('./decode');
|
import decode from './decode';
|
||||||
export import formats = require('./formats/index');
|
import formats from './formats/index';
|
||||||
|
export default {decode, formats};
|
||||||
|
|||||||
136
src/typings.ts
136
src/typings.ts
@ -1,136 +0,0 @@
|
|||||||
export interface IConfig {
|
|
||||||
// Authentication
|
|
||||||
pass?: string;
|
|
||||||
user?: string;
|
|
||||||
// Disables
|
|
||||||
cache?: boolean;
|
|
||||||
merge?: boolean;
|
|
||||||
// Filters
|
|
||||||
episode?: number;
|
|
||||||
volume?: number;
|
|
||||||
// Settings
|
|
||||||
format?: string;
|
|
||||||
output?: string;
|
|
||||||
series?: string;
|
|
||||||
tag?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IConfigLine extends IConfig {
|
|
||||||
args: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IConfigTask {
|
|
||||||
address: string;
|
|
||||||
config: IConfigLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEpisodePage {
|
|
||||||
id: number;
|
|
||||||
episode: number;
|
|
||||||
series: string;
|
|
||||||
volume: number;
|
|
||||||
swf: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEpisodePlayer {
|
|
||||||
subtitle?: {
|
|
||||||
id: number;
|
|
||||||
iv: string;
|
|
||||||
data: string;
|
|
||||||
};
|
|
||||||
video: {
|
|
||||||
file: string;
|
|
||||||
host: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEpisodePlayerConfig {
|
|
||||||
'default:preload': {
|
|
||||||
subtitle: {
|
|
||||||
$: {
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
iv: string;
|
|
||||||
data: string;
|
|
||||||
};
|
|
||||||
stream_info: {
|
|
||||||
file: string;
|
|
||||||
host: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IFormatterTable {
|
|
||||||
[key: string]: (input: string|Buffer, done: (err: Error, subtitle?: string) => void) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISeries {
|
|
||||||
episodes: ISeriesEpisode[];
|
|
||||||
series: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISeriesEpisode {
|
|
||||||
address: string;
|
|
||||||
episode: number;
|
|
||||||
volume: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISubtitle {
|
|
||||||
$: {
|
|
||||||
title: string;
|
|
||||||
wrap_style: string;
|
|
||||||
play_res_x: string;
|
|
||||||
play_res_y: string;
|
|
||||||
id: string;
|
|
||||||
lang_string: string;
|
|
||||||
created: string;
|
|
||||||
};
|
|
||||||
events: ISubtitleEvent;
|
|
||||||
styles: ISubtitleStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISubtitleEvent {
|
|
||||||
event: {
|
|
||||||
$: {
|
|
||||||
end: string;
|
|
||||||
start: string;
|
|
||||||
style: string;
|
|
||||||
name: string;
|
|
||||||
margin_l: string;
|
|
||||||
margin_r: string;
|
|
||||||
margin_v: string;
|
|
||||||
effect: string;
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISubtitleStyle {
|
|
||||||
style: {
|
|
||||||
$: {
|
|
||||||
name: string;
|
|
||||||
font_name: string;
|
|
||||||
font_size: string;
|
|
||||||
primary_colour: string;
|
|
||||||
secondary_colour: string;
|
|
||||||
outline_colour: string;
|
|
||||||
back_colour: string;
|
|
||||||
bold: string;
|
|
||||||
italic: string;
|
|
||||||
underline: string;
|
|
||||||
strikeout: string;
|
|
||||||
scale_x: string;
|
|
||||||
scale_y: string;
|
|
||||||
spacing: string;
|
|
||||||
angle: string;
|
|
||||||
border_style: string;
|
|
||||||
outline: string;
|
|
||||||
shadow: string;
|
|
||||||
alignment: string;
|
|
||||||
margin_l: string;
|
|
||||||
margin_r: string;
|
|
||||||
margin_v: string;
|
|
||||||
encoding: string;
|
|
||||||
};
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@ -1,3 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export import merge = require('./merge');
|
import merge from './merge';
|
||||||
export import stream = require('./stream');
|
import stream from './stream';
|
||||||
|
export default {merge, stream};
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
|
||||||
import childProcess = require('child_process');
|
import childProcess = require('child_process');
|
||||||
import fs = require('fs');
|
import fs = require('fs');
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
import os = require('os');
|
import os = require('os');
|
||||||
import subtitle = require('../subtitle/index');
|
import subtitle from '../subtitle/index';
|
||||||
import typings = require('../typings');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the subtitle and video files into a Matroska Multimedia Container.
|
* Merges the subtitle and video files into a Matroska Multimedia Container.
|
||||||
*/
|
*/
|
||||||
function main(config: typings.IConfig, isSubtitled: boolean, rtmpInputPath: string, filePath: string, done: (err: Error) => void) {
|
export default function(config: IConfig, isSubtitled: boolean, rtmpInputPath: string, filePath: string, done: (err: Error) => void) {
|
||||||
var subtitlePath = filePath + '.' + (subtitle.formats[config.format] ? config.format : 'ass');
|
var subtitlePath = filePath + '.' + (subtitle.formats[config.format] ? config.format : 'ass');
|
||||||
var videoPath = filePath + path.extname(rtmpInputPath);
|
var videoPath = filePath + path.extname(rtmpInputPath);
|
||||||
childProcess.exec(command() + ' ' +
|
childProcess.exec(command() + ' ' +
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export = main;
|
|
||||||
import childProcess = require('child_process');
|
import childProcess = require('child_process');
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
import os = require('os');
|
import os = require('os');
|
||||||
@ -7,7 +6,7 @@ import os = require('os');
|
|||||||
/**
|
/**
|
||||||
* Streams the video to disk.
|
* Streams the video to disk.
|
||||||
*/
|
*/
|
||||||
function main(rtmpUrl: string, rtmpInputPath: string, swfUrl: string, filePath: string, done: (err: Error) => void) {
|
export default function(rtmpUrl: string, rtmpInputPath: string, swfUrl: string, filePath: string, done: (err: Error) => void) {
|
||||||
childProcess.exec(command() + ' ' +
|
childProcess.exec(command() + ' ' +
|
||||||
'-r "' + rtmpUrl + '" ' +
|
'-r "' + rtmpUrl + '" ' +
|
||||||
'-y "' + rtmpInputPath + '" ' +
|
'-y "' + rtmpInputPath + '" ' +
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.4.1",
|
"version": "1.5.1-beta",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
@ -18,6 +18,18 @@
|
|||||||
"src/cli.ts",
|
"src/cli.ts",
|
||||||
"src/episode.ts",
|
"src/episode.ts",
|
||||||
"src/index.ts",
|
"src/index.ts",
|
||||||
|
"src/interface/IConfig.d.ts",
|
||||||
|
"src/interface/IConfigLine.d.ts",
|
||||||
|
"src/interface/IConfigTask.d.ts",
|
||||||
|
"src/interface/IEpisodePage.d.ts",
|
||||||
|
"src/interface/IEpisodePlayer.d.ts",
|
||||||
|
"src/interface/IEpisodePlayerConfig.d.ts",
|
||||||
|
"src/interface/IFormatterTable.d.ts",
|
||||||
|
"src/interface/ISeries.d.ts",
|
||||||
|
"src/interface/ISeriesEpisode.d.ts",
|
||||||
|
"src/interface/ISubtitle.d.ts",
|
||||||
|
"src/interface/ISubtitleEvent.d.ts",
|
||||||
|
"src/interface/ISubtitleStyle.d.ts",
|
||||||
"src/request.ts",
|
"src/request.ts",
|
||||||
"src/series.ts",
|
"src/series.ts",
|
||||||
"src/subtitle/decode.ts",
|
"src/subtitle/decode.ts",
|
||||||
@ -25,7 +37,6 @@
|
|||||||
"src/subtitle/formats/index.ts",
|
"src/subtitle/formats/index.ts",
|
||||||
"src/subtitle/formats/srt.ts",
|
"src/subtitle/formats/srt.ts",
|
||||||
"src/subtitle/index.ts",
|
"src/subtitle/index.ts",
|
||||||
"src/typings.ts",
|
|
||||||
"src/video/index.ts",
|
"src/video/index.ts",
|
||||||
"src/video/merge.ts",
|
"src/video/merge.ts",
|
||||||
"src/video/stream.ts",
|
"src/video/stream.ts",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user