From 10f1db4541e40ef776e41f572ff07a5ed64205ca Mon Sep 17 00:00:00 2001 From: A Farzat Date: Mon, 2 Mar 2026 13:24:38 +0300 Subject: Add file and chapter details fetching Fetching file details allows us to download them to the correct location later. Chapter details are currently limited to is_skippable, which might be used to determine whether to make the corresponding spine item non-linear. Other details such as the title shall be fetched from the spine and table-of-contents endpoints later. --- src/main.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 165d6be..30f08ff 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::{EpubResponse, SearchResponse}; +use models::{Chapter, EpubResponse, FileEntry, Paginated, SearchResponse}; use reqwest::Client; /// Download and generate an EPUB from Safari Books Online. @@ -50,6 +50,34 @@ async fn fetch_epub_data(client: &Client, bookid: &str) -> Result Ok(response) } +/// Fetch a paginated API. +async fn fetch_all_pages(client: &reqwest::Client, mut url: String) -> Result> +where + T: serde::de::DeserializeOwned, +{ + let mut items = Vec::new(); + loop { + // GET current URL and deserialize into Paginated. + let response = client + .get(&url) + .send() + .await? + .error_for_status()? + .json::>() + .await + .context("Failed to deserialize API response.")?; + // Extend items with the page's results. + items.extend(response.results); + // Set url to next page if available, else break. + if let Some(next) = response.next { + url = next; + } else { + break; + } + } + Ok(items) +} + #[tokio::main] async fn main() -> Result<()> { // Parse the command line arguments @@ -81,5 +109,9 @@ async fn main() -> Result<()> { println!("Resources URL: {}", epub_data.files); println!("------------------\n"); + println!("Fetching book structure..."); + let chapters: Vec = fetch_all_pages(&client, epub_data.chapters.clone()).await?; + let file_entries: Vec = fetch_all_pages(&client, epub_data.files.clone()).await?; + Ok(()) } -- cgit v1.2.3-70-g09d2