1use anyhow::anyhow;
2use serde_json::json;
3
4pub mod analyzer;
5pub mod book;
6pub mod book_source;
7pub mod error;
8pub mod http_client;
9pub mod utils;
10pub use analyzer::*;
11pub use book::*;
12pub use book_source::*;
13pub use error::*;
14pub use http_client::*;
15
16#[derive(Debug, Clone)]
17pub struct BookSourceParser {
18    pub book_source: BookSource,
19    pub http_client: HttpClient,
20    pub analyzer: AnalyzerManager,
21    pub temp: Option<String>,
22}
23
24unsafe impl Send for BookSourceParser {}
25unsafe impl Sync for BookSourceParser {}
26
27impl TryFrom<BookSource> for BookSourceParser {
28    type Error = ParseError;
29
30    fn try_from(book_source: BookSource) -> Result<Self> {
31        let mut http_config = book_source.http_config.clone();
32        if let Some(ref header) = book_source.header {
33            http_config.header = Some(serde_json::from_str(header)?);
34        }
35
36        if let Some(ref response_time) = book_source.respond_time {
37            http_config.timeout = Some(*response_time);
38        }
39
40        Ok(Self {
41            http_client: HttpClient::new(&book_source.book_source_url, &http_config)?,
42            book_source,
43            analyzer: AnalyzerManager::new()?,
44            temp: None,
45        })
46    }
47}
48
49impl BookSourceParser {
50    pub fn new(book_source: BookSource) -> Result<Self> {
51        Self::try_from(book_source)
52    }
53
54    pub async fn get_explores(&mut self) -> Result<ExploreList> {
56        if let Some(ref explore_url) = self.book_source.explore_url {
57            if let Some(ref rule_explore_item) = self.book_source.rule_explore_item {
58                let res = self
59                    .http_client
60                    .get(&self.book_source.book_source_url)
61                    .await?
62                    .text()
63                    .await?;
64
65                let list = self.analyzer.get_element(explore_url, &res)?;
66
67                let res = list
68                    .into_iter()
69                    .flat_map(|item| {
70                        rule_explore_item.parse_to_explore_item(&mut self.analyzer, &item)
71                    })
72                    .collect::<Vec<_>>();
73                return Ok(res);
74            } else {
75                return Ok(serde_json::from_str(explore_url)?);
76            }
77        }
78
79        Ok(vec![])
80    }
81
82    pub async fn search_books(&mut self, key: &str, page: u32, page_size: u32) -> Result<BookList> {
84        let url = self.analyzer.get_string(
85            &self.book_source.search_url,
86            "",
87            Some(json!({
88                "key": key,
89                "page": page,
90                "page_size": page_size,
91            })),
92        )?;
93
94        let mut res = String::new();
95
96        for i in url.split(",") {
97            res = self.http_client.get(i).await?.text().await?;
98        }
99
100        let list = self
101            .analyzer
102            .get_element(&self.book_source.rule_search.book_list, &res)?;
103
104        let res = list
105            .into_iter()
106            .flat_map(|item| {
107                self.book_source
108                    .rule_search
109                    .parse_to_book_list_item(&mut self.analyzer, &item)
110            })
111            .collect::<Vec<_>>();
112
113        Ok(res)
114    }
115
116    pub async fn explore_books(
118        &mut self,
119        url: &str,
120        page: u32,
121        page_size: u32,
122    ) -> Result<BookList> {
123        if self.book_source.rule_explore.is_none() {
124            return Err(anyhow!("explore rule is none").into());
125        }
126        let url = self.analyzer.get_string(
127            url,
128            "",
129            Some(json!({
130                "page": page,
131                "page_size": page_size,
132            })),
133        )?;
134
135        let res = self.http_client.get(url.as_str()).await?.text().await?;
136
137        let list = self.analyzer.get_element(
138            &self.book_source.rule_explore.as_ref().unwrap().book_list,
139            &res,
140        )?;
141
142        let res = list
143            .into_iter()
144            .flat_map(|item| {
145                self.book_source
146                    .rule_explore
147                    .as_ref()
148                    .unwrap()
149                    .parse_to_book_list_item(&mut self.analyzer, &item)
150            })
151            .collect::<Vec<_>>();
152
153        Ok(res)
154    }
155
156    pub async fn get_book_info(&mut self, book_url: &str) -> Result<BookInfo> {
158        let res = self.http_client.get(book_url).await?.text().await?;
159
160        let book_info = self
161            .book_source
162            .rule_book_info
163            .parse_to_book_info(&mut self.analyzer, &res);
164
165        self.temp = Some(res);
166
167        book_info
168    }
169
170    pub async fn get_chapters(&mut self, toc_url: &str) -> Result<Vec<Chapter>> {
171        let res = if toc_url.starts_with("/") || toc_url.starts_with("http") {
173            self.http_client.get(toc_url).await?.text().await?
174        } else {
175            self.temp.clone().ok_or(anyhow!("temp is none"))?
176        };
177
178        let list = self
179            .analyzer
180            .get_element(&self.book_source.rule_toc.chapter_list, &res)?;
181
182        let res = list
183            .into_iter()
184            .flat_map(|item| {
185                self.book_source
186                    .rule_toc
187                    .parse_to_chapter(&mut self.analyzer, &item)
188            })
189            .collect::<Vec<_>>();
190
191        Ok(res)
192    }
193
194    pub async fn get_content(&mut self, chapter_url: &str) -> Result<String> {
195        let mut res = self.http_client.get(chapter_url).await?.text().await?;
196
197        match &self.book_source.rule_content {
198            RuleContent::One { content } => self.analyzer.get_string(content, &res, None),
199
200            RuleContent::More {
201                content,
202                next_content_url,
203                start,
204                end,
205            } => {
206                let end = self
207                    .analyzer
208                    .get_string(end, &res, None)?
209                    .parse::<usize>()?;
210                let mut contents = vec![];
211                let mut start = *start;
212
213                loop {
214                    let content = self.analyzer.get_string(content, &res, None)?;
215                    contents.push(content);
216
217                    if start > end {
218                        break;
219                    }
220
221                    let next_url = self.analyzer.get_string(
222                        next_content_url,
223                        &res,
224                        Some(json!({
225                            "index": start,
226                        })),
227                    )?;
228                    res = self
229                        .http_client
230                        .get(next_url.as_str())
231                        .await?
232                        .text()
233                        .await?;
234                    start += 1;
235                }
236
237                Ok(contents.join("  "))
238            }
239        }
240    }
241}