1use anyhow::Result;
2use argon2::{self, Config};
3use openssl::aes::{aes_ige, AesKey};
4use openssl::symm::Mode;
5
6use select::document::Document;
7use select::predicate::{Attr, Class, Predicate};
8pub mod types;
9
10use types::AnimeCollection;
11use util::UTIL_VARS;
12
13pub mod util;
14
15fn get_document(url: &String) -> Result<Document> {
16 let resp = reqwest::blocking::get(url)?;
17 let body = resp.text()?;
18 let html = body.to_string();
19 let document = Document::from_read(html.as_bytes())?;
20 Ok(document)
21}
22
23pub fn search_anime(keyword: &str) -> Result<AnimeCollection> {
24 let search_url = format!("{}//search.html?keyword={}", UTIL_VARS.base_url, keyword);
25
26 let document = get_document(&search_url)?;
27
28 let elements = document
29 .find(
30 Class(util::UTIL_VARS.search_result_class_value)
31 .descendant(Attr("class", util::UTIL_VARS.anime_title_tag)),
32 )
33 .map(|node| {
34 let anime_node = node.first_child().unwrap();
35 types::Anime {
36 title: anime_node.attr("title").unwrap().to_string(),
37 url: format!(
38 "{}{}",
39 UTIL_VARS.base_url.to_string(),
40 anime_node.attr("href").unwrap().to_string()
41 ),
42 episodes: Vec::new(),
43 }
44 })
45 .collect();
46
47 Ok(elements)
48}
49
50pub fn get_episodes(anime: &types::Anime) -> Result<Vec<u32>> {
51 let document = get_document(&anime.url.clone())?;
52
53 let mut episodes: Vec<u32> = Vec::new();
54 episodes.push(1);
55
56 let active_episodes = document
57 .find(Class(util::UTIL_VARS.active_tag))
58 .last()
59 .unwrap();
60 let latest_episode = active_episodes
61 .attr(util::UTIL_VARS.latest_episode_value)
62 .unwrap();
63 episodes.push(latest_episode.parse::<u32>().unwrap());
64
65 Ok(episodes)
66}
67
68pub fn get_episode_link(anime: &types::Anime, episode: String) -> Result<String> {
69 let mut url = anime.url.clone();
70 url = url.split("/").last().unwrap().to_string();
71 url = format!("{}/{}-episode-{}", UTIL_VARS.base_url, url, episode);
72
73 Ok(url)
74}
75pub fn get_video_link(episode_url: &String) -> Result<String> {
76 let document = get_document(episode_url).unwrap();
77 let video_tag = document
78 .find(Class(util::UTIL_VARS.embed_video_tag))
79 .last()
80 .unwrap()
81 .children()
82 .nth(1)
83 .unwrap();
84
85 let video_embed = video_tag.attr(util::UTIL_VARS.video_embed_tag).unwrap();
86 let video_link = format!("{}{}", "https:", video_embed);
87 Ok(video_link)
88}
89
90pub fn decrypt_link(video_link: &String) -> Result<String> {
92 let mut id = video_link.split("=").nth(1).unwrap().to_string();
93 id = id.split("&").nth(0).unwrap().to_string();
94 println!("got id from video link: {}", id);
95 if id.len() < 8 {
96 let padding = "10160310 0304 "; let mut iter = padding.chars();
99 iter.by_ref().nth(8 - (id.len() % 16));
100 let slice = iter.as_str();
101 id = format!("{}{}", slice, id);
102 } else {
103 let last_char = id.chars().last().unwrap();
104 println!("last char: {}", last_char);
105 let mut digit_char = last_char.to_digit(10).unwrap();
106 digit_char = digit_char ^ 10;
107 let octal_char = format!("{:o}", digit_char);
108 id = id.replace(last_char, &octal_char);
109 }
110 let padding_2 = "10160310 0304 "; let final_id = format!("{}{}", id, padding_2);
113 let mut config = Config::default();
114 config.hash_length = 128;
115
116 let hash = argon2::hash_raw(
117 final_id.as_bytes(),
118 UTIL_VARS.secret_key.as_bytes(),
119 &config,
120 )?;
121
122 let key = AesKey::new_encrypt(&hash[..]).unwrap();
123 let mut temp_iv = UTIL_VARS.iv.clone().to_string();
125
126 unsafe {
127 let mut iv = temp_iv.as_bytes_mut();
128 let mut output = [0u8; 16];
129 aes_ige(
130 final_id.as_bytes(),
131 &mut output,
132 &key,
133 &mut iv,
134 Mode::Encrypt,
135 );
136 let encrypted_id = String::from_utf8(output.to_vec()).unwrap();
137
138 let client = reqwest::blocking::Client::new();
139 let response = client
141 .get(UTIL_VARS.video_host)
142 .header("X-Requested-With", "XMLHttpRequest")
143 .body(format!("id={}", encrypted_id))
144 .send()?;
145
146 println!("{:?}", response);
147 }
148
149 Ok(id)
150}