ani-cli-npm 2.1.3 → 2.1.5
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/README.MD +2 -0
- package/bin/Anime.js +46 -30
- package/bin/IO/help.js +59 -0
- package/bin/IO/input.js +89 -0
- package/bin/cover_manager.js +3 -0
- package/bin/download.js +2 -2
- package/bin/file_managment/change_config.js +3 -2
- package/bin/file_managment/load_config.js +2 -1
- package/bin/index.js +8 -3
- package/bin/url_genoration/generate_link.js +47 -0
- package/bin/url_genoration/search_anime.js +39 -0
- package/package.json +1 -1
- package/src/Anime.ts +427 -0
- package/src/IO/help.ts +64 -0
- package/src/IO/input.ts +92 -0
- package/src/core_utils/curl.ts +32 -0
- package/src/core_utils/interfaces.ts +25 -0
- package/src/core_utils/libs.ts +13 -0
- package/src/core_utils/regex.ts +5 -0
- package/src/cover_manager.ts +9 -0
- package/src/download.ts +35 -0
- package/src/file_managment/cache.ts +58 -0
- package/src/file_managment/change_config.ts +126 -0
- package/src/file_managment/load_config.ts +79 -0
- package/src/index.ts +143 -0
- package/src/url_genoration/generate_link.ts +53 -0
- package/src/url_genoration/search_anime.ts +41 -0
- package/src/video_quality.ts +6 -0
- package/temp.sh +676 -0
package/src/Anime.ts
ADDED
@@ -0,0 +1,427 @@
|
|
1
|
+
import {curl} from "./core_utils/curl";
|
2
|
+
import {RegexParse} from "./core_utils/regex";
|
3
|
+
import {generate_link} from "./url_genoration/generate_link";
|
4
|
+
import {config_interface, player} from "./core_utils/interfaces";
|
5
|
+
import {search_cache, new_cache} from "./file_managment/cache";
|
6
|
+
import {number_input, selection} from "./IO/input";
|
7
|
+
import {write_config} from "./file_managment/load_config";
|
8
|
+
const W2GClient = require("w2g-client")
|
9
|
+
const open = require("open")
|
10
|
+
const PlayerController = require("media-player-controller")
|
11
|
+
const dl = require("download-file-with-progressbar");
|
12
|
+
const chalk = require("chalk")
|
13
|
+
const m3u8ToMp4 = require("m3u8-to-mp4");
|
14
|
+
const converter = new m3u8ToMp4();
|
15
|
+
|
16
|
+
|
17
|
+
class Anime{
|
18
|
+
/*
|
19
|
+
Class for handling a show/film
|
20
|
+
|
21
|
+
Stores anime dpage links assigned with anime_id.
|
22
|
+
|
23
|
+
Initialised with Anime.init()
|
24
|
+
|
25
|
+
*/
|
26
|
+
|
27
|
+
id: string = "";
|
28
|
+
episode_list: string[] = [];
|
29
|
+
most_recent:number = 0;
|
30
|
+
player:player = new class implements player {
|
31
|
+
play(episode_link: string): {} {
|
32
|
+
return {};
|
33
|
+
}
|
34
|
+
player: any;
|
35
|
+
};
|
36
|
+
current_pos:number = 0;
|
37
|
+
current_episode:number = 0;
|
38
|
+
|
39
|
+
async init(anime_id: string, cache_folder:string){ // init mate
|
40
|
+
/*
|
41
|
+
Initiate Anime object
|
42
|
+
|
43
|
+
Will first search cache folder for cache file (this will contain id and dpage links)
|
44
|
+
|
45
|
+
If no cache is found, it will use get_ep_bases(anime_id) to get links. (Webscrapes from animixplay.to), then creates cache
|
46
|
+
|
47
|
+
anime_id:
|
48
|
+
*/
|
49
|
+
let cache_object = search_cache(cache_folder, anime_id)
|
50
|
+
this.id = anime_id
|
51
|
+
if (cache_object == 0){
|
52
|
+
await this.get_ep_bases(this.id)
|
53
|
+
new_cache(cache_folder,{
|
54
|
+
id: this.id,
|
55
|
+
episode_list: this.episode_list,
|
56
|
+
most_recent: this.most_recent
|
57
|
+
})
|
58
|
+
}else{
|
59
|
+
try{
|
60
|
+
this.episode_list = cache_object.episode_list
|
61
|
+
if (cache_object.most_recent != undefined){
|
62
|
+
this.most_recent = cache_object.most_recent
|
63
|
+
}
|
64
|
+
if (cache_object.position != undefined){
|
65
|
+
this.current_pos = cache_object.position
|
66
|
+
}
|
67
|
+
}catch{
|
68
|
+
await this.get_ep_bases(this.id)
|
69
|
+
}
|
70
|
+
}
|
71
|
+
new_cache(cache_folder,{
|
72
|
+
id: this.id,
|
73
|
+
episode_list: this.episode_list,
|
74
|
+
most_recent: this.most_recent
|
75
|
+
})
|
76
|
+
return 0;
|
77
|
+
}
|
78
|
+
|
79
|
+
async get_episode_link(episode:number, player:string = "VLC"){
|
80
|
+
let episode_dpage = this.episode_list[episode]
|
81
|
+
let id = episode_dpage.replace("//gogohd.pro/streaming.php?id=","")
|
82
|
+
id = id.slice(0, id.indexOf("="))
|
83
|
+
let link:string = await generate_link(1,id, player)
|
84
|
+
if (!link){
|
85
|
+
link = await generate_link(2,id, player)
|
86
|
+
}
|
87
|
+
if (!link){
|
88
|
+
console.log(chalk.red("Failed to generate links"))
|
89
|
+
}
|
90
|
+
if (player == "VLC" && link.includes("m3u8")){
|
91
|
+
console.log(chalk.red("Warning; VLC is not compatible with m3u8 playlist files without custom plugins."))
|
92
|
+
}
|
93
|
+
return link
|
94
|
+
}
|
95
|
+
|
96
|
+
async get_ep_bases(anime_id:string){
|
97
|
+
/*
|
98
|
+
Scrapes animixplay.to for dpage links.
|
99
|
+
returns array with all dpage links
|
100
|
+
*/
|
101
|
+
let html = (await(curl("https://animixplay.to/v1/"+anime_id))).split("\n") //POTENTIAL BREAK POINT. animixplay.to may change domain address
|
102
|
+
let lines = ""
|
103
|
+
for (let x in html){
|
104
|
+
if(RegexParse(html[x], "*<div id=\"epslistplace\"*")){
|
105
|
+
lines = (html[x])
|
106
|
+
}
|
107
|
+
}
|
108
|
+
lines = lines.slice(55, lines.length).replace("}</div>", "")
|
109
|
+
lines = "{" + lines.slice(lines.indexOf(",")+1, lines.length) + "}"
|
110
|
+
let json = JSON.parse(lines)
|
111
|
+
for (const value of Object.entries(json) as unknown as string[]) {
|
112
|
+
if (typeof value[1] == "string"){
|
113
|
+
this.episode_list.push(value[1].replace("//gogohd.pro/streaming.php?id=",""))
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
async play_head(episode:number, config:config_interface, config_dir:string){
|
119
|
+
/*
|
120
|
+
# Starts play cascade.
|
121
|
+
|
122
|
+
## Takes in:
|
123
|
+
### Episode number, counting from 0
|
124
|
+
### Config object
|
125
|
+
### Config save directory
|
126
|
+
|
127
|
+
- If config.player is set to MPV or VLC, it will use the media-player-controller package.
|
128
|
+
|
129
|
+
- If set to Browser, it will use the "open" packer.
|
130
|
+
|
131
|
+
- If set to Link, it will simply print the media stream link to console, primarily for debuting peruses.
|
132
|
+
*/
|
133
|
+
console.clear()
|
134
|
+
console.log(`Playing ${this.id} episode ${episode+1}`)// from ${new Date(this.current_pos * 1000).toISOString().slice(11, 19)}`)
|
135
|
+
if (this.current_pos != 0){
|
136
|
+
console.log(`Most recent position: ${new Date(this.current_pos * 1000).toISOString().slice(11, 19)}`)
|
137
|
+
}
|
138
|
+
switch (config.player){
|
139
|
+
case "MPV":
|
140
|
+
console.log(("Opening MPV.."))
|
141
|
+
this.player.player = await new PlayerController({
|
142
|
+
app: 'mpv',
|
143
|
+
args: ['--fullscreen', '--keep-open=yes'],// `--start=+${this.current_pos}`],
|
144
|
+
media: await this.get_episode_link(episode, config.player),
|
145
|
+
ipcPath: config.mpv_socket_path
|
146
|
+
});
|
147
|
+
this.player.play = (async (episode_link:string) => {
|
148
|
+
this.player.player.load(episode_link)
|
149
|
+
})
|
150
|
+
this.player.player.on('playback', (data: any) =>{
|
151
|
+
if (data.name == "time-pos" && data.value >= 0){
|
152
|
+
this.current_pos = data.value;
|
153
|
+
}
|
154
|
+
//console.log(data)
|
155
|
+
})
|
156
|
+
this.player.player.on('app-exit', (code: any) => {
|
157
|
+
config.most_recent.anime_id = this.id
|
158
|
+
config.most_recent.episode_number = episode
|
159
|
+
config.most_recent.episode_second = this.current_pos
|
160
|
+
write_config(config_dir, config)
|
161
|
+
this.most_recent = episode;
|
162
|
+
new_cache(config_dir,{
|
163
|
+
id: this.id,
|
164
|
+
episode_list: this.episode_list,
|
165
|
+
most_recent: this.most_recent,
|
166
|
+
position: this.current_pos
|
167
|
+
})
|
168
|
+
})
|
169
|
+
// @ts-ignore
|
170
|
+
await this.player.player.launch(err => {
|
171
|
+
if (err) return console.error(err.message);
|
172
|
+
});
|
173
|
+
|
174
|
+
break
|
175
|
+
case "VLC":
|
176
|
+
console.log(("Opening VLC.."))
|
177
|
+
this.player.player = await new PlayerController({
|
178
|
+
app: 'vlc',
|
179
|
+
args: ['--fullscreen'],//, `--start-time ${this.current_pos}`],
|
180
|
+
media: await this.get_episode_link(episode, config.player),
|
181
|
+
//httpPort: (config.vlc_socket !== 0)? config.vlc_socket : null,
|
182
|
+
//httpPass: (config.vlc_pass !== "")? config.vlc_socket : null,
|
183
|
+
});
|
184
|
+
// @ts-ignore
|
185
|
+
await this.player.player.launch(err => {
|
186
|
+
if (err) return console.error(err.message);
|
187
|
+
});
|
188
|
+
|
189
|
+
this.player.play = (async (episode_link:string) => {
|
190
|
+
this.player.player.quit()
|
191
|
+
this.player.player = await new PlayerController({
|
192
|
+
app: 'vlc',
|
193
|
+
args: ['--fullscreen'],// "--start-time 0"],
|
194
|
+
media: episode_link
|
195
|
+
//httpPort: (config.vlc_socket !== 0)? config.vlc_socket : null,
|
196
|
+
//httpPass: (config.vlc_pass !== "")? config.vlc_socket : null,
|
197
|
+
});
|
198
|
+
this.player.player.on('playback', (data: any) =>{
|
199
|
+
if (data.name == "time-pos" && data.value >= 0){
|
200
|
+
this.current_pos = data.value;
|
201
|
+
}
|
202
|
+
//console.log(data)
|
203
|
+
})
|
204
|
+
|
205
|
+
this.player.player.on('app-exit', (code: any) => {
|
206
|
+
config.most_recent.anime_id = this.id
|
207
|
+
config.most_recent.episode_number = episode
|
208
|
+
config.most_recent.episode_second = this.current_pos
|
209
|
+
write_config(config_dir, config)
|
210
|
+
this.most_recent = episode;
|
211
|
+
new_cache(config_dir,{
|
212
|
+
id: this.id,
|
213
|
+
episode_list: this.episode_list,
|
214
|
+
most_recent: this.most_recent,
|
215
|
+
position: this.current_pos
|
216
|
+
})
|
217
|
+
})
|
218
|
+
// @ts-ignore
|
219
|
+
await this.player.player.launch(err => {
|
220
|
+
if (err) return console.error(err.message);
|
221
|
+
});
|
222
|
+
|
223
|
+
|
224
|
+
})
|
225
|
+
break
|
226
|
+
case "BROWSER":
|
227
|
+
this.player.play = (async (episode_link:string) => {
|
228
|
+
console.log(("Opening browser..."))
|
229
|
+
await open(episode_link)
|
230
|
+
})
|
231
|
+
console.log(("Opening browser..."))
|
232
|
+
await open(await this.get_episode_link(episode, config.player))
|
233
|
+
break
|
234
|
+
case "W2G":
|
235
|
+
try{
|
236
|
+
this.player.player = new W2GClient.W2GClient(config.w2g_api_key);
|
237
|
+
await this.player.player.create(await this.get_episode_link(episode, config.player))
|
238
|
+
console.log(chalk.green("Room link: " + await this.player.player.getLink()));
|
239
|
+
}catch{
|
240
|
+
console.log(chalk.red("Failed to create w2g.tv room. \nthis can often be because your API token is invalid. You can change it in options."))
|
241
|
+
process.exit()
|
242
|
+
}
|
243
|
+
this.player.play = (async (episode_link:string) => {
|
244
|
+
console.log(("Updating W2G room..."))
|
245
|
+
console.log(chalk.green("Room link: " + await this.player.player.getLink()));
|
246
|
+
try{
|
247
|
+
await this.player.player.update(episode_link)
|
248
|
+
}catch{
|
249
|
+
console.log(chalk.red("Error updating W2G room. Very sorry, w2g functionality is a bit broken at present. Worst case you should be able to just restart with a new room for each episode."))
|
250
|
+
}
|
251
|
+
})
|
252
|
+
console.log("Opening W2G.tv...")
|
253
|
+
await open(await this.player.player.getLink())
|
254
|
+
|
255
|
+
break
|
256
|
+
case "LINK":
|
257
|
+
this.player.play = (async (episode_link:string) => {
|
258
|
+
console.log(chalk.green(episode_link))
|
259
|
+
});
|
260
|
+
this.player.play(await this.get_episode_link(episode))
|
261
|
+
break
|
262
|
+
}
|
263
|
+
await this.play_controller(episode, config, config_dir, true)
|
264
|
+
}
|
265
|
+
|
266
|
+
async next(player:string){
|
267
|
+
this.current_episode += 1
|
268
|
+
this.current_pos = 0
|
269
|
+
this.player.play(await this.get_episode_link(this.current_episode, player))
|
270
|
+
}
|
271
|
+
async previous(player:string){
|
272
|
+
this.current_episode -= 1
|
273
|
+
this.current_pos = 0
|
274
|
+
this.player.play(await this.get_episode_link(this.current_episode, player))
|
275
|
+
}
|
276
|
+
|
277
|
+
private async play_controller(episode:number, config:config_interface, config_dir:string, first:boolean=false){
|
278
|
+
if (config.show_cover){
|
279
|
+
|
280
|
+
}
|
281
|
+
console.clear()
|
282
|
+
console.log(`Playing ${this.id} episode ${episode+1}`)// from ${new Date(this.current_pos * 1000).toISOString().slice(11, 19)}`)
|
283
|
+
// if (!first){
|
284
|
+
// console.clear()
|
285
|
+
// console.log(chalk.blue(`Playing ${this.id} episode ${episode+1}`))
|
286
|
+
// if (this.player == 0){
|
287
|
+
// await open(await this.get_episode_link(episode, "BROWSER"))
|
288
|
+
// }else if(this.player == 1){
|
289
|
+
// console.log(await this.get_episode_link(episode))
|
290
|
+
// } else if (this.player.roomID != undefined){
|
291
|
+
// console.log(chalk.green("Room link: "+ await this.player.getLink()));
|
292
|
+
// this.player.update(await this.get_episode_link(episode))
|
293
|
+
// } else if (this.player.opts.app == "mpv"){
|
294
|
+
// await this.player.load(await this.get_episode_link(episode))
|
295
|
+
// }else{
|
296
|
+
// this.player.quit()
|
297
|
+
// this.player = await new PlayerController({
|
298
|
+
// app: 'vlc',
|
299
|
+
// args: ['--fullscreen'],
|
300
|
+
// media: await this.get_episode_link(episode, config.player)
|
301
|
+
// });
|
302
|
+
// // @ts-ignore
|
303
|
+
// await this.player.launch(err => {
|
304
|
+
// if (err) return console.error(err.message);
|
305
|
+
// });
|
306
|
+
// }
|
307
|
+
// }
|
308
|
+
this.current_episode = episode
|
309
|
+
config.most_recent.anime_id = this.id
|
310
|
+
config.most_recent.episode_number = episode
|
311
|
+
config.most_recent.episode_second = this.current_pos
|
312
|
+
write_config(config_dir, config)
|
313
|
+
this.most_recent = episode;
|
314
|
+
new_cache(config_dir,{
|
315
|
+
id: this.id,
|
316
|
+
episode_list: this.episode_list,
|
317
|
+
most_recent: this.most_recent,
|
318
|
+
position: this.current_pos
|
319
|
+
})
|
320
|
+
|
321
|
+
|
322
|
+
let selected:number; // Look, I'm sorry, but there is no way I can possibly document this in a sane way. It's a dumb patch.
|
323
|
+
do{
|
324
|
+
console.clear()
|
325
|
+
selected = await selection(
|
326
|
+
(episode <= 0)? [chalk.yellow("1/n) Next"), chalk.grey("2/p) Previous"), chalk.yellow("3/s) Select"), chalk.green("4/q) Quit")]:
|
327
|
+
(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")] :
|
328
|
+
[chalk.yellow("1/n) Next"), chalk.green("2/p) Previous"), chalk.yellow("3/s) Select"), chalk.green("4/q) Quit")],
|
329
|
+
|
330
|
+
["n", "p", "s", "q"],
|
331
|
+
((thing:string) => {return (thing)}),
|
332
|
+
((thing:string) => {return (thing)}),
|
333
|
+
true
|
334
|
+
)
|
335
|
+
if (!(selected != ((episode <= 0)? 1 : (episode >= this.episode_list.length-1)? 0 : -1))){
|
336
|
+
console.log(chalk.red("Invalid choice."))
|
337
|
+
}
|
338
|
+
}while (!(selected != ((episode <= 0)? 1 : (episode >= this.episode_list.length-1)? 0 : -1)))
|
339
|
+
|
340
|
+
switch(selected){
|
341
|
+
case 0:
|
342
|
+
if (episode >= this.episode_list.length-1){
|
343
|
+
await this.next(config.player)
|
344
|
+
await this.play_controller(episode-1, config, config_dir)
|
345
|
+
}else{
|
346
|
+
await this.next(config.player)
|
347
|
+
await this.play_controller(episode+1, config, config_dir)
|
348
|
+
}
|
349
|
+
break
|
350
|
+
case 1:
|
351
|
+
if ((episode >= this.episode_list.length-1) || (episode <= 0)){
|
352
|
+
break
|
353
|
+
}
|
354
|
+
await this.previous(config.player)
|
355
|
+
await this.play_controller(episode-1, config, config_dir)
|
356
|
+
break
|
357
|
+
case 2:
|
358
|
+
if (this.episode_list.length == 1){
|
359
|
+
this.player.play(await this.get_episode_link(0, config.player))
|
360
|
+
await this.play_controller(0, config, config_dir)
|
361
|
+
}else{
|
362
|
+
console.log(`Select episode [1-${this.episode_list.length}]`)
|
363
|
+
let episode = await number_input(this.episode_list.length, 1)-1
|
364
|
+
this.player.play(await this.get_episode_link(episode, config.player))
|
365
|
+
await this.play_controller(episode, config, config_dir)
|
366
|
+
}
|
367
|
+
break
|
368
|
+
case 3:
|
369
|
+
break
|
370
|
+
}
|
371
|
+
}
|
372
|
+
|
373
|
+
async download(episode:number, download_folder:string, final_ep:number){
|
374
|
+
/*
|
375
|
+
## Downloads an episode (counting from 0) to download_folder, with progress bar.
|
376
|
+
*/
|
377
|
+
while (episode <= final_ep){
|
378
|
+
|
379
|
+
}
|
380
|
+
try {
|
381
|
+
let ep_link: string = await this.get_episode_link(episode)
|
382
|
+
let file_name = `${this.id}-${episode + 1}.mp4`
|
383
|
+
if (ep_link.includes(".m3u8")){
|
384
|
+
console.log(chalk.green(`Downloading episode ${episode+1} of ${this.id.replace("-", "")} to ${download_folder+"/"+file_name}...`))
|
385
|
+
console.log("Progress bar unavailable for m3u8 files.")
|
386
|
+
await converter
|
387
|
+
.setInputFile(ep_link)
|
388
|
+
.setOutputFile((download_folder+"/"+file_name))
|
389
|
+
.start();
|
390
|
+
console.log(chalk.green("Download finished."))
|
391
|
+
}else{
|
392
|
+
// @ts-ignore
|
393
|
+
let option = {
|
394
|
+
filename: (ep_link.includes("m3u8") ? file_name.replace("mp4", "m3u8") : file_name),
|
395
|
+
dir: download_folder,
|
396
|
+
onDone: (final_ep > episode) ? ((info: any) => {
|
397
|
+
// @ts-ignore
|
398
|
+
console.log(chalk.green(`\n -- 1Download finished -- \nLocation: ${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
|
399
|
+
this.download(episode + 1, download_folder, final_ep)
|
400
|
+
}) : ((info: any) => {
|
401
|
+
// @ts-ignore
|
402
|
+
console.log(chalk.green(`\n -- 2Download finished -- \n${info.path}. Size: ${Math.round(info.size / 100000) * 10} Bytes\n`));
|
403
|
+
}),
|
404
|
+
// @ts-ignore
|
405
|
+
onError: (err) => {
|
406
|
+
console.log(chalk.red('error', err));
|
407
|
+
this.download(episode, download_folder, final_ep)
|
408
|
+
},
|
409
|
+
// @ts-ignore
|
410
|
+
onProgress: (curr, total) => {
|
411
|
+
process.stdout.clearLine(0);
|
412
|
+
process.stdout.cursorTo(0);
|
413
|
+
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")
|
414
|
+
}
|
415
|
+
}
|
416
|
+
//console.log((`${option.dir}/${option.filename}`))
|
417
|
+
|
418
|
+
return await dl(ep_link, option);
|
419
|
+
}
|
420
|
+
}catch{
|
421
|
+
await this.download(episode, download_folder, final_ep)
|
422
|
+
}
|
423
|
+
}
|
424
|
+
|
425
|
+
}
|
426
|
+
|
427
|
+
export {Anime}
|
package/src/IO/help.ts
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
import {selection} from "./input";
|
2
|
+
|
3
|
+
const chalk = require("chalk")
|
4
|
+
|
5
|
+
|
6
|
+
const helps = [
|
7
|
+
(async () => { // Playing anime
|
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 () => { // Downloading anime
|
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
|
+
))
|
49
|
+
await help()
|
50
|
+
return
|
51
|
+
}),
|
52
|
+
(async () => {
|
53
|
+
return
|
54
|
+
})
|
55
|
+
|
56
|
+
]
|
57
|
+
|
58
|
+
|
59
|
+
async function help(){
|
60
|
+
console.log(chalk.cyan("Help page select: \n"))
|
61
|
+
return helps[await selection(["Playing", "Downloading", "Options", "Quit"], ["p", "d", "o", "q"])]()
|
62
|
+
}
|
63
|
+
|
64
|
+
export {help}
|
package/src/IO/input.ts
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
import chalk from "chalk";
|
2
|
+
const _prompt = require("simple-input");
|
3
|
+
|
4
|
+
|
5
|
+
async function selection(options:string[], extra_options:string[] = [], color1 = ((thing:string) => {return chalk.yellow(thing)}), color2 = ((thing:string) => {return chalk.green(thing)}), overwrite:boolean=false){
|
6
|
+
/*
|
7
|
+
selection(options, extra_options, color1, color2)
|
8
|
+
|
9
|
+
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.
|
10
|
+
|
11
|
+
|
12
|
+
- options: array of options; e.g. ["play", "download", "continue", "quit"] REQUIRED
|
13
|
+
|
14
|
+
|
15
|
+
- extra_options: array of characters as alternatives to numbers (both will be displayed). e.g. ["p", "d", "c", "q"].
|
16
|
+
|
17
|
+
default: []
|
18
|
+
|
19
|
+
- color1 and color2: functions that will dictate what 2 colors the options with alternate between (option1 will be color1, option2;color2, option3;color1, etc).
|
20
|
+
recommended for this function to return a chalk.____() parsed string.
|
21
|
+
|
22
|
+
default: ((thing:string) => {return chalk.yellow(thing)}) and ((thing:string) => {return chalk.green(thing)})
|
23
|
+
|
24
|
+
- 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.
|
25
|
+
*/
|
26
|
+
|
27
|
+
|
28
|
+
let color:boolean = true;
|
29
|
+
for (let x in options){
|
30
|
+
if (!overwrite){
|
31
|
+
if (color){
|
32
|
+
console.log(
|
33
|
+
color1((parseInt(x)+1).toString()+
|
34
|
+
((extra_options[x] == undefined)? "" : "/"+extra_options[x])+
|
35
|
+
") "+options[x].replaceAll("-", " "))
|
36
|
+
)
|
37
|
+
}else{
|
38
|
+
console.log(
|
39
|
+
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:string = ""
|
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.red("Invalid choice."))
|
60
|
+
}
|
61
|
+
}while(!(1 <= parseInt(input) && parseInt(input) <= options.length))
|
62
|
+
return parseInt(input)-1
|
63
|
+
}
|
64
|
+
|
65
|
+
async function input(){
|
66
|
+
return await _prompt(">")
|
67
|
+
}
|
68
|
+
|
69
|
+
async function number_input(max:number, min:number=1, extra_options:string[] =[], extra_option_values:number[]=[]){
|
70
|
+
let selector:string;
|
71
|
+
let selection:number;
|
72
|
+
do{
|
73
|
+
selector = await _prompt(">")
|
74
|
+
if (extra_options.includes(selector.toLowerCase())){
|
75
|
+
selection = extra_option_values[extra_options.indexOf(selector)]
|
76
|
+
}else{
|
77
|
+
selection = parseInt(selector)
|
78
|
+
}
|
79
|
+
if (selector == ""){
|
80
|
+
selection = min
|
81
|
+
}
|
82
|
+
if (!(min <= selection && selection <= max)){
|
83
|
+
console.log(chalk.red("Invalid choice."))
|
84
|
+
}
|
85
|
+
}while (!(min <= selection && selection <= max))
|
86
|
+
|
87
|
+
return selection
|
88
|
+
}
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
export {selection, input, number_input}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
const fetch = require("node-fetch")
|
2
|
+
const chalk = require("chalk")
|
3
|
+
async function curl(url: string, method="GET", redirect = false){
|
4
|
+
try{
|
5
|
+
let response = await fetch(url, {
|
6
|
+
//"agent": proxyAgent,
|
7
|
+
"headers": {
|
8
|
+
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0',
|
9
|
+
"X-Requested-With": "XMLHttpRequest"
|
10
|
+
},
|
11
|
+
"referrerPolicy": "origin",
|
12
|
+
"body": null,
|
13
|
+
"method": method,
|
14
|
+
"redirect": 'follow',
|
15
|
+
// "follow": 10,
|
16
|
+
}).catch(async function(err:string) {
|
17
|
+
console.warn(chalk.red(`Something went wrong connecting to ${url}. ${err}`));
|
18
|
+
process.exit()
|
19
|
+
})
|
20
|
+
if (redirect){
|
21
|
+
return response.url
|
22
|
+
}else{
|
23
|
+
return await response.text()
|
24
|
+
}
|
25
|
+
}catch{
|
26
|
+
console.log(chalk.red("Something went wrong in curl()"))
|
27
|
+
process.exit()
|
28
|
+
}
|
29
|
+
|
30
|
+
}
|
31
|
+
|
32
|
+
export {curl}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
interface config_interface{
|
2
|
+
player: string,
|
3
|
+
proxy: string,
|
4
|
+
user_agent: string,
|
5
|
+
most_recent: {
|
6
|
+
episode_number: number,
|
7
|
+
episode_second: number,
|
8
|
+
anime_id: string,
|
9
|
+
}
|
10
|
+
download_folder:string,
|
11
|
+
debug_mode: boolean,
|
12
|
+
mpv_socket_path: string,
|
13
|
+
vlc_socket:number,
|
14
|
+
vlc_pass:string,
|
15
|
+
w2g_api_key:string,
|
16
|
+
show_cover: boolean
|
17
|
+
}
|
18
|
+
|
19
|
+
interface player{
|
20
|
+
player: any,
|
21
|
+
play: ((episode_link:string) => {}),
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
export {config_interface, player}
|