1use ahash::AHashMap;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum PageProgressionDirection {
8 #[default]
9 Ltr,
10 Rtl,
11 Default,
12}
13
14#[derive(Debug, Clone, Default, Serialize, Deserialize)]
16pub struct Metadata {
17 pub title: String,
18 pub creators: Vec<String>,
19 pub publishers: Vec<String>,
20 pub languages: Vec<String>,
21 pub rights: Option<String>,
22 pub description: Option<String>,
23 pub identifier: Option<String>,
24 pub pub_date: Option<String>,
25 pub modified_date: Option<String>,
26 pub subjects: Vec<String>,
27 pub cover_id: Option<String>,
28 pub cover_href: Option<String>,
29 pub direction: PageProgressionDirection,
30 pub meta_properties: AHashMap<String, String>,
31 pub accessibility: AccessibilityMetadata,
32}
33
34impl Metadata {
35 pub fn creator(&self) -> &str {
37 self.creators.first().map(|s| s.as_str()).unwrap_or("")
38 }
39
40 pub fn publisher(&self) -> Option<&str> {
42 self.publishers.first().map(|s| s.as_str())
43 }
44
45 pub fn language(&self) -> &str {
47 self.languages.first().map(|s| s.as_str()).unwrap_or("")
48 }
49}
50
51#[derive(Debug, Clone, Default, Serialize, Deserialize)]
53pub struct AccessibilityMetadata {
54 pub access_modes: Vec<String>,
55 pub access_modes_sufficient: Vec<Vec<String>>,
56 pub accessibility_features: Vec<String>,
57 pub accessibility_hazards: Vec<String>,
58 pub accessibility_summary: Option<String>,
59 pub certified_by: Option<String>,
60 pub certifier_credential: Option<String>,
61 pub certifier_report: Option<String>,
62 pub is_accessible: bool,
63}
64
65impl AccessibilityMetadata {
66 pub fn has_alternative_text(&self) -> bool {
68 self.accessibility_features
69 .iter()
70 .any(|f| f.contains("alternativeText"))
71 }
72
73 pub fn has_structural_navigation(&self) -> bool {
75 self.accessibility_features
76 .iter()
77 .any(|f| f.contains("structuralNavigation") || f.contains("tableOfContents"))
78 }
79
80 pub fn is_screen_reader_friendly(&self) -> bool {
82 self.access_modes.iter().any(|m| m == "textual") && self.has_structural_navigation()
83 }
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct ManifestItem {
89 pub id: String,
90 pub href: String,
91 pub full_path: String,
92 pub media_type: String,
93 pub properties: Vec<String>,
94 pub fallback: Option<String>,
95 pub media_overlay: Option<String>,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct SpineItem {
101 pub idref: String,
102 pub linear: bool,
103 pub properties: Vec<String>,
104 pub index: usize,
105 pub href: String,
106 pub media_type: String,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct GuideItem {
112 pub type_: String,
113 pub title: String,
114 pub href: String,
115 pub full_path: String,
116}