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