pinakes-tui: add book management view and api key authentication
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I20f205d9e06a93a89e8f4433ed6f80576a6a6964
This commit is contained in:
parent
3d9f8933d2
commit
66861b8a20
18 changed files with 917 additions and 251 deletions
|
|
@ -145,10 +145,64 @@ pub struct TypeCount {
|
|||
pub count: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BookMetadataResponse {
|
||||
pub media_id: String,
|
||||
pub title: Option<String>,
|
||||
pub subtitle: Option<String>,
|
||||
pub publisher: Option<String>,
|
||||
pub language: Option<String>,
|
||||
pub isbn: Option<String>,
|
||||
pub isbn13: Option<String>,
|
||||
pub page_count: Option<i32>,
|
||||
pub series: Option<String>,
|
||||
pub series_index: Option<f64>,
|
||||
pub authors: Vec<BookAuthorResponse>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BookAuthorResponse {
|
||||
pub name: String,
|
||||
pub role: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct ReadingProgressResponse {
|
||||
pub media_id: String,
|
||||
pub current_page: i32,
|
||||
pub total_pages: Option<i32>,
|
||||
pub status: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct SeriesSummary {
|
||||
pub name: String,
|
||||
pub count: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct AuthorSummary {
|
||||
pub name: String,
|
||||
pub count: u64,
|
||||
}
|
||||
|
||||
impl ApiClient {
|
||||
pub fn new(base_url: &str) -> Self {
|
||||
pub fn new(base_url: &str, api_key: Option<&str>) -> Self {
|
||||
let client = api_key.map_or_else(Client::new, |key| {
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
if let Ok(val) =
|
||||
reqwest::header::HeaderValue::from_str(&format!("Bearer {key}"))
|
||||
{
|
||||
headers.insert(reqwest::header::AUTHORIZATION, val);
|
||||
}
|
||||
Client::builder()
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
.unwrap_or_default()
|
||||
});
|
||||
Self {
|
||||
client: Client::new(),
|
||||
client,
|
||||
base_url: base_url.trim_end_matches('/').to_string(),
|
||||
}
|
||||
}
|
||||
|
|
@ -346,10 +400,10 @@ impl ApiClient {
|
|||
&self,
|
||||
path: Option<&str>,
|
||||
) -> Result<Vec<ScanResponse>> {
|
||||
let body = match path {
|
||||
Some(p) => serde_json::json!({"path": p}),
|
||||
None => serde_json::json!({"path": null}),
|
||||
};
|
||||
let body = path.map_or_else(
|
||||
|| serde_json::json!({"path": null}),
|
||||
|p| serde_json::json!({"path": p}),
|
||||
);
|
||||
let resp = self
|
||||
.client
|
||||
.post(self.url("/scan"))
|
||||
|
|
@ -488,4 +542,90 @@ impl ApiClient {
|
|||
.error_for_status()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_book_metadata(
|
||||
&self,
|
||||
media_id: &str,
|
||||
) -> Result<BookMetadataResponse> {
|
||||
let resp = self
|
||||
.client
|
||||
.get(self.url(&format!("/books/{media_id}/metadata")))
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
pub async fn list_books(
|
||||
&self,
|
||||
offset: u64,
|
||||
limit: u64,
|
||||
) -> Result<Vec<MediaResponse>> {
|
||||
let resp = self
|
||||
.client
|
||||
.get(self.url("/books"))
|
||||
.query(&[("offset", offset.to_string()), ("limit", limit.to_string())])
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
pub async fn list_series(&self) -> Result<Vec<SeriesSummary>> {
|
||||
let resp = self
|
||||
.client
|
||||
.get(self.url("/books/series"))
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
pub async fn list_book_authors(&self) -> Result<Vec<AuthorSummary>> {
|
||||
let resp = self
|
||||
.client
|
||||
.get(self.url("/books/authors"))
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
pub async fn get_reading_progress(
|
||||
&self,
|
||||
media_id: &str,
|
||||
) -> Result<ReadingProgressResponse> {
|
||||
let resp = self
|
||||
.client
|
||||
.get(self.url(&format!("/books/{media_id}/progress")))
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
pub async fn update_reading_progress(
|
||||
&self,
|
||||
media_id: &str,
|
||||
current_page: i32,
|
||||
) -> Result<()> {
|
||||
self
|
||||
.client
|
||||
.put(self.url(&format!("/books/{media_id}/progress")))
|
||||
.json(&serde_json::json!({"current_page": current_page}))
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue