From aff6c429ce76a69426e7dba121e89badc9bf7de7 Mon Sep 17 00:00:00 2001 From: Ninjdai Date: Mon, 4 Aug 2025 13:15:15 +0200 Subject: [PATCH] feat: BNF API instead of openlibrary to expand the available book search --- Cargo.lock | 11 +++++ Cargo.toml | 1 + src/utils/bnf.rs | 108 +++++++++++++++++++++++++++++++++++++++++++++++ src/utils/mod.rs | 1 + 4 files changed, 121 insertions(+) create mode 100644 src/utils/bnf.rs diff --git a/Cargo.lock b/Cargo.lock index 5253f1f..31abc0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,7 @@ dependencies = [ "openssl", "password-hash", "pretty_env_logger", + "quick-xml", "rand_core 0.9.3", "reqwest", "sea-orm", @@ -2082,6 +2083,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "quick-xml" +version = "0.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9845d9dccf565065824e69f9f235fafba1587031eda353c1f1561cd6a6be78f4" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quinn" version = "0.11.8" diff --git a/Cargo.toml b/Cargo.toml index 6d82748..208b10e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,4 +25,5 @@ rand_core = { version = "0.9.3", features = ["os_rng"] } password-hash = { version = "0.5.0", features = ["getrandom"] } jsonwebtoken = "9.3.1" openssl = { version = "0.10.73", features = ["vendored"] } +quick-xml = { version = "0.38.1", features = ["serialize"] } diff --git a/src/utils/bnf.rs b/src/utils/bnf.rs new file mode 100644 index 0000000..782bf06 --- /dev/null +++ b/src/utils/bnf.rs @@ -0,0 +1,108 @@ +use reqwest::StatusCode; +use sea_orm::ActiveValue::{NotSet, Set}; +use serde::Deserialize; +use serde_json::Value; + +use crate::entities::book; + +#[derive(Deserialize)] +pub struct Response { + #[serde(rename = "numberOfRecords")] + records_number: u32, + #[serde(rename = "records")] + records: Vec +} + +#[derive(Deserialize)] +pub struct RecordListElement { + #[serde(rename = "record")] + record: Record +} + +#[derive(Deserialize)] +pub struct Record { + #[serde(rename = "recordData")] + record_data: RecordData +} + +#[derive(Deserialize)] +pub struct RecordData { + #[serde(rename = "record")] + record: RecordDataFields +} + +#[derive(Deserialize)] +pub struct RecordDataFields { + #[serde(rename = "datafield")] + datafields: Vec +} + +#[derive(Deserialize)] +pub struct DataField { + #[serde(rename = "@tag")] + tag: String, + #[serde(rename = "subfield")] + subfields: Vec +} + +#[derive(Deserialize, Clone)] +pub struct SubField { + #[serde(rename = "@code")] + code: String, + #[serde(rename = "$text")] + value: String +} + + +pub struct FetchedBook { + pub ean: String, + pub title: String, + pub author: String +} + +impl FetchedBook { + pub fn to_active_model(&self) -> book::ActiveModel { + book::ActiveModel { + id: NotSet, + ean: Set(self.ean.clone()), + title: Set(self.title.clone()), + author: Set(self.author.clone()) + } + } +} + +pub async fn fetch_book_by_ean(web_client: &reqwest::Client, ean: &String) -> Option { + let body = web_client.execute( + web_client.get(format!("https://catalogue.bnf.fr/api/SRU?version=1.2&operation=searchRetrieve&query=bib.isbn any \"{ean}\"")) + .build() + .expect("get request creation failed") + ).await.unwrap(); + match body.status() { + StatusCode::OK => { + let res = body.text().await.unwrap().replace("\n", ""); + log::debug!(target: "api", "BNF book fetch result: {res:#?}"); + let der: Result = quick_xml::de::from_str(&res); + match der { + Ok(v) => { + if v.records_number == 0 { + log::debug!(target: "api", "BNF returned 0 records for fetch"); + return None; + } + let data_dubfield = v.records.first().unwrap().record_data.record.record.datafields.iter().find(|d| d.tag == "200").unwrap().subfields.clone(); + Some(FetchedBook { + ean: ean.to_string(), + title: data_dubfield.iter().find(|p| p.code == "a").unwrap().value.clone(), + author: data_dubfield.iter().find(|p| p.code == "f").unwrap().value.clone(), + }) + }, + Err(e) => { + log::debug!(target: "api", "Error while deserializing: {e:?}"); + None + } + } + }, + _ => None + } +} + +//https://catalogue.bnf.fr/api/SRU?version=1.2&operation=searchRetrieve&query=bib.isbn%20any%20%{ean}%22 diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 8068292..4566cf7 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,4 +1,5 @@ pub mod auth; +pub mod bnf; pub mod cli; pub mod events; pub mod open_library;