reddit_tube/types/
main_page.rs

1use once_cell::sync::Lazy;
2use scraper::{
3    Html,
4    Selector,
5};
6
7/// Error that may occur while parsing a [`MainPage`] from [`Html`].
8#[derive(Debug, thiserror::Error)]
9pub enum FromHtmlError {
10    /// missing download form
11    #[error("missing download form")]
12    MissingDownloadForm,
13
14    /// Missing csrf data
15    #[error("missing csrf data")]
16    MissingCsrf,
17}
18
19/// The main page
20#[derive(Debug)]
21pub struct MainPage {
22    /// The csrf key
23    pub csrf_key: String,
24
25    /// The csrf value
26    pub csrf_value: String,
27}
28
29impl MainPage {
30    /// Make a [`MainPage`] from [`Html`].
31    pub(crate) fn from_html(html: &Html) -> Result<Self, FromHtmlError> {
32        static DOWNLOAD_FORM_SELECTOR: Lazy<Selector> = Lazy::new(|| {
33            Selector::parse("#download-form").expect("invalid download form selector")
34        });
35        static CSRF_SELECTOR: Lazy<Selector> =
36            Lazy::new(|| Selector::parse("[name][value]").expect("invalid csrf selector"));
37
38        let download_form = html
39            .select(&DOWNLOAD_FORM_SELECTOR)
40            .next()
41            .ok_or(FromHtmlError::MissingDownloadForm)?;
42
43        let (csrf_key, csrf_value) = download_form
44            .select(&CSRF_SELECTOR)
45            .filter_map(|element| {
46                let value = element.value();
47                Some((value.attr("name")?, value.attr("value")?))
48            })
49            .find(|(name, _)| name != &"url")
50            .ok_or(FromHtmlError::MissingCsrf)?;
51
52        Ok(MainPage {
53            csrf_key: csrf_key.to_string(),
54            csrf_value: csrf_value.to_string(),
55        })
56    }
57}
58
59#[cfg(test)]
60mod test {
61    use super::*;
62
63    const SAMPLE_1: &str = include_str!("../../test_data/main_page.html");
64
65    #[test]
66    fn parse() {
67        let html = Html::parse_document(SAMPLE_1);
68        let page = MainPage::from_html(&html).expect("failed to parse main page sample 1");
69        dbg!(page);
70    }
71}