anime_pls/
lib.rs

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
90// not able to use this way :/
91pub 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	"; // hacky way to pad the id
97
98        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	"; // hacky way to pad the id
111
112    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 iv_bytes = UTIL_VARS.iv.as_bytes();
124    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        // :
140        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}