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

@ -1,7 +1,11 @@
use serde::Serialize;
use time::OffsetDateTime;
use super::{content::Content, link::Link};
use crate::data::book::Book;
use super::{
author::Author, content::Content, link::Link, media_type::MediaType, relation::Relation,
};
#[derive(Debug, Serialize)]
#[serde(rename = "entry")]
@ -11,10 +15,46 @@ pub struct Entry {
#[serde(with = "time::serde::rfc3339")]
pub updated: OffsetDateTime,
pub content: Content,
pub author: Option<Author>,
#[serde(rename = "link")]
pub links: Vec<Link>,
}
impl From<Book> for Entry {
fn from(value: Book) -> Self {
let author = Author {
name: value.clone().author.name,
uri: format!("/opds/authors/{}", value.author.id),
email: None,
};
let mut links = vec![Link {
href: format!("/cover/{}", value.id),
media_type: MediaType::Jpeg,
rel: Relation::Image,
title: None,
count: None,
}];
let mut format_links: Vec<Link> = value
.formats
.iter()
.map(|(key, val)| Link::from((&value, (key, val.as_str()))))
.collect();
links.append(&mut format_links);
Self {
title: value.title.clone(),
id: format!("urn:uuid:{}", value.uuid),
updated: value.last_modified,
content: Content {
media_type: MediaType::Html,
content: value.description.clone().unwrap_or("".to_string()),
},
author: Some(author),
links,
}
}
}
#[cfg(test)]
mod tests {
use quick_xml::se::to_string;
@ -33,6 +73,7 @@ mod tests {
media_type: MediaType::Text,
content: "All authors".to_string(),
},
author: None,
links: vec![
Link {
href: "/opds".to_string(),

View file

@ -1,5 +1,7 @@
use serde::Serialize;
use crate::data::book::{Book, Format};
use super::{media_type::MediaType, relation::Relation};
#[derive(Debug, Serialize)]
@ -19,6 +21,20 @@ pub struct Link {
pub count: Option<u64>,
}
impl From<(&Book, (&Format, &str))> for Link {
fn from(value: (&Book, (&Format, &str))) -> Self {
let format = value.1 .0.clone();
let media_type: MediaType = format.into();
Self {
href: format!("/book/{}/{}", value.0.id, value.1 .0),
media_type,
rel: media_type.into(),
title: Some(value.1 .0 .0.clone()),
count: None,
}
}
}
#[cfg(test)]
mod tests {
use quick_xml::se::to_string;

View file

@ -1,6 +1,8 @@
use serde_with::SerializeDisplay;
#[derive(Debug, SerializeDisplay)]
use crate::data::book::Format;
#[derive(Debug, Copy, Clone, SerializeDisplay)]
pub enum MediaType {
Acquisition,
Epub,
@ -11,6 +13,16 @@ pub enum MediaType {
Text,
}
impl From<Format> for MediaType {
fn from(value: Format) -> Self {
match value.0.as_ref() {
"epub" => MediaType::Epub,
"pdf" => MediaType::Pdf,
_ => MediaType::Text,
}
}
}
impl std::fmt::Display for MediaType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {

View file

@ -1,5 +1,7 @@
use serde_with::SerializeDisplay;
use super::media_type::MediaType;
#[derive(Debug, SerializeDisplay)]
pub enum Relation {
Image,
@ -7,6 +9,21 @@ pub enum Relation {
Start,
Subsection,
Thumbnail,
Acquisition,
}
impl From<MediaType> for Relation {
fn from(value: MediaType) -> Self {
match value {
MediaType::Acquisition => Relation::Acquisition,
MediaType::Epub => Relation::Acquisition,
MediaType::Html => Relation::Acquisition,
MediaType::Jpeg => Relation::Image,
MediaType::Navigation => Relation::Myself,
MediaType::Pdf => Relation::Acquisition,
MediaType::Text => Relation::Acquisition,
}
}
}
impl std::fmt::Display for Relation {
@ -17,6 +34,7 @@ impl std::fmt::Display for Relation {
Relation::Start => write!(f, "start"),
Relation::Subsection => write!(f, "subsection"),
Relation::Thumbnail => write!(f, "http://opds-spec.org/image/thumbnail"),
Relation::Acquisition => write!(f, "http://opds-spec.org/acquisition"),
}
}
}