1use reqwest::Url;
2use serde::{de::Error, Deserialize, Deserializer};
3use std::result::Result as StdResult;
4
5fn parse_url<'de, D>(deserializer: D) -> StdResult<Url, D::Error>
6where
7 D: Deserializer<'de>,
8{
9 let s: &str = Deserialize::deserialize(deserializer)?;
10 Url::parse(s).map_err(D::Error::custom)
11}
12
13fn parse_vec_url<'de, D>(deserializer: D) -> StdResult<Vec<Url>, D::Error>
14where
15 D: Deserializer<'de>,
16{
17 let vec: Vec<&str> = Deserialize::deserialize(deserializer)?;
18 vec.into_iter()
19 .map(Url::parse)
20 .collect::<std::result::Result<_, _>>()
21 .map_err(D::Error::custom)
22}
23
24fn to_xhtml<'de, D>(deserializer: D) -> StdResult<String, D::Error>
25where
26 D: Deserializer<'de>,
27{
28 let s: String = Deserialize::deserialize(deserializer)?;
29 Ok(s.replace(".html", ".xhtml"))
30}
31
32#[derive(Deserialize, Debug)]
33pub(crate) struct BillingInfo {
34 pub subscription: SubscriptionInfo,
35 pub trial: TrialInfo,
36}
37
38#[derive(Deserialize, Debug, Default)]
39pub(crate) struct SubscriptionInfo {
40 pub cancellation_date: Option<String>,
41}
42
43#[derive(Deserialize, Debug, Default)]
44pub(crate) struct TrialInfo {
45 pub trial_expiration_date: Option<String>,
46}
47
48#[derive(Deserialize, Debug)]
49pub(crate) struct Credentials {
50 pub logged_in: bool,
51}
52
53#[derive(Deserialize, Debug)]
54pub(crate) struct LoginLookup {
55 pub password_login_allowed: bool,
56}
57
58#[derive(Deserialize, Debug)]
59pub struct Author {
60 pub name: String,
61}
62
63#[derive(Deserialize, Debug)]
64pub struct Subject {
65 pub name: String,
66}
67
68#[derive(Deserialize, Debug)]
69pub struct Publisher {
70 pub name: String,
71}
72
73#[derive(Deserialize, Debug)]
74pub struct Book {
75 pub identifier: String,
76 pub isbn: String,
77 #[serde(deserialize_with = "parse_url")]
78 pub cover: Url,
79 pub chapter_list: String,
80 pub toc: String,
81 pub flat_toc: String,
82 pub title: String,
83 pub source: String,
84 pub pagecount: usize,
85 pub authors: Vec<Author>,
86 pub subjects: Vec<Subject>,
87 pub publishers: Vec<Publisher>,
88 pub description: String,
89 pub issued: String,
90 #[serde(default)]
91 pub rights: String,
92 pub language: String,
93}
94
95#[derive(Deserialize, Debug)]
96pub struct Stylesheet {
97 pub full_path: String,
98 #[serde(deserialize_with = "parse_url")]
99 pub url: Url,
100 pub original_url: String,
101}
102
103#[derive(Deserialize, Debug)]
104pub struct ChapterNode {
105 pub url: String,
106 pub web_url: String,
107 pub title: String,
108}
109
110#[derive(Deserialize, Debug)]
111pub struct ChapterMeta {
112 #[serde(deserialize_with = "parse_url")]
113 pub asset_base_url: Url,
114 pub title: String,
115 #[serde(deserialize_with = "to_xhtml")]
116 pub filename: String,
117 pub images: Vec<String>,
118 pub stylesheets: Vec<Stylesheet>,
119 #[serde(deserialize_with = "parse_vec_url")]
120 pub site_styles: Vec<Url>,
121 #[serde(deserialize_with = "parse_url", rename = "content")]
122 pub content_url: Url,
123 #[serde(default)]
124 pub position: usize,
125}
126
127#[derive(Debug)]
128pub struct Chapter {
129 pub meta: ChapterMeta,
130 pub content: String,
131}
132
133#[derive(Deserialize, Debug)]
134pub(crate) struct ChaptersResponse {
135 pub count: usize,
136 pub results: Vec<ChapterMeta>,
137}
138
139#[derive(Deserialize, Debug)]
140pub struct TocElement {
141 pub depth: usize,
142 pub url: String,
143 pub minutes_required: f64,
144 pub fragment: String,
145 pub filename: String,
146 pub natural_key: Vec<String>,
147 pub label: String,
148 pub full_path: String,
149 #[serde(deserialize_with = "to_xhtml")]
150 pub href: String,
151 pub id: String,
152 pub media_type: String,
153 pub children: Vec<TocElement>,
154}