ani-cli-npm 1.4.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,586 @@
1
+ #! /usr/bin/env node
2
+
3
+ const {emitWarning} = process;
4
+
5
+ process.emitWarning = (warning, ...args) => {
6
+ if (args[0] === 'ExperimentalWarning') {
7
+ return;
8
+ }
9
+
10
+ if (args[0] && typeof args[0] === 'object' && args[0].type === 'ExperimentalWarning') {
11
+ return;
12
+ }
13
+
14
+ return emitWarning(warning, ...args);
15
+ };
16
+ const fetch = require('node-fetch');
17
+ const PlayerController = require("media-player-controller")
18
+ const open = require("open")
19
+ const prompt = require("simple-input");
20
+ const getAppDataPath = require("appdata-path")
21
+ const fs = require("fs")
22
+ const dl = require("download-file-with-progressbar");
23
+
24
+
25
+
26
+ let config = {
27
+ player: "BROWSER",
28
+ proxy: "",
29
+ user_agent: "Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0",
30
+ most_recent: {
31
+ episode_number: 0,
32
+ anime_id: "",
33
+ episodes: []
34
+ },
35
+ download_folder: "./",
36
+ download_progress_bar: true
37
+ }
38
+
39
+
40
+ function read_config(){
41
+ try{
42
+ try {
43
+ config = JSON.parse(fs.readFileSync(getAppDataPath() + "/ani-cli-npm.conf")) //getAppDataPath()
44
+ if (!config.hasOwnProperty("player")) config.player = "BROWSER";
45
+ if (!config.hasOwnProperty("user_agent")) config.user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0";
46
+ if (!config.hasOwnProperty("proxy")) config.user_agent = "";
47
+ if (!config.hasOwnProperty("most_recent")) config.most_recent = null;
48
+ if (!config.hasOwnProperty("download_folder")) config.download_folder = "./";
49
+ if (!config.hasOwnProperty("download_progress_bar")) config.download_progress_bar = true;
50
+ fs.writeFileSync(getAppDataPath() + "/ani-cli-npm.conf", JSON.stringify(config))
51
+ } catch {
52
+ fs.writeFileSync(getAppDataPath() + "/ani-cli-npm.conf", JSON.stringify(config))
53
+ }
54
+ }catch{
55
+ console.log(colors.Red, "Failed to read config file")
56
+ }
57
+ }
58
+
59
+ function write_config(){
60
+ try{
61
+ fs.writeFileSync(getAppDataPath() + "/ani-cli-npm.conf", JSON.stringify(config))
62
+ }catch{
63
+ console.log(colors.Red, "Failed to write to config file")
64
+ }
65
+ }
66
+
67
+
68
+
69
+ const gogohd_url="https://gogohd.net/"
70
+ const base_url="https://animixplay.to"
71
+ const colors = {
72
+ Black: "\x1b[30m%s\x1b[0m",
73
+ Red: "\x1b[31m%s\x1b[0m",
74
+ Green: "\x1b[32m%s\x1b[0m",
75
+ Yellow: "\x1b[33m%s\x1b[0m",
76
+ Blue: "\x1b[34m%s\x1b[0m",
77
+ Magenta: "\x1b[35m%s\x1b[0m",
78
+ Cyan: "\x1b[36m%s\x1b[0m",
79
+ White: "\x1b[37m%s\x1b[0m"
80
+ }
81
+
82
+
83
+ //const HttpsProxyAgent = require('https-proxy-agent');
84
+ //let proxyAgent = new HttpsProxyAgent(config.proxy);
85
+
86
+
87
+ async function config_(temp){
88
+ console.clear()
89
+ console.log(colors.Blue, "ANI-CLI-NPM \n")
90
+ console.log(colors.Yellow, "Config:\n")
91
+ console.log(colors.Cyan, `1) Player; ${temp.player}`)
92
+ console.log(colors.Cyan, `2) Proxy; ${temp.proxy}`)
93
+ console.log(colors.Cyan, `3) User agent; ${temp.user_agent}`)
94
+ console.log(colors.Cyan, `4) Download folder; ${config.download_folder}`)
95
+ console.log(colors.Cyan, "5) Save and exit")
96
+ console.log(colors.Cyan, "6) Exit without saving changes")
97
+ let choice = parseInt(await input(""));
98
+ switch (choice){
99
+ case 1:
100
+ console.log(colors.Cyan, `1) VLC (default)`)
101
+ console.log(colors.Cyan, `2) Browser`)
102
+ console.log(colors.Cyan, `3) MPV`)
103
+ let player = parseInt(await input("New Player;"))
104
+ switch (player){
105
+ case 1:
106
+ temp.player = "VLC"
107
+ break
108
+ case 2:
109
+ temp.player = "BROWSER"
110
+ break
111
+ case 3:
112
+ temp.player = "MPV"
113
+ break
114
+ }
115
+ return temp,0
116
+ case 2:
117
+ temp.proxy = (await(input("New Proxy;"))).replaceAll(" ", "")
118
+ return temp, 0
119
+ case 3:
120
+ temp.user_agent = await(input("New User agent;"))
121
+ return temp, 0
122
+ case 4:
123
+ temp.download_folder = await(input("New download folder: "))
124
+ return temp, 0
125
+ case 5:
126
+ return temp, 1
127
+ case 6:
128
+ return temp, 2
129
+ }
130
+ }
131
+
132
+ async function input(message){
133
+ if (message){
134
+ console.log(colors.Magenta,message)
135
+ }
136
+ return await prompt(">")
137
+ }
138
+
139
+ async function curl(url, method="GET", redirect = false){
140
+ //try{
141
+ let response = await fetch(url, {
142
+ //"agent": proxyAgent,
143
+ "headers": {
144
+ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0',
145
+ "X-Requested-With": "XMLHttpRequest"
146
+ },
147
+ "referrerPolicy": "origin",
148
+ "body": null,
149
+ "method": method,
150
+ "redirect": 'follow',
151
+ "follow": 10,
152
+ }).catch(async function(err) {
153
+ console.warn(colors.Red, `Something went wrong connecting to ${url}.`);
154
+ await search();
155
+ process.exit()
156
+ })
157
+ if (redirect){
158
+ return response.url
159
+ }else{
160
+ return await response.text()
161
+ }
162
+ /*}catch{
163
+ console.log(colors.Red, "Something went wrong in curl()")
164
+ await main()
165
+ }*/
166
+
167
+ }
168
+
169
+ async function _continue(){
170
+ let link = await get_video_link(config.most_recent.episodes[config.most_recent.episode_number])
171
+ await play(link, config.most_recent)
172
+ process.exit()
173
+ }
174
+
175
+
176
+ function RegexParse(str, rule) {
177
+ let escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
178
+ return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$").test(str);
179
+ }
180
+
181
+ async function search_anime(search){
182
+ let filter = "*<ahref=\"/category/*\"title=\"*\">"
183
+ let html = (await curl("https://gogoanime.dk//search.html?keyword="+search)).split("\n")
184
+ let lines = []
185
+ for (x in html){
186
+ html[x] = html[x].replaceAll(/ /g,'').replaceAll(/\t/g,'')
187
+ if (RegexParse(html[x], filter)){
188
+ html[x] = html[x].slice(html[x].indexOf("/category/")+10);
189
+ html[x] = html[x].slice(0, html[x].indexOf("\"title="));
190
+ lines.push(html[x])
191
+ }
192
+ }
193
+ if (!lines[0]){
194
+ lines.pop()
195
+ }
196
+
197
+
198
+ return lines
199
+ }
200
+
201
+ async function episode_list(anime_id){
202
+ let html = (await curl(base_url+"/v1/"+anime_id)).split("\n")
203
+ let lines = ""
204
+
205
+ for (let x in html){
206
+ if(RegexParse(html[x], "*<div id=\"epslistplace\"*")){
207
+ lines = (html[x])
208
+ }
209
+ }
210
+
211
+ lines = lines.slice(55, lines.length).replace("}</div>", "")
212
+ lines = "{" + lines.slice(lines.indexOf(",")+1, lines.length) + "}"
213
+ lines = JSON.parse(lines)
214
+
215
+ let json = []
216
+ for (x in lines){
217
+ json.push(lines[x])
218
+ }
219
+ return json
220
+ }
221
+
222
+ function download(link, file_name){
223
+ if (link.includes("m3u8")) console.log(colors.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.");
224
+ let option = {
225
+ filename: link.includes("m3u8") ? file_name.replace("mp4", "m3u8") : file_name,
226
+ dir: config.download_folder,
227
+ onDone: (info)=>{
228
+ console.log(colors.Green, `\n -- Download finished -- \nLocation: ${info.path}\nSize: ${Math.round(info.size/100000)*10} Bytes`);
229
+ return 0;
230
+ },
231
+ onError: (err) => {
232
+ console.log(colors.Red, 'error', err);
233
+ },
234
+ onProgress: (curr, total) => {
235
+ process.stdout.clearLine(0);
236
+ process.stdout.cursorTo(0);
237
+ if (config.download_progress_bar){
238
+ process.stdout.write("\x1b[32m -- "+(curr / total * 100).toFixed(2)+"% "+"#". repeat(Math.ceil((curr / total)*(process.stdout.columns-20)))+"~".repeat(Math.ceil((process.stdout.columns-20) - (curr / total)*(process.stdout.columns-20)))+" -- \x1b[0m")
239
+
240
+ }else{
241
+ process.stdout.write(('\x1b[32m -- progress '+ (curr / total * 100).toFixed(2) + '% -- \x1b[0m'));
242
+ }
243
+ },
244
+ }
245
+ console.log(colors.White, `${option.dir}/${option.filename}`)
246
+
247
+ return dl(link, option);
248
+
249
+ }
250
+
251
+ async function selection(options, prompt, extra_options = []){
252
+ let selection = 0
253
+ while (true){
254
+ selection = (await input(prompt))
255
+ if ((selection <= options && selection >= 1) || extra_options.includes(selection)){
256
+ break
257
+ }
258
+ console.log(colors.Red,`Please input a valid option.`)
259
+ }
260
+ return selection
261
+ }
262
+
263
+ async function process_search(query) {
264
+ console.log(colors.Yellow, "Searching: "+query)
265
+
266
+ let search_results = await search_anime(query)
267
+ if (!search_results[0]) {
268
+ console.log(colors.Red, "No results.")
269
+ await main()
270
+ process.exit()
271
+ } else {
272
+ for (x in search_results) {
273
+ console.log(colors.Cyan,`${parseInt(x)+1})${" ".repeat(((search_results.length).toString().length+1)-((parseInt(x)+1).toString().length))}${search_results[x].replaceAll("-", " ")}`)
274
+ }
275
+ }
276
+
277
+ let anime_id = search_results[await selection(search_results.length, "Please select an anime.")-1]
278
+ let episodes = await episode_list(anime_id)
279
+ let episode_number = 0;
280
+ if (episodes.length > 1){
281
+ episode_number = (await selection(episodes.length, `Please select an episode (1-${episodes.length}).`))-1
282
+ }
283
+ return {
284
+ anime_id: anime_id,
285
+ episodes: episodes,
286
+ episode_number: episode_number
287
+ }
288
+ }
289
+
290
+ async function get_video_link(episode_dpage){
291
+ let id = episode_dpage.replace("//gogohd.net/streaming.php?id=","")
292
+ id = id.slice(0, id.indexOf("="))
293
+ let link = await generate_link(1,id)
294
+ if (!link){
295
+ link = await generate_link(2,id)
296
+ }
297
+ return link
298
+ }
299
+
300
+ async function generate_link(provider, id){
301
+ let html = ""
302
+ let provider_name = ""
303
+ switch (provider) {
304
+ case 1:
305
+ html = await curl(`${gogohd_url}streaming.php?id=${id}`)
306
+ provider_name = 'Xstreamcdn'
307
+ console.log(colors.Yellow, `Fetching ${provider_name} links...`)
308
+ html = html.split("\n")
309
+ let fb_id = ""
310
+ for (x in html){
311
+ if (RegexParse(html[x], "*<li class=\"linkserver\" data-status=\"1\" data-video=\"https://fembed9hd.com/v/*")){
312
+ fb_id = html[x].slice(html[x].indexOf("/v/")+3, html[x].indexOf("\">X"))
313
+ break
314
+ }
315
+ }
316
+ if (!fb_id){
317
+ console.log("Error, no fb_id found.")
318
+ return 0
319
+ }
320
+
321
+ //let refr = "https://fembed-hd.com/v/"+fb_id
322
+ let post = await curl("https://fembed-hd.com/api/source/"+fb_id, "POST")
323
+ post = post.slice(post.indexOf(",\"data\":[{\"file\":\"")+18, post.length)
324
+ post = post.slice(0, post.indexOf("\"")).replaceAll("\\/","/")
325
+ return post
326
+ case 2:
327
+ provider_name = 'Animixplay'
328
+ let buffer = new Buffer(id)
329
+ let enc_id = buffer.toString("base64")
330
+ buffer = new Buffer(id+"LTXs3GrU8we9O"+enc_id)
331
+ let ani_id = buffer.toString("base64")
332
+ buffer = Buffer.from((await curl(`${base_url}/api/live${ani_id}`, "GET", true)).split("#")[1], "base64")
333
+ if (config.player === "BROWSER"){
334
+ return `${base_url}/api/live${ani_id}`
335
+ }
336
+ return buffer.toString("utf-8") //TODO m3u8 player
337
+
338
+
339
+ }
340
+ }
341
+
342
+ async function post_play(link, anime, player = null){
343
+ while (true){
344
+ config.most_recent = anime
345
+ write_config()
346
+
347
+ console.log(colors.Yellow, `Playing episode ${anime.episode_number+1} of ${anime.anime_id.replaceAll("-", " ")}\n`)
348
+ console.log(colors.Cyan, "1/l) Show Link")
349
+ console.log(colors.Cyan, "2/n) Next Episode")
350
+ console.log(colors.Cyan, "3/p) Prev Episode")
351
+ console.log(colors.Cyan, "4/d) Download")
352
+ console.log(colors.Cyan, "5/q) Quit")
353
+ switch (await selection(5, "select;", ["l", "n", "p", "d", "q"])){
354
+ case "l":
355
+ case "1":
356
+ console.log(colors.Yellow, "Link: "+link)
357
+ break
358
+ case "n":
359
+ case "2":
360
+ if (anime.episode_number > anime.episodes.length-2){
361
+ console.log(colors.Red, "Damn, all out of episodes?")
362
+ break
363
+ }
364
+ anime.episode_number += 1
365
+ link = await get_video_link(anime.episodes[anime.episode_number])
366
+ await play(link, anime, player)
367
+ process.exit()
368
+ break
369
+ //EVEN MORE NEEDLESS QUIT STATEMENTS!!!!!!
370
+ case "p":
371
+ case "3":
372
+ if (anime.episode_number < 2){
373
+ console.log(colors.Red, "Error; Episode 0 is only available for premium members")
374
+ break
375
+ }
376
+ anime.episode_number -= 1
377
+ link = await get_video_link(anime.episodes[anime.episode_number])
378
+ await play(link, anime, player)
379
+ process.exit()
380
+ break
381
+ case "d":
382
+ case "4":
383
+ console.log(colors.Yellow, "Beware of the dysfunctional await clause.")
384
+ await download(link, anime.anime_id+(anime.episode_number+1)+".mp4")
385
+ post_play(link, anime, player)
386
+ break
387
+ case "q":
388
+ case "5":
389
+ console.clear()
390
+ await main()
391
+ process.exit()
392
+ break
393
+ }
394
+ }
395
+ }
396
+
397
+ async function play(link, anime, player){
398
+ console.clear()
399
+ console.log(colors.Blue, "ANI-CLI-NPM \n")
400
+ if (config.player === "VLC"){
401
+ if (!player){
402
+ console.log(colors.Yellow, "Loading VLC... ")
403
+ player = new PlayerController({
404
+ app: 'vlc',
405
+ args: ['--fullscreen'],
406
+ media: link
407
+ });
408
+ await player.launch(err => {
409
+ if (err) return console.error(err.message);
410
+ });
411
+ }else{
412
+ player.quit()
413
+ console.log(colors.Yellow, "Loading VLC... ")
414
+ player = new PlayerController({
415
+ app: 'vlc',
416
+ args: ['--fullscreen'],
417
+ media: link
418
+ });
419
+ await player.launch(err => {
420
+ if (err) return console.error(err.message);
421
+ });
422
+ }
423
+
424
+ await post_play(link, anime, player)
425
+ process.exit()
426
+
427
+
428
+ }else if (config.player === "BROWSER"){
429
+ console.log(colors.Yellow, "Opening video in browser... ")
430
+ open(link)
431
+ await post_play(link, anime)
432
+ process.exit()
433
+ }else if (config.player === "MPV"){
434
+ if (!player){
435
+ console.log(colors.Yellow, "Loading MPV... ")
436
+ player = new PlayerController({
437
+ app: 'mpv',
438
+ args: ['--fullscreen'],
439
+ media: link
440
+ });
441
+ await player.launch(err => {
442
+ if (err) return console.error(err.message);
443
+ });
444
+ }else{
445
+ player.load(link)
446
+ }
447
+
448
+ await post_play(link, anime, player)
449
+ process.exit()
450
+ }
451
+ }
452
+
453
+ async function search(){
454
+ console.log(colors.Magenta, "Search...")
455
+ let choice = await input("")
456
+ let anime = await process_search(choice)
457
+
458
+ console.log("\n")
459
+
460
+ console.log(colors.Blue, "Indexing video...")
461
+ let link = await get_video_link(anime.episodes[anime.episode_number])
462
+ if (!link){
463
+ console.log(colors.Red, "Np link for this episode found?")
464
+ console.log(colors.Yellow, "^ at current this is due to not all of the required video repos being implemented.")
465
+ console.log(colors.Yellow, "Sorry for any inconvenience, this should soon by implemented. We appreciate your patience.")
466
+ process.exit()
467
+ }
468
+ console.log(colors.Blue, `Episode ${anime.episode_number+1} of ${anime.anime_id.replaceAll("-", " ")} found.\n`)
469
+ if (link.includes("animixplay.to") && config.player === "VLC"){
470
+ console.log(colors.Red, "Warning; animix.to uses m3u8 playlists. Without custom plugins, VLC will not be able to play this file format. It is recomended to use another player for this show/film.")
471
+ }
472
+ console.log(colors.Cyan, "1/p) Play")
473
+ console.log(colors.Cyan, "2/d) Download")
474
+ console.log(colors.Cyan, "3/l) Show Link")
475
+ console.log(colors.Cyan, "4/q) quit")
476
+ choice = (await selection(4, "select;", ["p", "d", "l", "q"]))
477
+ switch (choice){
478
+ case "p":
479
+ case "1":
480
+ await play(link, anime, null)
481
+ break
482
+ case "d":
483
+ case "2":
484
+ await download(link, anime.anime_id+(anime.episode_number+1)+".mp4")
485
+ break
486
+ case "l":
487
+ case "3":
488
+ console.log(colors.Yellow, "Link: "+link)
489
+ console.log(colors.Cyan, "\n1/p) Play")
490
+ console.log(colors.Cyan, "2/d) Download")
491
+ console.log(colors.Cyan, "3/q) quit")
492
+ choice = (await selection(3, "select;", ["p", "d", "q"]))
493
+ switch (choice){
494
+ case "p":
495
+ case "1":
496
+ await play(link, anime, null)
497
+ break
498
+ case "d":
499
+ case "2":
500
+ await download(link, anime.anime_id+anime.episode_number+".mp4")
501
+ break
502
+ case "q":
503
+ case "3":
504
+ await main()
505
+ process.exit()
506
+ }
507
+ break
508
+ case "q":
509
+ case "4":
510
+ await main()
511
+ process.exit()
512
+ }
513
+ }
514
+
515
+
516
+ console.clear()
517
+ read_config()
518
+ console.log(colors.Blue, "Welcome to Ani-Cli-npm\n")
519
+ if (config.most_recent.episode_number !== 0){
520
+ console.log(colors.White, `Most recently played: ${config.most_recent.anime_id}, ep${config.most_recent.episode_number+1}`)
521
+ }
522
+ async function main(){
523
+ if (config.player === "VLC"){
524
+ console.log(colors.Red, "Warning; if you do not have mpv video player installed, you will have to change your video player to either vlc or browser in config.\n")
525
+ }
526
+ console.log(colors.Cyan, "\n1/s) Search")
527
+ if (config.most_recent.episode_number !== 0){
528
+ console.log(colors.Cyan, "2/c) Continue")
529
+ }else{
530
+ console.log(colors.White, "2/c) Continue")
531
+ }
532
+ console.log(colors.Cyan, "3/C) Config")
533
+ console.log(colors.Cyan, "4/q) Quit")
534
+ let choice = await selection(4, "select;", ["s", "c", "C", "q"])
535
+ switch (choice){
536
+ case "s":
537
+ case "1":
538
+ await search()
539
+ break
540
+ case "c":
541
+ case "2":
542
+ if (config.most_recent.episode_number !== 0){
543
+ await _continue()
544
+ }else{
545
+ console.log(colors.White, "No episodes watched recently")
546
+ await main()
547
+ }
548
+
549
+ break
550
+ case "C":
551
+ case "3":
552
+ let temp = structuredClone(config);
553
+ let exit_code;
554
+ while (true) {
555
+ temp, exit_code = await config_(temp)
556
+ if (exit_code === 1) {
557
+ config = temp
558
+ //proxyAgent = new HttpsProxyAgent(config.proxy);
559
+ console.clear()
560
+ console.log(colors.Blue, "ANI-CLI-NPM \n")
561
+ console.log(colors.Yellow, "Config changed.")
562
+ break
563
+ } else if (exit_code === 2) {
564
+ temp = config
565
+ console.clear()
566
+ console.log(colors.Blue, "ANI-CLI-NPM \n")
567
+ console.log(colors.Yellow, "Config changes disregarded.")
568
+ break
569
+ }
570
+ }
571
+ try{
572
+ fs.writeFileSync(getAppDataPath()+"/ani-cli-npm.conf", JSON.stringify(config))
573
+ }catch{
574
+ console.log(colors.Red, "Error writing to .conf file.")
575
+ }
576
+ await main()
577
+ break
578
+ case "q":
579
+ case "4":
580
+ console.log(colors.Black, "Exiting...")
581
+ process.exit()
582
+ }
583
+ }
584
+
585
+
586
+ main()
package/bin/input.js ADDED
@@ -0,0 +1,63 @@
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); })) {
10
+ let color = true;
11
+ for (let x in options) {
12
+ if (color) {
13
+ console.log(color1((parseInt(x) + 1).toString() +
14
+ ((extra_options[x] == undefined) ? "" : "/" + extra_options[x]) +
15
+ ") " + options[x]));
16
+ }
17
+ else {
18
+ console.log(color2((parseInt(x) + 1).toString() +
19
+ ((extra_options[x] == undefined) ? "" : "/" + extra_options[x]) +
20
+ ") " + options[x]));
21
+ }
22
+ color = !color;
23
+ }
24
+ let input = "";
25
+ do {
26
+ // @ts-ignore
27
+ input = (await _prompt(">")).toLowerCase();
28
+ for (let x in extra_options) {
29
+ if (extra_options[x].toLowerCase() == input) {
30
+ input = (parseInt(x) + 1).toString();
31
+ }
32
+ }
33
+ if (!(1 <= parseInt(input) && parseInt(input) <= options.length)) {
34
+ console.log(chalk_1.default.red("Invalid choice."));
35
+ }
36
+ } while (!(1 <= parseInt(input) && parseInt(input) <= options.length));
37
+ return parseInt(input) - 1;
38
+ }
39
+ exports.selection = selection;
40
+ async function input() {
41
+ return await _prompt(">");
42
+ }
43
+ exports.input = input;
44
+ async function number_input(max, min = 1) {
45
+ let selection;
46
+ do {
47
+ selection = parseInt(await _prompt(">"));
48
+ if (!(min <= selection && selection <= max)) {
49
+ console.log(chalk_1.default.red("Invalid choice."));
50
+ }
51
+ } while (!(min <= selection && selection <= max));
52
+ return selection;
53
+ }
54
+ exports.number_input = number_input;
55
+ async function number_input_range(max, min = 1) {
56
+ let selection;
57
+ do {
58
+ selection = await _prompt(">");
59
+ if (!(min <= parseInt(selection[0]) && parseInt(selection[0]) <= max)) {
60
+ console.log(chalk_1.default.red("Invalid choice."));
61
+ }
62
+ } while (!(min <= parseInt(selection[0]) && parseInt(selection[0]) <= max));
63
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/bin/libs.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ // Random functions
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.range = void 0;
5
+ function range(start, end) {
6
+ let ans = [];
7
+ for (let i = start; i <= end; i++) {
8
+ ans.push(i);
9
+ }
10
+ return ans;
11
+ }
12
+ exports.range = range;