book feed

This commit is contained in:
Sebastian Hugentobler 2024-05-09 11:18:47 +02:00
parent 603c2fbe48
commit 12341d01a6
Signed by: shu
GPG key ID: BB32CF3CA052C2F0
15 changed files with 219 additions and 41 deletions

View file

@ -7,7 +7,11 @@ use poem::{
IntoResponse,
};
use crate::{app_state::AppState, data::book::Book, handlers::error::HandlerError};
use crate::{
app_state::AppState,
data::book::{Book, Format},
handlers::error::HandlerError,
};
#[handler]
pub async fn handler(
@ -19,18 +23,14 @@ pub async fn handler(
.scalar_book(id)
.map_err(HandlerError::DataError)?;
let book = Book::full_book(&book, &state).ok_or(NotFoundError)?;
let format: &str = format.as_str();
let file_name = book.formats.get(format).ok_or(NotFoundError)?;
let format = Format(format);
let file_name = book.formats.get(&format).ok_or(NotFoundError)?;
let file_path = state.config.library_path.join(book.path).join(file_name);
let mut file = File::open(file_path).map_err(|_| NotFoundError)?;
let mut data = Vec::new();
file.read_to_end(&mut data).map_err(|_| NotFoundError)?;
let content_type = match format {
"pdf" => "application/pdf",
"epub" => "application/epub+zip",
_ => unreachable!(),
};
let content_type = format.0;
Ok(data
.with_content_type(content_type)

View file

@ -1,5 +1,6 @@
use std::sync::Arc;
use calibre_db::data::pagination::SortOrder;
use poem::{
handler,
web::{Data, WithContentType},
@ -9,6 +10,7 @@ use time::OffsetDateTime;
use crate::{
app_state::AppState,
data::book::Book,
handlers::error::HandlerError,
opds::{
author::Author, content::Content, entry::Entry, feed::Feed, link::Link,
@ -16,22 +18,72 @@ use crate::{
},
};
#[handler]
pub async fn handler(state: Data<&Arc<AppState>>) -> Result<WithContentType<String>, poem::Error> {
let now = OffsetDateTime::now_utc();
fn create_feed(
now: OffsetDateTime,
self_link: Link,
mut additional_links: Vec<Link>,
entries: Vec<Entry>,
) -> Feed {
let author = Author {
name: "Thallian".to_string(),
uri: "https://code.vanwa.ch/shu/rusty-library".to_string(),
email: None,
};
let home_link = Link {
href: "/opds".to_string(),
let mut links = vec![
Link {
href: "/opds".to_string(),
media_type: MediaType::Navigation,
rel: Relation::Start,
title: Some("Home".to_string()),
count: None,
},
self_link,
];
links.append(&mut additional_links);
Feed {
title: "rusty-library".to_string(),
id: "rusty:catalog".to_string(),
updated: now,
icon: "favicon.ico".to_string(),
author,
links,
entries,
}
}
#[handler]
pub async fn books(state: Data<&Arc<AppState>>) -> Result<WithContentType<String>, poem::Error> {
let books: Vec<Book> = state
.calibre
.books(u32::MAX.into(), None, &SortOrder::ASC)
.map(|x| {
x.iter()
.filter_map(|y| Book::full_book(y, &state))
.collect()
})
.map_err(HandlerError::DataError)?;
let entries: Vec<Entry> = books.into_iter().map(Entry::from).collect();
let now = OffsetDateTime::now_utc();
let self_link = Link {
href: "/opds/books".to_string(),
media_type: MediaType::Navigation,
rel: Relation::Start,
title: Some("Home".to_string()),
rel: Relation::Myself,
title: None,
count: None,
};
let feed = create_feed(now, self_link, vec![], entries);
let xml = feed.as_xml().map_err(HandlerError::OpdsError)?;
Ok(xml.with_content_type("application/atom+xml"))
}
#[handler]
pub async fn handler(state: Data<&Arc<AppState>>) -> Result<WithContentType<String>, poem::Error> {
let now = OffsetDateTime::now_utc();
let self_link = Link {
href: "/opds".to_string(),
media_type: MediaType::Navigation,
@ -47,6 +99,7 @@ pub async fn handler(state: Data<&Arc<AppState>>) -> Result<WithContentType<Stri
media_type: MediaType::Text,
content: "Index of all books".to_string(),
},
author: None,
links: vec![Link {
href: "/opds/books".to_string(),
media_type: MediaType::Navigation,
@ -56,15 +109,7 @@ pub async fn handler(state: Data<&Arc<AppState>>) -> Result<WithContentType<Stri
}],
};
let feed = Feed {
title: "rusty-library".to_string(),
id: "rusty:catalog".to_string(),
updated: now,
icon: "favicon.ico".to_string(),
author,
links: vec![home_link, self_link],
entries: vec![books_entry],
};
let feed = create_feed(now, self_link, vec![], vec![books_entry]);
let xml = feed.as_xml().map_err(HandlerError::OpdsError)?;
Ok(xml.with_content_type("application/atom+xml"))