feat: BNF API instead of openlibrary to expand the available book search
This commit is contained in:
parent
c36a38cd7a
commit
aff6c429ce
4 changed files with 121 additions and 0 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"] }
|
||||
|
||||
|
|
|
|||
108
src/utils/bnf.rs
Normal file
108
src/utils/bnf.rs
Normal file
|
|
@ -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<RecordListElement>
|
||||
}
|
||||
|
||||
#[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<DataField>
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DataField {
|
||||
#[serde(rename = "@tag")]
|
||||
tag: String,
|
||||
#[serde(rename = "subfield")]
|
||||
subfields: Vec<SubField>
|
||||
}
|
||||
|
||||
#[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<FetchedBook> {
|
||||
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<Response, quick_xml::DeError> = 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
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
pub mod auth;
|
||||
pub mod bnf;
|
||||
pub mod cli;
|
||||
pub mod events;
|
||||
pub mod open_library;
|
||||
|
|
|
|||
Reference in a new issue