ani-cli-npm 2.0.3 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
package/README.MD CHANGED
@@ -36,6 +36,7 @@ npx ani-cli-npm@latest
36
36
  ```
37
37
  git clone https://github.com/Bumpkin-Pi/ani-cli-npm.git
38
38
  cd ani-cli-npm
39
+ npm i
39
40
  npm run build
40
41
  npm run start
41
42
  ```
@@ -69,4 +70,5 @@ npm run start
69
70
  #### Download folder - The folder in which to download episodes.
70
71
 
71
72
 
72
- ## Happy watching :)
73
+
74
+ <a href="https://www.buymeacoffee.com/bumpkinpi" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
package/bin/Anime.js CHANGED
@@ -11,24 +11,40 @@ const open = require("open");
11
11
  const PlayerController = require("media-player-controller");
12
12
  const dl = require("download-file-with-progressbar");
13
13
  const chalk = require("chalk");
14
- // const gogohd_url="https://gogohd.net/"
15
- const base_url = "https://animixplay.to";
16
14
  class Anime {
15
+ /*
16
+ Class for handling a show/film
17
+
18
+ Stores anime dpage links assigned with anime_id.
19
+
20
+ Initialised with Anime.init()
21
+
22
+ */
17
23
  id = "";
18
24
  episode_list = [];
19
25
  player = 0;
20
26
  async init(anime_id, cache_folder) {
27
+ /*
28
+ Initiate Anime object
29
+
30
+ Will first search cache folder for cache file (this will contain id and dpage links)
31
+
32
+ If no cache is found, it will use get_ep_bases(anime_id) to get links. (Webscrapes from animixplay.to), then creates cache
33
+
34
+ anime_id:
35
+ */
21
36
  let cache_object = (0, cache_1.search_cache)(cache_folder, anime_id);
22
37
  this.id = anime_id;
23
38
  if (cache_object == 0) {
24
- await this.get_ap_bases(anime_id);
39
+ await this.get_ep_bases(this.id);
40
+ (0, cache_1.new_cache)(cache_folder, this);
25
41
  }
26
42
  else {
27
43
  try {
28
44
  this.episode_list = cache_object.episode_list;
29
45
  }
30
46
  catch {
31
- await this.get_ap_bases(anime_id);
47
+ await this.get_ep_bases(this.id);
32
48
  }
33
49
  }
34
50
  return 0;
@@ -49,8 +65,12 @@ class Anime {
49
65
  }
50
66
  return link;
51
67
  }
52
- async get_ap_bases(anime_id) {
53
- let html = (await ((0, curl_1.curl)(base_url + "/v1/" + anime_id))).split("\n");
68
+ async get_ep_bases(anime_id) {
69
+ /*
70
+ Scrapes animixplay.to for dpage links.
71
+ returns array with all dpage links
72
+ */
73
+ let html = (await ((0, curl_1.curl)("https://animixplay.to/v1/" + anime_id))).split("\n"); //POTENTIAL BREAK POINT. animixplay.to may change domain address
54
74
  let lines = "";
55
75
  for (let x in html) {
56
76
  if ((0, regex_1.RegexParse)(html[x], "*<div id=\"epslistplace\"*")) {
@@ -65,6 +85,20 @@ class Anime {
65
85
  }
66
86
  }
67
87
  async play_head(episode, config, config_dir) {
88
+ /*
89
+ # Starts play cascade.
90
+
91
+ ## Takes in:
92
+ ### Episode number, counding from 0
93
+ ### Config object
94
+ ### Config save directory
95
+
96
+ - If config.player is set to MPV or VLC, it will use the media-player-controller package.
97
+
98
+ - If set to Browser, it will use the "open" packer.
99
+
100
+ - If set to Link, it will simply print the media stream link to console, primarily for debuting peruses.
101
+ */
68
102
  console.clear();
69
103
  console.log(`Playing ${this.id} episode ${episode + 1}`);
70
104
  switch (config.player) {
@@ -148,6 +182,10 @@ class Anime {
148
182
  }
149
183
  }
150
184
  async play(episode, config, config_dir) {
185
+ /*
186
+ # Continues play cascade
187
+ ## Continues on from play_head()
188
+ */
151
189
  console.clear();
152
190
  console.log(`Playing ${this.id} episode ${episode + 1}`);
153
191
  if (this.player == 0) {
@@ -216,42 +254,46 @@ class Anime {
216
254
  }
217
255
  }
218
256
  }
219
- async download(episode, download_folder) {
220
- // @ts-ignore
221
- let ep_link = await this.get_episode_link(episode);
222
- let file_name = `${this.id}-${episode + 1}.mp4`;
223
- if (ep_link.includes(".m3u8"))
224
- 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."));
225
- // @ts-ignore
226
- let option = {
227
- filename: ep_link.includes("m3u8") ? file_name.replace("mp4", "m3u8") : file_name,
228
- dir: download_folder,
257
+ async download(episode, download_folder, final_ep) {
258
+ /*
259
+ ## Downloads an episode (counting from 0) to download_folder, with progress bar.
260
+ */
261
+ try {
229
262
  // @ts-ignore
230
- onDone: (info) => {
231
- // @ts-ignore
232
- console.log(chalk.green(`\n -- Download finished -- \nLocation: ${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`) + ">");
233
- return 0;
234
- },
235
- // @ts-ignore
236
- onError: (err) => {
237
- console.log(chalk.red('error', err));
238
- },
263
+ let ep_link = await this.get_episode_link(episode);
264
+ let file_name = `${this.id}-${episode + 1}.mp4`;
265
+ if (ep_link.includes(".m3u8"))
266
+ 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."));
239
267
  // @ts-ignore
240
- onProgress: (curr, total) => {
241
- process.stdout.clearLine(0);
242
- process.stdout.cursorTo(0);
243
- 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");
244
- }
245
- };
246
- //console.log((`${option.dir}/${option.filename}`))
247
- return await dl(ep_link, option);
248
- }
249
- async bulk_download(start_episode, end_episode, download_folder) {
250
- let downloaders = [];
251
- for (let episode = start_episode; episode <= end_episode; episode++) {
252
- downloaders.push(await this.download(episode, download_folder));
268
+ let option = {
269
+ filename: (ep_link.includes("m3u8") ? file_name.replace("mp4", "m3u8") : file_name),
270
+ dir: download_folder,
271
+ onDone: (final_ep > episode) ? ((info) => {
272
+ // @ts-ignore
273
+ console.log(chalk.green(`\n -- 1Download finished -- \nLocation: ${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
274
+ this.download(episode + 1, download_folder, final_ep);
275
+ }) : ((info) => {
276
+ // @ts-ignore
277
+ console.log(chalk.green(`\n -- 2Download finished -- \n${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
278
+ }),
279
+ // @ts-ignore
280
+ onError: (err) => {
281
+ console.log(chalk.red('error', err));
282
+ this.download(episode, download_folder, final_ep);
283
+ },
284
+ // @ts-ignore
285
+ onProgress: (curr, total) => {
286
+ process.stdout.clearLine(0);
287
+ process.stdout.cursorTo(0);
288
+ 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");
289
+ }
290
+ };
291
+ //console.log((`${option.dir}/${option.filename}`))
292
+ return await dl(ep_link, option);
293
+ }
294
+ catch {
295
+ this.download(episode, download_folder, final_ep);
253
296
  }
254
- return await Promise.all(downloaders);
255
297
  }
256
298
  }
257
299
  exports.Anime = Anime;
package/bin/cache.js CHANGED
@@ -39,24 +39,33 @@ function clear_cache(location, show) {
39
39
  }
40
40
  }
41
41
  exports.clear_cache = clear_cache;
42
- function new_cache(location, anime, show) {
42
+ function new_cache(location, anime) {
43
+ /*
44
+ Creates cache of Anime object, in cache file.
45
+ */
43
46
  try {
44
47
  fs.writeFileSync(location + "/" + anime.id + ".cache", JSON.stringify(anime));
45
48
  }
46
49
  catch {
47
- if (show) {
48
- console.log("Failed to write to cache");
49
- }
50
+ console.log("Failed to write to cache");
50
51
  }
51
52
  }
52
53
  exports.new_cache = new_cache;
53
54
  function get_cache(location, anime_id) {
55
+ /*
56
+ ## Get cache by anime_id. Does not check if the cache exists.
57
+ */
54
58
  return JSON.parse(fs.readFileSync(location + "/" + anime_id + ".cache").toString());
55
59
  }
56
- function search_cache(location, anime_id) {
60
+ function search_cache(cache_folder, anime_id) {
61
+ /*
62
+ ## Searches cache folder for cache file with name of anime_id, at the location of cache_folder
63
+
64
+ ### returns boolean for weather it is found.
65
+ */
57
66
  try {
58
- if (check_cache(location, anime_id)) {
59
- return get_cache(location, anime_id);
67
+ if (check_cache(cache_folder, anime_id)) {
68
+ return get_cache(cache_folder, anime_id);
60
69
  }
61
70
  return false;
62
71
  }
@@ -4,6 +4,9 @@ exports.config_ = void 0;
4
4
  const chalk = require("chalk");
5
5
  const input_1 = require("./input");
6
6
  async function config_(temp) {
7
+ /*
8
+ ## Lets user change a single attribute of config. Returns new config object, and an exit code
9
+ */
7
10
  console.clear();
8
11
  console.log(chalk.blue("ANI-CLI-NPM \n"));
9
12
  console.log(chalk.yellow("Config:\n"));
package/bin/curl.js CHANGED
@@ -2,33 +2,34 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.curl = void 0;
4
4
  const fetch = require("node-fetch");
5
+ const chalk = require("chalk");
5
6
  async function curl(url, method = "GET", redirect = false) {
6
- //try{
7
- let response = await fetch(url, {
8
- //"agent": proxyAgent,
9
- "headers": {
10
- 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0',
11
- "X-Requested-With": "XMLHttpRequest"
12
- },
13
- "referrerPolicy": "origin",
14
- "body": null,
15
- "method": method,
16
- "redirect": 'follow',
17
- // "follow": 10,
18
- }); /*.catch(async function(err) {
19
- console.warn(colors.Red, `Something went wrong connecting to ${url}.`);
20
- await search();
21
- process.exit()
22
- })*/
23
- if (redirect) {
24
- return response.url;
7
+ try {
8
+ let response = await fetch(url, {
9
+ //"agent": proxyAgent,
10
+ "headers": {
11
+ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0',
12
+ "X-Requested-With": "XMLHttpRequest"
13
+ },
14
+ "referrerPolicy": "origin",
15
+ "body": null,
16
+ "method": method,
17
+ "redirect": 'follow',
18
+ // "follow": 10,
19
+ }).catch(async function (err) {
20
+ console.warn(chalk.red(`Something went wrong connecting to ${url}. ${err}`));
21
+ process.exit();
22
+ });
23
+ if (redirect) {
24
+ return response.url;
25
+ }
26
+ else {
27
+ return await response.text();
28
+ }
25
29
  }
26
- else {
27
- return await response.text();
30
+ catch {
31
+ console.log(chalk.red("Something went wrong in curl()"));
32
+ process.exit();
28
33
  }
29
- /*}catch{
30
- console.log(colors.Red, "Something went wrong in curl()")
31
- await main()
32
- }*/
33
34
  }
34
35
  exports.curl = curl;
package/bin/download.js CHANGED
@@ -1,18 +1,17 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.download = void 0;
7
4
  const search_anime_1 = require("./search_anime");
8
5
  const Anime_1 = require("./Anime");
9
6
  const input_1 = require("./input");
10
- const libs_1 = require("./libs");
11
- const chalk_1 = __importDefault(require("chalk"));
12
7
  async function download(cache_folder, config) {
13
8
  try {
14
9
  console.clear();
15
- let download_id = await (0, search_anime_1.search)();
10
+ let temp_ = await (0, search_anime_1.search)();
11
+ if (temp_ == 1) {
12
+ return 2;
13
+ }
14
+ let download_id = temp_;
16
15
  let download = new Anime_1.Anime();
17
16
  await download.init(download_id, cache_folder);
18
17
  let start_ep_number;
@@ -27,21 +26,7 @@ async function download(cache_folder, config) {
27
26
  console.log(`Select end episode [${start_ep_number}-${download.episode_list.length}]`);
28
27
  end_ep_number = await (0, input_1.number_input)(download.episode_list.length, start_ep_number) - 1;
29
28
  }
30
- let to_do = (0, libs_1.range)(start_ep_number, end_ep_number + 1);
31
- do {
32
- for (let x in to_do) {
33
- try {
34
- await download.download(to_do[x] - 1, config.download_folder);
35
- to_do.splice(Number(x), 1);
36
- }
37
- catch {
38
- console.log(chalk_1.default.red("Failed to download episode " + to_do[x]));
39
- }
40
- }
41
- if (to_do[0] !== undefined) { //TODO fix buggy downloads
42
- console.log(chalk_1.default.red("Failed to download episodes: " + to_do) + "\nRetrying...");
43
- }
44
- } while (to_do[0] !== undefined);
29
+ await download.download(start_ep_number - 1, config.download_folder, end_ep_number);
45
30
  }
46
31
  catch {
47
32
  return 1;
package/bin/index.js CHANGED
@@ -18,9 +18,10 @@ const download_1 = require("./download");
18
18
  const fs_1 = __importDefault(require("fs"));
19
19
  const app_data_folder = (0, appdata_path_1.default)();
20
20
  const cache_folder = app_data_folder + "/ani-cli-npm";
21
+ (0, load_config_1.make_config_dir)(cache_folder, true);
21
22
  console.clear();
22
23
  async function main() {
23
- let config = (0, load_config_1.load_config)(app_data_folder);
24
+ let config = (0, load_config_1.load_config)(cache_folder);
24
25
  console.log(chalk.magenta("Ani-cli-npm!\n"));
25
26
  if (config.most_recent.anime_id !== "") {
26
27
  console.log(chalk.grey(`Most recently played: ${config.most_recent.anime_id} episode ${config.most_recent.episode_number + 1}\n`));
@@ -34,7 +35,12 @@ async function main() {
34
35
  ], ["s", "c", "d", "o", "q"], ((thing) => { return chalk.magenta(thing); }), ((thing) => { return chalk.magenta(thing); }));
35
36
  switch (choice) {
36
37
  case 0: // Search
37
- let anime_id = await (0, search_anime_1.search)();
38
+ let temp_ = await (0, search_anime_1.search)();
39
+ if (temp_ == 1) {
40
+ await main();
41
+ process.exit();
42
+ }
43
+ let anime_id = temp_;
38
44
  let anime = new Anime_1.Anime();
39
45
  await anime.init(anime_id, cache_folder);
40
46
  let episode_number;
@@ -59,7 +65,9 @@ async function main() {
59
65
  let continue_anime = new Anime_1.Anime();
60
66
  await continue_anime.init(config.most_recent.anime_id, cache_folder);
61
67
  await continue_anime.play_head(config.most_recent.episode_number, config, cache_folder);
62
- await continue_anime.player.quit();
68
+ if (continue_anime.player != 0 && continue_anime.player != 1) {
69
+ await continue_anime.player.quit();
70
+ }
63
71
  await main();
64
72
  break;
65
73
  case 2: // Download
@@ -67,7 +75,6 @@ async function main() {
67
75
  if (code == 1) {
68
76
  console.log(chalk.red("Error downloading episodes"));
69
77
  }
70
- await main();
71
78
  break;
72
79
  case 3: // Options
73
80
  let temp = structuredClone(config);
@@ -100,6 +107,7 @@ async function main() {
100
107
  case 4: // Quit
101
108
  console.log("Exit");
102
109
  }
110
+ return 0;
103
111
  // await search()
104
112
  }
105
113
  main();
package/bin/input.js CHANGED
@@ -7,6 +7,24 @@ exports.number_input = exports.input = exports.selection = void 0;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
8
  const _prompt = require("simple-input");
9
9
  async function selection(options, extra_options = [], color1 = ((thing) => { return chalk_1.default.yellow(thing); }), color2 = ((thing) => { return chalk_1.default.green(thing); })) {
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
+ */
10
28
  let color = true;
11
29
  for (let x in options) {
12
30
  if (color) {
@@ -57,12 +75,3 @@ async function number_input(max, min = 1) {
57
75
  return selection;
58
76
  }
59
77
  exports.number_input = number_input;
60
- async function number_input_range(max, min = 1) {
61
- let selection;
62
- do {
63
- selection = await _prompt(">");
64
- if (!(min <= parseInt(selection[0]) && parseInt(selection[0]) <= max)) {
65
- console.log(chalk_1.default.red("Invalid choice."));
66
- }
67
- } while (!(min <= parseInt(selection[0]) && parseInt(selection[0]) <= max));
68
- }
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.write_config = exports.load_config = void 0;
26
+ exports.make_config_dir = exports.write_config = exports.load_config = void 0;
27
27
  const fs = __importStar(require("fs"));
28
28
  function make_config_dir(cache_dir, debug) {
29
29
  try {
@@ -36,9 +36,10 @@ function make_config_dir(cache_dir, debug) {
36
36
  }
37
37
  }
38
38
  }
39
+ exports.make_config_dir = make_config_dir;
39
40
  function write_config(cache_dir, config) {
40
41
  try {
41
- make_config_dir(cache_dir, config.debug_mode);
42
+ //make_config_dir(cache_dir, config.debug_mode)
42
43
  fs.writeFileSync(cache_dir + "/config.conf", JSON.stringify(config));
43
44
  }
44
45
  catch {
@@ -30,6 +30,10 @@ async function search() {
30
30
  console.log(chalk_1.default.magenta("Search..."));
31
31
  let _selection = await (0, input_1.input)();
32
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
+ }
33
37
  return results[await (0, input_1.selection)(results)];
34
38
  }
35
39
  exports.search = search;
@@ -0,0 +1,9 @@
1
+ #EXTM3U
2
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=120532,RESOLUTION=640x360,NAME="360p"
3
+ ep.1.1657688701.360.m3u8
4
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=195379,RESOLUTION=854x480,NAME="480p"
5
+ ep.1.1657688701.480.m3u8
6
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=418741,RESOLUTION=1280x720,NAME="720p"
7
+ ep.1.1657688701.720.m3u8
8
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=903363,RESOLUTION=1920x1080,NAME="1080p"
9
+ ep.1.1657688701.1080.m3u8
@@ -0,0 +1,9 @@
1
+ #EXTM3U
2
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=112046,RESOLUTION=640x360,NAME="360p"
3
+ ep.2.1657689264.360.m3u8
4
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=180246,RESOLUTION=854x480,NAME="480p"
5
+ ep.2.1657689264.480.m3u8
6
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=382280,RESOLUTION=1280x720,NAME="720p"
7
+ ep.2.1657689264.720.m3u8
8
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=829748,RESOLUTION=1920x1080,NAME="1080p"
9
+ ep.2.1657689264.1080.m3u8
@@ -0,0 +1,9 @@
1
+ #EXTM3U
2
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=113161,RESOLUTION=640x360,NAME="360p"
3
+ ep.3.1657689714.360.m3u8
4
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=177223,RESOLUTION=854x480,NAME="480p"
5
+ ep.3.1657689714.480.m3u8
6
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=372889,RESOLUTION=1280x720,NAME="720p"
7
+ ep.3.1657689714.720.m3u8
8
+ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=798185,RESOLUTION=1920x1080,NAME="1080p"
9
+ ep.3.1657689714.1080.m3u8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ani-cli-npm",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "ani-cli tool rewritten as npm package",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -35,7 +35,6 @@
35
35
  "media-player-controller": "^1.5.3",
36
36
  "node-fetch": "^2.6.6",
37
37
  "open": "^8.4.0",
38
- "persistent-cache": "^0.1.0",
39
38
  "simple-input": "^1.0.1",
40
39
  "typescript": "^4.9.3"
41
40
  },