diff options
| author | A Farzat <a@farzat.xyz> | 2026-03-02 14:20:23 +0300 |
|---|---|---|
| committer | A Farzat <a@farzat.xyz> | 2026-03-02 15:05:28 +0300 |
| commit | 1cc32c35edaf6b8c2f468c22ccf61f3f07027e81 (patch) | |
| tree | ec8cb24273b9461960767641285ece8b8db0ad66 /src | |
| parent | 10f1db4541e40ef776e41f572ff07a5ed64205ca (diff) | |
| download | oreilly-epub-1cc32c35edaf6b8c2f468c22ccf61f3f07027e81.tar.gz oreilly-epub-1cc32c35edaf6b8c2f468c22ccf61f3f07027e81.zip | |
Refactor away SearchResponse model
Its functionality is covered by Paginated. The fetch_metadata function
was also replaced by the more generic fetch_all_pages.
Given that we are searching by the isbn, we should presumably get only 1
result, so only one call will be made even when fetch_all_pages is used.
This behaviour is not documented though, so switching to the metadata
endpoint in the future is recommended.
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 26 | ||||
| -rw-r--r-- | src/models.rs | 22 |
2 files changed, 15 insertions, 33 deletions
diff --git a/src/main.rs b/src/main.rs index 30f08ff..626427d 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, SearchResponse}; +use models::{Chapter, EpubResponse, FileEntry, Paginated, SearchResult}; use reqwest::Client; /// Download and generate an EPUB from Safari Books Online. @@ -22,21 +22,7 @@ struct Args { preserve_log: bool, } -/// Fetches book metadata from the search endpoint. -async fn fetch_metadata(client: &Client, bookid: &str) -> Result<SearchResponse> { - let url = format!("https://learning.oreilly.com/api/v2/search/?query={bookid}&limit=1"); - let response = client - .get(&url) - .send() - .await? - .error_for_status()? - .json::<SearchResponse>() - .await - .context("Failed to deserialize Search API response.")?; - Ok(response) -} - -/// Fetches EPUB structural data (like the chapters URL) +/// Fetches EPUB structural data (like the chapters URL). async fn fetch_epub_data(client: &Client, bookid: &str) -> Result<EpubResponse> { let url = format!("https://learning.oreilly.com/api/v2/epubs/urn:orm:book:{bookid}/"); let response = client @@ -92,8 +78,12 @@ async fn main() -> Result<()> { println!("Fetching book metadata..."); // Fetch from the search API. - let search_data = fetch_metadata(&client, &args.bookid).await?; - if let Some(book) = search_data.results.first() { + let search_url = format!( + "https://learning.oreilly.com/api/v2/search/?query={}", + args.bookid + ); + let search_data: Vec<SearchResult> = fetch_all_pages(&client, search_url).await?; + if let Some(book) = search_data.first() { println!("\n--- Book Found ---"); println!("Title: {}", book.title); println!("Authors: {}", book.authors.join(", ")); diff --git a/src/models.rs b/src/models.rs index 174b983..843744d 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,12 +1,13 @@ use serde::Deserialize; -// --- Models for the Search API --- - -#[derive(Debug, Deserialize)] -pub struct SearchResponse { - pub results: Vec<SearchResult>, +/// Generic Model for paginated API. +#[derive(Debug, serde::Deserialize)] +pub struct Paginated<T> { + pub next: Option<String>, + pub results: Vec<T>, } +/// Model for the Search API. #[derive(Debug, Deserialize)] pub struct SearchResult { pub title: String, @@ -15,8 +16,7 @@ pub struct SearchResult { pub cover_url: String, } -// --- Models for the EPUB API --- - +/// Model for the EPUB API. #[derive(Debug, Deserialize)] pub struct EpubResponse { pub publication_date: String, @@ -24,14 +24,6 @@ pub struct EpubResponse { pub files: String, // This is a URL to the resource files } -// --- Generic Model for paginated API --- - -#[derive(Debug, serde::Deserialize)] -pub struct Paginated<T> { - pub next: Option<String>, - pub results: Vec<T>, -} - /// Model for chapters API. #[derive(Debug, Deserialize)] pub struct Chapter { |
