ani-cli-npm 2.1.3 → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ import {search} from "./url_genoration/search_anime";
2
+ import {Anime} from "./Anime";
3
+ import {number_input} from "./IO/input";
4
+ import {config_interface} from "./core_utils/interfaces";
5
+
6
+ async function download(cache_folder:string, config:config_interface){
7
+ try{
8
+ console.clear()
9
+ let temp_:any = await search()
10
+ if (temp_ == 1){
11
+ return 2;
12
+ }
13
+ let download_id:string = temp_
14
+ let download: Anime = new Anime();
15
+ await download.init(download_id, cache_folder)
16
+ let start_ep_number:number;
17
+ let end_ep_number:number;
18
+ if (download.episode_list.length <= 1){
19
+ start_ep_number = 1
20
+ end_ep_number = 0
21
+ }else{
22
+ console.log(`Select start episode [1-${download.episode_list.length}]`)
23
+ start_ep_number = await number_input(download.episode_list.length)
24
+ console.log(`Select end episode [${start_ep_number}-${download.episode_list.length}]`)
25
+ end_ep_number = await number_input(download.episode_list.length, start_ep_number)-1
26
+ }
27
+ await download.download(start_ep_number-1, config.download_folder, end_ep_number)
28
+ }catch{
29
+ return 1;
30
+ }
31
+ return 0;
32
+ }
33
+
34
+
35
+ export {download}
@@ -0,0 +1,58 @@
1
+ import * as fs from "fs"
2
+ import chalk from "chalk"
3
+
4
+ async function clear_cache(location:string){
5
+ try{
6
+ await fs.readdir(location, (err, files) => {
7
+ if (err) throw err;
8
+ for (const file of files) {
9
+ if (file.includes(".cache")){fs.unlinkSync(location+"/"+file)}
10
+ }
11
+ });
12
+ }catch{
13
+ console.log(chalk.red("Error clearing cache."))
14
+ }
15
+ return 0
16
+ }
17
+
18
+ function new_cache(location:string, anime:any){
19
+ /*
20
+ Creates cache of Anime object, in cache file.
21
+ */
22
+ try{
23
+ fs.writeFileSync(location+"/"+anime.id+".cache", JSON.stringify(anime))
24
+ }catch{
25
+ console.log("Failed to write to cache")
26
+ }
27
+ }
28
+
29
+ function get_cache(location:string, anime_id:string){
30
+ /*
31
+ ## Get cache by anime_id. Does not check if the cache exists.
32
+ */
33
+ return JSON.parse(fs.readFileSync(location+"/"+anime_id+".cache").toString())
34
+ }
35
+
36
+ function search_cache(cache_folder:string, anime_id:string){
37
+ /*
38
+ ## Searches cache folder for cache file with name of anime_id, at the location of cache_folder
39
+
40
+ ### returns boolean for weather it is found.
41
+ */
42
+ try{
43
+ if (check_cache(cache_folder, anime_id)){
44
+ return get_cache(cache_folder, anime_id)
45
+ }
46
+ return false
47
+ }catch{
48
+ return false
49
+ }
50
+ }
51
+
52
+ function check_cache(location:string, anime_id:string){
53
+ return fs.readdirSync(location).includes(anime_id+".cache")
54
+ }
55
+
56
+
57
+
58
+ export {clear_cache, new_cache, search_cache}
@@ -0,0 +1,126 @@
1
+ const chalk = require("chalk")
2
+ import {selection, input} from "../IO/input";
3
+ import {config_interface} from "../core_utils/interfaces";
4
+
5
+ const configs = [ // List of functions, add function for extra config options.
6
+ (async (temp: config_interface)=> {
7
+ temp.player = [
8
+ "VLC",
9
+ "BROWSER",
10
+ "MPV",
11
+ "W2G",
12
+ "LINK",
13
+ ][await selection([
14
+ "VLC - VLC media player",
15
+ "Browser - Play in default browser",
16
+ "MPV - MPV media player",
17
+ "w2g.tv - Watch together with friends in browser (Specify api token to create rooms linked to your account)",
18
+ "Link - Simply display the link in console"
19
+ ], [], ((item) => {return chalk.cyan(item)}), ((item) => {return chalk.cyan(item)}))];
20
+ // @ts-ignore
21
+ return temp,0
22
+ }),
23
+ (async (temp: config_interface) => {
24
+ console.log(chalk.cyan("New Proxy;"))
25
+ temp.proxy = (await(input())).replaceAll(" ", "")
26
+ // @ts-ignore
27
+ return temp, 0
28
+ }),
29
+ (async (temp: config_interface) => {
30
+ console.log(chalk.cyan("New User Agent"))
31
+ temp.user_agent = await(input())
32
+ // @ts-ignore
33
+ return temp, 0
34
+ }),
35
+ (async (temp: config_interface) => {
36
+ console.log(chalk.cyan("New Downloads Folder"))
37
+ temp.download_folder = await(input())
38
+ // @ts-ignore
39
+ return temp, 0
40
+ }),
41
+ (async (temp: config_interface) => {
42
+ console.log(chalk.cyan("New socket file"))
43
+ temp.mpv_socket_path = await(input())
44
+ // @ts-ignore
45
+ return temp, 0
46
+ }),
47
+ (async (temp: config_interface) => {
48
+ console.log(chalk.cyan("New VLC socket"))
49
+ temp.vlc_socket = await(input())
50
+ // @ts-ignore
51
+ return temp, 0
52
+ }),
53
+ (async (temp: config_interface) => {
54
+ console.log(chalk.cyan("New VLC password"))
55
+ temp.vlc_pass = await(input())
56
+ // @ts-ignore
57
+ return temp, 0
58
+ }),
59
+ (async (temp: config_interface) => {
60
+ console.log(chalk.cyan("New w2g.tv api token"))
61
+ temp.w2g_api_key = await(input())
62
+ // @ts-ignore
63
+ return temp, 0
64
+ }),
65
+ (async (temp: config_interface) => {
66
+ let config: config_interface = {
67
+ player: "BROWSER",
68
+ proxy: "",
69
+ user_agent: "Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0",
70
+ most_recent: {
71
+ episode_number: 0,
72
+ episode_second: 0,
73
+ anime_id: ""
74
+ },
75
+ download_folder: ".",
76
+ debug_mode: false,
77
+ mpv_socket_path: "",
78
+ vlc_socket: 0,
79
+ vlc_pass: "",
80
+ w2g_api_key: "",
81
+ show_cover: false
82
+ }
83
+ console.log(config)
84
+ // @ts-ignore
85
+ return config, 0
86
+ }),
87
+ (async (temp: config_interface) => {
88
+ // @ts-ignore
89
+ return temp, 1
90
+ }),
91
+ (async (temp: config_interface) => {
92
+ // @ts-ignore
93
+ return temp, 2
94
+ })
95
+ ]
96
+
97
+
98
+ async function config_(temp:config_interface){
99
+ /*
100
+ ## Lets user change a single attribute of config. Returns new config object, and an exit code
101
+
102
+ ### 0 to continue (generic return)
103
+ ### 1 To confirm (Save and exit)
104
+ ### 2 to cancel (exit without saving changes)
105
+ */
106
+ console.clear()
107
+ console.log(chalk.blue("ANI-CLI-NPM \n"))
108
+ console.log(chalk.yellow("Config:\n"))
109
+
110
+ return configs[await selection([
111
+ "Player; "+temp.player,
112
+ "Proxy; "+temp.proxy,
113
+ "User agent; "+temp.user_agent,
114
+ "Downloads folder; "+temp.download_folder,
115
+ "Mpv socket connection file; "+temp.mpv_socket_path,
116
+ "VLC socket; "+temp.vlc_socket,
117
+ "VLC pass; "+temp.vlc_pass,
118
+ "W2G api token: "+temp.w2g_api_key,
119
+ "Reset to defaults",
120
+ "Save and exit",
121
+ "Exit without saving"
122
+ ], [], ((item) => {return chalk.cyan(item)}), ((item) => {return chalk.cyan(item)}))
123
+ ](temp)
124
+ }
125
+
126
+ export {config_}
@@ -0,0 +1,79 @@
1
+ import * as fs from "fs"
2
+ //import chalk from 'chalk';
3
+
4
+ import {config_interface} from "../core_utils/interfaces";
5
+
6
+ function make_config_dir(cache_dir:string, debug:boolean){
7
+ try{
8
+ if (!fs.existsSync(cache_dir+"/")) fs.mkdirSync(cache_dir+"/");
9
+ }catch{
10
+ if (debug){
11
+ console.log("Failed to make cache dir")
12
+ }
13
+ }
14
+ }
15
+
16
+ function write_config(cache_dir:string, config:config_interface){
17
+ try{
18
+ //make_config_dir(cache_dir, config.debug_mode)
19
+ fs.writeFileSync(cache_dir+"/config.conf", JSON.stringify(config), "utf-8")
20
+ }catch{
21
+ console.log(("Failed to write to config file."))
22
+ }
23
+ }
24
+
25
+ function load_config(cache_dir: string){
26
+ let config: config_interface = {
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
+ episode_second: 0,
33
+ anime_id: ""
34
+ },
35
+ download_folder: ".",
36
+ debug_mode: false,
37
+ mpv_socket_path: "",
38
+ vlc_socket: 0,
39
+ vlc_pass: "",
40
+ w2g_api_key: "",
41
+ show_cover:false
42
+ }
43
+ if (fs.existsSync(cache_dir+"/config.conf")){
44
+ // @ts-ignore
45
+ let tmp = JSON.parse(fs.readFileSync(cache_dir+"/config.conf"), "utf8")
46
+
47
+ // @ts-ignore
48
+ if (tmp.player !== undefined) config.player = tmp.player;
49
+ // @ts-ignore
50
+ if (tmp.proxy !== undefined) config.proxy = tmp.proxy;
51
+ // @ts-ignore
52
+ if (tmp.user_agent !== undefined) config.user_agent = tmp.user_agent;
53
+ // @ts-ignore
54
+ if (tmp.most_recent !== undefined) {
55
+ // @ts-ignore
56
+ if (tmp.most_recent.episode_number !== undefined) config.most_recent.episode_number = tmp.most_recent.episode_number;
57
+ // @ts-ignore
58
+ if (tmp.most_recent.anime_id !== undefined) config.most_recent.anime_id = tmp.most_recent.anime_id;
59
+ // @ts-ignore
60
+ if (tmp.most_recent.episode_second !== undefined) config.most_recent.episode_second = tmp.most_recent.episode_second;
61
+ }
62
+ // @ts-ignore
63
+ if (tmp.download_folder !== undefined) config.download_folder = tmp.download_folder;
64
+ // @ts-ignore
65
+ if (tmp.mpv_socket_path !== undefined) config.mpv_socket_path = tmp.mpv_socket_path;
66
+ // @ts-ignore
67
+ if (tmp.vlc_socket !== undefined) config.vlc_socket = tmp.vlc_socket;
68
+ // @ts-ignore
69
+ if (tmp.vlc_pass !== undefined) config.vlc_pass = tmp.vlc_pass;
70
+ // @ts-ignore
71
+ if (tmp.w2g_api_key !== undefined) config.w2g_api_key = tmp.w2g_api_key;
72
+ }
73
+
74
+ write_config(cache_dir, config)
75
+
76
+ return config
77
+ }
78
+
79
+ export {load_config, write_config, make_config_dir}
package/src/index.ts ADDED
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+ import * as process from "process";
3
+ //process.removeAllListeners() // Ignore warning
4
+ // TODO: Use terminal-kit properly
5
+ // External
6
+
7
+ import _appDataFolder from "appdata-path";
8
+ const terminal_kit = require("terminal-kit")
9
+ const chalk = require("chalk")
10
+
11
+ // Internal
12
+ import {Anime} from "./Anime";
13
+ import {search} from "./url_genoration/search_anime";
14
+ import {load_config, make_config_dir, write_config} from "./file_managment/load_config";
15
+ import {selection, number_input} from "./IO/input";
16
+ import {config_} from "./file_managment/change_config";
17
+ import {clear_cache} from "./file_managment/cache";
18
+ import {download} from "./download";
19
+ import {help} from "./IO/help";
20
+ // import {display_cover} from "./cover_manager";
21
+
22
+ const app_data_folder:string = _appDataFolder()
23
+ const cache_folder:string = app_data_folder+"/ani-cli-npm"
24
+ make_config_dir(cache_folder, true)
25
+ // display_cover()
26
+
27
+ console.clear()
28
+ terminal_kit.drawImage("https://gogocdn.net/cover/yuri-on-ice-dub.png")
29
+ async function main(){
30
+ let config = load_config(cache_folder)
31
+ console.log(chalk.magenta("Ani-cli-npm!\n"))
32
+ if (config.most_recent.anime_id !== ""){
33
+ console.log(chalk.grey(`Most recently played: ${config.most_recent.anime_id} episode ${config.most_recent.episode_number+1}\n`))
34
+ }
35
+ let choice:number = await selection([
36
+ "Search",
37
+ "Continue",
38
+ "Download",
39
+ "Option",
40
+ "Clear cache",
41
+ "Help",
42
+ "Quit",
43
+ ], ["s", "c", "d", "o", " ", "h", "q"],
44
+ ((thing:string) => {return chalk.magenta(thing)}),
45
+ ((thing:string) => {return chalk.magenta(thing)})
46
+ )
47
+
48
+ switch(choice){
49
+ case 0: // Search
50
+ let temp_:any = await search()
51
+ if (temp_ == 1){
52
+ await main()
53
+ process.exit()
54
+ }
55
+ let anime_id:string = temp_
56
+
57
+ let anime:Anime = new Anime();
58
+ await anime.init(anime_id, cache_folder)
59
+ let episode_number:number
60
+ if (anime.episode_list.length == 1){
61
+ episode_number = 1;
62
+ }else{
63
+ console.log(`Select episode [1-${anime.episode_list.length}] ${(anime.most_recent != 0)? `Or C to continue from ep${anime.most_recent+1}`: ""}`)
64
+ episode_number = await number_input(anime.episode_list.length, 1, (anime.most_recent != 0)? ["c"]: [], (anime.most_recent != 0)? [anime.most_recent+1] : [])
65
+ }
66
+ await anime.play_head(episode_number-1, config, cache_folder)
67
+ if(anime.player.hasOwnProperty("quit")){
68
+ await anime.player.player.quit()
69
+ }
70
+ await main()
71
+ break
72
+ case 1: // Continue
73
+ if (config.most_recent.anime_id == ""){
74
+ console.clear()
75
+ console.log(chalk.red("No episode played recently"))
76
+ await main()
77
+ break
78
+ }
79
+ let continue_anime:Anime = new Anime()
80
+ await continue_anime.init(config.most_recent.anime_id, cache_folder)
81
+ await continue_anime.play_head(config.most_recent.episode_number, config, cache_folder)
82
+ try{
83
+ await continue_anime.player.player.quit()
84
+ }catch{}
85
+ await main()
86
+ break
87
+ case 2: // Download
88
+ let code:number = await download(cache_folder, config)
89
+ if (code == 1){
90
+ console.log(chalk.red("Error downloading episodes"))
91
+ }
92
+ break
93
+ case 3: // Options
94
+ let temp = structuredClone(config);
95
+ let exit_code;
96
+ while (true) {
97
+ // @ts-ignore
98
+ temp, exit_code = await config_(temp)
99
+ if (exit_code === 1) {
100
+ config = temp
101
+ //proxyAgent = new HttpsProxyAgent(config.proxy);
102
+ console.clear()
103
+ try{
104
+ write_config(cache_folder, config)
105
+ console.log(chalk.yellow("Config changed."))
106
+ }catch{
107
+ console.log(chalk.red("Error writing to .conf file."))
108
+ }
109
+ break
110
+ } else if (exit_code === 2) {
111
+ temp = config
112
+ console.clear()
113
+ console.log(chalk.yellow("Config changes disregarded."))
114
+ break
115
+ }
116
+ }
117
+
118
+ await main()
119
+ break
120
+ case 4:
121
+ console.clear()
122
+ console.log(chalk.yellow("Warning, this will also clear your current position in each anime, are you sure you want to do this?"))
123
+ if (await selection(["yes", "no"], ["y", "n"]) == 0){
124
+ await clear_cache(cache_folder)
125
+ console.clear()
126
+ console.log(chalk.grey("Cache cleared"))
127
+ }else{
128
+ console.clear()
129
+ }
130
+ await main()
131
+ break
132
+ case 5:
133
+ await help()
134
+ break
135
+ case 6: // Quit
136
+ console.log("Exit")
137
+ }
138
+ return 0;
139
+
140
+ // await search()
141
+ }
142
+
143
+ main()
@@ -0,0 +1,53 @@
1
+ const gogohd_url="https://gogohd.pro/"
2
+ const base_url="https://animixplay.to"
3
+
4
+ import {curl} from "./core_utils/curl";
5
+ import {RegexParse} from "./core_utils/regex";
6
+ const chalk = require("chalk")
7
+
8
+
9
+ async function generate_link(provider: number, id: string, player:string){
10
+ let html_:string = ""
11
+ let provider_name = ""
12
+ switch (provider) {
13
+ case 1:
14
+ html_ = await curl(`${gogohd_url}streaming.php?id=${id}`)
15
+ provider_name = 'Xstreamcdn'
16
+ console.log(`Fetching ${provider_name} links...`)
17
+ let html: string[] = html_.split("\n")
18
+ let fb_id = ""
19
+ for (let x in html){
20
+ if (RegexParse(html[x], "*<li class=\"linkserver\" data-status=\"1\" data-video=\"https://fembed9hd.com/v/*")){
21
+ fb_id = html[x].slice(html[x].indexOf("/v/")+3, html[x].indexOf("\">X"))
22
+ break
23
+ }
24
+ }
25
+ if (!fb_id){
26
+ console.log("Error, no fb_id found.")
27
+ return 0
28
+ }
29
+
30
+ //let refr = "https://fembed-hd.com/v/"+fb_id
31
+ let post = await curl("https://fembed-hd.com/api/source/"+fb_id, "POST")
32
+ post = post.slice(post.indexOf(",\"data\":[{\"file\":\"")+18, post.length)
33
+ post = post.slice(0, post.indexOf("\"")).replaceAll("\\/","/")
34
+ return post
35
+ case 2:
36
+ console.log(chalk.red("Error: Animixplay.to has shut down. This removes a large amount of shows from this cli. Fix being worked on currently. Sorry for any inconvenience."))
37
+ process.exit()
38
+ // provider_name = 'Animixplay'
39
+ // console.log(`Fetching ${provider_name} links...`)
40
+ // let buffer = new Buffer(id)
41
+ // let enc_id = buffer.toString("base64")
42
+ // buffer = new Buffer(id+"LTXs3GrU8we9O"+enc_id)
43
+ // let ani_id = buffer.toString("base64")
44
+ // if (player === "BROWSER"){
45
+ // return `${base_url}/api/live${ani_id}`
46
+ // }
47
+ // buffer = Buffer.from((await curl(`${base_url}/api/live${ani_id}`, "GET", true)).split("#")[1], "base64")
48
+ // return buffer.toString("utf-8")
49
+ }
50
+ }
51
+
52
+
53
+ export { generate_link }
@@ -0,0 +1,41 @@
1
+ import {RegexParse} from "../core_utils/regex";
2
+ import {curl} from "../core_utils/curl";
3
+ import {input, selection} from "../IO/input";
4
+ import chalk from "chalk";
5
+
6
+
7
+ async function search_anime(search: string){
8
+ let filter = "*<ahref=\"/category/*\"title=\"*\">"
9
+ let html: string[] = (await curl("https://gogoanime.dk//search.html?keyword="+search)).split("\n")
10
+ let lines: string[] = []
11
+ for (let x in html){
12
+ html[x] = html[x].replaceAll(/ /g,'').replaceAll(/\t/g,'')
13
+ if (RegexParse(html[x], filter)){
14
+ html[x] = html[x].slice(html[x].indexOf("/category/")+10);
15
+ html[x] = html[x].slice(0, html[x].indexOf("\"title="));
16
+ lines.push(html[x])
17
+ }
18
+ }
19
+ if (!lines[0]){
20
+ lines.pop()
21
+ }
22
+
23
+
24
+ return lines
25
+ }
26
+
27
+ async function search(){
28
+ console.clear()
29
+ console.log(chalk.magenta("Search..."))
30
+ let _selection = await input()
31
+ let results:string[] = await search_anime(_selection)
32
+ if (results[0] === undefined){
33
+ console.log(chalk.red("No results found."))
34
+ return 1;
35
+ }
36
+ return results[await selection(results)]
37
+ }
38
+
39
+
40
+
41
+ export {search}
@@ -0,0 +1,6 @@
1
+ function video_quality_mp4(quality:string, link:string){
2
+ switch (quality){
3
+ case "best":
4
+
5
+ }
6
+ }