ani-cli-npm 2.1.3 → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
package/README.MD CHANGED
@@ -3,6 +3,8 @@
3
3
  ### An Anime client, writen in nodeJS, to access any* anime without the need for ad filled websites! Just install, search for the anime of your choice, and watch in the video player of your choice.
4
4
  ### Typescript rewrite of the [ani-cli](https://github.com/pystardust/ani-cli) package for linux.
5
5
 
6
+ # Warning: due to shutdowns of Animixplay, this tool, along with ani-cli, is broken at present. I am currently working on a fix, but for now this will not work.
7
+
6
8
  ![image](https://user-images.githubusercontent.com/74017165/205444723-20520eb1-55dd-4103-811b-07e2cf6c466d.png)
7
9
 
8
10
 
package/bin/Anime.js CHANGED
@@ -3,15 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Anime = void 0;
4
4
  const curl_1 = require("./core_utils/curl");
5
5
  const regex_1 = require("./core_utils/regex");
6
- const generate_link_1 = require("./generate_link");
6
+ const generate_link_1 = require("./url_genoration/generate_link");
7
7
  const cache_1 = require("./file_managment/cache");
8
- const input_1 = require("./input");
8
+ const input_1 = require("./IO/input");
9
9
  const load_config_1 = require("./file_managment/load_config");
10
10
  const W2GClient = require("w2g-client");
11
11
  const open = require("open");
12
12
  const PlayerController = require("media-player-controller");
13
13
  const dl = require("download-file-with-progressbar");
14
14
  const chalk = require("chalk");
15
+ const m3u8ToMp4 = require("m3u8-to-mp4");
16
+ const converter = new m3u8ToMp4();
15
17
  class Anime {
16
18
  /*
17
19
  Class for handling a show/film
@@ -267,6 +269,9 @@ class Anime {
267
269
  this.player.play(await this.get_episode_link(this.current_episode, player));
268
270
  }
269
271
  async play_controller(episode, config, config_dir, first = false) {
272
+ if (config.show_cover) {
273
+ }
274
+ console.clear();
270
275
  console.log(`Playing ${this.id} episode ${episode + 1}`); // from ${new Date(this.current_pos * 1000).toISOString().slice(11, 19)}`)
271
276
  // if (!first){
272
277
  // console.clear()
@@ -307,6 +312,7 @@ class Anime {
307
312
  });
308
313
  let selected; // Look, I'm sorry, but there is no way I can possibly document this in a sane way. It's a dumb patch.
309
314
  do {
315
+ console.clear();
310
316
  selected = await (0, input_1.selection)((episode <= 0) ? [chalk.yellow("1/n) Next"), chalk.grey("2/p) Previous"), chalk.yellow("3/s) Select"), chalk.green("4/q) Quit")] :
311
317
  (episode >= this.episode_list.length - 1) ? [chalk.grey("1/n) Next"), chalk.green("2/p) Previous"), chalk.yellow("3/s) Select"), chalk.green("4/q) Quit")] :
312
318
  [chalk.yellow("1/n) Next"), chalk.green("2/p) Previous"), chalk.yellow("3/s) Select"), chalk.green("4/q) Quit")], ["n", "p", "s", "q"], ((thing) => { return (thing); }), ((thing) => { return (thing); }), true);
@@ -352,41 +358,51 @@ class Anime {
352
358
  /*
353
359
  ## Downloads an episode (counting from 0) to download_folder, with progress bar.
354
360
  */
361
+ while (episode <= final_ep) {
362
+ }
355
363
  try {
356
- // @ts-ignore
357
364
  let ep_link = await this.get_episode_link(episode);
358
365
  let file_name = `${this.id}-${episode + 1}.mp4`;
359
- if (ep_link.includes(".m3u8"))
360
- console.log(chalk.red("Warning: Animixplay will download an m3u8 file. This will require some extra steps to play. It is advised to use a 3rd party website or tool to download these from the link."));
361
- // @ts-ignore
362
- let option = {
363
- filename: (ep_link.includes("m3u8") ? file_name.replace("mp4", "m3u8") : file_name),
364
- dir: download_folder,
365
- onDone: (final_ep > episode) ? ((info) => {
366
+ if (ep_link.includes(".m3u8")) {
367
+ console.log(chalk.green(`Downloading episode ${episode + 1} of ${this.id.replace("-", "")} to ${download_folder + "/" + file_name}...`));
368
+ console.log("Progress bar unavailable for m3u8 files.");
369
+ await converter
370
+ .setInputFile(ep_link)
371
+ .setOutputFile((download_folder + "/" + file_name))
372
+ .start();
373
+ console.log(chalk.green("Download finished."));
374
+ }
375
+ else {
376
+ // @ts-ignore
377
+ let option = {
378
+ filename: (ep_link.includes("m3u8") ? file_name.replace("mp4", "m3u8") : file_name),
379
+ dir: download_folder,
380
+ onDone: (final_ep > episode) ? ((info) => {
381
+ // @ts-ignore
382
+ console.log(chalk.green(`\n -- 1Download finished -- \nLocation: ${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
383
+ this.download(episode + 1, download_folder, final_ep);
384
+ }) : ((info) => {
385
+ // @ts-ignore
386
+ console.log(chalk.green(`\n -- 2Download finished -- \n${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
387
+ }),
366
388
  // @ts-ignore
367
- console.log(chalk.green(`\n -- 1Download finished -- \nLocation: ${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
368
- this.download(episode + 1, download_folder, final_ep);
369
- }) : ((info) => {
389
+ onError: (err) => {
390
+ console.log(chalk.red('error', err));
391
+ this.download(episode, download_folder, final_ep);
392
+ },
370
393
  // @ts-ignore
371
- console.log(chalk.green(`\n -- 2Download finished -- \n${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
372
- }),
373
- // @ts-ignore
374
- onError: (err) => {
375
- console.log(chalk.red('error', err));
376
- this.download(episode, download_folder, final_ep);
377
- },
378
- // @ts-ignore
379
- onProgress: (curr, total) => {
380
- process.stdout.clearLine(0);
381
- process.stdout.cursorTo(0);
382
- process.stdout.write("\x1b[32m -- " + (curr / total * 100).toFixed(2) + "% " + "#".repeat(Math.ceil((curr / total) * ((process.stdout.columns - 20) / 1.5))) + "~".repeat(Math.ceil(((process.stdout.columns - 20) / 1.5) - (curr / total) * ((process.stdout.columns - 20) / 1.5))) + " -- \x1b[0m");
383
- }
384
- };
385
- //console.log((`${option.dir}/${option.filename}`))
386
- return await dl(ep_link, option);
394
+ onProgress: (curr, total) => {
395
+ process.stdout.clearLine(0);
396
+ process.stdout.cursorTo(0);
397
+ process.stdout.write("\x1b[32m -- " + (curr / total * 100).toFixed(2) + "% " + "#".repeat(Math.ceil((curr / total) * ((process.stdout.columns - 20) / 1.5))) + "~".repeat(Math.ceil(((process.stdout.columns - 20) / 1.5) - (curr / total) * ((process.stdout.columns - 20) / 1.5))) + " -- \x1b[0m");
398
+ }
399
+ };
400
+ //console.log((`${option.dir}/${option.filename}`))
401
+ return await dl(ep_link, option);
402
+ }
387
403
  }
388
404
  catch {
389
- this.download(episode, download_folder, final_ep);
405
+ await this.download(episode, download_folder, final_ep);
390
406
  }
391
407
  }
392
408
  }
package/bin/IO/help.js ADDED
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.help = void 0;
4
+ const input_1 = require("./input");
5
+ const chalk = require("chalk");
6
+ const helps = [
7
+ (async () => {
8
+ console.log(chalk.cyan("Playing anime: \n" +
9
+ " Search: \n" +
10
+ " Search for a show/movie. This will search on gogoanime.dk.\n" +
11
+ " Episode selection: \n" +
12
+ " Once an anime is selected, select an episode. If there is only 1 episode " +
13
+ "(in the case of a movie), the episode will be played automatically.\n" +
14
+ " The episode selected will be played in the video player selected in options. Info on video players can be found in options help."));
15
+ await help();
16
+ return;
17
+ }),
18
+ (async () => {
19
+ console.log(chalk.cyan("Downloading anime: \n" +
20
+ " Search: \n" +
21
+ " Search for a show/movie. This will search on gogoanime.dk.\n" +
22
+ " Episode selection: \n" +
23
+ " Once an anime is selected, select a start episode and an end episode. If there is only 1 episode " +
24
+ "(in the case of a movie), the episode will be downloaded automatically. Download folder can be changed in options. Default to run location.\n" +
25
+ " The selected episodes will be downloaded. It is common for episode links to fail to be fetched, when this happens the episode will be passed, then reattempted in another pass.\n" +
26
+ " Episodes sourced from Animixplay links will download m3u8 file, which you will have difficulty playing, if you are able to at all."));
27
+ await help();
28
+ return;
29
+ }),
30
+ (async () => {
31
+ console.log(chalk.cyan("Options: \n" +
32
+ " Player: \n" +
33
+ " Player used to play anime.\n" +
34
+ " Proxy: \n" +
35
+ " https proxy address and port in form ip:port. This is not currently implemented.\n" +
36
+ " User agent:\n" +
37
+ " node-fetch user agent.\n" +
38
+ " Downloads folder:\n" +
39
+ " Folder to place downloaded episodes.\n" +
40
+ " MPV socket connection file:\n" +
41
+ " File for mpv socket, used to control mpv instance with outside tools.\n" +
42
+ " VLC socket:\n" +
43
+ " VLC http control socket\n" +
44
+ " VLC pass:\n" +
45
+ " VLC http control password\n" +
46
+ " W2G api token:\n" +
47
+ " Your user access token for w2g.tv. Can be found at https://w2g.tv/en/account/edit_user under Tools/API\n"));
48
+ await help();
49
+ return;
50
+ }),
51
+ (async () => {
52
+ return;
53
+ })
54
+ ];
55
+ async function help() {
56
+ console.log(chalk.cyan("Help page select: \n"));
57
+ return helps[await (0, input_1.selection)(["Playing", "Downloading", "Options", "Quit"], ["p", "d", "o", "q"])]();
58
+ }
59
+ exports.help = help;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.number_input = exports.input = exports.selection = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const _prompt = require("simple-input");
9
+ async function selection(options, extra_options = [], color1 = ((thing) => { return chalk_1.default.yellow(thing); }), color2 = ((thing) => { return chalk_1.default.green(thing); }), overwrite = false) {
10
+ /*
11
+ selection(options, extra_options, color1, color2)
12
+
13
+ Gives use prompt to choose from a list of options. Either by inputting a number ranging from 1, to the length of the list. Or by inputting a letter (non-caps-sensitive) relating to the option.
14
+
15
+
16
+ - options: array of options; e.g. ["play", "download", "continue", "quit"] REQUIRED
17
+
18
+
19
+ - extra_options: array of characters as alternatives to numbers (both will be displayed). e.g. ["p", "d", "c", "q"].
20
+
21
+ default: []
22
+
23
+ - color1 and color2: functions that will dictate what 2 colors the options with alternate between (option1 will be color1, option2;color2, option3;color1, etc).
24
+ recommended for this function to return a chalk.____() parsed string.
25
+
26
+ default: ((thing:string) => {return chalk.yellow(thing)}) and ((thing:string) => {return chalk.green(thing)})
27
+
28
+ - Overwrite: boolean. Please dont use this. I should not be using it. It prints out the raw string instead of adding numbers to them to allow for bogus.
29
+ */
30
+ let color = true;
31
+ for (let x in options) {
32
+ if (!overwrite) {
33
+ if (color) {
34
+ console.log(color1((parseInt(x) + 1).toString() +
35
+ ((extra_options[x] == undefined) ? "" : "/" + extra_options[x]) +
36
+ ") " + options[x].replaceAll("-", " ")));
37
+ }
38
+ else {
39
+ console.log(color2((parseInt(x) + 1).toString() +
40
+ ((extra_options[x] == undefined) ? "" : "/" + extra_options[x]) +
41
+ ") " + options[x].replaceAll("-", " ")));
42
+ }
43
+ }
44
+ else {
45
+ console.log(options[x]);
46
+ }
47
+ color = !color;
48
+ }
49
+ let input = "";
50
+ do {
51
+ // @ts-ignore
52
+ input = (await _prompt(">")).toLowerCase();
53
+ for (let x in extra_options) {
54
+ if (extra_options[x].toLowerCase() == input) {
55
+ input = (parseInt(x) + 1).toString();
56
+ }
57
+ }
58
+ if (!(1 <= parseInt(input) && parseInt(input) <= options.length)) {
59
+ console.log(chalk_1.default.red("Invalid choice."));
60
+ }
61
+ } while (!(1 <= parseInt(input) && parseInt(input) <= options.length));
62
+ return parseInt(input) - 1;
63
+ }
64
+ exports.selection = selection;
65
+ async function input() {
66
+ return await _prompt(">");
67
+ }
68
+ exports.input = input;
69
+ async function number_input(max, min = 1, extra_options = [], extra_option_values = []) {
70
+ let selector;
71
+ let selection;
72
+ do {
73
+ selector = await _prompt(">");
74
+ if (extra_options.includes(selector.toLowerCase())) {
75
+ selection = extra_option_values[extra_options.indexOf(selector)];
76
+ }
77
+ else {
78
+ selection = parseInt(selector);
79
+ }
80
+ if (selector == "") {
81
+ selection = min;
82
+ }
83
+ if (!(min <= selection && selection <= max)) {
84
+ console.log(chalk_1.default.red("Invalid choice."));
85
+ }
86
+ } while (!(min <= selection && selection <= max));
87
+ return selection;
88
+ }
89
+ exports.number_input = number_input;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // let base:string = "https://gogocdn.net/cover/yuri-on-ice-dub.png"
3
+ // export {display_cover}
package/bin/download.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.download = void 0;
4
- const search_anime_1 = require("./search_anime");
4
+ const search_anime_1 = require("./url_genoration/search_anime");
5
5
  const Anime_1 = require("./Anime");
6
- const input_1 = require("./input");
6
+ const input_1 = require("./IO/input");
7
7
  async function download(cache_folder, config) {
8
8
  try {
9
9
  console.clear();
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.config_ = void 0;
4
4
  const chalk = require("chalk");
5
- const input_1 = require("../input");
5
+ const input_1 = require("../IO/input");
6
6
  const configs = [
7
7
  (async (temp) => {
8
8
  temp.player = [
@@ -78,7 +78,8 @@ const configs = [
78
78
  mpv_socket_path: "",
79
79
  vlc_socket: 0,
80
80
  vlc_pass: "",
81
- w2g_api_key: ""
81
+ w2g_api_key: "",
82
+ show_cover: false
82
83
  };
83
84
  console.log(config);
84
85
  // @ts-ignore
@@ -62,7 +62,8 @@ function load_config(cache_dir) {
62
62
  mpv_socket_path: "",
63
63
  vlc_socket: 0,
64
64
  vlc_pass: "",
65
- w2g_api_key: ""
65
+ w2g_api_key: "",
66
+ show_cover: false
66
67
  };
67
68
  if (fs.existsSync(cache_dir + "/config.conf")) {
68
69
  // @ts-ignore
package/bin/index.js CHANGED
@@ -29,22 +29,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
30
  const process = __importStar(require("process"));
31
31
  //process.removeAllListeners() // Ignore warning
32
+ // TODO: Use terminal-kit properly
32
33
  // External
33
34
  const appdata_path_1 = __importDefault(require("appdata-path"));
35
+ const terminal_kit = require("terminal-kit");
34
36
  const chalk = require("chalk");
35
37
  // Internal
36
38
  const Anime_1 = require("./Anime");
37
- const search_anime_1 = require("./search_anime");
39
+ const search_anime_1 = require("./url_genoration/search_anime");
38
40
  const load_config_1 = require("./file_managment/load_config");
39
- const input_1 = require("./input");
41
+ const input_1 = require("./IO/input");
40
42
  const change_config_1 = require("./file_managment/change_config");
41
43
  const cache_1 = require("./file_managment/cache");
42
44
  const download_1 = require("./download");
43
- const help_1 = require("./help");
45
+ const help_1 = require("./IO/help");
46
+ // import {display_cover} from "./cover_manager";
44
47
  const app_data_folder = (0, appdata_path_1.default)();
45
48
  const cache_folder = app_data_folder + "/ani-cli-npm";
46
49
  (0, load_config_1.make_config_dir)(cache_folder, true);
50
+ // display_cover()
47
51
  console.clear();
52
+ terminal_kit.draw("https://gogocdn.net/cover/yuri-on-ice-dub.png");
48
53
  async function main() {
49
54
  let config = (0, load_config_1.load_config)(cache_folder);
50
55
  console.log(chalk.magenta("Ani-cli-npm!\n"));
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generate_link = void 0;
4
+ const gogohd_url = "https://gogohd.net/";
5
+ const base_url = "https://animixplay.to";
6
+ const curl_1 = require("../core_utils/curl");
7
+ const regex_1 = require("../core_utils/regex");
8
+ async function generate_link(provider, id, player) {
9
+ let html_ = "";
10
+ let provider_name = "";
11
+ switch (provider) {
12
+ case 1:
13
+ html_ = await (0, curl_1.curl)(`${gogohd_url}streaming.php?id=${id}`);
14
+ provider_name = 'Xstreamcdn';
15
+ console.log(`Fetching ${provider_name} links...`);
16
+ let html = html_.split("\n");
17
+ let fb_id = "";
18
+ for (let x in html) {
19
+ if ((0, regex_1.RegexParse)(html[x], "*<li class=\"linkserver\" data-status=\"1\" data-video=\"https://fembed9hd.com/v/*")) {
20
+ fb_id = html[x].slice(html[x].indexOf("/v/") + 3, html[x].indexOf("\">X"));
21
+ break;
22
+ }
23
+ }
24
+ if (!fb_id) {
25
+ console.log("Error, no fb_id found.");
26
+ return 0;
27
+ }
28
+ //let refr = "https://fembed-hd.com/v/"+fb_id
29
+ let post = await (0, curl_1.curl)("https://fembed-hd.com/api/source/" + fb_id, "POST");
30
+ post = post.slice(post.indexOf(",\"data\":[{\"file\":\"") + 18, post.length);
31
+ post = post.slice(0, post.indexOf("\"")).replaceAll("\\/", "/");
32
+ return post;
33
+ case 2:
34
+ provider_name = 'Animixplay';
35
+ console.log(`Fetching ${provider_name} links...`);
36
+ let buffer = new Buffer(id);
37
+ let enc_id = buffer.toString("base64");
38
+ buffer = new Buffer(id + "LTXs3GrU8we9O" + enc_id);
39
+ let ani_id = buffer.toString("base64");
40
+ buffer = Buffer.from((await (0, curl_1.curl)(`${base_url}/api/live${ani_id}`, "GET", true)).split("#")[1], "base64");
41
+ if (player === "BROWSER") {
42
+ return `${base_url}/api/live${ani_id}`;
43
+ }
44
+ return buffer.toString("utf-8");
45
+ }
46
+ }
47
+ exports.generate_link = generate_link;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.search = void 0;
7
+ const regex_1 = require("../core_utils/regex");
8
+ const curl_1 = require("../core_utils/curl");
9
+ const input_1 = require("../IO/input");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ async function search_anime(search) {
12
+ let filter = "*<ahref=\"/category/*\"title=\"*\">";
13
+ let html = (await (0, curl_1.curl)("https://gogoanime.dk//search.html?keyword=" + search)).split("\n");
14
+ let lines = [];
15
+ for (let x in html) {
16
+ html[x] = html[x].replaceAll(/ /g, '').replaceAll(/\t/g, '');
17
+ if ((0, regex_1.RegexParse)(html[x], filter)) {
18
+ html[x] = html[x].slice(html[x].indexOf("/category/") + 10);
19
+ html[x] = html[x].slice(0, html[x].indexOf("\"title="));
20
+ lines.push(html[x]);
21
+ }
22
+ }
23
+ if (!lines[0]) {
24
+ lines.pop();
25
+ }
26
+ return lines;
27
+ }
28
+ async function search() {
29
+ console.clear();
30
+ console.log(chalk_1.default.magenta("Search..."));
31
+ let _selection = await (0, input_1.input)();
32
+ let results = await search_anime(_selection);
33
+ if (results[0] === undefined) {
34
+ console.log(chalk_1.default.red("No results found."));
35
+ return 1;
36
+ }
37
+ return results[await (0, input_1.selection)(results)];
38
+ }
39
+ exports.search = search;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ani-cli-npm",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
4
4
  "description": "ani-cli tool rewritten as npm package",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {