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.
@@ -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
+ }