aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs20
-rw-r--r--src/models.rs25
2 files changed, 42 insertions, 3 deletions
diff --git a/src/main.rs b/src/main.rs
index 626427d..8bc25ea 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,7 +4,7 @@ mod models;
use anyhow::{Context, Result};
use clap::Parser;
use http_client::build_authenticated_client;
-use models::{Chapter, EpubResponse, FileEntry, Paginated, SearchResult};
+use models::{Chapter, EpubResponse, FileEntry, Paginated, SearchResult, SpineItem, TocNode};
use reqwest::Client;
/// Download and generate an EPUB from Safari Books Online.
@@ -36,6 +36,22 @@ async fn fetch_epub_data(client: &Client, bookid: &str) -> Result<EpubResponse>
Ok(response)
}
+/// Fetches a direct array endpoint (no pagination, simple list).
+async fn fetch_direct_array<T>(client: &Client, url: &str) -> Result<Vec<T>>
+where
+ T: serde::de::DeserializeOwned,
+{
+ let response = client
+ .get(url)
+ .send()
+ .await?
+ .error_for_status()?
+ .json::<Vec<T>>()
+ .await
+ .context("Failed to deserialize API response")?;
+ Ok(response)
+}
+
/// Fetch a paginated API.
async fn fetch_all_pages<T>(client: &reqwest::Client, mut url: String) -> Result<Vec<T>>
where
@@ -102,6 +118,8 @@ async fn main() -> Result<()> {
println!("Fetching book structure...");
let chapters: Vec<Chapter> = fetch_all_pages(&client, epub_data.chapters.clone()).await?;
let file_entries: Vec<FileEntry> = fetch_all_pages(&client, epub_data.files.clone()).await?;
+ let spine_items: Vec<SpineItem> = fetch_all_pages(&client, epub_data.spine.clone()).await?;
+ let toc_vec: Vec<TocNode> = fetch_direct_array(&client, &epub_data.table_of_contents).await?;
Ok(())
}
diff --git a/src/models.rs b/src/models.rs
index 843744d..2809711 100644
--- a/src/models.rs
+++ b/src/models.rs
@@ -20,8 +20,10 @@ pub struct SearchResult {
#[derive(Debug, Deserialize)]
pub struct EpubResponse {
pub publication_date: String,
- pub chapters: String, // This is a URL to the chapters list
- pub files: String, // This is a URL to the resource files
+ pub chapters: String, // This is a URL to the chapters list
+ pub files: String, // This is a URL to the resource files
+ pub spine: String, // This is a URL to the spine list
+ pub table_of_contents: String, // This is a URL to the table of contents
}
/// Model for chapters API.
@@ -42,3 +44,22 @@ pub struct FileEntry {
pub filename_ext: String,
pub kind: String,
}
+
+/// Model for spine API.
+#[derive(Debug, Deserialize)]
+pub struct SpineItem {
+ pub ourn: String,
+ pub reference_id: String,
+ pub title: String,
+}
+
+/// Model for table of contents API.
+#[derive(Debug, Deserialize)]
+pub struct TocNode {
+ pub depth: u32,
+ pub reference_id: String,
+ pub ourn: String,
+ pub fragment: String,
+ pub title: String,
+ pub children: Vec<TocNode>,
+}