pinakes-core: update remaining modules and tests
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I9e0ff5ea33a5cf697473423e88f167ce6a6a6964
This commit is contained in:
parent
c8425a4c34
commit
3d9f8933d2
44 changed files with 1207 additions and 578 deletions
|
|
@ -1,8 +1,10 @@
|
|||
use std::fmt::Write as _;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::{PinakesError, Result};
|
||||
|
||||
/// OpenLibrary API client for book metadata enrichment
|
||||
/// `OpenLibrary` API client for book metadata enrichment
|
||||
pub struct OpenLibraryClient {
|
||||
client: reqwest::Client,
|
||||
base_url: String,
|
||||
|
|
@ -15,23 +17,31 @@ impl Default for OpenLibraryClient {
|
|||
}
|
||||
|
||||
impl OpenLibraryClient {
|
||||
/// Create a new `OpenLibraryClient`.
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
let client = reqwest::Client::builder()
|
||||
.user_agent("Pinakes/1.0")
|
||||
.timeout(std::time::Duration::from_secs(10))
|
||||
.build()
|
||||
.unwrap_or_else(|_| reqwest::Client::new());
|
||||
Self {
|
||||
client: reqwest::Client::builder()
|
||||
.user_agent("Pinakes/1.0")
|
||||
.timeout(std::time::Duration::from_secs(10))
|
||||
.build()
|
||||
.expect("Failed to build HTTP client"),
|
||||
client,
|
||||
base_url: "https://openlibrary.org".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch book metadata by ISBN
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the HTTP request fails or the response cannot be
|
||||
/// parsed.
|
||||
pub async fn fetch_by_isbn(&self, isbn: &str) -> Result<OpenLibraryBook> {
|
||||
let url = format!("{}/isbn/{}.json", self.base_url, isbn);
|
||||
|
||||
let response = self.client.get(&url).send().await.map_err(|e| {
|
||||
PinakesError::External(format!("OpenLibrary request failed: {}", e))
|
||||
PinakesError::External(format!("OpenLibrary request failed: {e}"))
|
||||
})?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
|
|
@ -43,13 +53,17 @@ impl OpenLibraryClient {
|
|||
|
||||
response.json::<OpenLibraryBook>().await.map_err(|e| {
|
||||
PinakesError::External(format!(
|
||||
"Failed to parse OpenLibrary response: {}",
|
||||
e
|
||||
"Failed to parse OpenLibrary response: {e}"
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Search for books by title and author
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the HTTP request fails or the response cannot be
|
||||
/// parsed.
|
||||
pub async fn search(
|
||||
&self,
|
||||
title: &str,
|
||||
|
|
@ -62,13 +76,13 @@ impl OpenLibraryClient {
|
|||
);
|
||||
|
||||
if let Some(author) = author {
|
||||
url.push_str(&format!("&author={}", urlencoding::encode(author)));
|
||||
let _ = write!(url, "&author={}", urlencoding::encode(author));
|
||||
}
|
||||
|
||||
url.push_str("&limit=5");
|
||||
|
||||
let response = self.client.get(&url).send().await.map_err(|e| {
|
||||
PinakesError::External(format!("OpenLibrary search failed: {}", e))
|
||||
PinakesError::External(format!("OpenLibrary search failed: {e}"))
|
||||
})?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
|
|
@ -80,13 +94,18 @@ impl OpenLibraryClient {
|
|||
|
||||
let search_response: OpenLibrarySearchResponse =
|
||||
response.json().await.map_err(|e| {
|
||||
PinakesError::External(format!("Failed to parse search results: {}", e))
|
||||
PinakesError::External(format!("Failed to parse search results: {e}"))
|
||||
})?;
|
||||
|
||||
Ok(search_response.docs)
|
||||
}
|
||||
|
||||
/// Fetch cover image by cover ID
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the HTTP request fails or the response cannot be
|
||||
/// read.
|
||||
pub async fn fetch_cover(
|
||||
&self,
|
||||
cover_id: i64,
|
||||
|
|
@ -98,13 +117,11 @@ impl OpenLibraryClient {
|
|||
CoverSize::Large => "L",
|
||||
};
|
||||
|
||||
let url = format!(
|
||||
"https://covers.openlibrary.org/b/id/{}-{}.jpg",
|
||||
cover_id, size_str
|
||||
);
|
||||
let url =
|
||||
format!("https://covers.openlibrary.org/b/id/{cover_id}-{size_str}.jpg");
|
||||
|
||||
let response = self.client.get(&url).send().await.map_err(|e| {
|
||||
PinakesError::External(format!("Cover download failed: {}", e))
|
||||
PinakesError::External(format!("Cover download failed: {e}"))
|
||||
})?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
|
|
@ -115,11 +132,16 @@ impl OpenLibraryClient {
|
|||
}
|
||||
|
||||
response.bytes().await.map(|b| b.to_vec()).map_err(|e| {
|
||||
PinakesError::External(format!("Failed to read cover data: {}", e))
|
||||
PinakesError::External(format!("Failed to read cover data: {e}"))
|
||||
})
|
||||
}
|
||||
|
||||
/// Fetch cover by ISBN
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the HTTP request fails or the response cannot be
|
||||
/// read.
|
||||
pub async fn fetch_cover_by_isbn(
|
||||
&self,
|
||||
isbn: &str,
|
||||
|
|
@ -131,13 +153,11 @@ impl OpenLibraryClient {
|
|||
CoverSize::Large => "L",
|
||||
};
|
||||
|
||||
let url = format!(
|
||||
"https://covers.openlibrary.org/b/isbn/{}-{}.jpg",
|
||||
isbn, size_str
|
||||
);
|
||||
let url =
|
||||
format!("https://covers.openlibrary.org/b/isbn/{isbn}-{size_str}.jpg");
|
||||
|
||||
let response = self.client.get(&url).send().await.map_err(|e| {
|
||||
PinakesError::External(format!("Cover download failed: {}", e))
|
||||
PinakesError::External(format!("Cover download failed: {e}"))
|
||||
})?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
|
|
@ -148,7 +168,7 @@ impl OpenLibraryClient {
|
|||
}
|
||||
|
||||
response.bytes().await.map(|b| b.to_vec()).map_err(|e| {
|
||||
PinakesError::External(format!("Failed to read cover data: {}", e))
|
||||
PinakesError::External(format!("Failed to read cover data: {e}"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -220,6 +240,7 @@ pub enum StringOrObject {
|
|||
}
|
||||
|
||||
impl StringOrObject {
|
||||
#[must_use]
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Self::String(s) => s,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue